#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 #else #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 ); tcsetattr( STDIN_FILENO, TCSANOW, &newattr ); ch = getchar(); tcsetattr( STDIN_FILENO, TCSANOW, &oldattr ); return ch; } /* reads from keypress, echoes */ int getche(void) { struct termios oldattr, newattr; int ch; tcgetattr( STDIN_FILENO, &oldattr ); newattr = oldattr; newattr.c_lflag &= ~( ICANON ); 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) { *v = *h = 0; vt100CursorPos(1000000, 1000000); printf("\033[6n"); getch(); getch(); int c; while ((c = getch()) != ';') *v = (10*(*v)+(c-'0')); while ((c = getch()) != 'R') *h = (10*(*h)+(c-'0')); } // 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() { int c = GetChar(); ungetch(c); 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 = peekch()), (c != '\r') && (c != '\n')) { JSONNodePush(result, JSONNodeNewStr(GetStr())); JSONNodePush(result, GetNode(result)); } getch(); break; } case 'a': { result->kind = JSONNodeKind_Arr; while ((c = peekch()), (c != '\r') && (c != '\n')) { JSONNodePush(result, GetNode(result)); } getch(); 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; }