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