Reduce flicker on some SDL platforms
[clav.git] / ui-cli.c
blob8098799b139b41eb624b4a0f6928986defbb33df
1 /*
2 * Copyright (c) 2016-2019, S. Gilles <sgilles@math.umd.edu>
4 * Permission to use, copy, modify, and/or distribute this software
5 * for any purpose with or without fee is hereby granted, provided
6 * that the above copyright notice and this permission notice appear
7 * in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <errno.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "macros.h"
25 #include "quiver.h"
26 #include "ui.h"
28 /* Do special things on first frame */
29 static uint_fast8_t first_time = 1;
31 /* The quiver */
32 struct quiver *q;
34 /* Max line length to accept as command */
35 static size_t bufsize = 1 << 11;
37 /* Memory which must be passed back to clav.c, then freed */
38 static void *free_this = 0;
40 /* Intialize CLI */
41 int
42 ui_init(struct quiver *i_q)
44 q = i_q;
46 return 0;
49 /* Acknowledge a successful load */
50 int
51 ui_respond_successful_load(const char *filename)
53 printf("Loaded %s\n", filename);
55 return 0;
58 /* Acknowledge a successful save */
59 int
60 ui_respond_successful_save(const char *filename)
62 printf("Saved to %s\n", filename);
64 return 0;
67 /* Deal with the fact that the quiver was changed */
68 int
69 ui_respond_quiver_change(void)
71 return 0;
74 /* Tear down CLI */
75 int
76 ui_teardown(void)
78 if (free_this) {
79 free(free_this);
80 free_this = 0;
83 return 0;
86 /* Record that a frame has been started */
87 int
88 ui_start_frame(void)
90 return 0;
93 /* Draw a frame, sleep to framelimit */
94 int
95 ui_finish_frame(void)
97 return 0;
100 /* Print help */
101 static void
102 print_help(void)
104 printf(
105 "------------------------------------------------------------\n");
106 printf("help This message\n");
107 printf("print Display the quiver\n");
108 printf("mutate <num> Mutate at <num>\n");
109 printf(
110 "mutatename <str> Mutate at vertex with name <str>\n");
111 printf("delete <num> Delete vertex <num>\n");
112 printf(
113 "delete <num1> <num2> Delete edges between <num> and <num>\n");
114 printf(
115 "vertex <v> Create vertex with name <v>, fatness 1\n");
116 printf(
117 "edge <num1> <num2> <p>/<q> Add an edge from <num> to <num>, weight <p>/<q>\n");
118 printf("rename <num> <str> Rename vertex <num> to <str>\n");
119 printf("renamename <str1> <str2> Rename vertex <str1> to <str2>\n");
120 printf(
121 "incfat <num> Increase fatness of vertex <num> by 1\n");
122 printf(
123 "decfat <num> Decrease fatness of vertex <num> by 1\n");
124 printf("save <str> Write quiver to file <str>\n");
125 printf("load <str> Load quiver from file <str>\n");
126 printf("quit Quit\n");
127 printf(
128 "------------------------------------------------------------\n");
131 /* Print current quiver */
132 static void
133 print_quiver(void)
135 size_t i = 0;
136 size_t j = 0;
137 struct rational *e = 0;
138 size_t line_length = 0;
140 printf("Vertices:\n");
141 printf("%*s | Name\n-----------\n", 4, "i");
143 for (j = 0; j < q->v_num; ++j) {
144 printf("%*llu | %s\n", 4, (long long unsigned) j, q->v[j].name);
147 putchar('\n');
148 printf("Edges (i -> j):\n");
149 line_length = printf("%*s| ", 4, "i\\j");
151 for (j = 0; j < q->v_num; ++j) {
152 line_length += printf("%*llu", 5, (long long unsigned) j);
155 putchar('\n');
157 for (j = 0; j < line_length; ++j) {
158 putchar('-');
161 for (i = 0; i < q->v_num; ++i) {
162 printf("\n %*llu| ", 3, (long long unsigned) i);
164 for (j = 0; j < q->v_num; ++j) {
165 e = &(q->e[i * q->v_len + j]);
167 if (e->p == 0) {
168 printf("%*s", 5, "");
169 } else if (e->q == 1) {
170 printf("%*lld", 5, (long long int) e->p);
171 } else {
172 printf("%*lld/%llu", 3, (long long int) e->p,
173 (long long unsigned) e->q);
178 printf("\n");
179 fflush(stdout);
182 /* Check for `help' */
183 static int
184 check_help(char *buf)
186 return strcmp(buf, "help");
189 /* Check for `print' */
190 static int
191 check_print(char *buf)
193 return strcmp(buf, "print");
196 /* Check for `quit' */
197 static int
198 check_quit(char *buf)
200 return strcmp(buf, "quit");
203 /* Check for `mutate' */
204 static int
205 check_mutate(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
207 size_t i = 0;
208 char dummy = 0;
210 if (strncmp(buf, "mutate", 6)) {
211 return 1;
214 *partial_match = 1;
216 if (sscanf(buf, "mutate %zu%c", &i, &dummy) != 1) {
217 printf("Type `help' to see how to use `mutate'\n");
219 return 1;
222 if (i >= q->v_num) {
223 printf("Cannot mutate at %zu: not in quiver\n", i);
225 return 1;
228 *e = (struct ui_event) { .type = ET_MUTATE, .idx_1 = i };
230 return 0;
233 /* Check for `mutatename' */
234 static int
235 check_mutatename(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
237 char *s = 0;
238 size_t i = q->v_num;
239 char dummy = 0;
240 int ret = 1;
242 if (!(s = malloc(1024))) {
243 perror(L("malloc"));
244 goto done;
247 if (strncmp(buf, "mutatename", 10)) {
248 goto done;
251 *partial_match = 1;
253 if (sscanf(buf, "mutatename %1023s %c", s, &dummy) != 1) {
254 printf("Type `help' to see how to use `mutatename'\n");
255 goto done;
258 for (size_t j = 0; j < q->v_num; ++j) {
259 if (!(strcmp(q->v[j].name, s))) {
260 i = j;
261 break;
265 if (i >= q->v_num) {
266 printf("Cannot mutate at %s: not in quiver\n", s);
267 goto done;
270 ret = 0;
271 *e = (struct ui_event) { .type = ET_MUTATE, .idx_1 = i };
272 done:
273 free(s);
275 return ret;
278 /* Check for `delete' */
279 static int
280 check_delete(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
282 size_t i = 0;
283 size_t j = 0;
284 char dummy = 0;
286 if (strncmp(buf, "delete", 6)) {
287 return 1;
290 *partial_match = 1;
291 int r = sscanf(buf, "delete %zu %zu%c", &i, &j, &dummy);
293 if (r < 1 &&
294 r > 2) {
295 printf("Type `help' to see how to use `delete'\n");
297 return 1;
300 if (r == 1) {
301 if (i >= q->v_num) {
302 printf("Cannot delete %zu: not in quiver\n", i);
304 return 1;
305 } else {
306 *e = (struct ui_event) { .type = ET_DELETE_VERTEX,
307 .idx_1 = i };
309 } else if (r == 2) {
310 if (i >= q->v_num ||
311 j >= q->v_num) {
312 printf(
313 "Cannot delete edges between %zu and %zu: not in quiver\n",
314 i, j);
316 return 1;
317 } else {
318 *e = (struct ui_event) { .type = ET_DELETE_EDGE,
319 .idx_1 = i, .idx_2 = j };
323 return 0;
326 /* Check for `vertex' */
327 static int
328 check_vertex(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
330 char *s = 0;
331 char dummy = 0;
332 int ret = 0;
334 if (!(s = malloc(1024))) {
335 perror(L("malloc"));
336 goto done_err;
339 if (strncmp(buf, "vertex", 6)) {
340 goto done_err;
343 *partial_match = 1;
345 if (sscanf(buf, "vertex %1023s %c", s, &dummy) != 1) {
346 printf("Type `help' to see how to use `vertex'\n");
347 goto done_err;
350 *e = (struct ui_event) { .type = ET_NEW_VERTEX, .z = 0x8282b2, .str =
351 s };
352 free_this = s;
353 done:
355 return ret;
356 done_err:
357 ret = 1;
358 free(s);
359 goto done;
362 /* Check for `edge' */
363 static int
364 check_edge(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
366 size_t i = 0;
367 size_t j = 0;
368 int a = 0;
369 int b = 1;
370 char slash = 0;
371 char dummy = 0;
373 if (strncmp(buf, "edge", 4)) {
374 return 1;
377 *partial_match = 1;
378 int r = sscanf(buf, "edge %zu %zu %d %c %d%c", &i, &j, &a, &slash, &b,
379 &dummy);
381 if ((r != 3 &&
382 r != 5) ||
383 (r >= 4 &&
384 slash != '/')) {
385 printf("Type `help' to see how to use `edge'\n");
387 return 1;
390 if (i >= q->v_num ||
391 j >= q->v_num) {
392 printf("Cannot add edge from %zu to %zu: not in quiver\n", i,
395 return 1;
398 if (!b) {
399 printf("Cannot add edge of weight %d/%d: division by zero\n", a,
402 return 1;
405 if (b < 0) {
406 a *= -1;
407 b *= -1;
410 if (a <= INT_FAST8_MIN ||
411 a >= INT_FAST8_MAX ||
412 b >= UINT_FAST8_MAX) {
413 printf(
414 "Cannot add edge of weight %d/%d: representation out of range\n",
415 a, b);
417 return 1;
420 *e = (struct ui_event) { .type = ET_NEW_EDGE, .idx_1 = i, .idx_2 = j,
421 .a = a, .b = b };
423 return 0;
426 /* Check for `renamename' */
427 static int
428 check_renamename(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
430 size_t i = 0;
431 size_t j = 0;
432 uint_fast8_t seen = 0;
433 char *s = 0;
434 char *t = 0;
435 char dummy = 0;
436 int ret = 0;
438 if (!(s = malloc(1024))) {
439 perror(L("malloc"));
440 goto done_err;
443 if (!(t = malloc(1024))) {
444 perror(L("malloc"));
445 goto done_err;
448 if (strncmp(buf, "renamename", 10)) {
449 goto done_err;
452 *partial_match = 1;
454 if (sscanf(buf, "renamename %1023s %1023s %c", s, t, &dummy) != 2) {
455 printf("Type `help' to see how to use `renamename'\n");
456 goto done_err;
459 for (j = 0; j < q->v_num; ++j) {
460 if (!(strcmp(q->v[j].name, s))) {
461 i = j;
462 seen++;
466 if (seen < 1) {
467 printf("Cannot rename %s: not in quiver\n", s);
468 goto done_err;
471 if (seen > 1) {
472 printf("Cannot rename %s: ambiguous\n", s);
473 goto done_err;
476 ret = 0;
477 *e = (struct ui_event) { .type = ET_RENAME, .idx_1 = i, .str = t };
478 free(s);
479 free_this = t;
480 done:
482 return ret;
483 done_err:
484 ret = 1;
485 free(s);
486 free(t);
487 goto done;
490 /* Check for `rename' */
491 static int
492 check_rename(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
494 size_t i = 0;
495 char *s = 0;
496 char dummy = 0;
497 int ret = 0;
499 if (!(s = malloc(1024))) {
500 perror(L("malloc"));
501 goto done_err;
504 if (strncmp(buf, "rename", 6)) {
505 goto done_err;
508 *partial_match = 1;
510 if (sscanf(buf, "rename %zu %1023s %c", &i, s, &dummy) != 2) {
511 printf("Type `help' to see how to use `rename'\n");
512 goto done_err;
515 if (i >= q->v_num) {
516 printf("Cannot rename %zu: not in quiver\n", i);
517 goto done_err;
520 ret = 0;
521 *e = (struct ui_event) { .type = ET_RENAME, .idx_1 = i, .str = s };
522 free_this = s;
523 done:
525 return ret;
526 done_err:
527 ret = 1;
528 free(s);
529 goto done;
532 /* Check for `incfat' */
533 static int
534 check_incfat(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
536 size_t i = 0;
537 char dummy = 0;
539 if (strncmp(buf, "incfat", 6)) {
540 return 1;
543 *partial_match = 1;
545 if (sscanf(buf, "incfat %zu%c", &i, &dummy) != 1) {
546 printf("Type `help' to see how to use `incfat'\n");
548 return 1;
551 if (i >= q->v_num) {
552 printf("Cannot increase fatness of %zu: not in quiver\n", i);
554 return 1;
557 if (q->v[i].fatness >= UINT_FAST8_MAX) {
558 printf("Cannot increase fatness of %zu: unrepresentable\n", i);
560 return 1;
563 *e = (struct ui_event) { .type = ET_CHANGE_FATNESS, .idx_1 = i, .int_1 =
564 1 };
566 return 0;
569 /* Check for `decfat' */
570 static int
571 check_decfat(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
573 size_t i = 0;
574 char dummy = 0;
576 if (strncmp(buf, "decfat", 6)) {
577 return 1;
580 *partial_match = 1;
582 if (sscanf(buf, "decfat %zu%c", &i, &dummy) != 1) {
583 printf("Type `help' to see how to use `decfat'\n");
585 return 1;
588 if (i >= q->v_num) {
589 printf("Cannot decrease fatness of %zu: not in quiver\n", i);
591 return 1;
594 if (q->v[i].fatness <= 1) {
595 printf(
596 "Cannot decrease fatness of %zu: fatness must be positive\n",
599 return 1;
602 *e = (struct ui_event) { .type = ET_CHANGE_FATNESS, .idx_1 = i, .int_1 =
603 -1 };
605 return 0;
608 /* Check for `save' */
609 static int
610 check_save(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
612 char *s = 0;
613 char dummy = 0;
614 int ret = 0;
616 if (!(s = malloc(1024))) {
617 perror(L("malloc"));
618 goto done_err;
621 if (strncmp(buf, "save", 4)) {
622 goto done_err;
625 *partial_match = 1;
627 if (sscanf(buf, "save %1023s %c", s, &dummy) != 1) {
628 printf("Type `help' to see how to use `save'\n");
629 goto done_err;
632 if (!s) {
633 printf("Cannot save: some kind of resource allocation error\n");
634 goto done_err;
637 ret = 0;
638 *e = (struct ui_event) { .type = ET_SAVE, .str = s };
639 free_this = s;
640 done:
642 return ret;
643 done_err:
644 ret = 1;
645 free(s);
646 goto done;
649 /* Check for `load' */
650 static int
651 check_load(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
653 char *s = 0;
654 char dummy = 0;
656 if (!(s = malloc(1024))) {
657 perror(L("malloc"));
659 return 1;
662 free_this = s;
664 if (strncmp(buf, "load", 4)) {
665 return 1;
668 *partial_match = 1;
670 if (sscanf(buf, "load %1023s %c", s, &dummy) != 1) {
671 printf("Type `help' to see how to use `load'\n");
673 return 1;
676 if (!s) {
677 printf("Cannot load: some kind of resource allocation error\n");
679 return 1;
682 *e = (struct ui_event) { .type = ET_LOAD, .str = s };
684 return 0;
687 /* Where the meat of this UI is. Read commands until events are needed */
689 ui_get_event(struct ui_event *e, uint_fast8_t *more)
691 char buf[bufsize];
692 uint_fast8_t partial_match = 0;
694 if (first_time) {
695 first_time = 0;
696 print_quiver();
697 print_help();
700 printf("> ");
701 fflush(stdout);
703 while (fgets(buf, bufsize, stdin)) {
704 buf[strcspn(buf, "\n")] = '\0';
705 partial_match = 0;
707 if (free_this) {
708 free(free_this);
709 free_this = 0;
712 if (!buf[0]) {
713 continue;
716 if (!check_help(buf)) {
717 print_help();
718 } else if (!check_print(buf)) {
719 print_quiver();
720 } else if (!check_quit(buf)) {
721 break;
722 } else if (!partial_match &&
723 !check_mutatename(buf, e, &partial_match)) {
724 goto have_something;
725 } else if (!partial_match &&
726 !check_mutate(buf, e, &partial_match)) {
727 goto have_something;
728 } else if (!partial_match &&
729 !check_delete(buf, e, &partial_match)) {
730 goto have_something;
731 } else if (!partial_match &&
732 !check_vertex(buf, e, &partial_match)) {
733 goto have_something;
734 } else if (!partial_match &&
735 !check_edge(buf, e, &partial_match)) {
736 goto have_something;
737 } else if (!partial_match &&
738 !check_renamename(buf, e, &partial_match)) {
739 goto have_something;
740 } else if (!partial_match &&
741 !check_rename(buf, e, &partial_match)) {
742 goto have_something;
743 } else if (!partial_match &&
744 !check_incfat(buf, e, &partial_match)) {
745 goto have_something;
746 } else if (!partial_match &&
747 !check_decfat(buf, e, &partial_match)) {
748 goto have_something;
749 } else if (!partial_match &&
750 !check_save(buf, e, &partial_match)) {
751 goto have_something;
752 } else if (!partial_match &&
753 !check_load(buf, e, &partial_match)) {
754 goto have_something;
755 } else if (!partial_match) {
756 printf("Unknown command (try `help')\n");
759 printf("> ");
760 fflush(stdout);
763 /* ^D works like `quit' */
764 printf("\n");
765 *e = (struct ui_event) { .type = ET_QUIT };
766 have_something:
767 *more = 0;
769 return 0;