]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/command.c
xx commands: measure cpu freq, test bus cycles
[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
265 /* reset getopt() */
266 optind = 0;
267
268 int opt;
269 while ((opt = getopt(argc, argv, PSTR("afk"))) != -1) {
270 switch (opt) {
271 case 'a':
272 options |= OPT_ALL;
273 break;
274 case 'f':
275 options |= OPT_NAME | OPT_ALL;
276 break;
277 case 'k':
278 options |= OPT_USAGE | OPT_ALL;
279 break;
280 default: /* '?' */
281 return CMD_RET_USAGE;
282 }
283 }
5caa8c2b 284
c646b5a9
L
285 /* remaining arguments */
286 argc -= optind;
287 argv += optind;
ccb6ffb9 288
c646b5a9
L
289 if ((options & (OPT_USAGE|OPT_NAME)) == (OPT_USAGE|OPT_NAME)) {
290 puts_P(PSTR("Inkompatible options: -f -k\n"
291 "Try 'help help'"));
292 return CMD_RET_USAGE;
293 }
294 if (options & OPT_USAGE)
295 options |= OPT_NAME;
296
297 if ((options & (OPT_NAME | OPT_USAGE)) == 0 && argc > 0)
298 options |= OPT_LONG;
299
300 char *optenv = getenv_str(PSTR("cmd"));
301 if (optenv && strstr_P(optenv, PSTR("debug")) != NULL)
302 options |= OPT_DBG_CMDS;
303
304 uint_fast8_t maxlen_cmd;
305 int cmd_items;
306 cmd_tbl_t **cmd_list = NULL;
307 for (uint_fast8_t pass = 0; pass < 2; ++pass) {
308 maxlen_cmd = 0;
309 if (pass == 0)
310 cmd_items = 0;
311 else {
312 cmd_list = (cmd_tbl_t **) malloc(cmd_items * sizeof(cmd_tbl_t *));
313 /* TODO: Check error */
314 }
d684c216 315
292f0519
L
316 /* Make array of commands */
317 cmd_tbl_t *tp = tbl_start;
04f84937
L
318 int i = 0;
319 while (tp->name != NULL) {
dab74a42 320 if (tp->subcmd) {
04f84937
L
321 cmd_tbl_t *sub = tp->subcmd;
322 while (sub->name != NULL) {
c646b5a9
L
323 if (options & OPT_ALL || sub->flags & CTBL_SUBCMDAUTO) {
324 if (pass == 0)
325 ++cmd_items;
326 else {
327 cmd_list[i++] = sub;
328 uint_fast8_t len = strlen_P(sub->name);
329 if ((sub->flags & CTBL_SUBCMDAUTO) == 0) {
330 len += strlen_P(tp->name) + 1;
331 }
332 if (len > maxlen_cmd) {
333 maxlen_cmd = len;
334 }
335//debug_cmd("### i:%3d, maxlen:%3d, tp: '%S', sub: '%S'\n", i, maxlen_cmd, tp->name, sub->name);
336 }
04f84937
L
337 }
338 sub++;
339 }
340 }
dab74a42 341 if ((tp->flags & CTBL_SUBCMDAUTO) == 0) {
c646b5a9
L
342 if (pass == 0)
343 ++cmd_items;
344 else {
dab74a42 345 cmd_list[i++] = tp;
c646b5a9
L
346 uint_fast8_t len = strlen_P(tp->name);
347 cmd_tbl_t *top = get_cmd_tbl_parent(tp);
348 if (top)
349 len += strlen_P(top->name) + 1;
350 if (len > maxlen_cmd)
351 maxlen_cmd = len;
352 }
dab74a42
L
353 }
354 tp++;
d684c216 355 }
c646b5a9
L
356//debug_cmd("### pass: %d, cmd_items: %d, i: %d, maxlen_cmd: %d\n", pass, cmd_items, i, maxlen_cmd);
357 }
d684c216 358
c646b5a9
L
359 /* Sort command list */
360 qsort(cmd_list, cmd_items, sizeof (cmd_tbl_t *), cmpstring_PP);
ccb6ffb9 361
c646b5a9
L
362 if ((options & OPT_LONG) == 0) {
363 /* print short help (usage) */
364 for (uint_fast8_t cmdi = 0; cmdi < cmd_items; cmdi++) {
e96dcd6d
L
365
366 /* allow user abort */
367 if (ctrlc ()) {
c646b5a9 368 res = CMD_RET_FAILURE;
e96dcd6d 369 break;
ccb6ffb9 370 }
c646b5a9
L
371 if ((cmd_list[cmdi]->flags & CTBL_DBG) && !(options & OPT_DBG_CMDS))
372 continue;
373 if (cmd_list[cmdi]->usage == NULL)
374 continue;
8da60ec5 375
c646b5a9
L
376 if (argc == 0)
377 print_usage_line(cmd_list[cmdi], maxlen_cmd);
378 else {
379 for (uint_fast8_t argi = 0; argi < argc; argi++) {
380 if (((options & OPT_NAME) &&
381 strcasestr_P2(cmd_list[cmdi]->name, argv[argi])) ||
382 ((options & OPT_USAGE) &&
383 strcasestr_P2(cmd_list[cmdi]->usage, argv[argi]))) {
384 print_usage_line(cmd_list[cmdi], maxlen_cmd);
385 }
386 }
387 }
388 }
389 } else {
390 /* command help (long version) */
391 for (uint_fast8_t argi = 0; argi < argc; ++argi) {
392 uint_fast8_t got = 0;
f766ff54
L
393 cmd_tbl_t *tp = find_cmd(argv[argi], tbl_start);
394 if (tp) {
395 cmd_usage(tp);
396 got = 1;
397 }
398 if (options & OPT_ALL) {
399 for (cmd_tbl_t *sub = tbl_start; sub->name != NULL; sub++) {
400 if (sub->subcmd) {
401 tp = find_cmd(argv[argi], sub->subcmd);
402 if (tp) {
403 cmd_usage(tp);
404 got = 1;
405 }
406 }
c646b5a9
L
407 }
408 }
409 if (!got) {
410 printf_P(PSTR("Unknown command '%s' - try 'help help'\n"),
411 argv[argi]);
412 res = CMD_RET_FAILURE;
413 break;
414 }
d684c216
L
415 }
416 }
c646b5a9
L
417 free(cmd_list);
418 return res;
d684c216
L
419}
420
d684c216 421
04f84937 422command_ret_t cmd_usage(cmd_tbl_t *cmdtp)
d684c216 423{
e96dcd6d 424 print_usage_line(cmdtp, 0);
d684c216 425#ifdef CONFIG_SYS_LONGHELP
d684c216 426 my_puts_P(PSTR("Usage:\n"));
022330eb 427 print_prefixed_name(cmdtp);
f338df2a 428 my_puts_P(PSTR(" "));
d684c216 429
e96dcd6d
L
430 if (cmdtp->help && *cmdtp->help != '\0')
431 puts_P(cmdtp->help);
432 else
d684c216 433 my_puts_P(PSTR(" - No additional help available.\n"));
d684c216 434#endif /* CONFIG_SYS_LONGHELP */
d0581f88 435 return CMD_RET_FAILURE;
d684c216
L
436}
437
438#ifdef CONFIG_AUTO_COMPLETE
439
440int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
441{
dea9a315 442 static char tmp_buf[CONFIG_SYS_CBSIZE];
d684c216
L
443 int space;
444
445 space = last_char == '\0' || isblank(last_char);
446
447 if (space && argc == 1)
448 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
449
450 if (!space && argc == 2)
451 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
452
453 return 0;
454}
455
456/*************************************************************************************/
457
dea9a315
L
458/* TODO: cmdtp points to FLASH */
459
d684c216
L
460static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
461{
462 cmd_tbl_t *cmdtp = cmd_tbl;
463// const int count = ARRAY_SIZE(cmd_tbl);
464// const cmd_tbl_t *cmdend = cmdtp + count;
465// const char *p;
466 int len, clen;
467 int n_found = 0;
468 const char *cmd;
469
470 /* sanity? */
471 if (maxv < 2)
472 return -2;
473
474 cmdv[0] = NULL;
475
476 if (argc == 0) {
477 /* output full list of commands */
478 for (; cmdtp->name[0] != '\0'; cmdtp++) {
479 if (n_found >= maxv - 2) {
480 cmdv[n_found++] = "...";
481 break;
482 }
483 cmdv[n_found++] = cmdtp->name;
484 }
485 cmdv[n_found] = NULL;
486 return n_found;
487 }
488
489 /* more than one arg or one but the start of the next */
490 if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
8da60ec5 491 cmdtp = find_cmd(argv[0], cmd_tbl);
d684c216
L
492 if (cmdtp == NULL || cmdtp->complete == NULL) {
493 cmdv[0] = NULL;
494 return 0;
495 }
496 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
497 }
498
499 cmd = argv[0];
500
501 len = strlen(cmd);
502
503 /* return the partial matches */
504 for (; cmdtp->name[0] != '\0'; cmdtp++) {
505
506 clen = strlen(cmdtp->name);
507 if (clen < len)
508 continue;
509
510 if (memcmp(cmd, cmdtp->name, len) != 0)
511 continue;
512
513 /* too many! */
514 if (n_found >= maxv - 2) {
515 cmdv[n_found++] = "...";
516 break;
517 }
518
519 cmdv[n_found++] = cmdtp->name;
520 }
521
522 cmdv[n_found] = NULL;
523 return n_found;
524}
525
526static int make_argv(char *s, int argvsz, char *argv[])
527{
528 int argc = 0;
529
530 /* split into argv */
531 while (argc < argvsz - 1) {
532
533 /* skip any white space */
534 while (isblank(*s))
535 ++s;
536
537 if (*s == '\0') /* end of s, no more args */
538 break;
539
540 argv[argc++] = s; /* begin of argument string */
541
542 /* find end of string */
543 while (*s && !isblank(*s))
544 ++s;
545
546 if (*s == '\0') /* end of s, no more args */
547 break;
548
549 *s++ = '\0'; /* terminate current arg */
550 }
551 argv[argc] = NULL;
552
553 return argc;
554}
555
556static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[])
557{
558 int ll = leader != NULL ? strlen(leader) : 0;
559 int sl = sep != NULL ? strlen(sep) : 0;
560 int len, i;
561
562 if (banner) {
563 my_puts_P(PSTR("\n"));
564 my_puts(banner);
565 }
566
567 i = linemax; /* force leader and newline */
568 while (*argv != NULL) {
569 len = strlen(*argv) + sl;
570 if (i + len >= linemax) {
571 my_puts_P(PSTR("\n"));
572 if (leader)
573 my_puts(leader);
574 i = ll - sl;
575 } else if (sep)
576 my_puts(sep);
577 my_puts(*argv++);
578 i += len;
579 }
580 my_puts_P(PSTR("\n"));
581}
582
583static int find_common_prefix(char * const argv[])
584{
585 int i, len;
586 char *anchor, *s, *t;
587
588 if (*argv == NULL)
589 return 0;
590
591 /* begin with max */
592 anchor = *argv++;
593 len = strlen(anchor);
594 while ((t = *argv++) != NULL) {
595 s = anchor;
596 for (i = 0; i < len; i++, t++, s++) {
597 if (*t != *s)
598 break;
599 }
600 len = s - anchor;
601 }
602 return len;
603}
604
605static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
606
dea9a315 607
d684c216
L
608int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp)
609{
610 int n = *np, col = *colp;
611 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
612 char *cmdv[20];
613 char *s, *t;
614 const char *sep;
615 int i, j, k, len, seplen, argc;
616 int cnt;
617 char last_char;
618
619 if (strcmp_PP(prompt, CONFIG_SYS_PROMPT) != 0)
620 return 0; /* not in normal console */
621
622 cnt = strlen(buf);
623 if (cnt >= 1)
624 last_char = buf[cnt - 1];
625 else
626 last_char = '\0';
627
628 /* copy to secondary buffer which will be affected */
629 strcpy(tmp_buf, buf);
630
631 /* separate into argv */
632 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
633
634 /* do the completion and return the possible completions */
635 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
636
637 /* no match; bell and out */
638 if (i == 0) {
639 if (argc > 1) /* allow tab for non command */
640 return 0;
641 putchar('\a');
642 return 1;
643 }
644
645 s = NULL;
646 len = 0;
647 sep = NULL;
648 seplen = 0;
649 if (i == 1) { /* one match; perfect */
650 k = strlen(argv[argc - 1]);
651 s = cmdv[0] + k;
652 len = strlen(s);
653 sep = " ";
654 seplen = 1;
655 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
656 k = strlen(argv[argc - 1]);
657 j -= k;
658 if (j > 0) {
659 s = cmdv[0] + k;
660 len = j;
661 }
662 }
663
664 if (s != NULL) {
665 k = len + seplen;
666 /* make sure it fits */
667 if (n + k >= CONFIG_SYS_CBSIZE - 2) {
668 putchar('\a');
669 return 1;
670 }
671
672 t = buf + cnt;
673 for (i = 0; i < len; i++)
674 *t++ = *s++;
675 if (sep != NULL)
676 for (i = 0; i < seplen; i++)
677 *t++ = sep[i];
678 *t = '\0';
679 n += k;
680 col += k;
681 my_puts(t - k);
682 if (sep == NULL)
683 putchar('\a');
684 *np = n;
685 *colp = col;
686 } else {
687 print_argv(NULL, " ", " ", 78, cmdv);
688
689 my_puts_P(prompt);
690 my_puts(buf);
691 }
692 return 1;
693}
694
695#endif /* CONFIG_AUTO_COMPLETE */
696
697
022330eb 698static cmd_tbl_t *cmd_invocation_ptr;
d684c216
L
699
700/**
701 * Call a command function. This should be the only route in U-Boot to call
702 * a command, so that we can track whether we are waiting for input or
703 * executing a command.
704 *
705 * @param cmdtp Pointer to the command to execute
706 * @param flag Some flags normally 0 (see CMD_FLAG_.. above)
707 * @param argc Number of arguments (arg 0 must be the command text)
708 * @param argv Arguments
709 * @return 0 if command succeeded, else non-zero (CMD_RET_...)
710 */
fcf1d5b3 711command_ret_t cmd_call(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
d684c216 712{
d0581f88 713 command_ret_t result;
d684c216
L
714
715 result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
13e88ed5
L
716// if (result != CMD_RET_SUCCESS)
717// debug("Command failed, result=%d\n", result);
d684c216
L
718 return result;
719}
720
7eecbdac
L
721#pragma GCC diagnostic ignored "-Wclobbered"
722
fcf1d5b3 723command_ret_t cmd_process(uint_fast8_t flag, int argc, char * const argv[],
d684c216
L
724 uint_fast8_t *repeatable)
725{
d0581f88 726 command_ret_t rc = CMD_RET_SUCCESS;
d684c216
L
727 cmd_tbl_t *cmdtp;
728
729 /* Look up command in command table */
4077419c 730 cmdtp = find_cmd(argv[0], cmd_tbl);
9d6c43fa
L
731 if (cmdtp != NULL) {
732 /* Check if this command has subcommands */
733 if (cmdtp->subcmd && argc > 1) {
734
735 /* Look up subcommand in subcommand table */
4077419c 736 cmd_tbl_t *cmdtpsub = find_cmd(argv[1], cmdtp->subcmd);
9d6c43fa
L
737 if (cmdtpsub == NULL) {
738 printf_P(PSTR("Unknown '%s' subcommand '%s' - try '%s help'\n"), argv[0], argv[1], argv[0]);
739 return CMD_RET_FAILURE;
740 }
741 cmdtp = cmdtpsub;
742 --argc;
743 ++argv;
744 }
7a1ed620 745 }
9d6c43fa 746
d684c216
L
747 if (cmdtp == NULL) {
748 printf_P(PSTR("Unknown command '%s' - try 'help'\n"), argv[0]);
d0581f88 749 return CMD_RET_FAILURE;
d684c216 750 }
8da60ec5 751
d684c216
L
752 /* found - check max args */
753 if (argc > cmdtp->maxargs)
754 rc = CMD_RET_USAGE;
755
756#if defined(CONFIG_CMD_BOOTD)
757 /* avoid "bootd" recursion */
758 else if (cmdtp->cmd == do_bootd) {
759 if (flag & CMD_FLAG_BOOTD) {
760 my_puts_P(PSTR("'bootd' recursion detected\n"));
761 rc = CMD_RET_FAILURE;
762 } else {
763 flag |= CMD_FLAG_BOOTD;
764 }
765 }
766#endif
767
fcd2239e
L
768 if (setjmp(cmd_jbuf) != 0)
769 return CMD_RET_FAILURE;
770
d684c216
L
771 /* If OK so far, then do the command */
772 if (!rc) {
022330eb 773 cmd_invocation_ptr = cmdtp;
d684c216 774 rc = cmd_call(cmdtp, flag, argc, argv);
7a1ed620 775 *repeatable &= (cmdtp->flags & CTBL_RPT) != 0;
d684c216
L
776 }
777 if (rc == CMD_RET_USAGE)
778 rc = cmd_usage(cmdtp);
779 return rc;
780}
781
782int cmd_process_error(cmd_tbl_t *cmdtp, int err)
783{
784 char buf[strlen_P(cmdtp->name) + 1];
785 strcpy_P(buf, cmdtp->name);
786
787 if (err) {
788 printf_P(PSTR("Command '%s' failed: Error %d\n"), buf, err);
789 return 1;
790 }
791
792 return 0;
793}
022330eb 794
414caa77 795void cmd_error(int status, int errnum, const char *fmt, ...)
022330eb
L
796{
797 va_list ap;
798 va_start(ap, fmt);
799 print_prefixed_name(cmd_invocation_ptr);
414caa77
L
800 if (fmt != NULL) {
801 my_puts_P(PSTR(": "));
802 vfprintf_P(stdout, fmt, ap);
803 }
022330eb 804 va_end(ap);
414caa77
L
805
806 if (errnum != 0)
807 printf_P(PSTR(": %S"), my_strerror_P(errnum));
808
022330eb
L
809 putchar('\n');
810 _delay_ms(20);
414caa77
L
811
812 if (status != 0) {
813 longjmp(cmd_jbuf, 1);
814 }
022330eb 815}