-#include <stdio.h>\r
-\r
-#ifdef _WIN32\r
-#include <conio.h>\r
-#else\r
-#include <termios.h>\r
-#include <unistd.h>\r
-#include <stdio.h>\r
-\r
-/* reads from keypress, doesn't echo */\r
-int getch(void)\r
-{\r
- struct termios oldattr, newattr;\r
- int ch;\r
- tcgetattr( STDIN_FILENO, &oldattr );\r
- newattr = oldattr;\r
- newattr.c_lflag &= ~( ICANON | ECHO );\r
- tcsetattr( STDIN_FILENO, TCSANOW, &newattr );\r
- ch = getchar();\r
- tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );\r
- return ch;\r
-}\r
-\r
-/* reads from keypress, echoes */\r
-int getche(void)\r
-{\r
- struct termios oldattr, newattr;\r
- int ch;\r
- tcgetattr( STDIN_FILENO, &oldattr );\r
- newattr = oldattr;\r
- newattr.c_lflag &= ~( ICANON );\r
- tcsetattr( STDIN_FILENO, TCSANOW, &newattr );\r
- ch = getchar();\r
- tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );\r
- return ch;\r
-}\r
-#endif\r
-\r
-#define ASCII_ESC 27\r
-\r
-int main() {\r
- int c;\r
- printf("Hallo\n");\r
- c = getch();\r
- printf("%c[2J", ASCII_ESC);\r
- printf("%c[H", ASCII_ESC);\r
- printf("c: %c\n", c);\r
-\r
- c = getch();\r
-\r
- return 0;\r
-}
\ No newline at end of file
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+/* TODO
+- whitelist input on GetStr/GetInt
+*/
+
+// Memory
+
+#define NEW(TYPE) ((TYPE *)calloc(1, sizeof(TYPE)))
+#define NEWARR(TYPE, NUM) ((TYPE *)calloc(NUM, sizeof(TYPE)))
+
+
+// getch
+
+#ifdef _WIN32
+#include <windows.h>
+#include <conio.h>
+#else
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <stdio.h>
+
+/* reads from keypress, doesn't echo */
+int getch(void)
+{
+ struct termios oldattr, newattr;
+ int ch;
+ tcgetattr( STDIN_FILENO, &oldattr );
+ newattr = oldattr;
+ newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?)
+ tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
+ ch = getchar();
+ tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
+ return ch;
+}
+
+/* ungets keypress */
+void ungetch(int ch)
+{
+ struct termios oldattr, newattr;
+ tcgetattr( STDIN_FILENO, &oldattr );
+ newattr = oldattr;
+ newattr.c_lflag &= ~( ICANON | ECHO );
+ tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
+ ungetc(ch, stdin);
+ tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
+}
+#endif
+
+int
+peekch() {
+ int c = getch();
+ //ungetc(c, stdin);
+ ungetch(c);
+ return c;
+}
+
+
+// VT100
+
+#define ASCII_ESC 27
+
+void vt100Escape(const char * str, ...) {
+ va_list args;
+ va_start(args, str);
+
+ printf("%c", ASCII_ESC);
+ vprintf(str, args);
+}
+
+void vt100ClearScreen() { vt100Escape("[2J"); }
+void vt100CursorHome() { vt100Escape("[H"); }
+void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); }
+void vt100SaveCursor() { vt100Escape("7"); }
+void vt100RestoreCursor() { vt100Escape("8"); }
+void vt100GetScreenSize(int * v, int * h) {
+#ifdef _WIN32
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+ *h = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+ *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+#else
+ struct winsize w;
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
+ *h = w.ws_row;
+ *v = w.ws_col;
+#endif
+}
+
+
+// JSON
+
+typedef enum {
+ JSONNodeKind_Nul,
+ JSONNodeKind_Int,
+ JSONNodeKind_Str,
+ JSONNodeKind_Obj,
+ JSONNodeKind_Arr,
+} JSONNodeKind;
+
+struct JSONNode;
+typedef struct JSONNode {
+ JSONNodeKind kind;
+ size_t data;
+ struct JSONNode * parent;
+ struct JSONNode * children;
+ struct JSONNode * next;
+} JSONNode;
+
+JSONNode *
+JSONNodeNew(JSONNodeKind kind, size_t data) {
+ JSONNode * result = NEW(JSONNode);
+ result->kind = kind;
+ result->data = data;
+ return result;
+}
+
+JSONNode *
+JSONNodeNewNul() {
+ return JSONNodeNew(JSONNodeKind_Nul, (size_t)NULL);
+}
+
+JSONNode *
+JSONNodeNewInt(int i) {
+ return JSONNodeNew(JSONNodeKind_Int, (size_t)i);
+}
+
+JSONNode *
+JSONNodeNewStr(const char * str) {
+ return JSONNodeNew(JSONNodeKind_Str, (size_t)str);
+}
+
+JSONNode *
+JSONNodeNewObj() {
+ return JSONNodeNew(JSONNodeKind_Obj, (size_t)NULL);
+}
+
+JSONNode *
+JSONNodeNewArr() {
+ return JSONNodeNew(JSONNodeKind_Arr, (size_t)NULL);
+}
+
+JSONNode *
+JSONNodePush(JSONNode * this, JSONNode * that) {
+ if (this->children == NULL) {
+ this->children = that;
+ }
+ else {
+ JSONNode * lastNode = this->children;
+ while (lastNode->next != NULL)
+ lastNode = lastNode->next;
+ lastNode->next = that;
+ }
+ that->parent = this;
+ that->next = NULL;
+
+ return that;
+}
+
+void
+JSONNodePop(JSONNode * this) {
+ if (this != NULL) {
+ JSONNode * ptr = this->children;
+
+ if (ptr == NULL) { // no children
+ JSONNodePop(this->parent);
+ }
+ else if (ptr->next == NULL) { // one child
+ this->children = NULL;
+
+ }
+ else { // more than one child
+ while (ptr->next->next != NULL)
+ ptr = ptr->next;
+ ptr->next = NULL;
+ }
+ }
+}
+
+void
+Indent(int indent) {
+ for (int i = 0; i < indent; i++)
+ printf(" ");
+}
+
+void
+JSONNodePrint(JSONNode * node) {
+ if (node == NULL)
+ return;
+
+ static int indent;
+ if (node->parent == NULL)
+ indent = 0;
+
+ switch (node->kind) {
+ case JSONNodeKind_Nul: {
+ printf("null");
+ break;
+ }
+ case JSONNodeKind_Int: {
+ int i = (int)node->data;
+ printf("%d", i);
+ break;
+ }
+ case JSONNodeKind_Str: {
+ char * str = (char *)node->data;
+ printf("\"%s\"", str == NULL ? "" : str);
+ break;
+ }
+ case JSONNodeKind_Obj: {
+ printf("{\n");
+ JSONNode * ptr = node->children;
+ indent++;
+ while (ptr != NULL) {
+ char * key = (char *)ptr->data;
+ JSONNode * value = ptr->next;
+ Indent(indent);
+ printf("\"%s\": ", key);
+ JSONNodePrint(value);
+ if (ptr->next != NULL)
+ ptr = ptr->next->next;
+ else
+ ptr = NULL;
+ printf("%s\n", (ptr == NULL ? "" : ","));
+ }
+ indent--;
+ Indent(indent);
+ printf("}");
+ break;
+ }
+ case JSONNodeKind_Arr: {
+ printf("[ ");
+ JSONNode * ptr = node->children;
+ while (ptr != NULL) {
+ JSONNode * value = ptr;
+ JSONNodePrint(value);
+ ptr = ptr->next;
+ printf("%s", (ptr == NULL ? "" : ", "));
+ }
+ printf(" ]");
+ break;
+ }
+ }
+}
+
+
+// Input
+
+JSONNode * g_DrawNode = NULL;
+const char * g_DrawStr = "";
+
+void
+Draw(void) {
+ vt100ClearScreen();
+ vt100CursorHome();
+
+ if (g_DrawNode != NULL)
+ JSONNodePrint(g_DrawNode);
+
+ int v, h;
+ vt100GetScreenSize(&v, &h);
+ vt100CursorPos(v, 0);
+ printf("> %s", g_DrawStr);
+
+ vt100CursorPos(v, strlen(g_DrawStr) + 3);
+}
+
+int
+GetChar() {
+ Draw();
+ int c = getch();
+ return c;
+}
+
+int
+PeekChar() {
+ Draw();
+ int c = peekch();
+ return c;
+}
+
+int
+GetInt() {
+ static char intStr[16];
+ intStr[0] = '\0';
+ int intStrLen = 0;
+ int result = 0;
+ int c;
+ g_DrawStr = intStr;
+ while ((c = GetChar()), (c != '\r') && (c != '\n')) {
+ if ((c == 8 || c == 127) && intStrLen > 0) {
+ intStrLen--;
+ intStr[intStrLen] = '\0';
+ result /= 10;
+ }
+ else if (intStrLen < 16 - 1 && (c >= '0' && c <= '9')) {
+ intStr[intStrLen++] = c;
+ intStr[intStrLen] = '\0';
+ result *= 10;
+ result += c - '0';
+ }
+ }
+ g_DrawStr = "";
+ return result;
+}
+
+char *
+GetStr() {
+ char * str = NEWARR(char, 16);
+ int strLen = 0;
+ int c;
+ g_DrawStr = str;
+ while ((c = GetChar()), (c != '\r') && (c != '\n')) {
+ if ((c == 8 || c == 127) && strLen > 0) {
+ strLen--;
+ str[strLen] = '\0';
+ }
+ else if (strLen < 16 - 1) {
+ str[strLen++] = c;
+ str[strLen] = '\0';
+ }
+ }
+ g_DrawStr = "";
+ return str;
+}
+
+JSONNode *
+GetNode(JSONNode * parent) {
+ int c = GetChar();
+
+ JSONNode * result = JSONNodeNewNul();
+
+ if (parent == NULL)
+ g_DrawNode = result;
+
+ if (parent != NULL && result != NULL)
+ JSONNodePush(parent, result);
+
+ switch (c) {
+ case 'i': {
+ result->kind = JSONNodeKind_Int;
+ result->data = (size_t)GetInt();
+ break;
+ }
+ case 's': {
+ result->kind = JSONNodeKind_Str;
+ result->data = (size_t)GetStr();
+ break;
+ }
+ case 'o': {
+ result->kind = JSONNodeKind_Obj;
+ while ((c = PeekChar()), (c != '\r') && (c != '\n')) {
+ JSONNodePush(result, JSONNodeNewStr(GetStr()));
+
+ JSONNodePush(result, GetNode(result));
+ }
+ GetChar();
+ break;
+ }
+ case 'a': {
+ result->kind = JSONNodeKind_Arr;
+ while ((c = PeekChar()), (c != '\r') && (c != '\n')) {
+ JSONNodePush(result, GetNode(result));
+ }
+ GetChar();
+ break;
+ }
+ case 8:
+ case 127:
+ JSONNodePop(parent);
+ result = GetNode(parent);
+ break;
+ case 't':
+ result->kind = JSONNodeKind_Int;
+ result->data = (size_t)GetChar();
+ break;
+ }
+
+ return result;
+}
+
+
+
+
+int main() {
+ Draw();
+
+ JSONNode * n = GetNode(NULL);
+ //JSONNode * n = TestNode();
+
+ vt100ClearScreen();
+ vt100CursorHome();
+ JSONNodePrint(n);
+ printf("\n");
+
+ // JSONFree(n);
+
+ return 0;
+}