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