]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/command.c
pwd hack
[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;
383
384 for (uint_fast8_t cmdi = 0; cmdi < cmd_items; cmdi++) {
385 if (strcmp_P(argv[argi], cmd_list[cmdi]->name) == 0) {
386 cmd_usage(cmd_list[cmdi]);
387 got = 1;
388 }
389 }
390 if (!got) {
391 printf_P(PSTR("Unknown command '%s' - try 'help help'\n"),
392 argv[argi]);
393 res = CMD_RET_FAILURE;
394 break;
395 }
d684c216
L
396 }
397 }
c646b5a9
L
398 free(cmd_list);
399 return res;
d684c216
L
400}
401
d684c216 402
04f84937 403command_ret_t cmd_usage(cmd_tbl_t *cmdtp)
d684c216 404{
e96dcd6d 405 print_usage_line(cmdtp, 0);
d684c216 406#ifdef CONFIG_SYS_LONGHELP
d684c216 407 my_puts_P(PSTR("Usage:\n"));
bc72540a 408 print_name_prefix(cmdtp);
d684c216 409 my_puts_P(cmdtp->name);
f338df2a 410 my_puts_P(PSTR(" "));
d684c216 411
e96dcd6d
L
412 if (cmdtp->help && *cmdtp->help != '\0')
413 puts_P(cmdtp->help);
414 else
d684c216 415 my_puts_P(PSTR(" - No additional help available.\n"));
d684c216 416#endif /* CONFIG_SYS_LONGHELP */
d0581f88 417 return CMD_RET_FAILURE;
d684c216
L
418}
419
420#ifdef CONFIG_AUTO_COMPLETE
421
422int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
423{
dea9a315 424 static char tmp_buf[CONFIG_SYS_CBSIZE];
d684c216
L
425 int space;
426
427 space = last_char == '\0' || isblank(last_char);
428
429 if (space && argc == 1)
430 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
431
432 if (!space && argc == 2)
433 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
434
435 return 0;
436}
437
438/*************************************************************************************/
439
dea9a315
L
440/* TODO: cmdtp points to FLASH */
441
d684c216
L
442static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
443{
444 cmd_tbl_t *cmdtp = cmd_tbl;
445// const int count = ARRAY_SIZE(cmd_tbl);
446// const cmd_tbl_t *cmdend = cmdtp + count;
447// const char *p;
448 int len, clen;
449 int n_found = 0;
450 const char *cmd;
451
452 /* sanity? */
453 if (maxv < 2)
454 return -2;
455
456 cmdv[0] = NULL;
457
458 if (argc == 0) {
459 /* output full list of commands */
460 for (; cmdtp->name[0] != '\0'; cmdtp++) {
461 if (n_found >= maxv - 2) {
462 cmdv[n_found++] = "...";
463 break;
464 }
465 cmdv[n_found++] = cmdtp->name;
466 }
467 cmdv[n_found] = NULL;
468 return n_found;
469 }
470
471 /* more than one arg or one but the start of the next */
472 if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
8da60ec5 473 cmdtp = find_cmd(argv[0], cmd_tbl);
d684c216
L
474 if (cmdtp == NULL || cmdtp->complete == NULL) {
475 cmdv[0] = NULL;
476 return 0;
477 }
478 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
479 }
480
481 cmd = argv[0];
482
483 len = strlen(cmd);
484
485 /* return the partial matches */
486 for (; cmdtp->name[0] != '\0'; cmdtp++) {
487
488 clen = strlen(cmdtp->name);
489 if (clen < len)
490 continue;
491
492 if (memcmp(cmd, cmdtp->name, len) != 0)
493 continue;
494
495 /* too many! */
496 if (n_found >= maxv - 2) {
497 cmdv[n_found++] = "...";
498 break;
499 }
500
501 cmdv[n_found++] = cmdtp->name;
502 }
503
504 cmdv[n_found] = NULL;
505 return n_found;
506}
507
508static int make_argv(char *s, int argvsz, char *argv[])
509{
510 int argc = 0;
511
512 /* split into argv */
513 while (argc < argvsz - 1) {
514
515 /* skip any white space */
516 while (isblank(*s))
517 ++s;
518
519 if (*s == '\0') /* end of s, no more args */
520 break;
521
522 argv[argc++] = s; /* begin of argument string */
523
524 /* find end of string */
525 while (*s && !isblank(*s))
526 ++s;
527
528 if (*s == '\0') /* end of s, no more args */
529 break;
530
531 *s++ = '\0'; /* terminate current arg */
532 }
533 argv[argc] = NULL;
534
535 return argc;
536}
537
538static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[])
539{
540 int ll = leader != NULL ? strlen(leader) : 0;
541 int sl = sep != NULL ? strlen(sep) : 0;
542 int len, i;
543
544 if (banner) {
545 my_puts_P(PSTR("\n"));
546 my_puts(banner);
547 }
548
549 i = linemax; /* force leader and newline */
550 while (*argv != NULL) {
551 len = strlen(*argv) + sl;
552 if (i + len >= linemax) {
553 my_puts_P(PSTR("\n"));
554 if (leader)
555 my_puts(leader);
556 i = ll - sl;
557 } else if (sep)
558 my_puts(sep);
559 my_puts(*argv++);
560 i += len;
561 }
562 my_puts_P(PSTR("\n"));
563}
564
565static int find_common_prefix(char * const argv[])
566{
567 int i, len;
568 char *anchor, *s, *t;
569
570 if (*argv == NULL)
571 return 0;
572
573 /* begin with max */
574 anchor = *argv++;
575 len = strlen(anchor);
576 while ((t = *argv++) != NULL) {
577 s = anchor;
578 for (i = 0; i < len; i++, t++, s++) {
579 if (*t != *s)
580 break;
581 }
582 len = s - anchor;
583 }
584 return len;
585}
586
587static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
588
dea9a315 589
d684c216
L
590int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp)
591{
592 int n = *np, col = *colp;
593 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
594 char *cmdv[20];
595 char *s, *t;
596 const char *sep;
597 int i, j, k, len, seplen, argc;
598 int cnt;
599 char last_char;
600
601 if (strcmp_PP(prompt, CONFIG_SYS_PROMPT) != 0)
602 return 0; /* not in normal console */
603
604 cnt = strlen(buf);
605 if (cnt >= 1)
606 last_char = buf[cnt - 1];
607 else
608 last_char = '\0';
609
610 /* copy to secondary buffer which will be affected */
611 strcpy(tmp_buf, buf);
612
613 /* separate into argv */
614 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
615
616 /* do the completion and return the possible completions */
617 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
618
619 /* no match; bell and out */
620 if (i == 0) {
621 if (argc > 1) /* allow tab for non command */
622 return 0;
623 putchar('\a');
624 return 1;
625 }
626
627 s = NULL;
628 len = 0;
629 sep = NULL;
630 seplen = 0;
631 if (i == 1) { /* one match; perfect */
632 k = strlen(argv[argc - 1]);
633 s = cmdv[0] + k;
634 len = strlen(s);
635 sep = " ";
636 seplen = 1;
637 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
638 k = strlen(argv[argc - 1]);
639 j -= k;
640 if (j > 0) {
641 s = cmdv[0] + k;
642 len = j;
643 }
644 }
645
646 if (s != NULL) {
647 k = len + seplen;
648 /* make sure it fits */
649 if (n + k >= CONFIG_SYS_CBSIZE - 2) {
650 putchar('\a');
651 return 1;
652 }
653
654 t = buf + cnt;
655 for (i = 0; i < len; i++)
656 *t++ = *s++;
657 if (sep != NULL)
658 for (i = 0; i < seplen; i++)
659 *t++ = sep[i];
660 *t = '\0';
661 n += k;
662 col += k;
663 my_puts(t - k);
664 if (sep == NULL)
665 putchar('\a');
666 *np = n;
667 *colp = col;
668 } else {
669 print_argv(NULL, " ", " ", 78, cmdv);
670
671 my_puts_P(prompt);
672 my_puts(buf);
673 }
674 return 1;
675}
676
677#endif /* CONFIG_AUTO_COMPLETE */
678
679
680
681/**
682 * Call a command function. This should be the only route in U-Boot to call
683 * a command, so that we can track whether we are waiting for input or
684 * executing a command.
685 *
686 * @param cmdtp Pointer to the command to execute
687 * @param flag Some flags normally 0 (see CMD_FLAG_.. above)
688 * @param argc Number of arguments (arg 0 must be the command text)
689 * @param argv Arguments
690 * @return 0 if command succeeded, else non-zero (CMD_RET_...)
691 */
fcf1d5b3 692command_ret_t cmd_call(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
d684c216 693{
d0581f88 694 command_ret_t result;
d684c216
L
695
696 result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
13e88ed5
L
697// if (result != CMD_RET_SUCCESS)
698// debug("Command failed, result=%d\n", result);
d684c216
L
699 return result;
700}
701
7eecbdac
L
702#pragma GCC diagnostic ignored "-Wclobbered"
703
fcf1d5b3 704command_ret_t cmd_process(uint_fast8_t flag, int argc, char * const argv[],
d684c216
L
705 uint_fast8_t *repeatable)
706{
d0581f88 707 command_ret_t rc = CMD_RET_SUCCESS;
d684c216
L
708 cmd_tbl_t *cmdtp;
709
710 /* Look up command in command table */
4077419c 711 cmdtp = find_cmd(argv[0], cmd_tbl);
9d6c43fa
L
712 if (cmdtp != NULL) {
713 /* Check if this command has subcommands */
714 if (cmdtp->subcmd && argc > 1) {
715
716 /* Look up subcommand in subcommand table */
4077419c 717 cmd_tbl_t *cmdtpsub = find_cmd(argv[1], cmdtp->subcmd);
9d6c43fa
L
718 if (cmdtpsub == NULL) {
719 printf_P(PSTR("Unknown '%s' subcommand '%s' - try '%s help'\n"), argv[0], argv[1], argv[0]);
720 return CMD_RET_FAILURE;
721 }
722 cmdtp = cmdtpsub;
723 --argc;
724 ++argv;
725 }
7a1ed620 726 }
9d6c43fa 727
d684c216
L
728 if (cmdtp == NULL) {
729 printf_P(PSTR("Unknown command '%s' - try 'help'\n"), argv[0]);
d0581f88 730 return CMD_RET_FAILURE;
d684c216 731 }
8da60ec5 732
d684c216
L
733 /* found - check max args */
734 if (argc > cmdtp->maxargs)
735 rc = CMD_RET_USAGE;
736
737#if defined(CONFIG_CMD_BOOTD)
738 /* avoid "bootd" recursion */
739 else if (cmdtp->cmd == do_bootd) {
740 if (flag & CMD_FLAG_BOOTD) {
741 my_puts_P(PSTR("'bootd' recursion detected\n"));
742 rc = CMD_RET_FAILURE;
743 } else {
744 flag |= CMD_FLAG_BOOTD;
745 }
746 }
747#endif
748
fcd2239e
L
749 if (setjmp(cmd_jbuf) != 0)
750 return CMD_RET_FAILURE;
751
d684c216
L
752 /* If OK so far, then do the command */
753 if (!rc) {
754 rc = cmd_call(cmdtp, flag, argc, argv);
7a1ed620 755 *repeatable &= (cmdtp->flags & CTBL_RPT) != 0;
d684c216
L
756 }
757 if (rc == CMD_RET_USAGE)
758 rc = cmd_usage(cmdtp);
759 return rc;
760}
761
762int cmd_process_error(cmd_tbl_t *cmdtp, int err)
763{
764 char buf[strlen_P(cmdtp->name) + 1];
765 strcpy_P(buf, cmdtp->name);
766
767 if (err) {
768 printf_P(PSTR("Command '%s' failed: Error %d\n"), buf, err);
769 return 1;
770 }
771
772 return 0;
773}