]> Git Repo - J-u-boot.git/blame - common/command.c
Command usage cleanup
[J-u-boot.git] / common / command.c
CommitLineData
5dfa25f2 1/*
8bde7f77 2 * (C) Copyright 2000-2003
5dfa25f2
WD
3 * Wolfgang Denk, DENX Software Engineering, [email protected].
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * Command Processor Table
26 */
27
28#include <common.h>
29#include <command.h>
5dfa25f2
WD
30
31int
32do_version (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
33{
34 extern char version_string[];
35 printf ("\n%s\n", version_string);
36 return 0;
37}
38
0d498393
WD
39U_BOOT_CMD(
40 version, 1, 1, do_version,
2fb2604d 41 "print monitor version",
b0fce99b
WD
42 NULL
43);
44
c3517f91 45#if defined(CONFIG_CMD_ECHO)
953c5b6f 46
5dfa25f2
WD
47int
48do_echo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
49{
50 int i, putnl = 1;
51
52 for (i = 1; i < argc; i++) {
53 char *p = argv[i], c;
54
55 if (i > 1)
56 putc(' ');
71f95118 57 while ((c = *p++) != '\0') {
5dfa25f2
WD
58 if (c == '\\' && *p == 'c') {
59 putnl = 0;
60 p++;
71f95118 61 } else {
5dfa25f2 62 putc(c);
71f95118
WD
63 }
64 }
5dfa25f2
WD
65 }
66
67 if (putnl)
68 putc('\n');
69 return 0;
70}
71
0d498393 72U_BOOT_CMD(
6d0f6bcf 73 echo, CONFIG_SYS_MAXARGS, 1, do_echo,
2fb2604d 74 "echo args to console",
53677ef1 75 "[args..]\n"
b0fce99b
WD
76 " - echo args to console; \\c suppresses newline\n"
77);
78
90253178 79#endif
953c5b6f 80
6d0f6bcf 81#ifdef CONFIG_SYS_HUSH_PARSER
c26e454d
WD
82
83int
84do_test (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
85{
86 char **ap;
87 int left, adv, expr, last_expr, neg, last_cmp;
88
89 /* args? */
90 if (argc < 3)
91 return 1;
92
93#if 0
94 {
95 printf("test:");
6e592385 96 left = 1;
c26e454d
WD
97 while (argv[left])
98 printf(" %s", argv[left++]);
99 }
100#endif
6e592385 101
c26e454d
WD
102 last_expr = 0;
103 left = argc - 1; ap = argv + 1;
104 if (left > 0 && strcmp(ap[0], "!") == 0) {
105 neg = 1;
106 ap++;
107 left--;
108 } else
109 neg = 0;
110
111 expr = -1;
112 last_cmp = -1;
113 last_expr = -1;
114 while (left > 0) {
115
116 if (strcmp(ap[0], "-o") == 0 || strcmp(ap[0], "-a") == 0)
117 adv = 1;
118 else if (strcmp(ap[0], "-z") == 0 || strcmp(ap[0], "-n") == 0)
119 adv = 2;
120 else
121 adv = 3;
122
123 if (left < adv) {
124 expr = 1;
125 break;
126 }
127
128 if (adv == 1) {
129 if (strcmp(ap[0], "-o") == 0) {
130 last_expr = expr;
131 last_cmp = 0;
132 } else if (strcmp(ap[0], "-a") == 0) {
133 last_expr = expr;
134 last_cmp = 1;
135 } else {
136 expr = 1;
137 break;
138 }
139 }
140
141 if (adv == 2) {
142 if (strcmp(ap[0], "-z") == 0)
c26e454d 143 expr = strlen(ap[1]) == 0 ? 1 : 0;
20787e23
WD
144 else if (strcmp(ap[0], "-n") == 0)
145 expr = strlen(ap[1]) == 0 ? 0 : 1;
c26e454d
WD
146 else {
147 expr = 1;
148 break;
149 }
150
151 if (last_cmp == 0)
152 expr = last_expr || expr;
153 else if (last_cmp == 1)
154 expr = last_expr && expr;
155 last_cmp = -1;
156 }
157
158 if (adv == 3) {
159 if (strcmp(ap[1], "=") == 0)
160 expr = strcmp(ap[0], ap[2]) == 0;
161 else if (strcmp(ap[1], "!=") == 0)
162 expr = strcmp(ap[0], ap[2]) != 0;
163 else if (strcmp(ap[1], ">") == 0)
164 expr = strcmp(ap[0], ap[2]) > 0;
165 else if (strcmp(ap[1], "<") == 0)
166 expr = strcmp(ap[0], ap[2]) < 0;
167 else if (strcmp(ap[1], "-eq") == 0)
168 expr = simple_strtol(ap[0], NULL, 10) == simple_strtol(ap[2], NULL, 10);
169 else if (strcmp(ap[1], "-ne") == 0)
170 expr = simple_strtol(ap[0], NULL, 10) != simple_strtol(ap[2], NULL, 10);
171 else if (strcmp(ap[1], "-lt") == 0)
172 expr = simple_strtol(ap[0], NULL, 10) < simple_strtol(ap[2], NULL, 10);
173 else if (strcmp(ap[1], "-le") == 0)
174 expr = simple_strtol(ap[0], NULL, 10) <= simple_strtol(ap[2], NULL, 10);
175 else if (strcmp(ap[1], "-gt") == 0)
176 expr = simple_strtol(ap[0], NULL, 10) > simple_strtol(ap[2], NULL, 10);
177 else if (strcmp(ap[1], "-ge") == 0)
178 expr = simple_strtol(ap[0], NULL, 10) >= simple_strtol(ap[2], NULL, 10);
179 else {
180 expr = 1;
181 break;
182 }
183
184 if (last_cmp == 0)
185 expr = last_expr || expr;
186 else if (last_cmp == 1)
187 expr = last_expr && expr;
188 last_cmp = -1;
189 }
190
191 ap += adv; left -= adv;
192 }
193
194 if (neg)
195 expr = !expr;
196
197 expr = !expr;
198
53677ef1 199 debug (": returns %d\n", expr);
c26e454d
WD
200
201 return expr;
202}
203
204U_BOOT_CMD(
6d0f6bcf 205 test, CONFIG_SYS_MAXARGS, 1, do_test,
2fb2604d 206 "minimal test like /bin/sh",
53677ef1 207 "[args..]\n"
c26e454d
WD
208 " - test functionality\n"
209);
210
211int
212do_exit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
213{
214 int r;
215
216 r = 0;
217 if (argc > 1)
218 r = simple_strtoul(argv[1], NULL, 10);
219
220 return -r - 2;
221}
222
223U_BOOT_CMD(
224 exit, 2, 1, do_exit,
2fb2604d 225 "exit script",
c26e454d
WD
226 " - exit functionality\n"
227);
228
229
230#endif
231
5dfa25f2
WD
232/*
233 * Use puts() instead of printf() to avoid printf buffer overflow
234 * for long help messages
235 */
8bde7f77 236int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
5dfa25f2
WD
237{
238 int i;
239 int rcode = 0;
240
8bde7f77
WD
241 if (argc == 1) { /*show list of commands */
242
9d2b18a0
WD
243 int cmd_items = &__u_boot_cmd_end -
244 &__u_boot_cmd_start; /* pointer arith! */
245 cmd_tbl_t *cmd_array[cmd_items];
246 int i, j, swaps;
247
248 /* Make array of commands from .uboot_cmd section */
249 cmdtp = &__u_boot_cmd_start;
250 for (i = 0; i < cmd_items; i++) {
251 cmd_array[i] = cmdtp++;
8bde7f77 252 }
8bde7f77 253
9d2b18a0
WD
254 /* Sort command list (trivial bubble sort) */
255 for (i = cmd_items - 1; i > 0; --i) {
256 swaps = 0;
257 for (j = 0; j < i; ++j) {
258 if (strcmp (cmd_array[j]->name,
259 cmd_array[j + 1]->name) > 0) {
260 cmd_tbl_t *tmp;
261 tmp = cmd_array[j];
262 cmd_array[j] = cmd_array[j + 1];
263 cmd_array[j + 1] = tmp;
264 ++swaps;
265 }
8bde7f77 266 }
9d2b18a0
WD
267 if (!swaps)
268 break;
8bde7f77 269 }
5dfa25f2 270
8bde7f77 271 /* print short help (usage) */
9d2b18a0
WD
272 for (i = 0; i < cmd_items; i++) {
273 const char *usage = cmd_array[i]->usage;
274
5dfa25f2 275 /* allow user abort */
8bde7f77 276 if (ctrlc ())
5dfa25f2 277 return 1;
9d2b18a0 278 if (usage == NULL)
5dfa25f2 279 continue;
2fb2604d
PT
280 printf("%-*s- %s\n", CONFIG_SYS_HELP_CMD_WIDTH,
281 cmd_array[i]->name, usage);
5dfa25f2 282 }
5dfa25f2
WD
283 return 0;
284 }
5dfa25f2
WD
285 /*
286 * command help (long version)
287 */
8bde7f77
WD
288 for (i = 1; i < argc; ++i) {
289 if ((cmdtp = find_cmd (argv[i])) != NULL) {
6d0f6bcf 290#ifdef CONFIG_SYS_LONGHELP
5dfa25f2
WD
291 /* found - print (long) help info */
292 puts (cmdtp->name);
293 putc (' ');
294 if (cmdtp->help) {
295 puts (cmdtp->help);
296 } else {
297 puts ("- No help available.\n");
298 rcode = 1;
299 }
300 putc ('\n');
301#else /* no long help available */
302 if (cmdtp->usage)
2fb2604d 303 printf ("%s - %s\n", cmdtp->name, cmdtp->usage);
6d0f6bcf 304#endif /* CONFIG_SYS_LONGHELP */
71f95118 305 } else {
5dfa25f2
WD
306 printf ("Unknown command '%s' - try 'help'"
307 " without arguments for list of all"
8bde7f77
WD
308 " known commands\n\n", argv[i]
309 );
5dfa25f2
WD
310 rcode = 1;
311 }
312 }
313 return rcode;
314}
315
8bde7f77 316
0d498393 317U_BOOT_CMD(
6d0f6bcf 318 help, CONFIG_SYS_MAXARGS, 1, do_help,
2fb2604d 319 "print online help",
53677ef1
WD
320 "[command ...]\n"
321 " - show help information (for 'command')\n"
322 "'help' prints online help for the monitor commands.\n\n"
323 "Without arguments, it prints a short usage message for all commands.\n\n"
324 "To get detailed help information for specific commands you can type\n"
8bde7f77
WD
325 "'help' with one or more command names as arguments.\n"
326);
327
0d498393 328/* This do not ust the U_BOOT_CMD macro as ? can't be used in symbol names */
6d0f6bcf 329#ifdef CONFIG_SYS_LONGHELP
0d498393 330cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
6d0f6bcf 331 "?", CONFIG_SYS_MAXARGS, 1, do_help,
2fb2604d 332 "alias for 'help'",
8bde7f77 333 NULL
0d498393
WD
334};
335#else
336cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
6d0f6bcf 337 "?", CONFIG_SYS_MAXARGS, 1, do_help,
2fb2604d 338 "alias for 'help'"
0d498393 339};
6d0f6bcf 340#endif /* CONFIG_SYS_LONGHELP */
8bde7f77 341
5dfa25f2
WD
342/***************************************************************************
343 * find command table entry for a command
344 */
b799cb4c 345cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
5dfa25f2
WD
346{
347 cmd_tbl_t *cmdtp;
b799cb4c 348 cmd_tbl_t *cmdtp_temp = table; /*Init value */
9d2b18a0
WD
349 const char *p;
350 int len;
351 int n_found = 0;
352
353 /*
354 * Some commands allow length modifiers (like "cp.b");
355 * compare command name only until first dot.
356 */
357 len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
358
b799cb4c
KG
359 for (cmdtp = table;
360 cmdtp != table + table_len;
9d2b18a0
WD
361 cmdtp++) {
362 if (strncmp (cmd, cmdtp->name, len) == 0) {
363 if (len == strlen (cmdtp->name))
364 return cmdtp; /* full match */
365
366 cmdtp_temp = cmdtp; /* abbreviated command ? */
367 n_found++;
368 }
5dfa25f2 369 }
9d2b18a0 370 if (n_found == 1) { /* exactly one match */
8bde7f77 371 return cmdtp_temp;
9d2b18a0 372 }
5dfa25f2 373
9d2b18a0 374 return NULL; /* not found or ambiguous command */
8bde7f77 375}
04a85b3b 376
b799cb4c
KG
377cmd_tbl_t *find_cmd (const char *cmd)
378{
379 int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
380 return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
381}
382
62c3ae7c
PT
383void cmd_usage(cmd_tbl_t *cmdtp)
384{
2fb2604d 385 printf("Usage:\n%s - %s\n\n", cmdtp->name, cmdtp->usage);
62c3ae7c
PT
386}
387
04a85b3b
WD
388#ifdef CONFIG_AUTO_COMPLETE
389
390int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
391{
392 static char tmp_buf[512];
393 int space;
394
395 space = last_char == '\0' || last_char == ' ' || last_char == '\t';
396
397 if (space && argc == 1)
398 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
399
400 if (!space && argc == 2)
401 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
402
403 return 0;
404}
405
406static void install_auto_complete_handler(const char *cmd,
407 int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]))
408{
409 cmd_tbl_t *cmdtp;
410
411 cmdtp = find_cmd(cmd);
412 if (cmdtp == NULL)
413 return;
414
415 cmdtp->complete = complete;
416}
417
418void install_auto_complete(void)
419{
420 install_auto_complete_handler("printenv", var_complete);
421 install_auto_complete_handler("setenv", var_complete);
c3517f91 422#if defined(CONFIG_CMD_RUN)
04a85b3b
WD
423 install_auto_complete_handler("run", var_complete);
424#endif
425}
426
427/*************************************************************************************/
428
429static int complete_cmdv(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
430{
431 cmd_tbl_t *cmdtp;
432 const char *p;
433 int len, clen;
434 int n_found = 0;
435 const char *cmd;
436
437 /* sanity? */
438 if (maxv < 2)
439 return -2;
440
441 cmdv[0] = NULL;
442
443 if (argc == 0) {
444 /* output full list of commands */
445 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
446 if (n_found >= maxv - 2) {
447 cmdv[n_found++] = "...";
448 break;
449 }
450 cmdv[n_found++] = cmdtp->name;
451 }
452 cmdv[n_found] = NULL;
453 return n_found;
454 }
455
456 /* more than one arg or one but the start of the next */
457 if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) {
458 cmdtp = find_cmd(argv[0]);
459 if (cmdtp == NULL || cmdtp->complete == NULL) {
460 cmdv[0] = NULL;
461 return 0;
462 }
463 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
464 }
465
466 cmd = argv[0];
467 /*
468 * Some commands allow length modifiers (like "cp.b");
469 * compare command name only until first dot.
470 */
471 p = strchr(cmd, '.');
472 if (p == NULL)
473 len = strlen(cmd);
474 else
475 len = p - cmd;
476
477 /* return the partial matches */
478 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
479
480 clen = strlen(cmdtp->name);
481 if (clen < len)
482 continue;
483
484 if (memcmp(cmd, cmdtp->name, len) != 0)
485 continue;
486
487 /* too many! */
488 if (n_found >= maxv - 2) {
489 cmdv[n_found++] = "...";
490 break;
491 }
492
493 cmdv[n_found++] = cmdtp->name;
494 }
495
496 cmdv[n_found] = NULL;
497 return n_found;
498}
499
500static int make_argv(char *s, int argvsz, char *argv[])
501{
502 int argc = 0;
503
504 /* split into argv */
505 while (argc < argvsz - 1) {
506
507 /* skip any white space */
508 while ((*s == ' ') || (*s == '\t'))
509 ++s;
510
53677ef1 511 if (*s == '\0') /* end of s, no more args */
04a85b3b
WD
512 break;
513
514 argv[argc++] = s; /* begin of argument string */
515
516 /* find end of string */
517 while (*s && (*s != ' ') && (*s != '\t'))
518 ++s;
519
520 if (*s == '\0') /* end of s, no more args */
521 break;
522
523 *s++ = '\0'; /* terminate current arg */
524 }
525 argv[argc] = NULL;
526
527 return argc;
528}
529
530static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char *argv[])
531{
532 int ll = leader != NULL ? strlen(leader) : 0;
533 int sl = sep != NULL ? strlen(sep) : 0;
534 int len, i;
535
536 if (banner) {
537 puts("\n");
538 puts(banner);
539 }
540
541 i = linemax; /* force leader and newline */
542 while (*argv != NULL) {
543 len = strlen(*argv) + sl;
544 if (i + len >= linemax) {
545 puts("\n");
546 if (leader)
547 puts(leader);
548 i = ll - sl;
549 } else if (sep)
550 puts(sep);
551 puts(*argv++);
552 i += len;
553 }
554 printf("\n");
555}
556
557static int find_common_prefix(char *argv[])
558{
559 int i, len;
560 char *anchor, *s, *t;
561
562 if (*argv == NULL)
563 return 0;
564
565 /* begin with max */
566 anchor = *argv++;
567 len = strlen(anchor);
568 while ((t = *argv++) != NULL) {
569 s = anchor;
570 for (i = 0; i < len; i++, t++, s++) {
571 if (*t != *s)
572 break;
573 }
574 len = s - anchor;
575 }
576 return len;
577}
578
6d0f6bcf 579static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
04a85b3b
WD
580
581int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp)
582{
583 int n = *np, col = *colp;
6d0f6bcf 584 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
04a85b3b
WD
585 char *cmdv[20];
586 char *s, *t;
587 const char *sep;
588 int i, j, k, len, seplen, argc;
589 int cnt;
590 char last_char;
591
6d0f6bcf 592 if (strcmp(prompt, CONFIG_SYS_PROMPT) != 0)
04a85b3b
WD
593 return 0; /* not in normal console */
594
595 cnt = strlen(buf);
596 if (cnt >= 1)
597 last_char = buf[cnt - 1];
598 else
599 last_char = '\0';
600
601 /* copy to secondary buffer which will be affected */
602 strcpy(tmp_buf, buf);
603
604 /* separate into argv */
605 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
606
607 /* do the completion and return the possible completions */
608 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
609
610 /* no match; bell and out */
611 if (i == 0) {
612 if (argc > 1) /* allow tab for non command */
613 return 0;
614 putc('\a');
615 return 1;
616 }
617
618 s = NULL;
619 len = 0;
620 sep = NULL;
621 seplen = 0;
622 if (i == 1) { /* one match; perfect */
623 k = strlen(argv[argc - 1]);
624 s = cmdv[0] + k;
625 len = strlen(s);
626 sep = " ";
627 seplen = 1;
628 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
629 k = strlen(argv[argc - 1]);
630 j -= k;
631 if (j > 0) {
632 s = cmdv[0] + k;
633 len = j;
634 }
635 }
636
637 if (s != NULL) {
638 k = len + seplen;
639 /* make sure it fits */
6d0f6bcf 640 if (n + k >= CONFIG_SYS_CBSIZE - 2) {
04a85b3b
WD
641 putc('\a');
642 return 1;
643 }
644
645 t = buf + cnt;
646 for (i = 0; i < len; i++)
647 *t++ = *s++;
648 if (sep != NULL)
649 for (i = 0; i < seplen; i++)
650 *t++ = sep[i];
651 *t = '\0';
652 n += k;
653 col += k;
654 puts(t - k);
655 if (sep == NULL)
656 putc('\a');
657 *np = n;
658 *colp = col;
659 } else {
660 print_argv(NULL, " ", " ", 78, cmdv);
661
662 puts(prompt);
663 puts(buf);
664 }
665 return 1;
666}
667
668#endif
8a40fb14
JCPV
669
670#ifdef CMD_DATA_SIZE
671int cmd_get_data_size(char* arg, int default_size)
672{
673 /* Check for a size specification .b, .w or .l.
674 */
675 int len = strlen(arg);
676 if (len > 2 && arg[len-2] == '.') {
677 switch(arg[len-1]) {
678 case 'b':
679 return 1;
680 case 'w':
681 return 2;
682 case 'l':
683 return 4;
684 case 's':
685 return -2;
686 default:
687 return -1;
688 }
689 }
690 return default_size;
691}
692#endif
This page took 0.176532 seconds and 4 git commands to generate.