Stop being quite so clever in handling input_with_prefix
[clav.git] / ui-cli.c
blob3989643b2d3e0712e70dc4bbd20edb206f60224b
1 /*
2 * Copyright (c) 2018, 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(
120 "incfat <num> Increase fatness of vertex <num> by 1\n");
121 printf(
122 "decfat <num> Decrease fatness of vertex <num> by 1\n");
123 printf("save <str> Write quiver to file <str>\n");
124 printf("load <str> Load quiver from file <str>\n");
125 printf("quit Quit\n");
126 printf(
127 "------------------------------------------------------------\n");
130 /* Print current quiver */
131 static void
132 print_quiver(void)
134 size_t i = 0;
135 size_t j = 0;
136 struct rational *e = 0;
137 size_t line_length = 0;
139 printf("Vertices:\n");
140 printf("%*s | Name\n-----------\n", 4, "i");
142 for (j = 0; j < q->v_num; ++j) {
143 printf("%*llu | %s\n", 4, (long long unsigned) j, q->v[j].name);
146 putchar('\n');
147 printf("Edges (i -> j):\n");
148 line_length = printf("%*s| ", 4, "i\\j");
150 for (j = 0; j < q->v_num; ++j) {
151 line_length += printf("%*llu", 5, (long long unsigned) j);
154 putchar('\n');
156 for (j = 0; j < line_length; ++j) {
157 putchar('-');
160 for (i = 0; i < q->v_num; ++i) {
161 printf("\n %*llu| ", 3, (long long unsigned) i);
163 for (j = 0; j < q->v_num; ++j) {
164 e = &(q->e[i * q->v_len + j]);
166 if (e->p == 0) {
167 printf("%*s", 5, "");
168 } else if (e->q == 1) {
169 printf("%*lld", 5, (long long int) e->p);
170 } else {
171 printf("%*lld/%llu", 3, (long long int) e->p,
172 (long long unsigned) e->q);
177 printf("\n");
178 fflush(stdout);
181 /* Check for `help' */
182 static int
183 check_help(char *buf)
185 return strcmp(buf, "help");
188 /* Check for `print' */
189 static int
190 check_print(char *buf)
192 return strcmp(buf, "print");
195 /* Check for `quit' */
196 static int
197 check_quit(char *buf)
199 return strcmp(buf, "quit");
202 /* Check for `mutate' */
203 static int
204 check_mutate(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
206 size_t i = 0;
207 char dummy = 0;
209 if (strncmp(buf, "mutate", 6)) {
210 return 1;
213 *partial_match = 1;
215 if (sscanf(buf, "mutate %zu%c", &i, &dummy) != 1) {
216 printf("Type `help' to see how to use `mutate'\n");
218 return 1;
221 if (i >= q->v_num) {
222 printf("Cannot mutate at %zu: not in quiver\n", i);
224 return 1;
227 *e = (struct ui_event) { .type = ET_MUTATE, .idx_1 = i };
229 return 0;
232 /* Check for `mutatename' */
233 static int
234 check_mutatename(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
236 char *s = 0;
237 size_t i = q->v_num;
238 char dummy = 0;
239 int ret = 1;
241 if (!(s = malloc(1024))) {
242 perror(L("malloc"));
243 goto done;
246 if (strncmp(buf, "mutatename", 10)) {
247 goto done;
250 *partial_match = 1;
252 if (sscanf(buf, "mutatename %1023s %c", s, &dummy) != 1) {
253 printf("Type `help' to see how to use `mutatename'\n");
254 goto done;
257 for (size_t j = 0; j < q->v_num; ++j) {
258 if (!(strcmp(q->v[j].name, s))) {
259 i = j;
260 break;
264 if (i >= q->v_num) {
265 printf("Cannot mutate at %s: not in quiver\n", s);
266 goto done;
269 ret = 0;
270 *e = (struct ui_event) { .type = ET_MUTATE, .idx_1 = i };
271 done:
272 free(s);
274 return ret;
277 /* Check for `delete' */
278 static int
279 check_delete(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
281 size_t i = 0;
282 size_t j = 0;
283 char dummy = 0;
285 if (strncmp(buf, "delete", 6)) {
286 return 1;
289 *partial_match = 1;
290 int r = sscanf(buf, "delete %zu %zu%c", &i, &j, &dummy);
292 if (r < 1 &&
293 r > 2) {
294 printf("Type `help' to see how to use `delete'\n");
296 return 1;
299 if (r == 1) {
300 if (i >= q->v_num) {
301 printf("Cannot delete %zu: not in quiver\n", i);
303 return 1;
304 } else {
305 *e = (struct ui_event) { .type = ET_DELETE_VERTEX,
306 .idx_1 = i };
308 } else if (r == 2) {
309 if (i >= q->v_num ||
310 j >= q->v_num) {
311 printf(
312 "Cannot delete edges between %zu and %zu: not in quiver\n",
313 i, j);
315 return 1;
316 } else {
317 *e = (struct ui_event) { .type = ET_DELETE_EDGE,
318 .idx_1 = i, .idx_2 = j };
322 return 0;
325 /* Check for `vertex' */
326 static int
327 check_vertex(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
329 char *s = 0;
330 char dummy = 0;
331 int ret = 0;
333 if (!(s = malloc(1024))) {
334 perror(L("malloc"));
335 goto done_err;
338 if (strncmp(buf, "vertex", 6)) {
339 goto done_err;
342 *partial_match = 1;
344 if (sscanf(buf, "vertex %1023s %c", s, &dummy) != 1) {
345 printf("Type `help' to see how to use `vertex'\n");
346 goto done_err;
349 *e = (struct ui_event) { .type = ET_NEW_VERTEX, .z = 0x8282b2, .str =
350 s };
351 free_this = s;
352 done:
354 return ret;
355 done_err:
356 ret = 1;
357 free(s);
358 goto done;
361 /* Check for `edge' */
362 static int
363 check_edge(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
365 size_t i = 0;
366 size_t j = 0;
367 int a = 0;
368 int b = 1;
369 char slash = 0;
370 char dummy = 0;
372 if (strncmp(buf, "edge", 4)) {
373 return 1;
376 *partial_match = 1;
377 int r = sscanf(buf, "edge %zu %zu %d %c %d%c", &i, &j, &a, &slash, &b,
378 &dummy);
380 if ((r != 3 &&
381 r != 5) ||
382 (r >= 4 &&
383 slash != '/')) {
384 printf("Type `help' to see how to use `edge'\n");
386 return 1;
389 if (i >= q->v_num ||
390 j >= q->v_num) {
391 printf("Cannot add edge from %zu to %zu: not in quiver\n", i,
394 return 1;
397 if (!b) {
398 printf("Cannot add edge of weight %d/%d: division by zero\n", a,
401 return 1;
404 if (b < 0) {
405 a *= -1;
406 b *= -1;
409 if (a <= INT_FAST8_MIN ||
410 a >= INT_FAST8_MAX ||
411 b >= UINT_FAST8_MAX) {
412 printf(
413 "Cannot add edge of weight %d/%d: representation out of range\n",
414 a, b);
416 return 1;
419 *e = (struct ui_event) { .type = ET_NEW_EDGE, .idx_1 = i, .idx_2 = j,
420 .a = a, .b = b };
422 return 0;
425 /* Check for `rename' */
426 static int
427 check_rename(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
429 size_t i = 0;
430 char *s = 0;
431 char dummy = 0;
432 int ret = 0;
434 if (!(s = malloc(1024))) {
435 perror(L("malloc"));
436 goto done_err;
439 if (strncmp(buf, "rename", 6)) {
440 goto done_err;
443 *partial_match = 1;
445 if (sscanf(buf, "rename %zu %1023s %c", &i, s, &dummy) != 2) {
446 printf("Type `help' to see how to use `rename'\n");
447 goto done_err;
450 if (i >= q->v_num) {
451 printf("Cannot rename %zu: not in quiver\n", i);
452 goto done_err;
455 ret = 0;
456 *e = (struct ui_event) { .type = ET_RENAME, .idx_1 = i, .str = s };
457 free_this = s;
458 done:
460 return ret;
461 done_err:
462 ret = 1;
463 free(s);
464 goto done;
467 /* Check for `incfat' */
468 static int
469 check_incfat(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
471 size_t i = 0;
472 char dummy = 0;
474 if (strncmp(buf, "incfat", 6)) {
475 return 1;
478 *partial_match = 1;
480 if (sscanf(buf, "incfat %zu%c", &i, &dummy) != 1) {
481 printf("Type `help' to see how to use `incfat'\n");
483 return 1;
486 if (i >= q->v_num) {
487 printf("Cannot increase fatness of %zu: not in quiver\n", i);
489 return 1;
492 if (q->v[i].fatness >= UINT_FAST8_MAX) {
493 printf("Cannot increase fatness of %zu: unrepresentable\n", i);
495 return 1;
498 *e = (struct ui_event) { .type = ET_CHANGE_FATNESS, .idx_1 = i, .int_1 =
499 1 };
501 return 0;
504 /* Check for `decfat' */
505 static int
506 check_decfat(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
508 size_t i = 0;
509 char dummy = 0;
511 if (strncmp(buf, "decfat", 6)) {
512 return 1;
515 *partial_match = 1;
517 if (sscanf(buf, "decfat %zu%c", &i, &dummy) != 1) {
518 printf("Type `help' to see how to use `decfat'\n");
520 return 1;
523 if (i >= q->v_num) {
524 printf("Cannot decrease fatness of %zu: not in quiver\n", i);
526 return 1;
529 if (q->v[i].fatness <= 1) {
530 printf(
531 "Cannot decrease fatness of %zu: fatness must be positive\n",
534 return 1;
537 *e = (struct ui_event) { .type = ET_CHANGE_FATNESS, .idx_1 = i, .int_1 =
538 -1 };
540 return 0;
543 /* Check for `save' */
544 static int
545 check_save(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
547 char *s = 0;
548 char dummy = 0;
549 int ret = 0;
551 if (!(s = malloc(1024))) {
552 perror(L("malloc"));
553 goto done_err;
556 if (strncmp(buf, "save", 4)) {
557 goto done_err;
560 *partial_match = 1;
562 if (sscanf(buf, "save %1023s %c", s, &dummy) != 1) {
563 printf("Type `help' to see how to use `save'\n");
564 goto done_err;
567 if (!s) {
568 printf("Cannot save: some kind of resource allocation error\n");
569 goto done_err;
572 ret = 0;
573 *e = (struct ui_event) { .type = ET_SAVE, .str = s };
574 free_this = s;
575 done:
577 return ret;
578 done_err:
579 ret = 1;
580 free(s);
581 goto done;
584 /* Check for `load' */
585 static int
586 check_load(char *buf, struct ui_event *e, uint_fast8_t *partial_match)
588 char *s = 0;
589 char dummy = 0;
591 if (!(s = malloc(1024))) {
592 perror(L("malloc"));
594 return 1;
597 free_this = s;
599 if (strncmp(buf, "load", 4)) {
600 return 1;
603 *partial_match = 1;
605 if (sscanf(buf, "load %1023s %c", s, &dummy) != 1) {
606 printf("Type `help' to see how to use `load'\n");
608 return 1;
611 if (!s) {
612 printf("Cannot load: some kind of resource allocation error\n");
614 return 1;
617 *e = (struct ui_event) { .type = ET_LOAD, .str = s };
619 return 0;
622 /* Where the meat of this UI is. Read commands until events are needed */
624 ui_get_event(struct ui_event *e, uint_fast8_t *more)
626 char buf[bufsize];
627 uint_fast8_t partial_match = 0;
629 if (first_time) {
630 first_time = 0;
631 print_quiver();
632 print_help();
635 printf("> ");
636 fflush(stdout);
638 while (fgets(buf, bufsize, stdin)) {
639 buf[strcspn(buf, "\n")] = '\0';
640 partial_match = 0;
642 if (free_this) {
643 free(free_this);
644 free_this = 0;
647 if (!buf[0]) {
648 continue;
651 if (!check_help(buf)) {
652 print_help();
653 } else if (!check_print(buf)) {
654 print_quiver();
655 } else if (!check_quit(buf)) {
656 break;
657 } else if (!partial_match &&
658 !check_mutatename(buf, e, &partial_match)) {
659 goto have_something;
660 } else if (!partial_match &&
661 !check_mutate(buf, e, &partial_match)) {
662 goto have_something;
663 } else if (!partial_match &&
664 !check_delete(buf, e, &partial_match)) {
665 goto have_something;
666 } else if (!partial_match &&
667 !check_vertex(buf, e, &partial_match)) {
668 goto have_something;
669 } else if (!partial_match &&
670 !check_edge(buf, e, &partial_match)) {
671 goto have_something;
672 } else if (!partial_match &&
673 !check_rename(buf, e, &partial_match)) {
674 goto have_something;
675 } else if (!partial_match &&
676 !check_incfat(buf, e, &partial_match)) {
677 goto have_something;
678 } else if (!partial_match &&
679 !check_decfat(buf, e, &partial_match)) {
680 goto have_something;
681 } else if (!partial_match &&
682 !check_save(buf, e, &partial_match)) {
683 goto have_something;
684 } else if (!partial_match &&
685 !check_load(buf, e, &partial_match)) {
686 goto have_something;
687 } else if (!partial_match) {
688 printf("Unknown command (try `help')\n");
691 printf("> ");
692 fflush(stdout);
695 /* ^D works like `quit' */
696 printf("\n");
697 *e = (struct ui_event) { .type = ET_QUIT };
698 have_something:
699 *more = 0;
701 return 0;