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