#include #include #include #include #include /* 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 #include #else #include #include #include #include /* 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 vt100GetCursor(int * v, int * h) { *v = *h = 0; printf("\033[6n"); getch(); getch(); int c; while ((c = getch()) != ';') *v = (10*(*v)+(c-'0')); while ((c = getch()) != 'R') *h = (10*(*h)+(c-'0')); } 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_COUNT } 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(" "); } static int currV = 0; static int currH = 0; void JSONNodePrint(JSONNode * node, JSONNode * currNode) { 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, currNode); 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, currNode); ptr = ptr->next; printf("%s", (ptr == NULL ? "" : ", ")); } printf(" ]"); break; } } if (currNode == node) { int currOffsets[JSONNodeKind_COUNT]; currOffsets[JSONNodeKind_Nul] = 0; currOffsets[JSONNodeKind_Int] = 0; currOffsets[JSONNodeKind_Str] = 1; currOffsets[JSONNodeKind_Obj] = 1; currOffsets[JSONNodeKind_Arr] = 2; vt100GetCursor(&currV, &currH); currH -= currOffsets[node->kind]; } } // Input JSONNode * g_DrawNode = NULL; JSONNode * g_CurrNode = NULL; void Draw(void) { vt100ClearScreen(); vt100CursorHome(); if (g_DrawNode != NULL) { JSONNodePrint(g_DrawNode, g_CurrNode); vt100CursorPos(currV, currH); } } int GetChar() { Draw(); int c = getch(); return c; } int PeekChar() { Draw(); int c = peekch(); return c; } void GetInt(JSONNode * node) { char intStr[16] = ""; int intStrLen = 0; size_t * i = &node->data; int c; while ((c = GetChar()), (c != '\r') && (c != '\n')) { if ((c == 8 || c == 127) && intStrLen > 0) { intStrLen--; intStr[intStrLen] = '\0'; *i /= 10; } else if (intStrLen < 16 - 1 && (c >= '0' && c <= '9')) { intStr[intStrLen++] = c; intStr[intStrLen] = '\0'; *i *= 10; *i += c - '0'; } } } void GetStr(JSONNode * node) { node->data = (size_t)NEWARR(char, 16); int strLen = 0; char * str = (char *)node->data; int c; 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; strLen++; str[strLen] = '\0'; } } } void GetNode(JSONNode * parent, JSONNode * node) { int c = GetChar(); JSONNode * result = node; g_CurrNode = node; if (parent == NULL) g_DrawNode = result; if (parent != NULL && result != NULL) JSONNodePush(parent, result); switch (c) { case 'i': { result->kind = JSONNodeKind_Int; GetInt(result); break; } case 's': { result->kind = JSONNodeKind_Str; GetStr(result); break; } case 'o': { result->kind = JSONNodeKind_Obj; while ((c = PeekChar()), (c != '\r') && (c != '\n')) { JSONNode * newNode; newNode = JSONNodeNewStr(""); g_CurrNode = newNode; JSONNodePush(result, newNode); GetStr(newNode); newNode = JSONNodeNewNul(); JSONNodePush(result, newNode); GetNode(result, newNode); } g_CurrNode = result; GetChar(); break; } case 'a': { result->kind = JSONNodeKind_Arr; while ((c = PeekChar()), (c != '\r') && (c != '\n')) { JSONNode * newNode = JSONNodeNewNul(); g_CurrNode = newNode; JSONNodePush(result, newNode); GetNode(result, newNode); } g_CurrNode = result; GetChar(); break; } /* case 8: case 127: JSONNodePop(parent); JSONNode * newNode = JSONNodeNewNul(); GetNode(parent, newNode); break; */ case 't': result->kind = JSONNodeKind_Int; result->data = (size_t)GetChar(); break; } } int main() { Draw(); JSONNode * n = JSONNodeNewNul(); GetNode(NULL, n); //JSONNode * n = TestNode(); vt100ClearScreen(); vt100CursorHome(); JSONNodePrint(n, NULL); printf("\n"); // JSONFree(n); return 0; }