]> gitweb.ps.run Git - iftint/blob - main2.c
aeb0c5586d7daa90902f8d1ce203bd3c47c6459a
[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_Arr,
143     JSONNodeKind_COUNT
144 } JSONNodeKind;
145
146 struct JSONNode;
147 typedef struct JSONNode {
148     JSONNodeKind kind;
149     size_t data;
150     struct JSONNode * parent;
151     struct JSONNode * firstChild;
152     int childCount;
153     struct JSONNode * prev;
154     struct JSONNode * next;
155 } JSONNode;
156
157 JSONNode *
158 JSONNodeNew(JSONNodeKind kind) {
159     JSONNode * result = NEW(JSONNode);
160     result->kind = kind;
161     return result;
162 }
163
164 JSONNode *
165 JSONNodePush(JSONNode * this, JSONNode * that) {
166     if (this->firstChild == NULL) {
167         this->firstChild = that;
168     }
169     else {
170         JSONNode * lastNode = this->firstChild;
171         while (lastNode->next != NULL)
172             lastNode = lastNode->next;
173         lastNode->next = that;
174         that->prev = lastNode;
175     }
176     this->childCount++;
177     that->parent = this;
178     
179     return that;
180 }
181
182 JSONNode *
183 JSONNodeRemove(JSONNode * node) {
184     if (node->prev == NULL) { // first child
185         node->parent->firstChild = node->next;
186         if (node->next != NULL)
187             node->next->prev = NULL;
188         return node->parent;
189     }
190     else { // second child
191         node->prev->next = node->next;
192         if (node->next != NULL)
193             node->next->prev = node->prev;
194         return node->prev;
195     }
196 }
197
198 bool
199 JSONNodeEditable(JSONNode * node) {
200     if (node == NULL) return false;
201     else if (node->kind == JSONNodeKind_Int) return true;
202     else if (node->kind == JSONNodeKind_Str) return true;
203     return false;
204 }
205
206 void
207 Indent(int indent) {
208     for (int i = 0; i < indent; i++)
209         printf("  ");
210 }
211
212 void
213 JSONNodePrint(JSONNode * node, JSONNode * currNode) {
214     if (node == NULL)
215         return;
216     
217     static int indent;
218     if (node->parent == NULL)
219         indent = 0;
220
221     if (currNode == node) {
222         vt100SaveCursor();
223     }
224
225     switch (node->kind) {
226     case JSONNodeKind_Nul: {
227         printf("null");
228         break;
229     }
230     case JSONNodeKind_Int: {
231         char * str = (char *)node->data;
232         printf("%s", (str == NULL || strlen(str) == 0) ? "0" : str);
233         break;
234     }
235     case JSONNodeKind_Str: {
236         char * str = (char *)node->data;
237         printf("\"%s\"", str == NULL ? "" : str);
238         break;
239     }
240     case JSONNodeKind_Obj: {
241         printf("{\n");
242         JSONNode * ptr = node->firstChild;
243         indent++;
244         while (ptr != NULL) {
245             Indent(indent);
246             JSONNodePrint(ptr, currNode);
247             printf(": ");
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_Arr: {
260         printf("[\n");
261         JSONNode * ptr = node->firstChild;
262         indent++;
263         while (ptr != NULL) {
264             Indent(indent);
265             JSONNodePrint(ptr, currNode);
266             if (ptr->next != NULL)
267                 printf(",");
268             printf("\n");
269             ptr = ptr->next;
270         }
271         indent--;
272         Indent(indent);
273         printf("]");
274         break;
275     }
276     }
277 }
278
279
280 // Input
281
282 JSONNode * g_DrawNode = NULL;
283 JSONNode * g_CurrNode = NULL;
284
285 void
286 Draw(void) {
287     vt100ClearScreen();
288     vt100CursorHome();
289     
290     if (g_DrawNode != NULL) {
291         JSONNodePrint(g_DrawNode, g_CurrNode);
292         vt100RestoreCursor();
293     }
294 }
295
296 int
297 GetChar() {
298     Draw();
299     int c = getch();
300     return c;
301 }
302
303 int
304 PeekChar() {
305     Draw();
306     int c = peekch();
307     return c;
308 }
309
310 typedef bool(*CharPredicateFunc)(char, int);
311
312 bool predStr(char c, int i) { return c >= 'a' && c <= 'z'; }
313 bool predInt(char c, int i) { return c >= '0' && c <= '9'; }
314
315 JSONNode *
316 GetNode() {
317     JSONNode * result = NULL;
318     JSONNode * node = NULL;
319     int c;
320     int strLen = 0;
321
322     bool editingNode = false;
323
324     while (true) {
325         c = GetChar();
326
327         if (c == KEY_CTRL_C)
328             break;
329
330         /*
331
332         - editing
333           - primitive -> input
334           - obj/arr   -> new node inside
335         - not editing
336           - hjkl      -> movement
337           - isoa
338             - parent=obj -> new key/value node after
339             - parent=arr -> new node after
340             - else       -> nothing
341         */
342
343         if (isNewline(c)) {
344             if (editingNode) {
345                 editingNode = false;
346                 if (node->parent != NULL && node->parent->kind == JSONNodeKind_Obj && node->firstChild != NULL) {
347                     node = node->firstChild;
348                     editingNode = true;
349                 }
350                 else if (node->parent != NULL && node->parent->kind == JSONNodeKind_Str && node->parent->parent != NULL) {
351                     node = node->parent->parent;
352                     editingNode = true;
353                 }
354             }
355             else {
356                 if (node->parent != NULL)
357                     node = node->parent;
358             }
359
360             g_CurrNode = node;
361             
362             continue;
363         }
364
365         if (editingNode) {
366             if (JSONNodeEditable(node)) {
367                 if (node->data == (size_t)NULL) {
368                     node->data = (size_t)NEWARR(char, 16);
369                     strLen = 0;
370                 }
371                 
372                 char * str = (char *)node->data;
373
374                 if (isBackspace(c)) {
375                     str[strLen-1] = '\0';
376                     strLen--;
377                 }
378                 else if (strLen < 16 - 1) {
379                     str[strLen] = c;
380                     str[strLen+1] = '\0';
381                     strLen++;
382                 }
383             }
384             else {
385                 if (node->kind == JSONNodeKind_Obj) {
386                     /**/ if (c == 'i') { node = JSONNodePush(node, JSONNodePush(JSONNodeNew(JSONNodeKind_Str), JSONNodeNew(JSONNodeKind_Int))->parent); }
387                     else if (c == 's') { node = JSONNodePush(node, JSONNodePush(JSONNodeNew(JSONNodeKind_Str), JSONNodeNew(JSONNodeKind_Str))->parent); }
388                     else if (c == 'o') { node = JSONNodePush(node, JSONNodePush(JSONNodeNew(JSONNodeKind_Str), JSONNodeNew(JSONNodeKind_Obj))->parent); }
389                     else if (c == 'a') { node = JSONNodePush(node, JSONNodePush(JSONNodeNew(JSONNodeKind_Str), JSONNodeNew(JSONNodeKind_Arr))->parent); }
390                 }
391                 else if (node->kind == JSONNodeKind_Arr) {
392                     /**/ if (c == 'i') { node = JSONNodePush(node, JSONNodeNew(JSONNodeKind_Int)); }
393                     else if (c == 's') { node = JSONNodePush(node, JSONNodeNew(JSONNodeKind_Str)); }
394                     else if (c == 'o') { node = JSONNodePush(node, JSONNodeNew(JSONNodeKind_Obj)); }
395                     else if (c == 'a') { node = JSONNodePush(node, JSONNodeNew(JSONNodeKind_Arr)); }
396                 }
397                 g_CurrNode = node;
398             }
399         }
400         else {
401             if (node == NULL) {
402                 /**/ if (c == 'i') { node = JSONNodeNew(JSONNodeKind_Int); editingNode = true; }
403                 else if (c == 's') { node = JSONNodeNew(JSONNodeKind_Str); editingNode = true; }
404                 else if (c == 'o') { node = JSONNodeNew(JSONNodeKind_Obj); editingNode = true; }
405                 else if (c == 'a') { node = JSONNodeNew(JSONNodeKind_Arr); editingNode = true; }
406                 g_DrawNode = g_CurrNode = result = node;
407             }
408             // else if (node->kind == JSONNodeKind_Str && node->parent != NULL && node->parent->kind == JSONNodeKind_Obj) {
409                 
410             // }
411             else {
412                 /**/ if (c == 'i' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Int)); editingNode = true; }
413                 else if (c == 's' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Str)); editingNode = true; }
414                 else if (c == 'o' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Obj)); editingNode = true; }
415                 else if (c == 'a' && node->parent != NULL) { node = JSONNodePush(node->parent, JSONNodeNew(JSONNodeKind_Arr)); editingNode = true; }
416                 else if (c == 'h') { if (node->prev       != NULL) g_CurrNode = node = node->prev; }
417                 else if (c == 'l') { if (node->next       != NULL) g_CurrNode = node = node->next; }
418                 else if (c == 'k') { if (node->parent     != NULL) g_CurrNode = node = node->parent; }
419                 else if (c == 'j') { if (node->firstChild != NULL) g_CurrNode = node = node->firstChild; }
420                 else if (c == ' ') { editingNode = true; if (JSONNodeEditable(node) && (void *)node->data != NULL) strLen = strlen((char *)node->data); }
421                 else if (isBackspace(c)) { g_CurrNode = node = JSONNodeRemove(node); }
422
423                 g_CurrNode = node;
424             }
425         }
426     }
427
428     return result;
429 }
430
431
432
433
434 int main() {
435     vt100EnableAlternateBuffer();
436
437     JSONNode * n = GetNode();
438     
439     vt100DisableAlternateBuffer();
440
441     JSONNodePrint(n, NULL);
442
443     // JSONFree(n);
444
445     return 0;
446 }