1 /* 2 * (C) Copyright 2000-2003 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> 30 31 int 32 do_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 39 U_BOOT_CMD( 40 version, 1, 1, do_version, 41 "version - print monitor version\n", 42 NULL 43 ); 44 45 int 46 do_echo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 47 { 48 int i, putnl = 1; 49 50 for (i = 1; i < argc; i++) { 51 char *p = argv[i], c; 52 53 if (i > 1) 54 putc(' '); 55 while ((c = *p++) != '\0') { 56 if (c == '\\' && *p == 'c') { 57 putnl = 0; 58 p++; 59 } else { 60 putc(c); 61 } 62 } 63 } 64 65 if (putnl) 66 putc('\n'); 67 return 0; 68 } 69 70 U_BOOT_CMD( 71 echo, CFG_MAXARGS, 1, do_echo, 72 "echo - echo args to console\n", 73 "[args..]\n" 74 " - echo args to console; \\c suppresses newline\n" 75 ); 76 77 #ifdef CFG_HUSH_PARSER 78 79 int 80 do_test (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 81 { 82 char **ap; 83 int left, adv, expr, last_expr, neg, last_cmp; 84 85 /* args? */ 86 if (argc < 3) 87 return 1; 88 89 #if 0 90 { 91 printf("test:"); 92 left = 1; 93 while (argv[left]) 94 printf(" %s", argv[left++]); 95 } 96 #endif 97 98 last_expr = 0; 99 left = argc - 1; ap = argv + 1; 100 if (left > 0 && strcmp(ap[0], "!") == 0) { 101 neg = 1; 102 ap++; 103 left--; 104 } else 105 neg = 0; 106 107 expr = -1; 108 last_cmp = -1; 109 last_expr = -1; 110 while (left > 0) { 111 112 if (strcmp(ap[0], "-o") == 0 || strcmp(ap[0], "-a") == 0) 113 adv = 1; 114 else if (strcmp(ap[0], "-z") == 0 || strcmp(ap[0], "-n") == 0) 115 adv = 2; 116 else 117 adv = 3; 118 119 if (left < adv) { 120 expr = 1; 121 break; 122 } 123 124 if (adv == 1) { 125 if (strcmp(ap[0], "-o") == 0) { 126 last_expr = expr; 127 last_cmp = 0; 128 } else if (strcmp(ap[0], "-a") == 0) { 129 last_expr = expr; 130 last_cmp = 1; 131 } else { 132 expr = 1; 133 break; 134 } 135 } 136 137 if (adv == 2) { 138 if (strcmp(ap[0], "-z") == 0) 139 expr = strlen(ap[1]) == 0 ? 1 : 0; 140 else if (strcmp(ap[0], "-n") == 0) 141 expr = strlen(ap[1]) == 0 ? 0 : 1; 142 else { 143 expr = 1; 144 break; 145 } 146 147 if (last_cmp == 0) 148 expr = last_expr || expr; 149 else if (last_cmp == 1) 150 expr = last_expr && expr; 151 last_cmp = -1; 152 } 153 154 if (adv == 3) { 155 if (strcmp(ap[1], "=") == 0) 156 expr = strcmp(ap[0], ap[2]) == 0; 157 else if (strcmp(ap[1], "!=") == 0) 158 expr = strcmp(ap[0], ap[2]) != 0; 159 else 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], "-eq") == 0) 164 expr = simple_strtol(ap[0], NULL, 10) == simple_strtol(ap[2], NULL, 10); 165 else if (strcmp(ap[1], "-ne") == 0) 166 expr = simple_strtol(ap[0], NULL, 10) != simple_strtol(ap[2], NULL, 10); 167 else if (strcmp(ap[1], "-lt") == 0) 168 expr = simple_strtol(ap[0], NULL, 10) < simple_strtol(ap[2], NULL, 10); 169 else if (strcmp(ap[1], "-le") == 0) 170 expr = simple_strtol(ap[0], NULL, 10) <= simple_strtol(ap[2], NULL, 10); 171 else if (strcmp(ap[1], "-gt") == 0) 172 expr = simple_strtol(ap[0], NULL, 10) > simple_strtol(ap[2], NULL, 10); 173 else if (strcmp(ap[1], "-ge") == 0) 174 expr = simple_strtol(ap[0], NULL, 10) >= simple_strtol(ap[2], NULL, 10); 175 else { 176 expr = 1; 177 break; 178 } 179 180 if (last_cmp == 0) 181 expr = last_expr || expr; 182 else if (last_cmp == 1) 183 expr = last_expr && expr; 184 last_cmp = -1; 185 } 186 187 ap += adv; left -= adv; 188 } 189 190 if (neg) 191 expr = !expr; 192 193 expr = !expr; 194 195 #if 0 196 printf(": returns %d\n", expr); 197 #endif 198 199 return expr; 200 } 201 202 U_BOOT_CMD( 203 test, CFG_MAXARGS, 1, do_test, 204 "test - minimal test like /bin/sh\n", 205 "[args..]\n" 206 " - test functionality\n" 207 ); 208 209 int 210 do_exit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 211 { 212 int r; 213 214 r = 0; 215 if (argc > 1) 216 r = simple_strtoul(argv[1], NULL, 10); 217 218 return -r - 2; 219 } 220 221 U_BOOT_CMD( 222 exit, 2, 1, do_exit, 223 "exit - exit script\n", 224 " - exit functionality\n" 225 ); 226 227 228 #endif 229 230 /* 231 * Use puts() instead of printf() to avoid printf buffer overflow 232 * for long help messages 233 */ 234 int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 235 { 236 int i; 237 int rcode = 0; 238 239 if (argc == 1) { /*show list of commands */ 240 241 int cmd_items = &__u_boot_cmd_end - 242 &__u_boot_cmd_start; /* pointer arith! */ 243 cmd_tbl_t *cmd_array[cmd_items]; 244 int i, j, swaps; 245 246 /* Make array of commands from .uboot_cmd section */ 247 cmdtp = &__u_boot_cmd_start; 248 for (i = 0; i < cmd_items; i++) { 249 cmd_array[i] = cmdtp++; 250 } 251 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 } 264 } 265 if (!swaps) 266 break; 267 } 268 269 /* print short help (usage) */ 270 for (i = 0; i < cmd_items; i++) { 271 const char *usage = cmd_array[i]->usage; 272 273 /* allow user abort */ 274 if (ctrlc ()) 275 return 1; 276 if (usage == NULL) 277 continue; 278 puts (usage); 279 } 280 return 0; 281 } 282 /* 283 * command help (long version) 284 */ 285 for (i = 1; i < argc; ++i) { 286 if ((cmdtp = find_cmd (argv[i])) != NULL) { 287 #ifdef CFG_LONGHELP 288 /* found - print (long) help info */ 289 puts (cmdtp->name); 290 putc (' '); 291 if (cmdtp->help) { 292 puts (cmdtp->help); 293 } else { 294 puts ("- No help available.\n"); 295 rcode = 1; 296 } 297 putc ('\n'); 298 #else /* no long help available */ 299 if (cmdtp->usage) 300 puts (cmdtp->usage); 301 #endif /* CFG_LONGHELP */ 302 } else { 303 printf ("Unknown command '%s' - try 'help'" 304 " without arguments for list of all" 305 " known commands\n\n", argv[i] 306 ); 307 rcode = 1; 308 } 309 } 310 return rcode; 311 } 312 313 314 U_BOOT_CMD( 315 help, CFG_MAXARGS, 1, do_help, 316 "help - print online help\n", 317 "[command ...]\n" 318 " - show help information (for 'command')\n" 319 "'help' prints online help for the monitor commands.\n\n" 320 "Without arguments, it prints a short usage message for all commands.\n\n" 321 "To get detailed help information for specific commands you can type\n" 322 "'help' with one or more command names as arguments.\n" 323 ); 324 325 /* This do not ust the U_BOOT_CMD macro as ? can't be used in symbol names */ 326 #ifdef CFG_LONGHELP 327 cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = { 328 "?", CFG_MAXARGS, 1, do_help, 329 "? - alias for 'help'\n", 330 NULL 331 }; 332 #else 333 cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = { 334 "?", CFG_MAXARGS, 1, do_help, 335 "? - alias for 'help'\n" 336 }; 337 #endif /* CFG_LONGHELP */ 338 339 /*************************************************************************** 340 * find command table entry for a command 341 */ 342 cmd_tbl_t *find_cmd (const char *cmd) 343 { 344 cmd_tbl_t *cmdtp; 345 cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start; /*Init value */ 346 const char *p; 347 int len; 348 int n_found = 0; 349 350 /* 351 * Some commands allow length modifiers (like "cp.b"); 352 * compare command name only until first dot. 353 */ 354 len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd); 355 356 for (cmdtp = &__u_boot_cmd_start; 357 cmdtp != &__u_boot_cmd_end; 358 cmdtp++) { 359 if (strncmp (cmd, cmdtp->name, len) == 0) { 360 if (len == strlen (cmdtp->name)) 361 return cmdtp; /* full match */ 362 363 cmdtp_temp = cmdtp; /* abbreviated command ? */ 364 n_found++; 365 } 366 } 367 if (n_found == 1) { /* exactly one match */ 368 return cmdtp_temp; 369 } 370 371 return NULL; /* not found or ambiguous command */ 372 } 373 374 #ifdef CONFIG_AUTO_COMPLETE 375 376 int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[]) 377 { 378 static char tmp_buf[512]; 379 int space; 380 381 space = last_char == '\0' || last_char == ' ' || last_char == '\t'; 382 383 if (space && argc == 1) 384 return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf); 385 386 if (!space && argc == 2) 387 return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf); 388 389 return 0; 390 } 391 392 static void install_auto_complete_handler(const char *cmd, 393 int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[])) 394 { 395 cmd_tbl_t *cmdtp; 396 397 cmdtp = find_cmd(cmd); 398 if (cmdtp == NULL) 399 return; 400 401 cmdtp->complete = complete; 402 } 403 404 void install_auto_complete(void) 405 { 406 install_auto_complete_handler("printenv", var_complete); 407 install_auto_complete_handler("setenv", var_complete); 408 #if (CONFIG_COMMANDS & CFG_CMD_RUN) 409 install_auto_complete_handler("run", var_complete); 410 #endif 411 } 412 413 /*************************************************************************************/ 414 415 static int complete_cmdv(int argc, char *argv[], char last_char, int maxv, char *cmdv[]) 416 { 417 cmd_tbl_t *cmdtp; 418 const char *p; 419 int len, clen; 420 int n_found = 0; 421 const char *cmd; 422 423 /* sanity? */ 424 if (maxv < 2) 425 return -2; 426 427 cmdv[0] = NULL; 428 429 if (argc == 0) { 430 /* output full list of commands */ 431 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { 432 if (n_found >= maxv - 2) { 433 cmdv[n_found++] = "..."; 434 break; 435 } 436 cmdv[n_found++] = cmdtp->name; 437 } 438 cmdv[n_found] = NULL; 439 return n_found; 440 } 441 442 /* more than one arg or one but the start of the next */ 443 if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) { 444 cmdtp = find_cmd(argv[0]); 445 if (cmdtp == NULL || cmdtp->complete == NULL) { 446 cmdv[0] = NULL; 447 return 0; 448 } 449 return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv); 450 } 451 452 cmd = argv[0]; 453 /* 454 * Some commands allow length modifiers (like "cp.b"); 455 * compare command name only until first dot. 456 */ 457 p = strchr(cmd, '.'); 458 if (p == NULL) 459 len = strlen(cmd); 460 else 461 len = p - cmd; 462 463 /* return the partial matches */ 464 for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { 465 466 clen = strlen(cmdtp->name); 467 if (clen < len) 468 continue; 469 470 if (memcmp(cmd, cmdtp->name, len) != 0) 471 continue; 472 473 /* too many! */ 474 if (n_found >= maxv - 2) { 475 cmdv[n_found++] = "..."; 476 break; 477 } 478 479 cmdv[n_found++] = cmdtp->name; 480 } 481 482 cmdv[n_found] = NULL; 483 return n_found; 484 } 485 486 static int make_argv(char *s, int argvsz, char *argv[]) 487 { 488 int argc = 0; 489 490 /* split into argv */ 491 while (argc < argvsz - 1) { 492 493 /* skip any white space */ 494 while ((*s == ' ') || (*s == '\t')) 495 ++s; 496 497 if (*s == '\0') /* end of s, no more args */ 498 break; 499 500 argv[argc++] = s; /* begin of argument string */ 501 502 /* find end of string */ 503 while (*s && (*s != ' ') && (*s != '\t')) 504 ++s; 505 506 if (*s == '\0') /* end of s, no more args */ 507 break; 508 509 *s++ = '\0'; /* terminate current arg */ 510 } 511 argv[argc] = NULL; 512 513 return argc; 514 } 515 516 static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char *argv[]) 517 { 518 int ll = leader != NULL ? strlen(leader) : 0; 519 int sl = sep != NULL ? strlen(sep) : 0; 520 int len, i; 521 522 if (banner) { 523 puts("\n"); 524 puts(banner); 525 } 526 527 i = linemax; /* force leader and newline */ 528 while (*argv != NULL) { 529 len = strlen(*argv) + sl; 530 if (i + len >= linemax) { 531 puts("\n"); 532 if (leader) 533 puts(leader); 534 i = ll - sl; 535 } else if (sep) 536 puts(sep); 537 puts(*argv++); 538 i += len; 539 } 540 printf("\n"); 541 } 542 543 static int find_common_prefix(char *argv[]) 544 { 545 int i, len; 546 char *anchor, *s, *t; 547 548 if (*argv == NULL) 549 return 0; 550 551 /* begin with max */ 552 anchor = *argv++; 553 len = strlen(anchor); 554 while ((t = *argv++) != NULL) { 555 s = anchor; 556 for (i = 0; i < len; i++, t++, s++) { 557 if (*t != *s) 558 break; 559 } 560 len = s - anchor; 561 } 562 return len; 563 } 564 565 static char tmp_buf[CFG_CBSIZE]; /* copy of console I/O buffer */ 566 567 int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp) 568 { 569 int n = *np, col = *colp; 570 char *argv[CFG_MAXARGS + 1]; /* NULL terminated */ 571 char *cmdv[20]; 572 char *s, *t; 573 const char *sep; 574 int i, j, k, len, seplen, argc; 575 int cnt; 576 char last_char; 577 578 if (strcmp(prompt, CFG_PROMPT) != 0) 579 return 0; /* not in normal console */ 580 581 cnt = strlen(buf); 582 if (cnt >= 1) 583 last_char = buf[cnt - 1]; 584 else 585 last_char = '\0'; 586 587 /* copy to secondary buffer which will be affected */ 588 strcpy(tmp_buf, buf); 589 590 /* separate into argv */ 591 argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv); 592 593 /* do the completion and return the possible completions */ 594 i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv); 595 596 /* no match; bell and out */ 597 if (i == 0) { 598 if (argc > 1) /* allow tab for non command */ 599 return 0; 600 putc('\a'); 601 return 1; 602 } 603 604 s = NULL; 605 len = 0; 606 sep = NULL; 607 seplen = 0; 608 if (i == 1) { /* one match; perfect */ 609 k = strlen(argv[argc - 1]); 610 s = cmdv[0] + k; 611 len = strlen(s); 612 sep = " "; 613 seplen = 1; 614 } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */ 615 k = strlen(argv[argc - 1]); 616 j -= k; 617 if (j > 0) { 618 s = cmdv[0] + k; 619 len = j; 620 } 621 } 622 623 if (s != NULL) { 624 k = len + seplen; 625 /* make sure it fits */ 626 if (n + k >= CFG_CBSIZE - 2) { 627 putc('\a'); 628 return 1; 629 } 630 631 t = buf + cnt; 632 for (i = 0; i < len; i++) 633 *t++ = *s++; 634 if (sep != NULL) 635 for (i = 0; i < seplen; i++) 636 *t++ = sep[i]; 637 *t = '\0'; 638 n += k; 639 col += k; 640 puts(t - k); 641 if (sep == NULL) 642 putc('\a'); 643 *np = n; 644 *colp = col; 645 } else { 646 print_argv(NULL, " ", " ", 78, cmdv); 647 648 puts(prompt); 649 puts(buf); 650 } 651 return 1; 652 } 653 654 #endif 655