]> Git Repo - J-u-boot.git/blame - common/command.c
env_flash: Move conditional compilation to Makefile
[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,
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
WD
72U_BOOT_CMD(
73 echo, CFG_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
c26e454d
WD
81#ifdef CFG_HUSH_PARSER
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(
205 test, CFG_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) {
5dfa25f2
WD
289#ifdef CFG_LONGHELP
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);
303#endif /* CFG_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
WD
316U_BOOT_CMD(
317 help, CFG_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
WD
327/* This do not ust the U_BOOT_CMD macro as ? can't be used in symbol names */
328#ifdef CFG_LONGHELP
329cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
8bde7f77 330 "?", CFG_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 = {
336 "?", CFG_MAXARGS, 1, do_help,
53677ef1 337 "? - alias for 'help'\n"
0d498393
WD
338};
339#endif /* CFG_LONGHELP */
8bde7f77 340
5dfa25f2
WD
341/***************************************************************************
342 * find command table entry for a command
343 */
8bde7f77 344cmd_tbl_t *find_cmd (const char *cmd)
5dfa25f2
WD
345{
346 cmd_tbl_t *cmdtp;
8bde7f77 347 cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start; /*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
358 for (cmdtp = &__u_boot_cmd_start;
359 cmdtp != &__u_boot_cmd_end;
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
WD
375
376#ifdef CONFIG_AUTO_COMPLETE
377
378int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
379{
380 static char tmp_buf[512];
381 int space;
382
383 space = last_char == '\0' || last_char == ' ' || last_char == '\t';
384
385 if (space && argc == 1)
386 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
387
388 if (!space && argc == 2)
389 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
390
391 return 0;
392}
393
394static void install_auto_complete_handler(const char *cmd,
395 int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]))
396{
397 cmd_tbl_t *cmdtp;
398
399 cmdtp = find_cmd(cmd);
400 if (cmdtp == NULL)
401 return;
402
403 cmdtp->complete = complete;
404}
405
406void install_auto_complete(void)
407{
408 install_auto_complete_handler("printenv", var_complete);
409 install_auto_complete_handler("setenv", var_complete);
c3517f91 410#if defined(CONFIG_CMD_RUN)
04a85b3b
WD
411 install_auto_complete_handler("run", var_complete);
412#endif
413}
414
415/*************************************************************************************/
416
417static int complete_cmdv(int argc, char *argv[], char last_char, int maxv, char *cmdv[])
418{
419 cmd_tbl_t *cmdtp;
420 const char *p;
421 int len, clen;
422 int n_found = 0;
423 const char *cmd;
424
425 /* sanity? */
426 if (maxv < 2)
427 return -2;
428
429 cmdv[0] = NULL;
430
431 if (argc == 0) {
432 /* output full list of commands */
433 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
434 if (n_found >= maxv - 2) {
435 cmdv[n_found++] = "...";
436 break;
437 }
438 cmdv[n_found++] = cmdtp->name;
439 }
440 cmdv[n_found] = NULL;
441 return n_found;
442 }
443
444 /* more than one arg or one but the start of the next */
445 if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) {
446 cmdtp = find_cmd(argv[0]);
447 if (cmdtp == NULL || cmdtp->complete == NULL) {
448 cmdv[0] = NULL;
449 return 0;
450 }
451 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
452 }
453
454 cmd = argv[0];
455 /*
456 * Some commands allow length modifiers (like "cp.b");
457 * compare command name only until first dot.
458 */
459 p = strchr(cmd, '.');
460 if (p == NULL)
461 len = strlen(cmd);
462 else
463 len = p - cmd;
464
465 /* return the partial matches */
466 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
467
468 clen = strlen(cmdtp->name);
469 if (clen < len)
470 continue;
471
472 if (memcmp(cmd, cmdtp->name, len) != 0)
473 continue;
474
475 /* too many! */
476 if (n_found >= maxv - 2) {
477 cmdv[n_found++] = "...";
478 break;
479 }
480
481 cmdv[n_found++] = cmdtp->name;
482 }
483
484 cmdv[n_found] = NULL;
485 return n_found;
486}
487
488static int make_argv(char *s, int argvsz, char *argv[])
489{
490 int argc = 0;
491
492 /* split into argv */
493 while (argc < argvsz - 1) {
494
495 /* skip any white space */
496 while ((*s == ' ') || (*s == '\t'))
497 ++s;
498
53677ef1 499 if (*s == '\0') /* end of s, no more args */
04a85b3b
WD
500 break;
501
502 argv[argc++] = s; /* begin of argument string */
503
504 /* find end of string */
505 while (*s && (*s != ' ') && (*s != '\t'))
506 ++s;
507
508 if (*s == '\0') /* end of s, no more args */
509 break;
510
511 *s++ = '\0'; /* terminate current arg */
512 }
513 argv[argc] = NULL;
514
515 return argc;
516}
517
518static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char *argv[])
519{
520 int ll = leader != NULL ? strlen(leader) : 0;
521 int sl = sep != NULL ? strlen(sep) : 0;
522 int len, i;
523
524 if (banner) {
525 puts("\n");
526 puts(banner);
527 }
528
529 i = linemax; /* force leader and newline */
530 while (*argv != NULL) {
531 len = strlen(*argv) + sl;
532 if (i + len >= linemax) {
533 puts("\n");
534 if (leader)
535 puts(leader);
536 i = ll - sl;
537 } else if (sep)
538 puts(sep);
539 puts(*argv++);
540 i += len;
541 }
542 printf("\n");
543}
544
545static int find_common_prefix(char *argv[])
546{
547 int i, len;
548 char *anchor, *s, *t;
549
550 if (*argv == NULL)
551 return 0;
552
553 /* begin with max */
554 anchor = *argv++;
555 len = strlen(anchor);
556 while ((t = *argv++) != NULL) {
557 s = anchor;
558 for (i = 0; i < len; i++, t++, s++) {
559 if (*t != *s)
560 break;
561 }
562 len = s - anchor;
563 }
564 return len;
565}
566
567static char tmp_buf[CFG_CBSIZE]; /* copy of console I/O buffer */
568
569int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp)
570{
571 int n = *np, col = *colp;
572 char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
573 char *cmdv[20];
574 char *s, *t;
575 const char *sep;
576 int i, j, k, len, seplen, argc;
577 int cnt;
578 char last_char;
579
580 if (strcmp(prompt, CFG_PROMPT) != 0)
581 return 0; /* not in normal console */
582
583 cnt = strlen(buf);
584 if (cnt >= 1)
585 last_char = buf[cnt - 1];
586 else
587 last_char = '\0';
588
589 /* copy to secondary buffer which will be affected */
590 strcpy(tmp_buf, buf);
591
592 /* separate into argv */
593 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
594
595 /* do the completion and return the possible completions */
596 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
597
598 /* no match; bell and out */
599 if (i == 0) {
600 if (argc > 1) /* allow tab for non command */
601 return 0;
602 putc('\a');
603 return 1;
604 }
605
606 s = NULL;
607 len = 0;
608 sep = NULL;
609 seplen = 0;
610 if (i == 1) { /* one match; perfect */
611 k = strlen(argv[argc - 1]);
612 s = cmdv[0] + k;
613 len = strlen(s);
614 sep = " ";
615 seplen = 1;
616 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
617 k = strlen(argv[argc - 1]);
618 j -= k;
619 if (j > 0) {
620 s = cmdv[0] + k;
621 len = j;
622 }
623 }
624
625 if (s != NULL) {
626 k = len + seplen;
627 /* make sure it fits */
628 if (n + k >= CFG_CBSIZE - 2) {
629 putc('\a');
630 return 1;
631 }
632
633 t = buf + cnt;
634 for (i = 0; i < len; i++)
635 *t++ = *s++;
636 if (sep != NULL)
637 for (i = 0; i < seplen; i++)
638 *t++ = sep[i];
639 *t = '\0';
640 n += k;
641 col += k;
642 puts(t - k);
643 if (sep == NULL)
644 putc('\a');
645 *np = n;
646 *colp = col;
647 } else {
648 print_argv(NULL, " ", " ", 78, cmdv);
649
650 puts(prompt);
651 puts(buf);
652 }
653 return 1;
654}
655
656#endif
This page took 0.171553 seconds and 4 git commands to generate.