]> gitweb.ps.run Git - iftint/blob - main2.c
edit in place :D
[iftint] / main2.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdbool.h>
6
7 /* TODO
8 - whitelist input on GetStr/GetInt
9 */
10
11 // Memory
12
13 #define NEW(TYPE) ((TYPE *)calloc(1, sizeof(TYPE)))
14 #define NEWARR(TYPE, NUM) ((TYPE *)calloc(NUM, sizeof(TYPE)))
15
16
17 // getch
18
19 #ifdef _WIN32
20 #include <windows.h>
21 #include <conio.h>
22 #else
23 #include <sys/ioctl.h>
24 #include <termios.h>
25 #include <unistd.h>
26 #include <stdio.h>
27
28 /* reads from keypress, doesn't echo */
29 int getch(void)
30 {
31     struct termios oldattr, newattr;
32     int ch;
33     tcgetattr( STDIN_FILENO, &oldattr );
34     newattr = oldattr;
35     newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?)
36     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
37     ch = getchar();
38     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
39     return ch;
40 }
41
42 /* ungets keypress */
43 void ungetch(int ch)
44 {
45     struct termios oldattr, newattr;
46     tcgetattr( STDIN_FILENO, &oldattr );
47     newattr = oldattr;
48     newattr.c_lflag &= ~( ICANON | ECHO );
49     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
50     ungetc(ch, stdin);
51     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
52 }
53 #endif
54
55 int
56 peekch() {
57     int c = getch();
58     //ungetc(c, stdin);
59     ungetch(c);
60     return c;
61 }
62
63
64 // VT100
65
66 #define ASCII_ESC 27
67
68 void vt100Escape(const char * str, ...) {
69     va_list args;
70     va_start(args, str);
71
72     printf("%c", ASCII_ESC);
73     vprintf(str, args);
74 }
75
76 void vt100ClearScreen() { vt100Escape("[2J"); }
77 void vt100CursorHome() { vt100Escape("[H"); }
78 void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); }
79 void vt100SaveCursor() { vt100Escape("7"); }
80 void vt100RestoreCursor() { vt100Escape("8"); }
81 void vt100GetScreenSize(int * v, int * h) {
82 #ifdef _WIN32
83     CONSOLE_SCREEN_BUFFER_INFO csbi;
84     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
85     *h = csbi.srWindow.Right - csbi.srWindow.Left + 1;
86     *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
87 #else
88     struct winsize w;
89     ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
90     *h = w.ws_row;
91     *v = w.ws_col;
92 #endif
93 }
94
95
96 // JSON
97
98 typedef enum {
99     JSONNodeKind_Nul,
100     JSONNodeKind_Int,
101     JSONNodeKind_Str,
102     JSONNodeKind_Obj,
103     JSONNodeKind_Arr,
104 } JSONNodeKind;
105
106 struct JSONNode;
107 typedef struct JSONNode {
108     JSONNodeKind kind;
109     size_t data;
110     struct JSONNode * parent;
111     struct JSONNode * children;
112     struct JSONNode * next;
113 } JSONNode;
114
115 JSONNode *
116 JSONNodeNew(JSONNodeKind kind, size_t data) {
117     JSONNode * result = NEW(JSONNode);
118     result->kind = kind;
119     result->data = data;
120     return result;
121 }
122
123 JSONNode *
124 JSONNodeNewNul() {
125     return JSONNodeNew(JSONNodeKind_Nul, (size_t)NULL);
126 }
127
128 JSONNode *
129 JSONNodeNewInt(int i) {
130     return JSONNodeNew(JSONNodeKind_Int, (size_t)i);
131 }
132
133 JSONNode *
134 JSONNodeNewStr(const char * str) {
135     return JSONNodeNew(JSONNodeKind_Str, (size_t)str);
136 }
137
138 JSONNode *
139 JSONNodeNewObj() {
140     return JSONNodeNew(JSONNodeKind_Obj, (size_t)NULL);
141 }
142
143 JSONNode *
144 JSONNodeNewArr() {
145     return JSONNodeNew(JSONNodeKind_Arr, (size_t)NULL);
146 }
147
148 JSONNode *
149 JSONNodePush(JSONNode * this, JSONNode * that) {
150     if (this->children == NULL) {
151         this->children = that;
152     }
153     else {
154         JSONNode * lastNode = this->children;
155         while (lastNode->next != NULL)
156             lastNode = lastNode->next;
157         lastNode->next = that;
158     }
159     that->parent = this;
160     that->next = NULL;
161     
162     return that;
163 }
164
165 void
166 JSONNodePop(JSONNode * this) {
167     if (this != NULL) {
168         JSONNode * ptr = this->children;
169
170         if (ptr == NULL) { // no children
171             JSONNodePop(this->parent);
172         }
173         else if (ptr->next == NULL) { // one child
174             this->children = NULL;
175             
176         }
177         else { // more than one child
178             while (ptr->next->next != NULL)
179                 ptr = ptr->next;
180             ptr->next = NULL;
181         }
182     }
183 }
184
185 void
186 Indent(int indent) {
187     for (int i = 0; i < indent; i++)
188         printf("  ");
189 }
190
191 void
192 JSONNodePrint(JSONNode * node) {
193     if (node == NULL)
194         return;
195     
196     static int indent;
197     if (node->parent == NULL)
198         indent = 0;
199     
200     switch (node->kind) {
201     case JSONNodeKind_Nul: {
202         printf("null");
203         break;
204     }
205     case JSONNodeKind_Int: {
206         int i = (int)node->data;
207         printf("%d", i);
208         break;
209     }
210     case JSONNodeKind_Str: {
211         char * str = (char *)node->data;
212         printf("\"%s\"", str == NULL ? "" : str);
213         break;
214     }
215     case JSONNodeKind_Obj: {
216         printf("{\n");
217         JSONNode * ptr = node->children;
218         indent++;
219         while (ptr != NULL) {
220             char * key = (char *)ptr->data;
221             JSONNode * value = ptr->next;
222             Indent(indent);
223             printf("\"%s\": ", key);
224             JSONNodePrint(value);
225             if (ptr->next != NULL)
226                 ptr = ptr->next->next;
227             else
228                 ptr = NULL;
229             printf("%s\n", (ptr == NULL ? "" : ","));
230         }
231         indent--;
232         Indent(indent);
233         printf("}");
234         break;
235     }
236     case JSONNodeKind_Arr: {
237         printf("[ ");
238         JSONNode * ptr = node->children;
239         while (ptr != NULL) {
240             JSONNode * value = ptr;
241             JSONNodePrint(value);
242             ptr = ptr->next;
243             printf("%s", (ptr == NULL ? "" : ", "));
244         }
245         printf(" ]");
246         break;
247     }
248     }
249 }
250
251
252 // Input
253
254 JSONNode * g_DrawNode = NULL;
255 const char * g_DrawStr = "";
256
257 void
258 Draw(void) {
259     vt100ClearScreen();
260     vt100CursorHome();
261     
262     if (g_DrawNode != NULL)
263         JSONNodePrint(g_DrawNode);
264
265     int v, h;
266     vt100GetScreenSize(&v, &h);
267     vt100CursorPos(v, 0);
268     printf("> %s", g_DrawStr);
269
270     vt100CursorPos(v, strlen(g_DrawStr) + 3);
271 }
272
273 int
274 GetChar() {
275     Draw();
276     int c = getch();
277     return c;
278 }
279
280 int
281 PeekChar() {
282     Draw();
283     int c = peekch();
284     return c;
285 }
286
287 void
288 GetInt(JSONNode * node) {
289     char intStr[16] = "";
290     int intStrLen = 0;
291     
292     size_t * i = &node->data;
293     
294     int c;
295     g_DrawStr = intStr;
296     while ((c = GetChar()), (c != '\r') && (c != '\n')) {
297         if ((c == 8 || c == 127) && intStrLen > 0) {
298             intStrLen--;
299             intStr[intStrLen] = '\0';
300             *i /= 10;
301         }
302         else if (intStrLen < 16 - 1 && (c >= '0' && c <= '9')) {
303             intStr[intStrLen++] = c;
304             intStr[intStrLen] = '\0';
305             *i *= 10;
306             *i += c - '0';
307         }
308     }
309     g_DrawStr = "";
310 }
311
312 void
313 GetStr(JSONNode * node) {
314     node->data = (size_t)NEWARR(char, 16);
315     int strLen = 0;
316
317     char * str = (char *)node->data;
318     
319     int c;
320     g_DrawStr = str;
321     while ((c = GetChar()), (c != '\r') && (c != '\n')) {
322         if ((c == 8 || c == 127) && strLen > 0) {
323             strLen--;
324             str[strLen] = '\0';
325         }
326         else if (strLen < 16 - 1) {
327             str[strLen++] = c;
328             str[strLen] = '\0';
329         }
330     }
331     g_DrawStr = "";
332 }
333
334 void
335 GetNode(JSONNode * parent, JSONNode * node) {
336     int c = GetChar();
337
338     JSONNode * result = node;
339
340     if (parent == NULL)
341         g_DrawNode = result;
342
343     if (parent != NULL && result != NULL)
344         JSONNodePush(parent, result);
345
346     switch (c) {
347     case 'i': {
348         result->kind = JSONNodeKind_Int;
349         GetInt(result);
350         break;
351     }
352     case 's': {
353         result->kind = JSONNodeKind_Str;
354         GetStr(result);
355         break;
356     }
357     case 'o': {
358         result->kind = JSONNodeKind_Obj;
359         while ((c = PeekChar()), (c != '\r') && (c != '\n')) {
360             JSONNode * newNode;
361             
362             newNode = JSONNodeNewStr("");
363             JSONNodePush(result, newNode);
364             GetStr(newNode);
365
366             newNode = JSONNodeNewNul();
367             JSONNodePush(result, newNode);
368             GetNode(result, newNode);
369         }
370         GetChar();
371         break;
372     }
373     case 'a': {
374         result->kind = JSONNodeKind_Arr;
375         while ((c = PeekChar()), (c != '\r') && (c != '\n')) {
376             JSONNode * newNode = JSONNodeNewNul();
377             JSONNodePush(result, newNode);
378             GetNode(result, newNode);
379         }
380         GetChar();
381         break;
382     }
383     /*
384     case 8:
385     case 127:
386         JSONNodePop(parent);
387         JSONNode * newNode = JSONNodeNewNul();
388         GetNode(parent, newNode);
389         break;
390     */
391     case 't':
392         result->kind = JSONNodeKind_Int;
393         result->data = (size_t)GetChar();
394         break;
395     }
396 }
397
398
399
400
401 int main() {
402     Draw();
403
404     JSONNode * n = JSONNodeNewNul();
405     GetNode(NULL, n);
406     //JSONNode * n = TestNode();
407
408     vt100ClearScreen();
409     vt100CursorHome();
410     JSONNodePrint(n);
411     printf("\n");
412
413     // JSONFree(n);
414
415     return 0;
416 }