]> git.ipfire.org Git - people/ms/u-boot.git/blame - common/command.c
rename CFG_ macros to CONFIG_SYS
[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
04a85b3b
WD
382#ifdef CONFIG_AUTO_COMPLETE
383
384int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
385{
386 static char tmp_buf[512];
387 int space;
388
389 space = last_char == '\0' || last_char == ' ' || last_char == '\t';
390
391 if (space && argc == 1)
392 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
393
394 if (!space && argc == 2)
395 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
396
397 return 0;
398}
399
400static void install_auto_complete_handler(const char *cmd,
401 int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]))
402{
403 cmd_tbl_t *cmdtp;
404
405 cmdtp = find_cmd(cmd);
406 if (cmdtp == NULL)
407 return;
408
409 cmdtp->complete = complete;
410}
411
412void install_auto_complete(void)
413{
414 install_auto_complete_handler("printenv", var_complete);
415 install_auto_complete_handler("setenv", var_complete);
c3517f91 416#if defined(CONFIG_CMD_RUN)
04a85b3b
WD
417 install_auto_complete_handler("run", var_complete);
418#endif
419}
420
421/*************************************************************************************/
422
423static int complete_cmdv(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
424{
425 cmd_tbl_t *cmdtp;
426 const char *p;
427 int len, clen;
428 int n_found = 0;
429 const char *cmd;
430
431 /* sanity? */
432 if (maxv < 2)
433 return -2;
434
435 cmdv[0] = NULL;
436
437 if (argc == 0) {
438 /* output full list of commands */
439 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
440 if (n_found >= maxv - 2) {
441 cmdv[n_found++] = "...";
442 break;
443 }
444 cmdv[n_found++] = cmdtp->name;
445 }
446 cmdv[n_found] = NULL;
447 return n_found;
448 }
449
450 /* more than one arg or one but the start of the next */
451 if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) {
452 cmdtp = find_cmd(argv[0]);
453 if (cmdtp == NULL || cmdtp->complete == NULL) {
454 cmdv[0] = NULL;
455 return 0;
456 }
457 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
458 }
459
460 cmd = argv[0];
461 /*
462 * Some commands allow length modifiers (like "cp.b");
463 * compare command name only until first dot.
464 */
465 p = strchr(cmd, '.');
466 if (p == NULL)
467 len = strlen(cmd);
468 else
469 len = p - cmd;
470
471 /* return the partial matches */
472 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
473
474 clen = strlen(cmdtp->name);
475 if (clen < len)
476 continue;
477
478 if (memcmp(cmd, cmdtp->name, len) != 0)
479 continue;
480
481 /* too many! */
482 if (n_found >= maxv - 2) {
483 cmdv[n_found++] = "...";
484 break;
485 }
486
487 cmdv[n_found++] = cmdtp->name;
488 }
489
490 cmdv[n_found] = NULL;
491 return n_found;
492}
493
494static int make_argv(char *s, int argvsz, char *argv[])
495{
496 int argc = 0;
497
498 /* split into argv */
499 while (argc < argvsz - 1) {
500
501 /* skip any white space */
502 while ((*s == ' ') || (*s == '\t'))
503 ++s;
504
53677ef1 505 if (*s == '\0') /* end of s, no more args */
04a85b3b
WD
506 break;
507
508 argv[argc++] = s; /* begin of argument string */
509
510 /* find end of string */
511 while (*s && (*s != ' ') && (*s != '\t'))
512 ++s;
513
514 if (*s == '\0') /* end of s, no more args */
515 break;
516
517 *s++ = '\0'; /* terminate current arg */
518 }
519 argv[argc] = NULL;
520
521 return argc;
522}
523
524static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char *argv[])
525{
526 int ll = leader != NULL ? strlen(leader) : 0;
527 int sl = sep != NULL ? strlen(sep) : 0;
528 int len, i;
529
530 if (banner) {
531 puts("\n");
532 puts(banner);
533 }
534
535 i = linemax; /* force leader and newline */
536 while (*argv != NULL) {
537 len = strlen(*argv) + sl;
538 if (i + len >= linemax) {
539 puts("\n");
540 if (leader)
541 puts(leader);
542 i = ll - sl;
543 } else if (sep)
544 puts(sep);
545 puts(*argv++);
546 i += len;
547 }
548 printf("\n");
549}
550
551static int find_common_prefix(char *argv[])
552{
553 int i, len;
554 char *anchor, *s, *t;
555
556 if (*argv == NULL)
557 return 0;
558
559 /* begin with max */
560 anchor = *argv++;
561 len = strlen(anchor);
562 while ((t = *argv++) != NULL) {
563 s = anchor;
564 for (i = 0; i < len; i++, t++, s++) {
565 if (*t != *s)
566 break;
567 }
568 len = s - anchor;
569 }
570 return len;
571}
572
6d0f6bcf 573static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
04a85b3b
WD
574
575int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp)
576{
577 int n = *np, col = *colp;
6d0f6bcf 578 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
04a85b3b
WD
579 char *cmdv[20];
580 char *s, *t;
581 const char *sep;
582 int i, j, k, len, seplen, argc;
583 int cnt;
584 char last_char;
585
6d0f6bcf 586 if (strcmp(prompt, CONFIG_SYS_PROMPT) != 0)
04a85b3b
WD
587 return 0; /* not in normal console */
588
589 cnt = strlen(buf);
590 if (cnt >= 1)
591 last_char = buf[cnt - 1];
592 else
593 last_char = '\0';
594
595 /* copy to secondary buffer which will be affected */
596 strcpy(tmp_buf, buf);
597
598 /* separate into argv */
599 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
600
601 /* do the completion and return the possible completions */
602 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
603
604 /* no match; bell and out */
605 if (i == 0) {
606 if (argc > 1) /* allow tab for non command */
607 return 0;
608 putc('\a');
609 return 1;
610 }
611
612 s = NULL;
613 len = 0;
614 sep = NULL;
615 seplen = 0;
616 if (i == 1) { /* one match; perfect */
617 k = strlen(argv[argc - 1]);
618 s = cmdv[0] + k;
619 len = strlen(s);
620 sep = " ";
621 seplen = 1;
622 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
623 k = strlen(argv[argc - 1]);
624 j -= k;
625 if (j > 0) {
626 s = cmdv[0] + k;
627 len = j;
628 }
629 }
630
631 if (s != NULL) {
632 k = len + seplen;
633 /* make sure it fits */
6d0f6bcf 634 if (n + k >= CONFIG_SYS_CBSIZE - 2) {
04a85b3b
WD
635 putc('\a');
636 return 1;
637 }
638
639 t = buf + cnt;
640 for (i = 0; i < len; i++)
641 *t++ = *s++;
642 if (sep != NULL)
643 for (i = 0; i < seplen; i++)
644 *t++ = sep[i];
645 *t = '\0';
646 n += k;
647 col += k;
648 puts(t - k);
649 if (sep == NULL)
650 putc('\a');
651 *np = n;
652 *colp = col;
653 } else {
654 print_argv(NULL, " ", " ", 78, cmdv);
655
656 puts(prompt);
657 puts(buf);
658 }
659 return 1;
660}
661
662#endif
8a40fb14
JCPV
663
664#ifdef CMD_DATA_SIZE
665int cmd_get_data_size(char* arg, int default_size)
666{
667 /* Check for a size specification .b, .w or .l.
668 */
669 int len = strlen(arg);
670 if (len > 2 && arg[len-2] == '.') {
671 switch(arg[len-1]) {
672 case 'b':
673 return 1;
674 case 'w':
675 return 2;
676 case 'l':
677 return 4;
678 case 's':
679 return -2;
680 default:
681 return -1;
682 }
683 }
684 return default_size;
685}
686#endif