]> git.ipfire.org Git - people/ms/u-boot.git/blame - common/command.c
Standardize command usage messages with cmd_usage()
[people/ms/u-boot.git] / common / command.c
CommitLineData
5dfa25f2 1/*
8bde7f77 2 * (C) Copyright 2000-2003
5dfa25f2
WD
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
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,
53677ef1 41 "version - print monitor version\n",
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,
53677ef1
WD
74 "echo - echo args to console\n",
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,
53677ef1
WD
206 "test - minimal test like /bin/sh\n",
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,
53677ef1 225 "exit - exit script\n",
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;
9d2b18a0 280 puts (usage);
5dfa25f2 281 }
5dfa25f2
WD
282 return 0;
283 }
5dfa25f2
WD
284 /*
285 * command help (long version)
286 */
8bde7f77
WD
287 for (i = 1; i < argc; ++i) {
288 if ((cmdtp = find_cmd (argv[i])) != NULL) {
6d0f6bcf 289#ifdef CONFIG_SYS_LONGHELP
5dfa25f2
WD
290 /* found - print (long) help info */
291 puts (cmdtp->name);
292 putc (' ');
293 if (cmdtp->help) {
294 puts (cmdtp->help);
295 } else {
296 puts ("- No help available.\n");
297 rcode = 1;
298 }
299 putc ('\n');
300#else /* no long help available */
301 if (cmdtp->usage)
302 puts (cmdtp->usage);
6d0f6bcf 303#endif /* CONFIG_SYS_LONGHELP */
71f95118 304 } else {
5dfa25f2
WD
305 printf ("Unknown command '%s' - try 'help'"
306 " without arguments for list of all"
8bde7f77
WD
307 " known commands\n\n", argv[i]
308 );
5dfa25f2
WD
309 rcode = 1;
310 }
311 }
312 return rcode;
313}
314
8bde7f77 315
0d498393 316U_BOOT_CMD(
6d0f6bcf 317 help, CONFIG_SYS_MAXARGS, 1, do_help,
53677ef1
WD
318 "help - print online help\n",
319 "[command ...]\n"
320 " - show help information (for 'command')\n"
321 "'help' prints online help for the monitor commands.\n\n"
322 "Without arguments, it prints a short usage message for all commands.\n\n"
323 "To get detailed help information for specific commands you can type\n"
8bde7f77
WD
324 "'help' with one or more command names as arguments.\n"
325);
326
0d498393 327/* This do not ust the U_BOOT_CMD macro as ? can't be used in symbol names */
6d0f6bcf 328#ifdef CONFIG_SYS_LONGHELP
0d498393 329cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
6d0f6bcf 330 "?", CONFIG_SYS_MAXARGS, 1, do_help,
53677ef1 331 "? - alias for 'help'\n",
8bde7f77 332 NULL
0d498393
WD
333};
334#else
335cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
6d0f6bcf 336 "?", CONFIG_SYS_MAXARGS, 1, do_help,
53677ef1 337 "? - alias for 'help'\n"
0d498393 338};
6d0f6bcf 339#endif /* CONFIG_SYS_LONGHELP */
8bde7f77 340
5dfa25f2
WD
341/***************************************************************************
342 * find command table entry for a command
343 */
b799cb4c 344cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
5dfa25f2
WD
345{
346 cmd_tbl_t *cmdtp;
b799cb4c 347 cmd_tbl_t *cmdtp_temp = table; /*Init value */
9d2b18a0
WD
348 const char *p;
349 int len;
350 int n_found = 0;
351
352 /*
353 * Some commands allow length modifiers (like "cp.b");
354 * compare command name only until first dot.
355 */
356 len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
357
b799cb4c
KG
358 for (cmdtp = table;
359 cmdtp != table + table_len;
9d2b18a0
WD
360 cmdtp++) {
361 if (strncmp (cmd, cmdtp->name, len) == 0) {
362 if (len == strlen (cmdtp->name))
363 return cmdtp; /* full match */
364
365 cmdtp_temp = cmdtp; /* abbreviated command ? */
366 n_found++;
367 }
5dfa25f2 368 }
9d2b18a0 369 if (n_found == 1) { /* exactly one match */
8bde7f77 370 return cmdtp_temp;
9d2b18a0 371 }
5dfa25f2 372
9d2b18a0 373 return NULL; /* not found or ambiguous command */
8bde7f77 374}
04a85b3b 375
b799cb4c
KG
376cmd_tbl_t *find_cmd (const char *cmd)
377{
378 int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
379 return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
380}
381
62c3ae7c
PT
382void cmd_usage(cmd_tbl_t *cmdtp)
383{
384 printf("Usage:\n%s\n", cmdtp->usage);
385}
386
04a85b3b
WD
387#ifdef CONFIG_AUTO_COMPLETE
388
389int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
390{
391 static char tmp_buf[512];
392 int space;
393
394 space = last_char == '\0' || last_char == ' ' || last_char == '\t';
395
396 if (space && argc == 1)
397 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
398
399 if (!space && argc == 2)
400 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
401
402 return 0;
403}
404
405static void install_auto_complete_handler(const char *cmd,
406 int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]))
407{
408 cmd_tbl_t *cmdtp;
409
410 cmdtp = find_cmd(cmd);
411 if (cmdtp == NULL)
412 return;
413
414 cmdtp->complete = complete;
415}
416
417void install_auto_complete(void)
418{
419 install_auto_complete_handler("printenv", var_complete);
420 install_auto_complete_handler("setenv", var_complete);
c3517f91 421#if defined(CONFIG_CMD_RUN)
04a85b3b
WD
422 install_auto_complete_handler("run", var_complete);
423#endif
424}
425
426/*************************************************************************************/
427
428static int complete_cmdv(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
429{
430 cmd_tbl_t *cmdtp;
431 const char *p;
432 int len, clen;
433 int n_found = 0;
434 const char *cmd;
435
436 /* sanity? */
437 if (maxv < 2)
438 return -2;
439
440 cmdv[0] = NULL;
441
442 if (argc == 0) {
443 /* output full list of commands */
444 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
445 if (n_found >= maxv - 2) {
446 cmdv[n_found++] = "...";
447 break;
448 }
449 cmdv[n_found++] = cmdtp->name;
450 }
451 cmdv[n_found] = NULL;
452 return n_found;
453 }
454
455 /* more than one arg or one but the start of the next */
456 if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) {
457 cmdtp = find_cmd(argv[0]);
458 if (cmdtp == NULL || cmdtp->complete == NULL) {
459 cmdv[0] = NULL;
460 return 0;
461 }
462 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
463 }
464
465 cmd = argv[0];
466 /*
467 * Some commands allow length modifiers (like "cp.b");
468 * compare command name only until first dot.
469 */
470 p = strchr(cmd, '.');
471 if (p == NULL)
472 len = strlen(cmd);
473 else
474 len = p - cmd;
475
476 /* return the partial matches */
477 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
478
479 clen = strlen(cmdtp->name);
480 if (clen < len)
481 continue;
482
483 if (memcmp(cmd, cmdtp->name, len) != 0)
484 continue;
485
486 /* too many! */
487 if (n_found >= maxv - 2) {
488 cmdv[n_found++] = "...";
489 break;
490 }
491
492 cmdv[n_found++] = cmdtp->name;
493 }
494
495 cmdv[n_found] = NULL;
496 return n_found;
497}
498
499static int make_argv(char *s, int argvsz, char *argv[])
500{
501 int argc = 0;
502
503 /* split into argv */
504 while (argc < argvsz - 1) {
505
506 /* skip any white space */
507 while ((*s == ' ') || (*s == '\t'))
508 ++s;
509
53677ef1 510 if (*s == '\0') /* end of s, no more args */
04a85b3b
WD
511 break;
512
513 argv[argc++] = s; /* begin of argument string */
514
515 /* find end of string */
516 while (*s && (*s != ' ') && (*s != '\t'))
517 ++s;
518
519 if (*s == '\0') /* end of s, no more args */
520 break;
521
522 *s++ = '\0'; /* terminate current arg */
523 }
524 argv[argc] = NULL;
525
526 return argc;
527}
528
529static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char *argv[])
530{
531 int ll = leader != NULL ? strlen(leader) : 0;
532 int sl = sep != NULL ? strlen(sep) : 0;
533 int len, i;
534
535 if (banner) {
536 puts("\n");
537 puts(banner);
538 }
539
540 i = linemax; /* force leader and newline */
541 while (*argv != NULL) {
542 len = strlen(*argv) + sl;
543 if (i + len >= linemax) {
544 puts("\n");
545 if (leader)
546 puts(leader);
547 i = ll - sl;
548 } else if (sep)
549 puts(sep);
550 puts(*argv++);
551 i += len;
552 }
553 printf("\n");
554}
555
556static int find_common_prefix(char *argv[])
557{
558 int i, len;
559 char *anchor, *s, *t;
560
561 if (*argv == NULL)
562 return 0;
563
564 /* begin with max */
565 anchor = *argv++;
566 len = strlen(anchor);
567 while ((t = *argv++) != NULL) {
568 s = anchor;
569 for (i = 0; i < len; i++, t++, s++) {
570 if (*t != *s)
571 break;
572 }
573 len = s - anchor;
574 }
575 return len;
576}
577
6d0f6bcf 578static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
04a85b3b
WD
579
580int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp)
581{
582 int n = *np, col = *colp;
6d0f6bcf 583 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
04a85b3b
WD
584 char *cmdv[20];
585 char *s, *t;
586 const char *sep;
587 int i, j, k, len, seplen, argc;
588 int cnt;
589 char last_char;
590
6d0f6bcf 591 if (strcmp(prompt, CONFIG_SYS_PROMPT) != 0)
04a85b3b
WD
592 return 0; /* not in normal console */
593
594 cnt = strlen(buf);
595 if (cnt >= 1)
596 last_char = buf[cnt - 1];
597 else
598 last_char = '\0';
599
600 /* copy to secondary buffer which will be affected */
601 strcpy(tmp_buf, buf);
602
603 /* separate into argv */
604 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
605
606 /* do the completion and return the possible completions */
607 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
608
609 /* no match; bell and out */
610 if (i == 0) {
611 if (argc > 1) /* allow tab for non command */
612 return 0;
613 putc('\a');
614 return 1;
615 }
616
617 s = NULL;
618 len = 0;
619 sep = NULL;
620 seplen = 0;
621 if (i == 1) { /* one match; perfect */
622 k = strlen(argv[argc - 1]);
623 s = cmdv[0] + k;
624 len = strlen(s);
625 sep = " ";
626 seplen = 1;
627 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
628 k = strlen(argv[argc - 1]);
629 j -= k;
630 if (j > 0) {
631 s = cmdv[0] + k;
632 len = j;
633 }
634 }
635
636 if (s != NULL) {
637 k = len + seplen;
638 /* make sure it fits */
6d0f6bcf 639 if (n + k >= CONFIG_SYS_CBSIZE - 2) {
04a85b3b
WD
640 putc('\a');
641 return 1;
642 }
643
644 t = buf + cnt;
645 for (i = 0; i < len; i++)
646 *t++ = *s++;
647 if (sep != NULL)
648 for (i = 0; i < seplen; i++)
649 *t++ = sep[i];
650 *t = '\0';
651 n += k;
652 col += k;
653 puts(t - k);
654 if (sep == NULL)
655 putc('\a');
656 *np = n;
657 *colp = col;
658 } else {
659 print_argv(NULL, " ", " ", 78, cmdv);
660
661 puts(prompt);
662 puts(buf);
663 }
664 return 1;
665}
666
667#endif
8a40fb14
JCPV
668
669#ifdef CMD_DATA_SIZE
670int cmd_get_data_size(char* arg, int default_size)
671{
672 /* Check for a size specification .b, .w or .l.
673 */
674 int len = strlen(arg);
675 if (len > 2 && arg[len-2] == '.') {
676 switch(arg[len-1]) {
677 case 'b':
678 return 1;
679 case 'w':
680 return 2;
681 case 'l':
682 return 4;
683 case 's':
684 return -2;
685 default:
686 return -1;
687 }
688 }
689 return default_size;
690}
691#endif