Add Zickert's B2 quivers
[clav.git] / ui-cli.c
blob272b2b8b4da5423c16e5bf6b151fd84201ebc6ff
1 /*
2 * Copyright (c) 2017, 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 ui_init(struct quiver *i_q)
43 q = i_q;
45 return 0;
48 /* Deal with the fact that the quiver was changed */
49 int ui_respond_quiver_change(void)
51 return 0;
54 /* Tear down CLI */
55 int ui_teardown(void)
57 if (free_this) {
58 free(free_this);
59 free_this = 0;
62 return 0;
65 /* Record that a frame has been started */
66 int ui_start_frame(void)
68 return 0;
71 /* Draw a frame, sleep to framelimit */
72 int ui_finish_frame(void)
74 return 0;
77 /* Print help */
78 static void print_help(void)
80 printf(
81 "------------------------------------------------------------\n");
82 printf("help This message\n");
83 printf("print Display the quiver\n");
84 printf("mutate <num> Mutate at <num>\n");
85 printf("delete <num> Delete vertex <num>\n");
86 printf(
87 "delete <num1> <num2> Delete edges between <num> and <num>\n");
88 printf(
89 "vertex Create vertex with name \"v\", fatness 1\n");
90 printf(
91 "edge <num1> <num2> <p>/<q> Add an edge from <num> to <num>, weight <p>/<q>\n");
92 printf("rename <num> <str> Rename vertex <num> to <str>\n");
93 printf(
94 "incfat <num> Increase fatness of vertex <num> by 1\n");
95 printf(
96 "decfat <num> Decrease fatness of vertex <num> by 1\n");
97 printf("save <str> Write quiver to file <str>\n");
98 printf("load <str> Load quiver from file <str>\n");
99 printf("quit Quit\n");
100 printf(
101 "------------------------------------------------------------\n");
104 /* Print current quiver */
105 static void print_quiver(void)
107 size_t i = 0;
108 size_t j = 0;
109 struct rational *e = 0;
110 size_t line_length = 0;
112 printf("Vertices:\n");
113 printf("%*s | Name\n-----------\n", 4, "i");
115 for (j = 0; j < q->v_num; ++j) {
116 printf("%*llu | %s\n", 4, (long long unsigned) j, q->v[j].name);
119 putchar('\n');
120 printf("Edges (i -> j):\n");
121 line_length = printf("%*s| ", 4, "i\\j");
123 for (j = 0; j < q->v_num; ++j) {
124 line_length += printf("%*llu", 5, (long long unsigned) j);
127 putchar('\n');
129 for (j = 0; j < line_length; ++j) {
130 putchar('-');
133 for (i = 0; i < q->v_num; ++i) {
134 printf("\n %*llu| ", 3, (long long unsigned) i);
136 for (j = 0; j < q->v_num; ++j) {
137 e = &(q->e[i * q->v_len + j]);
139 if (e->p == 0) {
140 printf("%*s", 5, "");
141 } else if (e->q == 1) {
142 printf("%*lld", 5, (long long int) e->p);
143 } else {
144 printf("%*lld/%llu", 3, (long long int) e->p,
145 (long long unsigned) e->q);
150 printf("\n");
151 fflush(stdout);
154 /* Check for `help' */
155 static int check_help(char *buf)
157 return strcmp(buf, "help");
160 /* Check for `print' */
161 static int check_print(char *buf)
163 return strcmp(buf, "print");
166 /* Check for `quit' */
167 static int check_quit(char *buf)
169 return strcmp(buf, "quit");
172 /* Check for `mutate' */
173 static int check_mutate(char *buf, struct ui_event *e,
174 uint_fast8_t *partial_match)
176 size_t i = 0;
177 char dummy = 0;
179 if (strncmp(buf, "mutate", 6)) {
180 return 1;
183 *partial_match = 1;
185 if (sscanf(buf, "mutate %zu%c", &i, &dummy) != 1) {
186 printf("Type `help' to see how to use `mutate'\n");
188 return 1;
191 if (i >= q->v_num) {
192 printf("Cannot mutate at %zu: not in quiver\n", i);
194 return 1;
197 *e = (struct ui_event) { .type = ET_MUTATE, .idx_1 = i };
199 return 0;
202 /* Check for `delete' */
203 static int check_delete(char *buf, struct ui_event *e,
204 uint_fast8_t *partial_match)
206 size_t i = 0;
207 size_t j = 0;
208 char dummy = 0;
210 if (strncmp(buf, "delete", 6)) {
211 return 1;
214 *partial_match = 1;
215 int r = sscanf(buf, "delete %zu %zu%c", &i, &j, &dummy);
217 if (r < 1 &&
218 r > 2) {
219 printf("Type `help' to see how to use `delete'\n");
221 return 1;
224 if (r == 1) {
225 if (i >= q->v_num) {
226 printf("Cannot delete %zu: not in quiver\n", i);
228 return 1;
229 } else {
230 *e = (struct ui_event) { .type = ET_DELETE_VERTEX,
231 .idx_1 = i };
233 } else if (r == 2) {
234 if (i >= q->v_num ||
235 j >= q->v_num) {
236 printf(
237 "Cannot delete edges between %zu and %zu: not in quiver\n",
238 i, j);
240 return 1;
241 } else {
242 *e = (struct ui_event) { .type = ET_DELETE_EDGE,
243 .idx_1 = i, .idx_2 = j };
247 return 0;
250 /* Check for `vertex' */
251 static int check_vertex(char *buf, struct ui_event *e,
252 uint_fast8_t *partial_match)
254 char dummy = 0;
256 if (strncmp(buf, "vertex", 6)) {
257 return 1;
260 *partial_match = 1;
262 if (sscanf(buf, "vertex %c", &dummy) != 0) {
263 printf("Type `help' to see how to use `vertex'\n");
265 return 1;
268 /* XXX: need to allow sending in name and fatness */
269 *e = (struct ui_event) { .type = ET_NEW_VERTEX };
271 return 0;
274 /* Check for `edge' */
275 static int check_edge(char *buf, struct ui_event *e,
276 uint_fast8_t *partial_match)
278 size_t i = 0;
279 size_t j = 0;
280 int a = 0;
281 int b = 1;
282 char slash = 0;
283 char dummy = 0;
285 if (strncmp(buf, "edge", 4)) {
286 return 1;
289 *partial_match = 1;
290 int r = sscanf(buf, "edge %zu %zu %d %c %d%c", &i, &j, &a, &slash, &b,
291 &dummy);
293 if ((r != 3 &&
294 r != 5) ||
295 (r >= 4 &&
296 slash != '/')) {
297 printf("Type `help' to see how to use `edge'\n");
299 return 1;
302 if (i >= q->v_num ||
303 j >= q->v_num) {
304 printf("Cannot add edge from %zu to %zu: not in quiver\n", i,
307 return 1;
310 if (!b) {
311 printf("Cannot add edge of weight %d/%d: division by zero\n", a,
314 return 1;
317 if (b < 0) {
318 a *= -1;
319 b *= -1;
322 if (a <= INT_FAST8_MIN ||
323 a >= INT_FAST8_MAX ||
324 b >= UINT_FAST8_MAX) {
325 printf(
326 "Cannot add edge of weight %d/%d: representation out of range\n",
327 a, b);
329 return 1;
332 *e = (struct ui_event) { .type = ET_NEW_EDGE, .idx_1 = i, .idx_2 = j,
333 .a = a, .b = b };
335 return 0;
338 /* Check for `rename' */
339 static int check_rename(char *buf, struct ui_event *e,
340 uint_fast8_t *partial_match)
342 size_t i = 0;
343 char *s = 0;
344 char dummy = 0;
345 int ret = 0;
347 if (!(s = malloc(1024))) {
348 perror(L("malloc"));
349 goto done_err;
352 if (strncmp(buf, "rename", 6)) {
353 goto done_err;
356 *partial_match = 1;
358 if (sscanf(buf, "rename %zu %1023s %c", &i, s, &dummy) != 2) {
359 printf("Type `help' to see how to use `rename'\n");
360 goto done_err;
363 if (i >= q->v_num) {
364 printf("Cannot rename %zu: not in quiver\n", i);
365 goto done_err;
368 ret = 0;
369 *e = (struct ui_event) { .type = ET_RENAME, .idx_1 = i, .str = s };
370 free_this = s;
371 done:
373 return ret;
374 done_err:
375 ret = 1;
376 free(s);
377 goto done;
380 /* Check for `incfat' */
381 static int check_incfat(char *buf, struct ui_event *e,
382 uint_fast8_t *partial_match)
384 size_t i = 0;
385 char dummy = 0;
387 if (strncmp(buf, "incfat", 6)) {
388 return 1;
391 *partial_match = 1;
393 if (sscanf(buf, "incfat %zu%c", &i, &dummy) != 1) {
394 printf("Type `help' to see how to use `incfat'\n");
396 return 1;
399 if (i >= q->v_num) {
400 printf("Cannot increase fatness of %zu: not in quiver\n", i);
402 return 1;
405 if (q->v[i].fatness >= UINT_FAST8_MAX) {
406 printf("Cannot increase fatness of %zu: unrepresentable\n", i);
408 return 1;
411 *e = (struct ui_event) { .type = ET_CHANGE_FATNESS, .idx_1 = i, .int_1 =
412 1 };
414 return 0;
417 /* Check for `decfat' */
418 static int check_decfat(char *buf, struct ui_event *e,
419 uint_fast8_t *partial_match)
421 size_t i = 0;
422 char dummy = 0;
424 if (strncmp(buf, "decfat", 6)) {
425 return 1;
428 *partial_match = 1;
430 if (sscanf(buf, "decfat %zu%c", &i, &dummy) != 1) {
431 printf("Type `help' to see how to use `decfat'\n");
433 return 1;
436 if (i >= q->v_num) {
437 printf("Cannot decrease fatness of %zu: not in quiver\n", i);
439 return 1;
442 if (q->v[i].fatness <= 1) {
443 printf(
444 "Cannot decrease fatness of %zu: fatness must be positive\n",
447 return 1;
450 *e = (struct ui_event) { .type = ET_CHANGE_FATNESS, .idx_1 = i, .int_1 =
451 -1 };
453 return 0;
456 /* Check for `save' */
457 static int check_save(char *buf, struct ui_event *e,
458 uint_fast8_t *partial_match)
460 char *s = 0;
461 char dummy = 0;
462 int ret = 0;
464 if (!(s = malloc(1024))) {
465 perror(L("malloc"));
466 goto done_err;
469 if (strncmp(buf, "save", 4)) {
470 goto done_err;
473 *partial_match = 1;
475 if (sscanf(buf, "save %1023s %c", s, &dummy) != 1) {
476 printf("Type `help' to see how to use `save'\n");
477 goto done_err;
480 if (!s) {
481 printf("Cannot save: some kind of resource allocation error\n");
482 goto done_err;
485 ret = 0;
486 *e = (struct ui_event) { .type = ET_SAVE, .str = s };
487 free_this = s;
488 done:
490 return ret;
491 done_err:
492 ret = 1;
493 free(s);
494 goto done;
497 /* Check for `load' */
498 static int check_load(char *buf, struct ui_event *e,
499 uint_fast8_t *partial_match)
501 char *s = 0;
502 char dummy = 0;
504 if (!(s = malloc(1024))) {
505 perror(L("malloc"));
507 return 1;
510 free_this = s;
512 if (strncmp(buf, "load", 4)) {
513 return 1;
516 *partial_match = 1;
518 if (sscanf(buf, "load %1023s %c", s, &dummy) != 1) {
519 printf("Type `help' to see how to use `load'\n");
521 return 1;
524 if (!s) {
525 printf("Cannot load: some kind of resource allocation error\n");
527 return 1;
530 *e = (struct ui_event) { .type = ET_LOAD, .str = s };
532 return 0;
535 /* Where the meat of this UI is. Read commands until events are needed */
536 int ui_get_event(struct ui_event *e, uint_fast8_t *more)
538 char buf[bufsize];
539 uint_fast8_t partial_match = 0;
541 if (first_time) {
542 first_time = 0;
543 print_quiver();
544 print_help();
547 printf("> ");
548 fflush(stdout);
550 while (fgets(buf, bufsize, stdin)) {
551 buf[strcspn(buf, "\n")] = '\0';
552 partial_match = 0;
554 if (free_this) {
555 free(free_this);
556 free_this = 0;
559 if (!buf[0]) {
560 continue;
563 if (!check_help(buf)) {
564 print_help();
565 } else if (!check_print(buf)) {
566 print_quiver();
567 } else if (!check_quit(buf)) {
568 break;
569 } else if (!partial_match &&
570 !check_mutate(buf, e, &partial_match)) {
571 goto have_something;
572 } else if (!partial_match &&
573 !check_delete(buf, e, &partial_match)) {
574 goto have_something;
575 } else if (!partial_match &&
576 !check_vertex(buf, e, &partial_match)) {
577 goto have_something;
578 } else if (!partial_match &&
579 !check_edge(buf, e, &partial_match)) {
580 goto have_something;
581 } else if (!partial_match &&
582 !check_rename(buf, e, &partial_match)) {
583 goto have_something;
584 } else if (!partial_match &&
585 !check_incfat(buf, e, &partial_match)) {
586 goto have_something;
587 } else if (!partial_match &&
588 !check_decfat(buf, e, &partial_match)) {
589 goto have_something;
590 } else if (!partial_match &&
591 !check_save(buf, e, &partial_match)) {
592 goto have_something;
593 } else if (!partial_match &&
594 !check_load(buf, e, &partial_match)) {
595 goto have_something;
596 } else if (!partial_match) {
597 printf("Unknown command (try `help')\n");
600 printf("> ");
601 fflush(stdout);
604 /* ^D works like `quit' */
605 printf("\n");
606 *e = (struct ui_event) { .type = ET_QUIT };
607 have_something:
608 *more = 0;
610 return 0;