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