Add clav-mutation-find to installation
[clav.git] / ui-cli.c
blobca0fd86813c51b007874d7cb6c266d4c77c02b8c
1 /*
2 * Copyright (c) 2016, 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 return 0;
60 /* Record that a frame has been started */
61 int ui_start_frame(void)
63 return 0;
66 /* Draw a frame, sleep to framelimit */
67 int ui_finish_frame(void)
69 return 0;
72 /* Print help */
73 static void print_help(void)
75 printf(
76 "------------------------------------------------------------\n");
77 printf("help This message\n");
78 printf("print Display the quiver\n");
79 printf("mutate <num> Mutate at <num>\n");
80 printf("delete <num> Delete vertex <num>\n");
81 printf(
82 "delete <num1> <num2> Delete edges between <num> and <num>\n");
83 printf(
84 "vertex Create vertex with name \"v\", fatness 1\n");
85 printf(
86 "edge <num1> <num2> <p>/<q> Add an edge from <num> to <num>, weight <p>/<q>\n");
87 printf("rename <num> <str> Rename vertex <num> to <str>\n");
88 printf(
89 "incfat <num> Increase fatness of vertex <num> by 1\n");
90 printf(
91 "decfat <num> Decrease fatness of vertex <num> by 1\n");
92 printf("save <str> Write quiver to file <str>\n");
93 printf("load <str> Load quiver from file <str>\n");
94 printf("quit Quit\n");
95 printf(
96 "------------------------------------------------------------\n");
99 /* Print current quiver */
100 static void print_quiver(void)
102 size_t i = 0;
103 size_t j = 0;
104 struct rational *e = 0;
105 size_t line_length = 0;
107 printf("Vertices:\n");
108 printf("%*s | Name\n-----------\n", 4, "i");
110 for (j = 0; j < q->v_num; ++j) {
111 printf("%*llu | %s\n", 4, (long long unsigned) j, q->v[j].name);
114 putchar('\n');
115 printf("Edges (i -> j):\n");
116 line_length = printf("%*s| ", 4, "i\\j");
118 for (j = 0; j < q->v_num; ++j) {
119 line_length += printf("%*llu", 5, (long long unsigned) j);
122 putchar('\n');
124 for (j = 0; j < line_length; ++j) {
125 putchar('-');
128 for (i = 0; i < q->v_num; ++i) {
129 printf("\n %*llu| ", 3, (long long unsigned) i);
131 for (j = 0; j < q->v_num; ++j) {
132 e = &(q->e[i * q->v_len + j]);
134 if (e->p == 0) {
135 printf("%*s", 5, "");
136 } else if (e->q == 1) {
137 printf("%*lld", 5, (long long int) e->p);
138 } else {
139 printf("%*lld/%llu", 3, (long long int) e->p,
140 (long long unsigned) e->q);
145 printf("\n");
146 fflush(stdout);
149 /* Check for `help' */
150 static int check_help(char *buf)
152 return strcmp(buf, "help");
155 /* Check for `print' */
156 static int check_print(char *buf)
158 return strcmp(buf, "print");
161 /* Check for `quit' */
162 static int check_quit(char *buf)
164 return strcmp(buf, "quit");
167 /* Check for `mutate' */
168 static int check_mutate(char *buf, struct ui_event *e,
169 uint_fast8_t *partial_match)
171 size_t i = 0;
172 char dummy = 0;
174 if (strncmp(buf, "mutate", 6)) {
175 return 1;
178 *partial_match = 1;
180 if (sscanf(buf, "mutate %zu%c", &i, &dummy) != 1) {
181 printf("Type `help' to see how to use `mutate'\n");
183 return 1;
186 if (i >= q->v_num) {
187 printf("Cannot mutate at %zu: not in quiver\n", i);
189 return 1;
192 *e = (struct ui_event) { .type = ET_MUTATE, .idx_1 = i };
194 return 0;
197 /* Check for `delete' */
198 static int check_delete(char *buf, struct ui_event *e,
199 uint_fast8_t *partial_match)
201 size_t i = 0;
202 size_t j = 0;
203 char dummy = 0;
205 if (strncmp(buf, "delete", 6)) {
206 return 1;
209 *partial_match = 1;
210 int r = sscanf(buf, "delete %zu %zu%c", &i, &j, &dummy);
212 if (r < 1 &&
213 r > 2) {
214 printf("Type `help' to see how to use `delete'\n");
216 return 1;
219 if (r == 1) {
220 if (i >= q->v_num) {
221 printf("Cannot delete %zu: not in quiver\n", i);
223 return 1;
224 } else {
225 *e = (struct ui_event) { .type = ET_DELETE_VERTEX,
226 .idx_1 = i };
228 } else if (r == 2) {
229 if (i >= q->v_num ||
230 j >= q->v_num) {
231 printf(
232 "Cannot delete edges between %zu and %zu: not in quiver\n",
233 i, j);
235 return 1;
236 } else {
237 *e = (struct ui_event) { .type = ET_DELETE_EDGE,
238 .idx_1 = i, .idx_2 = j };
242 return 0;
245 /* Check for `vertex' */
246 static int check_vertex(char *buf, struct ui_event *e,
247 uint_fast8_t *partial_match)
249 char dummy = 0;
251 if (strncmp(buf, "vertex", 6)) {
252 return 1;
255 *partial_match = 1;
257 if (sscanf(buf, "vertex %c", &dummy) != 0) {
258 printf("Type `help' to see how to use `vertex'\n");
260 return 1;
263 /* XXX: need to allow sending in name and fatness */
264 *e = (struct ui_event) { .type = ET_NEW_VERTEX };
266 return 0;
269 /* Check for `edge' */
270 static int check_edge(char *buf, struct ui_event *e,
271 uint_fast8_t *partial_match)
273 size_t i = 0;
274 size_t j = 0;
275 int a = 0;
276 int b = 1;
277 char slash = 0;
278 char dummy = 0;
280 if (strncmp(buf, "edge", 4)) {
281 return 1;
284 *partial_match = 1;
285 int r = sscanf(buf, "edge %zu %zu %d %c %d%c", &i, &j, &a, &slash, &b,
286 &dummy);
288 if ((r != 3 &&
289 r != 5) ||
290 (r >= 4 &&
291 slash != '/')) {
292 printf("Type `help' to see how to use `edge'\n");
294 return 1;
297 if (i >= q->v_num ||
298 j >= q->v_num) {
299 printf("Cannot add edge from %zu to %zu: not in quiver\n", i,
302 return 1;
305 if (!b) {
306 printf("Cannot add edge of weight %d/%d: division by zero\n", a,
309 return 1;
312 if (b < 0) {
313 a *= -1;
314 b *= -1;
317 if (a <= INT_FAST8_MIN ||
318 a >= INT_FAST8_MAX ||
319 b >= UINT_FAST8_MAX) {
320 printf(
321 "Cannot add edge of weight %d/%d: representation out of range\n",
322 a, b);
324 return 1;
327 *e = (struct ui_event) { .type = ET_NEW_EDGE, .idx_1 = i, .idx_2 = j,
328 .a = a, .b = b };
330 return 0;
333 /* Check for `rename' */
334 static int check_rename(char *buf, struct ui_event *e,
335 uint_fast8_t *partial_match)
337 size_t i = 0;
338 char *s = 0;
339 char dummy = 0;
341 if (!(s = malloc(1024))) {
342 perror(L("malloc"));
344 return 1;
347 if (strncmp(buf, "rename", 6)) {
348 return 1;
351 *partial_match = 1;
353 if (sscanf(buf, "rename %zu %1023s %c", &i, s, &dummy) != 2) {
354 printf("Type `help' to see how to use `rename'\n");
355 free_this = s;
357 return 1;
360 if (i >= q->v_num) {
361 printf("Cannot rename %zu: not in quiver\n", i);
362 free_this = s;
364 return 1;
367 if (!s) {
368 printf(
369 "Cannot rename %zu: some kind of resource allocation error\n",
372 return 1;
375 *e = (struct ui_event) { .type = ET_RENAME, .idx_1 = i, .str = s };
377 return 0;
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;
463 if (!(s = malloc(1024))) {
464 perror(L("malloc"));
466 return 1;
469 if (strncmp(buf, "save", 4)) {
470 return 1;
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 free_this = s;
479 return 1;
482 if (!s) {
483 printf("Cannot save: some kind of resource allocation error\n");
485 return 1;
488 *e = (struct ui_event) { .type = ET_SAVE, .str = s };
490 return 0;
493 /* Check for `load' */
494 static int check_load(char *buf, struct ui_event *e,
495 uint_fast8_t *partial_match)
497 char *s = 0;
498 char dummy = 0;
500 if (!(s = malloc(1024))) {
501 perror(L("malloc"));
503 return 1;
506 if (strncmp(buf, "load", 4)) {
507 return 1;
510 *partial_match = 1;
512 if (sscanf(buf, "load %1023s %c", s, &dummy) != 1) {
513 printf("Type `help' to see how to use `load'\n");
514 free_this = s;
516 return 1;
519 if (!s) {
520 printf("Cannot load: some kind of resource allocation error\n");
522 return 1;
525 *e = (struct ui_event) { .type = ET_LOAD, .str = s };
527 return 0;
530 /* Where the meat of this UI is. Read commands until events are needed */
531 int ui_get_event(struct ui_event *e, uint_fast8_t *more)
533 char buf[bufsize];
534 uint_fast8_t partial_match = 0;
536 if (first_time) {
537 first_time = 0;
538 print_quiver();
539 print_help();
542 if (free_this) {
543 free(free_this);
544 free_this = 0;
547 printf("> ");
548 fflush(stdout);
550 while (fgets(buf, bufsize, stdin)) {
551 buf[strcspn(buf, "\n")] = '\0';
552 partial_match = 0;
554 if (!buf[0]) {
555 continue;
558 if (!check_help(buf)) {
559 print_help();
560 } else if (!check_print(buf)) {
561 print_quiver();
562 } else if (!check_quit(buf)) {
563 break;
564 } else if (!partial_match &&
565 !check_mutate(buf, e, &partial_match)) {
566 goto have_something;
567 } else if (!partial_match &&
568 !check_delete(buf, e, &partial_match)) {
569 goto have_something;
570 } else if (!partial_match &&
571 !check_vertex(buf, e, &partial_match)) {
572 goto have_something;
573 } else if (!partial_match &&
574 !check_edge(buf, e, &partial_match)) {
575 goto have_something;
576 } else if (!partial_match &&
577 !check_rename(buf, e, &partial_match)) {
578 goto have_something;
579 } else if (!partial_match &&
580 !check_incfat(buf, e, &partial_match)) {
581 goto have_something;
582 } else if (!partial_match &&
583 !check_decfat(buf, e, &partial_match)) {
584 goto have_something;
585 } else if (!partial_match &&
586 !check_save(buf, e, &partial_match)) {
587 goto have_something;
588 } else if (!partial_match &&
589 !check_load(buf, e, &partial_match)) {
590 goto have_something;
591 } else if (!partial_match) {
592 printf("Unknown command (try `help')\n");
595 printf("> ");
596 fflush(stdout);
599 /* ^D works like `quit' */
600 printf("\n");
601 *e = (struct ui_event) { .type = ET_QUIT };
602 have_something:
603 *more = 0;
605 return 0;