]> gitweb.ps.run Git - iftint/blob - main2.c
proof of concept
[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 // Util
18
19 bool
20 charInString(char c, const char * str) {
21     for (int i = 0; i < strlen(str); i++)
22         if (c == str[i])
23             return true;
24     return false;
25 }
26
27 bool
28 isNewline(char c) {
29     return c == '\n' || c == '\r';
30 }
31 bool
32 isBackspace(char c) {
33     return c == 8 || c == 127;
34 }
35
36
37 // Key defines
38
39 #define KEY_CTRL_C 3
40 #define KEY_BACKSPACE1 8
41 #define KEY_BACKSPACE2 127
42
43
44 // getch
45
46 #ifdef _WIN32
47 #include <windows.h>
48 #include <conio.h>
49 #else
50 #include <sys/ioctl.h>
51 #include <termios.h>
52 #include <unistd.h>
53 #include <stdio.h>
54
55 /* reads from keypress, doesn't echo */
56 int getch(void)
57 {
58     struct termios oldattr, newattr;
59     int ch;
60     tcgetattr( STDIN_FILENO, &oldattr );
61     newattr = oldattr;
62     newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?)
63     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
64     ch = getchar();
65     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
66     return ch;
67 }
68
69 /* ungets keypress */
70 void ungetch(int ch)
71 {
72     struct termios oldattr, newattr;
73     tcgetattr( STDIN_FILENO, &oldattr );
74     newattr = oldattr;
75     newattr.c_lflag &= ~( ICANON | ECHO );
76     tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
77     ungetc(ch, stdin);
78     tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
79 }
80 #endif
81
82 int
83 peekch() {
84     int c = getch();
85     //ungetc(c, stdin);
86     ungetch(c);
87     return c;
88 }
89
90
91 // VT100
92
93 #define ASCII_ESC 27
94
95 void vt100Escape(const char * str, ...) {
96     va_list args;
97     va_start(args, str);
98
99     printf("%c", ASCII_ESC);
100     vprintf(str, args);
101 }
102
103 void vt100ClearScreen() { vt100Escape("[2J"); }
104 void vt100CursorHome() { vt100Escape("[H"); }
105 void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); }
106 void vt100SaveCursor() { vt100Escape("7"); }
107 void vt100RestoreCursor() { vt100Escape("8"); }
108 // void vt100GetCursor(int * v, int * h) {
109 //     *v = *h = 0;
110 //     printf("\033[6n");
111 //     getch(); getch();
112 //     int c;
113 //     while ((c = getch()) != ';')
114 //         *v = (10*(*v)+(c-'0'));
115 //     while ((c = getch()) != 'R')
116 //         *h = (10*(*h)+(c-'0'));
117 // }
118 void vt100GetScreenSize(int * v, int * h) {
119 #ifdef _WIN32
120     CONSOLE_SCREEN_BUFFER_INFO csbi;
121     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
122     *h = csbi.srWindow.Right - csbi.srWindow.Left + 1;
123     *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
124 #else
125     struct winsize w;
126     ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
127     *h = w.ws_row;
128     *v = w.ws_col;
129 #endif
130 }
131 void vt100EnableAlternateBuffer() { vt100Escape("[?1049h"); }
132 void vt100DisableAlternateBuffer() { vt100Escape("[?1049l"); }
133
134
135 // JSON
136
137 typedef enum {
138     JSONNodeKind_Nul,
139     JSONNodeKind_Int,
140     JSONNodeKind_Str,
141     JSONNodeKind_Obj,
142     JSONNodeKind_Key,
143     JSONNodeKind_Arr,
144     JSONNodeKind_COUNT
145 } JSONNodeKind;
146
147 struct JSONNode;
148 typedef struct JSONNode {
149     JSONNodeKind kind;
150     size_t data;
151     struct JSONNode * parent;
152     struct JSONNode * firstChild;
153     int childCount;
154     struct JSONNode * prev;
155     struct JSONNode * next;
156 } JSONNode;
157
158 JSONNode *
159 JSONNodeNew(JSONNodeKind kind) {
160     JSONNode * result = NEW(JSONNode);
161     result->kind = kind;
162     return result;
163 }
164
165 JSONNode *
166 JSONNodePush(JSONNode * this, JSONNode * that) {
167     if (this->firstChild == NULL) {
168         this->firstChild = that;
169     }
170     else {
171         JSONNode * lastNode = this->firstChild;
172         while (lastNode->next != NULL)
173             lastNode = lastNode->next;
174         lastNode->next = that;
175         that->prev = lastNode;
176     }
177     this->childCount++;
178     that->parent = this;
179     
180     return that;
181 }
182
183 JSONNode *
184 JSONNodeRemove(JSONNode * node) {
185     if (node->prev == NULL) { // first child
186         node->parent->firstChild = node->next;
187         if (node->next != NULL)
188             node->next->prev = NULL;
189         return node->parent;
190     }
191     else { // second child
192         node->prev->next = node->next;
193         if (node->next != NULL)
194             node->next->prev = node->prev;
195         return node->prev;
196     }
197 }
198
199 bool
200 JSONNodeEditable(JSONNode * node) {
201     if (node == NULL) return false;
202     else if (node->kind == JSONNodeKind_Int) return true;
203     else if (node->kind == JSONNodeKind_Str) return true;
204     return false;
205 }
206
207 void
208 Indent(int indent) {
209     for (int i = 0; i < indent; i++)
210         printf("  ");
211 }
212
213 void
214 JSONNodePrint(JSONNode * node, JSONNode * currNode) {
215     if (node == NULL)
216         return;
217     
218     static int indent;
219     if (node->parent == NULL)
220         indent = 0;
221
222     if (currNode == node) {
223         vt100SaveCursor();
224     }
225
226     switch (node->kind) {
227     case JSONNodeKind_Nul: {
228         printf("null");
229         break;
230     }
231     case JSONNodeKind_Int: {
232         char * str = (char *)node->data;
233         printf("%s", (str == NULL || strlen(str) == 0) ? "0" : str);
234         break;
235     }
236     case JSONNodeKind_Str: {
237         char * str = (char *)node->data;
238         printf("\"%s\"", str == NULL ? "" : str);
239         break;
240     }
241     case JSONNodeKind_Obj: {
242         printf("{\n");
243         JSONNode * ptr = node->firstChild;
244         indent++;
245         while (ptr != NULL) {
246             Indent(indent);
247             JSONNodePrint(ptr, currNode);
248             JSONNodePrint(ptr->firstChild, currNode);
249             if (ptr->next != NULL)
250                 printf(",");
251             ptr = ptr->next;
252             printf("\n");
253         }
254         indent--;
255         Indent(indent);
256         printf("}");
257         break;
258     }
259     case JSONNodeKind_Key: {
260         char * str = (char *)node->data;
261         printf("\"%s\": ", str == NULL ? "" : str);
262         break;
263     }
264     case JSONNodeKind_Arr: {
265         printf("[\n");
266         JSONNode * ptr = node->firstChild;
267         indent++;
268         while (ptr != NULL) {
269             Indent(indent);
270             JSONNodePrint(ptr, currNode);
271             if (ptr->next != NULL)
272                 printf(",");
273             printf("\n");
274             ptr = ptr->next;
275         }
276         indent--;
277         Indent(indent);
278         printf("]");
279         break;
280     }
281     }
282 }
283
284
285 // Input
286
287 JSONNode * g_DrawNode = NULL;
288 JSONNode * g_CurrNode = NULL;
289
290 void
291 Draw(void) {
292     vt100ClearScreen();
293     vt100CursorHome();
294     
295     if (g_DrawNode != NULL) {
296         JSONNodePrint(g_DrawNode, g_CurrNode);
297         vt100RestoreCursor();
298     }
299 }
300
301 int
302 GetChar() {
303     Draw();
304     int c = getch();
305     return c;
306 }
307
308 int
309 PeekChar() {
310     Draw();
311     int c = peekch();
312     return c;
313 }
314
315 typedef bool(*CharPredicateFunc)(char, int);
316
317 bool predStr(char c, int i) { return c >= 'a' && c <= 'z'; }
318 bool predInt(char c, int i) { return c >= '0' && c <= '9'; }
319
320 void
321 GetInput(JSONNode * node, char c) {
322     if (node->data == (size_t)NULL) {
323         node->data = (size_t)NEWARR(char, 16);
324     }
325     
326     char * str = (char *)node->data;
327     int strLen = strlen(str);
328
329     if (isBackspace(c)) {
330         str[strLen-1] = '\0';
331     }
332     else if (strLen < 16 - 1) {
333         str[strLen] = c;
334         str[strLen+1] = '\0';
335     }
336 }
337
338 JSONNode *
339 GetNode() {
340     JSONNode * result = NULL;
341     JSONNode * node = NULL;
342     int c;
343
344     bool editingNode = false;
345
346     while (true) {
347         Draw();
348         c = getch();
349
350         if (c == KEY_CTRL_C)
351             break;
352
353         if (node == NULL) {
354             /**/ if (c == 'i') { node = JSONNodeNew(JSONNodeKind_Int); editingNode = true; }
355             else if (c == 's') { node = JSONNodeNew(JSONNodeKind_Str); editingNode = true; }
356             else if (c == 'o') { node = JSONNodeNew(JSONNodeKind_Obj); editingNode = true; }
357             else if (c == 'a') { node = JSONNodeNew(JSONNodeKind_Arr); editingNode = true; }
358             g_DrawNode = g_CurrNode = result = node;
359         }
360         else if (node->kind ==JSONNodeKind_Int) {
361             if (editingNode) {
362                 GetInput(node, c);
363             }
364             else {
365                 /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; }
366                 else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; }
367                 else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; }
368                 else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; }
369                 else if (c == 'h') { if (node->prev       != NULL) g_CurrNode = node = node->prev; }
370                 else if (c == 'l') { if (node->next       != NULL) g_CurrNode = node = node->next; }
371                 else if (c == 'k') { if (node->parent     != NULL) g_CurrNode = node = node->parent; }
372                 else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; }
373                 else if (c == ' ') { editingNode = true; }
374                 else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); }
375
376                 g_CurrNode = node;
377             }
378         }
379         else if (node->kind ==JSONNodeKind_Str) {
380             if (editingNode) {
381                 GetInput(node, c);
382             }
383             else {
384                 /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; }
385                 else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; }
386                 else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; }
387                 else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; }
388                 else if (c == 'h') { if (node->prev       != NULL) g_CurrNode = node = node->prev; }
389                 else if (c == 'l') { if (node->next       != NULL) g_CurrNode = node = node->next; }
390                 else if (c == 'k') { if (node->parent     != NULL) g_CurrNode = node = node->parent; }
391                 else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; }
392                 else if (c == ' ') { editingNode = true; }
393                 else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); }
394
395                 g_CurrNode = node;
396             }
397         }
398         else if (node->kind ==JSONNodeKind_Obj) {
399             if (editingNode) {
400                 GetInput(node, c);
401             }
402             else {
403                 /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; }
404                 else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; }
405                 else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; }
406                 else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; }
407                 else if (c == 'h') { if (node->prev       != NULL) g_CurrNode = node = node->prev; }
408                 else if (c == 'l') { if (node->next       != NULL) g_CurrNode = node = node->next; }
409                 else if (c == 'k') { if (node->parent     != NULL) g_CurrNode = node = node->parent; }
410                 else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; }
411                 else if (c == ' ') { editingNode = true; }
412                 else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); }
413
414                 g_CurrNode = node;
415             }
416         }
417         else if (node->kind ==JSONNodeKind_Key) {
418             if (editingNode) {
419                 GetInput(node, c);
420             }
421             else {
422                 /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; }
423                 else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; }
424                 else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; }
425                 else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; }
426                 else if (c == 'h') { if (node->prev       != NULL) g_CurrNode = node = node->prev; }
427                 else if (c == 'l') { if (node->next       != NULL) g_CurrNode = node = node->next; }
428                 else if (c == 'k') { if (node->parent     != NULL) g_CurrNode = node = node->parent; }
429                 else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; }
430                 else if (c == ' ') { editingNode = true; }
431                 else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); }
432
433                 g_CurrNode = node;
434             }
435         }
436         else if (node->kind ==JSONNodeKind_Arr) {
437             if (editingNode) {
438                 GetInput(node, c);
439             }
440             else {
441                 /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; }
442                 else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; }
443                 else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; }
444                 else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; }
445                 else if (c == 'h') { if (node->prev       != NULL) g_CurrNode = node = node->prev; }
446                 else if (c == 'l') { if (node->next       != NULL) g_CurrNode = node = node->next; }
447                 else if (c == 'k') { if (node->parent     != NULL) g_CurrNode = node = node->parent; }
448                 else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; }
449                 else if (c == ' ') { editingNode = true; }
450                 else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); }
451
452                 g_CurrNode = node;
453             }
454         }
455     }
456
457     return result;
458 }
459
460
461
462
463 int main() {
464     vt100EnableAlternateBuffer();
465
466     JSONNode * n = GetNode();
467     
468     vt100DisableAlternateBuffer();
469
470     JSONNodePrint(n, NULL);
471
472     // JSONFree(n);
473
474     return 0;
475 }