aboutsummaryrefslogtreecommitdiff
path: root/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell.c')
-rw-r--r--shell.c578
1 files changed, 578 insertions, 0 deletions
diff --git a/shell.c b/shell.c
new file mode 100644
index 0000000..1b8b70e
--- /dev/null
+++ b/shell.c
@@ -0,0 +1,578 @@
1#include <inttypes.h>
2#include <errno.h>
3#include <stdbool.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "src/cube.h"
9
10#define PRINTCUBE_BUFFER_SIZE 1024 /* Should be enough */
11#define SOLUTIONS_BUFFER_SIZE 500000 /* Should be enough */
12#define MAX_PATH_LENGTH 10000 /* Should be enough */
13
14typedef struct {
15 int command_index;
16 char cube[22];
17 char cube_perm[22];
18 char *str_cube;
19 char *str_format;
20 char *str_format_in;
21 char *str_format_out;
22 char *str_moves;
23 char *str_trans;
24 char *str_solver;
25 char *str_options; /* TODO: remove, use only solver */
26 char *str_nisstype; /* TODO: remove, use flags */
27 int8_t minmoves;
28 int8_t maxmoves;
29 int8_t optimal;
30 int64_t maxsolutions;
31 int64_t datasize; /* Option for gendata + solve, TODO change? */
32} args_t;
33
34static void print_cube_result(int64_t, char [static 22]);
35static void print_str_result(int64_t, char *);
36
37static int64_t compose_exec(args_t *);
38static int64_t inverse_exec(args_t *);
39static int64_t applymoves_exec(args_t *);
40static int64_t applytrans_exec(args_t *);
41static int64_t frommoves_exec(args_t *);
42static int64_t readcube_exec(args_t *);
43static int64_t writecube_exec(args_t *);
44static int64_t convertcube_exec(args_t *);
45static int64_t datasize_exec(args_t *);
46static int64_t gendata_exec(args_t *);
47static int64_t solve_exec(args_t *);
48
49static int parse_args(int, char **, args_t *);
50static bool parse_int8(char *, int8_t *);
51static bool parse_int64(char *, int64_t *);
52
53static bool set_cube(int, char **, args_t *);
54static bool set_cube_perm(int, char **, args_t *);
55static bool set_str_cube(int, char **, args_t *);
56static bool set_str_format(int, char **, args_t *);
57static bool set_str_format_in(int, char **, args_t *);
58static bool set_str_format_out(int, char **, args_t *);
59static bool set_str_moves(int, char **, args_t *);
60static bool set_str_trans(int, char **, args_t *);
61static bool set_str_solver(int, char **, args_t *);
62static bool set_str_options(int, char **, args_t *);
63static bool set_str_nisstype(int, char **, args_t *);
64static bool set_minmoves(int, char **, args_t *);
65static bool set_maxmoves(int, char **, args_t *);
66static bool set_optimal(int, char **, args_t *);
67static bool set_maxsolutions(int, char **, args_t *);
68
69#define COMMAND(N, E) { .name = N, .exec = E }
70struct {
71 char *name;
72 int64_t (*exec)(args_t *);
73} commands[] = {
74 COMMAND("compose", compose_exec),
75 COMMAND("inverse", inverse_exec),
76 COMMAND("applymoves", applymoves_exec),
77 COMMAND("applytrans", applytrans_exec),
78 COMMAND("frommoves", frommoves_exec),
79 COMMAND("readcube", readcube_exec),
80 COMMAND("writecube", writecube_exec),
81 COMMAND("convertcube", convertcube_exec),
82 COMMAND("datasize", datasize_exec),
83 COMMAND("gendata", gendata_exec),
84 COMMAND("solve", solve_exec),
85 COMMAND(NULL, NULL)
86};
87
88#define OPTION(N, A, S) { .name = N, .nargs = A, .set = S }
89struct {
90 char *name;
91 int nargs;
92 bool (*set)(int, char **, args_t *);
93} options[] = {
94 OPTION("-cube", 1, set_cube),
95 OPTION("-perm", 1, set_cube_perm),
96 OPTION("-cubestr", 1, set_str_cube),
97 OPTION("-format", 1, set_str_format),
98 OPTION("-fin", 1, set_str_format_in),
99 OPTION("-fout", 1, set_str_format_out),
100 OPTION("-moves", 1, set_str_moves),
101 OPTION("-trans", 1, set_str_trans),
102 OPTION("-solver", 1, set_str_solver),
103 OPTION("-options", 1, set_str_options), /* TODO: remove, use only solver */
104 OPTION("-nisstype", 1, set_str_nisstype), /* TODO: remove, use flags */
105 OPTION("-m", 1, set_minmoves),
106 OPTION("-M", 1, set_maxmoves),
107 OPTION("-O", 1, set_optimal),
108 OPTION("-n", 1, set_maxsolutions),
109 OPTION(NULL, 0, NULL)
110};
111
112char *tablepaths[] = {
113 "tables/",
114 "",
115 NULL
116};
117
118static void
119print_cube_result(int64_t ret, char result[static 22])
120{
121 switch (ret) {
122 case 0:
123 break;
124 case 1:
125 fprintf(stderr, "Warning: resulting cube not solvable\n");
126 break;
127 case 2: /* Fallthrough */
128 default:
129 fprintf(stderr, "Unknown error (result is inconsistent)\n");
130 }
131
132 printf("%s\n", result);
133}
134
135static void
136print_str_result(int64_t ret, char *result)
137{
138 switch (ret) {
139 case 0:
140 break;
141 default:
142 fprintf(stderr, "Unknown error\n");
143 }
144
145 printf("%s\n", result);
146}
147
148static int64_t
149compose_exec(args_t *args)
150{
151 char result[22];
152 int64_t ret;
153
154 ret = nissy_compose(args->cube, args->cube_perm, result);
155 print_cube_result(ret, result);
156
157 return ret;
158}
159
160static int64_t
161inverse_exec(args_t *args)
162{
163 char result[22];
164 int64_t ret;
165
166 ret = nissy_inverse(args->cube, result);
167 print_cube_result(ret, result);
168
169 return ret;
170}
171
172static int64_t
173applymoves_exec(args_t *args)
174{
175 char result[22];
176 int64_t ret;
177
178 ret = nissy_applymoves(args->cube, args->str_moves, result);
179 print_cube_result(ret, result);
180
181 return ret;
182}
183
184static int64_t
185applytrans_exec(args_t *args)
186{
187 char result[22];
188 int64_t ret;
189
190 ret = nissy_applytrans(args->cube, args->str_trans, result);
191 print_cube_result(ret, result);
192
193 return ret;
194}
195
196static int64_t
197frommoves_exec(args_t *args)
198{
199 char result[22];
200 int64_t ret;
201
202 ret = nissy_frommoves(args->str_trans, result);
203 print_cube_result(ret, result);
204
205 return ret;
206}
207
208static int64_t
209readcube_exec(args_t *args)
210{
211 char result[22];
212 int64_t ret;
213
214 ret = nissy_readcube(args->str_format, args->str_cube, result);
215 print_cube_result(ret, result);
216
217 return ret;
218}
219
220static int64_t
221writecube_exec(args_t *args)
222{
223 char result[PRINTCUBE_BUFFER_SIZE];
224 int64_t ret;
225
226 ret = nissy_writecube(args->str_format, args->str_cube, result);
227 print_str_result(ret, result);
228
229 return ret;
230}
231
232static int64_t
233convertcube_exec(args_t *args)
234{
235 char result[PRINTCUBE_BUFFER_SIZE];
236 int64_t ret;
237
238 ret = nissy_convertcube(
239 args->str_format_in, args->str_format_out, args->str_cube, result);
240 print_str_result(ret, result);
241
242 return ret;
243}
244
245static int64_t
246datasize_exec(args_t *args)
247{
248 int64_t ret;
249
250 ret = nissy_datasize(args->str_solver, args->str_options);
251 if (ret < 0)
252 fprintf(stderr, "Unknown error (make sure solver is valid)\n");
253 printf("%" PRId64 "\n", ret);
254
255 return ret;
256}
257
258static int64_t
259gendata_exec(args_t *args)
260{
261 int i;
262 FILE *file;
263 char *buf, path[MAX_PATH_LENGTH];
264 int64_t ret, size;
265 size_t written;
266
267 /* TODO: should give warning if overwriting existing file */
268 for (i = 0; tablepaths[i] != NULL; i++) {
269 strcpy(path, tablepaths[i]);
270 strcat(path, args->str_solver);
271 file = fopen(path, "wb");
272 if (file != NULL)
273 break;
274 }
275
276 if (tablepaths[i] == NULL) {
277 fprintf(stderr, "Cannot write data to file\n");
278 return -2;
279 }
280
281 size = nissy_datasize(args->str_solver, args->str_options);
282 if (size < 0) {
283 fprintf(stderr,
284 "Unknown error in retrieving data size"
285 "(make sure solver is valid)\n");
286 return -3;
287 }
288
289 buf = malloc(size);
290
291 ret = nissy_gendata(args->str_solver, args->str_options, buf);
292 if (ret < 0) {
293 fprintf(stderr, "Unknown error in generating data\n");
294 free(buf);
295 return -4;
296 }
297 if (ret != size) {
298 fprintf(stderr, "Unknown error: unexpected data size\n");
299 free(buf);
300 return -5;
301 }
302
303 written = fwrite(buf, size, 1, file);
304 free(buf);
305
306 if (written != (int64_t)size) {
307 fprintf(stderr,
308 "Error: data was generated correctly, but could not be "
309 "written to file (generated %" PRId64 " bytes, written "
310 "%zu)\n", written, size);
311 return -6;
312 }
313
314 args->datasize = size;
315 fprintf(stderr, "Data written to %s\n", path);
316
317 return 0;
318}
319
320static int64_t
321solve_exec(args_t *args)
322{
323 int i;
324 FILE *file;
325 char *buf, solutions[SOLUTIONS_BUFFER_SIZE], path[MAX_PATH_LENGTH];
326 int64_t ret, gendata_ret;
327 size_t read;
328
329 for (i = 0; tablepaths[i] != NULL; i++) {
330 strcpy(path, tablepaths[i]);
331 strcat(path, args->str_solver);
332 file = fopen(path, "rb");
333 if (file != NULL)
334 break;
335 }
336
337 if (tablepaths[i] == NULL) {
338 fprintf(stderr,
339 "Cannot read data file, "
340 "generating it (this can take a while)\n");
341 gendata_ret = gendata_exec(args);
342 if (gendata_ret)
343 return gendata_ret;
344 }
345
346 /* Ugh, this is not elegant TODO */
347 for (i = 0; tablepaths[i] != NULL; i++) {
348 strcpy(path, tablepaths[i]);
349 strcat(path, args->str_solver);
350 file = fopen(path, "rb");
351 if (file != NULL)
352 break;
353 }
354
355 if (tablepaths[i] == NULL) {
356 fprintf(stderr, "Error: data file not found\n");
357 return -1;
358 }
359
360 buf = malloc(args->datasize);
361 read = fread(buf, args->datasize, 1, file);
362 if (read != args->datasize) {
363 fprintf(stderr, "Error reading data from file\n");
364 return -2;
365 }
366
367 ret = nissy_solve(
368 args->cube, args->str_solver, args->str_options, args->str_nisstype,
369 args->minmoves, args->maxmoves, args->maxsolutions, args->optimal,
370 buf, solutions);
371
372 free(buf);
373
374 if (ret == 0)
375 fprintf(stderr, "No solutions found\n");
376 else
377 printf("%s", solutions);
378
379 return 0;
380}
381
382static int
383parse_args(int argc, char **argv, args_t *args)
384{
385/* TODO: this function should set sensible defaults for all options */
386 int i, j, n;
387
388 if (argc == 0) {
389 printf("No command given\n");
390 return 1;
391 }
392
393 for (i = 0; commands[i].name != NULL; i++) {
394 if (!strcmp(argv[0], commands[i].name)) {
395 args->command_index = i;
396 break;
397 }
398 }
399
400 if (commands[i].name == NULL) {
401 fprintf(stderr, "Unknown command %s\n", argv[0]);
402 return 1;
403 }
404
405 for (i = 1; i < argc; i++) {
406 for (j = 0; options[j].name != NULL; j++) {
407 n = argc - i - 1;
408 if (strcmp(argv[i], options[j].name))
409 continue;
410 if (n < options[j].nargs) {
411 fprintf(stderr,
412 "Too few arguments for option %s\n",
413 options[j].name);
414 return 1;
415 }
416 if (!options[j].set(n, argv+i, args)) {
417 fprintf(stderr,
418 "Error parsing arguments for option %s\n",
419 options[j].name);
420 return 1;
421 }
422 i += options[j].nargs;
423 break;
424 }
425 if (options[j].name == NULL) {
426 fprintf(stderr, "Unknown option %s\n", argv[i]);
427 return 1;
428 }
429 }
430
431 return 0;
432}
433
434bool
435parse_int8(char *argv, int8_t *result)
436{
437 bool noerror;
438 int64_t n;
439
440 noerror = parse_int64(argv, &n);
441 *result = (int8_t)n;
442
443 return noerror && n >= INT8_MIN && n <= INT8_MAX;
444}
445
446bool
447parse_int64(char *argv, int64_t *result)
448{
449 *result = strtoll(argv, NULL, 10);
450
451 return errno != 0;
452}
453
454static bool
455set_cube(int argc, char **argv, args_t *args)
456{
457 memcpy(args->cube, argv[0], 22);
458 args->cube[21] = 0;
459
460 return true;
461}
462
463static bool
464set_cube_perm(int argc, char **argv, args_t *args)
465{
466 memcpy(args->cube_perm, argv[0], 22);
467 args->cube_perm[21] = 0;
468
469 return true;
470}
471
472static bool
473set_str_cube(int argc, char **argv, args_t *args)
474{
475 args->str_cube = argv[0];
476
477 return true;
478}
479
480static bool
481set_str_format(int argc, char **argv, args_t *args)
482{
483 args->str_format = argv[0];
484
485 return true;
486}
487
488static bool
489set_str_format_in(int argc, char **argv, args_t *args)
490{
491 args->str_format_in = argv[0];
492
493 return true;
494}
495
496static bool
497set_str_format_out(int argc, char **argv, args_t *args)
498{
499 args->str_format_out = argv[0];
500
501 return true;
502}
503
504static bool
505set_str_moves(int argc, char **argv, args_t *args)
506{
507 args->str_moves = argv[0];
508
509 return true;
510}
511
512static bool
513set_str_trans(int argc, char **argv, args_t *args)
514{
515 args->str_trans = argv[0];
516
517 return true;
518}
519
520static bool
521set_str_solver(int argc, char **argv, args_t *args)
522{
523 args->str_solver = argv[0];
524
525 return true;
526}
527
528static bool
529set_str_options(int argc, char **argv, args_t *args)
530{
531 args->str_options = argv[0];
532
533 return true;
534}
535
536static bool
537set_str_nisstype(int argc, char **argv, args_t *args)
538{
539 args->str_nisstype = argv[0];
540
541 return true;
542}
543
544static bool
545set_minmoves(int argc, char **argv, args_t *args)
546{
547 return parse_int8(argv[0], &args->minmoves);
548}
549
550static bool
551set_maxmoves(int argc, char **argv, args_t *args)
552{
553 return parse_int8(argv[0], &args->maxmoves);
554}
555
556static bool
557set_optimal(int argc, char **argv, args_t *args)
558{
559 return parse_int8(argv[0], &args->optimal);
560}
561
562static bool
563set_maxsolutions(int argc, char **argv, args_t *args)
564{
565 return parse_int64(argv[0], &args->maxsolutions);
566}
567
568int main(int argc, char **argv)
569{
570 int parse_error;
571 args_t args;
572
573 parse_error = parse_args(argc-1, argv+1, &args);
574 if (parse_error)
575 return parse_error;
576
577 return (int)commands[args.command_index].exec(&args);
578}

Generated with cgit - Back to sebastiano.tronto.net