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