]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/command.c
error handling (WIP)
[z180-stamp.git] / avr / command.c
CommitLineData
35edb766 1/*
04f84937 2 * (C) Copyright 2014, 2016, 2018 Leo C. <erbl259-lmu@yahoo.de>
35edb766
L
3 *
4 * (C) Copyright 2000-2009
5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6 *
ccb6ffb9 7 * SPDX-License-Identifier: GPL-2.0
35edb766
L
8 */
9
d684c216
L
10/*
11 * Command Processor Table
12 */
13
fcd2239e 14#include "command.h"
d684c216 15#include "common.h"
d684c216 16#include <ctype.h>
fcd2239e 17#include <setjmp.h>
d684c216
L
18
19#include "config.h"
8f23e84c 20#include "print-utils.h"
d684c216
L
21#include "con-utils.h"
22#include "env.h"
8f23e84c 23#include "debug.h"
c646b5a9 24#include "getopt-min.h"
fcd2239e 25
c646b5a9 26#define DEBUG_CMD 0 /* set to 1 to debug */
dab74a42
L
27
28#define debug_cmd(fmt, args...) \
29 debug_cond(DEBUG_CMD, fmt, ##args)
30
fcd2239e
L
31
32jmp_buf cmd_jbuf;
d684c216 33
c646b5a9
L
34char *strcasestr_P2(const FLASH char *haystack, const char *needle)
35{
36 int nlen = strlen(needle);
37 int hlen = strlen_P(haystack) - nlen + 1;
38 int i;
39
40 for (i = 0; i < hlen; i++) {
41 int j;
42 for (j = 0; j < nlen; j++) {
43 unsigned char c1 = haystack[i+j];
44 unsigned char c2 = needle[j];
45 if (toupper(c1) != toupper(c2))
46 goto next;
47 }
48 return (char *) haystack + i;
49 next:
50 ;
51 }
52 return NULL;
53}
54
d684c216 55
c646b5a9 56#if 0
bc72540a
L
57static int cmd_tbl_item_count(cmd_tbl_t *p)
58{
59 int count = 0;
60
61 while (p->name != NULL) {
62 if (p->subcmd) {
63 cmd_tbl_t *sub = p->subcmd;
64 while (sub->name != NULL) {
65 if (sub->flags & CTBL_SUBCMDAUTO)
66 count++;
67 sub++;
68 }
69 }
70 if ((p->flags & CTBL_SUBCMDAUTO) == 0)
71 count++;
72 p++;
73 }
74 return count;
75}
c646b5a9 76#endif
bc72540a
L
77
78static cmd_tbl_t *get_cmd_tbl_base(cmd_tbl_t *cmdtp)
79{
80 cmd_tbl_t *p = cmdtp;
81
82 while (p->name != NULL)
83 ++p;
84
85 return p->subcmd;
86}
87
c646b5a9 88static cmd_tbl_t *get_cmd_tbl_parent(cmd_tbl_t *child)
bc72540a 89{
c646b5a9
L
90 if ((child->flags & CTBL_SUBCMDAUTO) == 0) {
91
92 cmd_tbl_t *tbl_start = get_cmd_tbl_base(child);
93 if (tbl_start != cmd_tbl) {
94 cmd_tbl_t *top = cmd_tbl;
95 while (top->subcmd != tbl_start)
96 ++top;
97 return top;
98 }
bc72540a 99 }
c646b5a9
L
100 return NULL;
101}
102
022330eb 103static int print_nameprefix(cmd_tbl_t *p)
c646b5a9
L
104{
105 cmd_tbl_t *top = get_cmd_tbl_parent(p);
bc72540a 106
c646b5a9
L
107 int width = 0;
108 if (top) {
109 width = printf_P(PSTR("%S "), top->name);
bc72540a 110 }
c646b5a9
L
111
112 return width;
bc72540a
L
113}
114
022330eb
L
115static int print_prefixed_name(cmd_tbl_t *p)
116{
117 int len;
118
119 len = print_nameprefix(p);
120 len += strlen_P(p->name);
121 my_puts_P(p->name);
122
123 return len;
124}
125
e96dcd6d 126static void print_usage_line(cmd_tbl_t *p, int width)
d684c216 127{
022330eb 128 width -= print_prefixed_name(p);
deb08cb6
L
129 if (width < 0)
130 width = 0;
deb08cb6 131 print_blanks(width);
d684c216 132 my_puts_P(PSTR(" - "));
e96dcd6d 133 puts_P(p->usage);
d684c216
L
134}
135
c646b5a9 136#if 0
bc72540a 137static int strcmp_PP(const FLASH char *s1, const FLASH char *s2)
d684c216
L
138{
139 unsigned char c1, c2;
140
c79c80b4 141 while ((c1 = *(const FLASH unsigned char *)s1++)
d684c216
L
142 == (c2 = *(const FLASH unsigned char *)s2++))
143 if (c1 == 0)
144 return 0;
145
146 return c1 - c2;
147}
c646b5a9 148#endif
d684c216 149
c646b5a9
L
150#if 1
151static int cmpstring_PP(const void *p1, const void *p2)
152{
153 char s1[21] = {'\0'};
154 char s2[21] = {'\0'};
155 cmd_tbl_t *cp1 = *(cmd_tbl_t **) p1;
156 cmd_tbl_t *cp2 = *(cmd_tbl_t **) p2;
157 cmd_tbl_t *top1 = get_cmd_tbl_parent(*(cmd_tbl_t **) p1);
158 cmd_tbl_t *top2 = get_cmd_tbl_parent(*(cmd_tbl_t **) p2);
159
160 if (top1)
161 strlcpy_P(s1, top1->name, 21);
162 if (top2)
163 strlcpy_P(s2, top2->name, 21);
164
165 strlcat_P(s1, cp1->name, 21);
166 strlcat_P(s2, cp2->name, 21);
167
168 return strcmp(s1, s2);
169}
170#else
bc72540a 171static int cmpstring_PP(const void *p1, const void *p2)
d684c216 172{
c646b5a9
L
173 cmd_tbl_t *cp1 = *(cmd_tbl_t **) p1;
174 cmd_tbl_t *cp2 = *(cmd_tbl_t **) p2;
175 cmd_tbl_t *top1 = get_cmd_tbl_parent(*(cmd_tbl_t **) p1);
176 cmd_tbl_t *top2 = get_cmd_tbl_parent(*(cmd_tbl_t **) p2);
177 int res;
178
179 if (top1 && top2) {
180 res = strcmp_PP(top1->name, top2->name);
181 if (res == 0)
182 res = strcmp_PP(cp1->name, cp2->name);
183 return res;
184 }
185 if (top1) {
186 res = strcmp_PP(top1->name, cp2->name);
187 if (res == 0)
188 res = strcmp_PP(cp1->name, cp2->name);
189 return res;
190 }
191 if (top2) {
192 res = strcmp_PP(cp1->name, top2->name);
193 if (res == 0)
194 res = strcmp_PP(cp1->name, cp2->name);
195 return res;
196 }
197 return strcmp_PP(cp1->name, cp2->name);
d684c216 198}
c646b5a9 199#endif
d684c216 200
9d6c43fa
L
201/****************************************************************************/
202
9d6c43fa 203/*
5caa8c2b
L
204 * find command table entry for a command
205 */
5caa8c2b 206
bc72540a 207static cmd_tbl_t *find_cmd (const char *cmd, cmd_tbl_t *table)
7a1ed620 208{
7a1ed620
L
209 if (!cmd)
210 return NULL;
211
212 char *optenv = getenv_str(PSTR("cmd"));
4077419c 213 uint8_t opt_debug = optenv && strstr_P(optenv, PSTR("debug")) != NULL;
7a1ed620 214
4077419c
L
215 cmd_tbl_t *cmdtp_ret = NULL;
216 uint_fast8_t n_found = 0;
217 uint_fast8_t len = strlen(cmd);
7a1ed620 218
4077419c
L
219 for (cmd_tbl_t *cmdtp = table; cmdtp->name != NULL; cmdtp++) {
220 if (cmdtp->subcmd) {
221 for (cmd_tbl_t *sub = cmdtp->subcmd; sub->name != NULL; sub++) {
222 if (sub->flags & CTBL_SUBCMDAUTO &&
223 strncmp_P(cmd, sub->name, len) == 0 &&
224 (opt_debug || !(sub->flags & CTBL_DBG))) {
225 if (len == strlen_P(sub->name))
226 return sub; /* full match */
227 cmdtp_ret = sub; /* abbreviated command ? */
228 ++n_found;
229 }
230 }
231 }
232 if ((cmdtp->flags & CTBL_SUBCMDAUTO) == 0 &&
233 strncmp_P(cmd, cmdtp->name, len) == 0 &&
234 (opt_debug || !(cmdtp->flags & CTBL_DBG))) {
235 if (len == strlen_P(cmdtp->name))
236 return cmdtp; /* full match */
237 cmdtp_ret = cmdtp; /* abbreviated command ? */
238 ++n_found;
239 }
240 }
5caa8c2b 241
4077419c
L
242 if (n_found == 1)
243 return cmdtp_ret; /* exactly one match */
5caa8c2b 244
4077419c 245 return NULL; /* not found or ambiguous command */
5caa8c2b
L
246}
247
d684c216
L
248/*
249 * Use puts() instead of printf() to avoid printf buffer overflow
250 * for long help messages
251 */
252
7a1ed620 253command_ret_t do_help(cmd_tbl_t *cmdtp, uint_fast8_t flag UNUSED, int argc, char * const argv[])
d684c216 254{
9d6c43fa 255 cmd_tbl_t *tbl_start = get_cmd_tbl_base(cmdtp);
c646b5a9
L
256 command_ret_t res = CMD_RET_SUCCESS;
257 uint_fast8_t options = 0;
258#define OPT_DBG_CMDS 0x01
259#define OPT_ALL 0x02
260#define OPT_NAME 0x04
261#define OPT_USAGE 0x08
262#define OPT_LONG 0x10
263
264 /* reset getopt() */
265 optind = 0;
266
267 int opt;
268 while ((opt = getopt(argc, argv, PSTR("afk"))) != -1) {
269 switch (opt) {
270 case 'a':
271 options |= OPT_ALL;
272 break;
273 case 'f':
274 options |= OPT_NAME | OPT_ALL;
275 break;
276 case 'k':
277 options |= OPT_USAGE | OPT_ALL;
278 break;
279 default: /* '?' */
280 return CMD_RET_USAGE;
281 }
282 }
5caa8c2b 283
c646b5a9
L
284 /* remaining arguments */
285 argc -= optind;
286 argv += optind;
ccb6ffb9 287
c646b5a9
L
288 if ((options & (OPT_USAGE|OPT_NAME)) == (OPT_USAGE|OPT_NAME)) {
289 puts_P(PSTR("Inkompatible options: -f -k\n"
290 "Try 'help help'"));
291 return CMD_RET_USAGE;
292 }
293 if (options & OPT_USAGE)
294 options |= OPT_NAME;
295
296 if ((options & (OPT_NAME | OPT_USAGE)) == 0 && argc > 0)
297 options |= OPT_LONG;
298
299 char *optenv = getenv_str(PSTR("cmd"));
300 if (optenv && strstr_P(optenv, PSTR("debug")) != NULL)
301 options |= OPT_DBG_CMDS;
302
303 uint_fast8_t maxlen_cmd;
304 int cmd_items;
305 cmd_tbl_t **cmd_list = NULL;
306 for (uint_fast8_t pass = 0; pass < 2; ++pass) {
307 maxlen_cmd = 0;
308 if (pass == 0)
309 cmd_items = 0;
310 else {
311 cmd_list = (cmd_tbl_t **) malloc(cmd_items * sizeof(cmd_tbl_t *));
312 /* TODO: Check error */
313 }
d684c216 314
292f0519
L
315 /* Make array of commands */
316 cmd_tbl_t *tp = tbl_start;
04f84937
L
317 int i = 0;
318 while (tp->name != NULL) {
dab74a42 319 if (tp->subcmd) {
04f84937
L
320 cmd_tbl_t *sub = tp->subcmd;
321 while (sub->name != NULL) {
c646b5a9
L
322 if (options & OPT_ALL || sub->flags & CTBL_SUBCMDAUTO) {
323 if (pass == 0)
324 ++cmd_items;
325 else {
326 cmd_list[i++] = sub;
327 uint_fast8_t len = strlen_P(sub->name);
328 if ((sub->flags & CTBL_SUBCMDAUTO) == 0) {
329 len += strlen_P(tp->name) + 1;
330 }
331 if (len > maxlen_cmd) {
332 maxlen_cmd = len;
333 }
334//debug_cmd("### i:%3d, maxlen:%3d, tp: '%S', sub: '%S'\n", i, maxlen_cmd, tp->name, sub->name);
335 }
04f84937
L
336 }
337 sub++;
338 }
339 }
dab74a42 340 if ((tp->flags & CTBL_SUBCMDAUTO) == 0) {
c646b5a9
L
341 if (pass == 0)
342 ++cmd_items;
343 else {
dab74a42 344 cmd_list[i++] = tp;
c646b5a9
L
345 uint_fast8_t len = strlen_P(tp->name);
346 cmd_tbl_t *top = get_cmd_tbl_parent(tp);
347 if (top)
348 len += strlen_P(top->name) + 1;
349 if (len > maxlen_cmd)
350 maxlen_cmd = len;
351 }
dab74a42
L
352 }
353 tp++;
d684c216 354 }
c646b5a9
L
355//debug_cmd("### pass: %d, cmd_items: %d, i: %d, maxlen_cmd: %d\n", pass, cmd_items, i, maxlen_cmd);
356 }
d684c216 357
c646b5a9
L
358 /* Sort command list */
359 qsort(cmd_list, cmd_items, sizeof (cmd_tbl_t *), cmpstring_PP);
ccb6ffb9 360
c646b5a9
L
361 if ((options & OPT_LONG) == 0) {
362 /* print short help (usage) */
363 for (uint_fast8_t cmdi = 0; cmdi < cmd_items; cmdi++) {
e96dcd6d
L
364
365 /* allow user abort */
366 if (ctrlc ()) {
c646b5a9 367 res = CMD_RET_FAILURE;
e96dcd6d 368 break;
ccb6ffb9 369 }
c646b5a9
L
370 if ((cmd_list[cmdi]->flags & CTBL_DBG) && !(options & OPT_DBG_CMDS))
371 continue;
372 if (cmd_list[cmdi]->usage == NULL)
373 continue;
8da60ec5 374
c646b5a9
L
375 if (argc == 0)
376 print_usage_line(cmd_list[cmdi], maxlen_cmd);
377 else {
378 for (uint_fast8_t argi = 0; argi < argc; argi++) {
379 if (((options & OPT_NAME) &&
380 strcasestr_P2(cmd_list[cmdi]->name, argv[argi])) ||
381 ((options & OPT_USAGE) &&
382 strcasestr_P2(cmd_list[cmdi]->usage, argv[argi]))) {
383 print_usage_line(cmd_list[cmdi], maxlen_cmd);
384 }
385 }
386 }
387 }
388 } else {
389 /* command help (long version) */
390 for (uint_fast8_t argi = 0; argi < argc; ++argi) {
391 uint_fast8_t got = 0;
f766ff54
L
392 cmd_tbl_t *tp = find_cmd(argv[argi], tbl_start);
393 if (tp) {
394 cmd_usage(tp);
395 got = 1;
396 }
397 if (options & OPT_ALL) {
398 for (cmd_tbl_t *sub = tbl_start; sub->name != NULL; sub++) {
399 if (sub->subcmd) {
400 tp = find_cmd(argv[argi], sub->subcmd);
401 if (tp) {
402 cmd_usage(tp);
403 got = 1;
404 }
405 }
c646b5a9
L
406 }
407 }
408 if (!got) {
409 printf_P(PSTR("Unknown command '%s' - try 'help help'\n"),
410 argv[argi]);
411 res = CMD_RET_FAILURE;
412 break;
413 }
d684c216
L
414 }
415 }
c646b5a9
L
416 free(cmd_list);
417 return res;
d684c216
L
418}
419
d684c216 420
04f84937 421command_ret_t cmd_usage(cmd_tbl_t *cmdtp)
d684c216 422{
e96dcd6d 423 print_usage_line(cmdtp, 0);
d684c216 424#ifdef CONFIG_SYS_LONGHELP
d684c216 425 my_puts_P(PSTR("Usage:\n"));
022330eb 426 print_prefixed_name(cmdtp);
f338df2a 427 my_puts_P(PSTR(" "));
d684c216 428
e96dcd6d
L
429 if (cmdtp->help && *cmdtp->help != '\0')
430 puts_P(cmdtp->help);
431 else
d684c216 432 my_puts_P(PSTR(" - No additional help available.\n"));
d684c216 433#endif /* CONFIG_SYS_LONGHELP */
d0581f88 434 return CMD_RET_FAILURE;
d684c216
L
435}
436
437#ifdef CONFIG_AUTO_COMPLETE
438
439int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
440{
dea9a315 441 static char tmp_buf[CONFIG_SYS_CBSIZE];
d684c216
L
442 int space;
443
444 space = last_char == '\0' || isblank(last_char);
445
446 if (space && argc == 1)
447 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
448
449 if (!space && argc == 2)
450 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
451
452 return 0;
453}
454
455/*************************************************************************************/
456
dea9a315
L
457/* TODO: cmdtp points to FLASH */
458
d684c216
L
459static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
460{
461 cmd_tbl_t *cmdtp = cmd_tbl;
462// const int count = ARRAY_SIZE(cmd_tbl);
463// const cmd_tbl_t *cmdend = cmdtp + count;
464// const char *p;
465 int len, clen;
466 int n_found = 0;
467 const char *cmd;
468
469 /* sanity? */
470 if (maxv < 2)
471 return -2;
472
473 cmdv[0] = NULL;
474
475 if (argc == 0) {
476 /* output full list of commands */
477 for (; cmdtp->name[0] != '\0'; cmdtp++) {
478 if (n_found >= maxv - 2) {
479 cmdv[n_found++] = "...";
480 break;
481 }
482 cmdv[n_found++] = cmdtp->name;
483 }
484 cmdv[n_found] = NULL;
485 return n_found;
486 }
487
488 /* more than one arg or one but the start of the next */
489 if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
8da60ec5 490 cmdtp = find_cmd(argv[0], cmd_tbl);
d684c216
L
491 if (cmdtp == NULL || cmdtp->complete == NULL) {
492 cmdv[0] = NULL;
493 return 0;
494 }
495 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
496 }
497
498 cmd = argv[0];
499
500 len = strlen(cmd);
501
502 /* return the partial matches */
503 for (; cmdtp->name[0] != '\0'; cmdtp++) {
504
505 clen = strlen(cmdtp->name);
506 if (clen < len)
507 continue;
508
509 if (memcmp(cmd, cmdtp->name, len) != 0)
510 continue;
511
512 /* too many! */
513 if (n_found >= maxv - 2) {
514 cmdv[n_found++] = "...";
515 break;
516 }
517
518 cmdv[n_found++] = cmdtp->name;
519 }
520
521 cmdv[n_found] = NULL;
522 return n_found;
523}
524
525static int make_argv(char *s, int argvsz, char *argv[])
526{
527 int argc = 0;
528
529 /* split into argv */
530 while (argc < argvsz - 1) {
531
532 /* skip any white space */
533 while (isblank(*s))
534 ++s;
535
536 if (*s == '\0') /* end of s, no more args */
537 break;
538
539 argv[argc++] = s; /* begin of argument string */
540
541 /* find end of string */
542 while (*s && !isblank(*s))
543 ++s;
544
545 if (*s == '\0') /* end of s, no more args */
546 break;
547
548 *s++ = '\0'; /* terminate current arg */
549 }
550 argv[argc] = NULL;
551
552 return argc;
553}
554
555static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[])
556{
557 int ll = leader != NULL ? strlen(leader) : 0;
558 int sl = sep != NULL ? strlen(sep) : 0;
559 int len, i;
560
561 if (banner) {
562 my_puts_P(PSTR("\n"));
563 my_puts(banner);
564 }
565
566 i = linemax; /* force leader and newline */
567 while (*argv != NULL) {
568 len = strlen(*argv) + sl;
569 if (i + len >= linemax) {
570 my_puts_P(PSTR("\n"));
571 if (leader)
572 my_puts(leader);
573 i = ll - sl;
574 } else if (sep)
575 my_puts(sep);
576 my_puts(*argv++);
577 i += len;
578 }
579 my_puts_P(PSTR("\n"));
580}
581
582static int find_common_prefix(char * const argv[])
583{
584 int i, len;
585 char *anchor, *s, *t;
586
587 if (*argv == NULL)
588 return 0;
589
590 /* begin with max */
591 anchor = *argv++;
592 len = strlen(anchor);
593 while ((t = *argv++) != NULL) {
594 s = anchor;
595 for (i = 0; i < len; i++, t++, s++) {
596 if (*t != *s)
597 break;
598 }
599 len = s - anchor;
600 }
601 return len;
602}
603
604static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
605
dea9a315 606
d684c216
L
607int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp)
608{
609 int n = *np, col = *colp;
610 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
611 char *cmdv[20];
612 char *s, *t;
613 const char *sep;
614 int i, j, k, len, seplen, argc;
615 int cnt;
616 char last_char;
617
618 if (strcmp_PP(prompt, CONFIG_SYS_PROMPT) != 0)
619 return 0; /* not in normal console */
620
621 cnt = strlen(buf);
622 if (cnt >= 1)
623 last_char = buf[cnt - 1];
624 else
625 last_char = '\0';
626
627 /* copy to secondary buffer which will be affected */
628 strcpy(tmp_buf, buf);
629
630 /* separate into argv */
631 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
632
633 /* do the completion and return the possible completions */
634 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
635
636 /* no match; bell and out */
637 if (i == 0) {
638 if (argc > 1) /* allow tab for non command */
639 return 0;
640 putchar('\a');
641 return 1;
642 }
643
644 s = NULL;
645 len = 0;
646 sep = NULL;
647 seplen = 0;
648 if (i == 1) { /* one match; perfect */
649 k = strlen(argv[argc - 1]);
650 s = cmdv[0] + k;
651 len = strlen(s);
652 sep = " ";
653 seplen = 1;
654 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
655 k = strlen(argv[argc - 1]);
656 j -= k;
657 if (j > 0) {
658 s = cmdv[0] + k;
659 len = j;
660 }
661 }
662
663 if (s != NULL) {
664 k = len + seplen;
665 /* make sure it fits */
666 if (n + k >= CONFIG_SYS_CBSIZE - 2) {
667 putchar('\a');
668 return 1;
669 }
670
671 t = buf + cnt;
672 for (i = 0; i < len; i++)
673 *t++ = *s++;
674 if (sep != NULL)
675 for (i = 0; i < seplen; i++)
676 *t++ = sep[i];
677 *t = '\0';
678 n += k;
679 col += k;
680 my_puts(t - k);
681 if (sep == NULL)
682 putchar('\a');
683 *np = n;
684 *colp = col;
685 } else {
686 print_argv(NULL, " ", " ", 78, cmdv);
687
688 my_puts_P(prompt);
689 my_puts(buf);
690 }
691 return 1;
692}
693
694#endif /* CONFIG_AUTO_COMPLETE */
695
696
022330eb 697static cmd_tbl_t *cmd_invocation_ptr;
d684c216
L
698
699/**
700 * Call a command function. This should be the only route in U-Boot to call
701 * a command, so that we can track whether we are waiting for input or
702 * executing a command.
703 *
704 * @param cmdtp Pointer to the command to execute
705 * @param flag Some flags normally 0 (see CMD_FLAG_.. above)
706 * @param argc Number of arguments (arg 0 must be the command text)
707 * @param argv Arguments
708 * @return 0 if command succeeded, else non-zero (CMD_RET_...)
709 */
fcf1d5b3 710command_ret_t cmd_call(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
d684c216 711{
d0581f88 712 command_ret_t result;
d684c216
L
713
714 result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
13e88ed5
L
715// if (result != CMD_RET_SUCCESS)
716// debug("Command failed, result=%d\n", result);
d684c216
L
717 return result;
718}
719
7eecbdac
L
720#pragma GCC diagnostic ignored "-Wclobbered"
721
fcf1d5b3 722command_ret_t cmd_process(uint_fast8_t flag, int argc, char * const argv[],
d684c216
L
723 uint_fast8_t *repeatable)
724{
d0581f88 725 command_ret_t rc = CMD_RET_SUCCESS;
d684c216
L
726 cmd_tbl_t *cmdtp;
727
728 /* Look up command in command table */
4077419c 729 cmdtp = find_cmd(argv[0], cmd_tbl);
9d6c43fa
L
730 if (cmdtp != NULL) {
731 /* Check if this command has subcommands */
732 if (cmdtp->subcmd && argc > 1) {
733
734 /* Look up subcommand in subcommand table */
4077419c 735 cmd_tbl_t *cmdtpsub = find_cmd(argv[1], cmdtp->subcmd);
9d6c43fa
L
736 if (cmdtpsub == NULL) {
737 printf_P(PSTR("Unknown '%s' subcommand '%s' - try '%s help'\n"), argv[0], argv[1], argv[0]);
738 return CMD_RET_FAILURE;
739 }
740 cmdtp = cmdtpsub;
741 --argc;
742 ++argv;
743 }
7a1ed620 744 }
9d6c43fa 745
d684c216
L
746 if (cmdtp == NULL) {
747 printf_P(PSTR("Unknown command '%s' - try 'help'\n"), argv[0]);
d0581f88 748 return CMD_RET_FAILURE;
d684c216 749 }
8da60ec5 750
d684c216
L
751 /* found - check max args */
752 if (argc > cmdtp->maxargs)
753 rc = CMD_RET_USAGE;
754
755#if defined(CONFIG_CMD_BOOTD)
756 /* avoid "bootd" recursion */
757 else if (cmdtp->cmd == do_bootd) {
758 if (flag & CMD_FLAG_BOOTD) {
759 my_puts_P(PSTR("'bootd' recursion detected\n"));
760 rc = CMD_RET_FAILURE;
761 } else {
762 flag |= CMD_FLAG_BOOTD;
763 }
764 }
765#endif
766
fcd2239e
L
767 if (setjmp(cmd_jbuf) != 0)
768 return CMD_RET_FAILURE;
769
d684c216
L
770 /* If OK so far, then do the command */
771 if (!rc) {
022330eb 772 cmd_invocation_ptr = cmdtp;
d684c216 773 rc = cmd_call(cmdtp, flag, argc, argv);
7a1ed620 774 *repeatable &= (cmdtp->flags & CTBL_RPT) != 0;
d684c216
L
775 }
776 if (rc == CMD_RET_USAGE)
777 rc = cmd_usage(cmdtp);
778 return rc;
779}
780
781int cmd_process_error(cmd_tbl_t *cmdtp, int err)
782{
783 char buf[strlen_P(cmdtp->name) + 1];
784 strcpy_P(buf, cmdtp->name);
785
786 if (err) {
787 printf_P(PSTR("Command '%s' failed: Error %d\n"), buf, err);
788 return 1;
789 }
790
791 return 0;
792}
022330eb
L
793
794
795void cmd_error(const char *fmt, ...)
796{
797 va_list ap;
798 va_start(ap, fmt);
799 print_prefixed_name(cmd_invocation_ptr);
800 my_puts_P(PSTR(": "));
801 vfprintf_P(stdout, fmt, ap);
802 va_end(ap);
803 putchar('\n');
804 _delay_ms(20);
805 //command_ret = CMD_RET_FAILURE;
806}