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