X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fcommand.c;h=0c66b7a1d9361e994fd0b7cff97c180d47f600ec;hb=206c00f26f56af02686cb69bfe5c75e979063171;hp=9e631f1c5dc57424c47bb8b0838a6815370d32da;hpb=7a8e9bed17d7924a9c5c4699b1f6a3a0359524ed;p=u-boot diff --git a/common/command.c b/common/command.c index 9e631f1c5d..0c66b7a1d9 100644 --- a/common/command.c +++ b/common/command.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2000 + * (C) Copyright 2000-2009 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this @@ -27,176 +27,70 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include /* Floppy support */ -#include /* USB support */ -#include -#include -#include -#include /* 4xx DCR register access */ -#include -#include -#include -#include - -#include /* board special functions */ - -#include -#include - -#include - -#include /* load a bitmap to the VFDs on TRAB */ -#include -#include -#include -#include - -#ifdef CONFIG_AMIGAONEG3SE -#include -#include -#endif - -/* - * HELP command - */ -#define CMD_TBL_HELP MK_CMD_TBL_ENTRY( \ - "help", 1, CFG_MAXARGS, 1, do_help, \ - "help - print online help\n", \ - "[command ...]\n" \ - " - show help information (for 'command')\n" \ - "'help' prints online help for the monitor commands.\n\n" \ - "Without arguments, it prints a short usage message for all commands.\n\n" \ - "To get detailed help information for specific commands you can type\n" \ - "'help' with one or more command names as arguments.\n" \ - ), - -#define CMD_TBL_QUES MK_CMD_TBL_ENTRY( \ - "?", 1, CFG_MAXARGS, 1, do_help, \ - "? - alias for 'help'\n", \ - NULL \ - ), - -#define CMD_TBL_VERS MK_CMD_TBL_ENTRY( \ - "version", 4, 1, 1, do_version, \ - "version - print monitor version\n", \ - NULL \ - ), - -#define CMD_TBL_ECHO MK_CMD_TBL_ENTRY( \ - "echo", 4, CFG_MAXARGS, 1, do_echo, \ - "echo - echo args to console\n", \ - "[args..]\n" \ - " - echo args to console; \\c suppresses newline\n" \ - ), - -int -do_version (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) -{ - extern char version_string[]; - printf ("\n%s\n", version_string); - return 0; -} - -int -do_echo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) -{ - int i, putnl = 1; - - for (i = 1; i < argc; i++) { - char *p = argv[i], c; - - if (i > 1) - putc(' '); - while ((c = *p++) != '\0') - if (c == '\\' && *p == 'c') { - putnl = 0; - p++; - } - else - putc(c); - } - - if (putnl) - putc('\n'); - return 0; -} /* * Use puts() instead of printf() to avoid printf buffer overflow * for long help messages */ -int -do_help (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) + +int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int + flag, int argc, char *argv[]) { int i; int rcode = 0; - if (argc == 1) { /* print short help (usage) */ + if (argc == 1) { /*show list of commands */ + cmd_tbl_t *cmd_array[cmd_items]; + int i, j, swaps; + + /* Make array of commands from .uboot_cmd section */ + cmdtp = cmd_start; + for (i = 0; i < cmd_items; i++) { + cmd_array[i] = cmdtp++; + } + + /* Sort command list (trivial bubble sort) */ + for (i = cmd_items - 1; i > 0; --i) { + swaps = 0; + for (j = 0; j < i; ++j) { + if (strcmp (cmd_array[j]->name, + cmd_array[j + 1]->name) > 0) { + cmd_tbl_t *tmp; + tmp = cmd_array[j]; + cmd_array[j] = cmd_array[j + 1]; + cmd_array[j + 1] = tmp; + ++swaps; + } + } + if (!swaps) + break; + } + + /* print short help (usage) */ + for (i = 0; i < cmd_items; i++) { + const char *usage = cmd_array[i]->usage; - for (cmdtp=&cmd_tbl[0]; cmdtp->name; cmdtp++) { /* allow user abort */ - if (ctrlc()) + if (ctrlc ()) return 1; - - if (cmdtp->usage == NULL) + if (usage == NULL) continue; - puts (cmdtp->usage); + printf("%-*s- %s\n", CONFIG_SYS_HELP_CMD_WIDTH, + cmd_array[i]->name, usage); } - return 0; } - /* * command help (long version) */ - for (i=1; iname); - putc (' '); - if (cmdtp->help) { - puts (cmdtp->help); - } else { - puts ("- No help available.\n"); - rcode = 1; - } - putc ('\n'); -#else /* no long help available */ - if (cmdtp->usage) - puts (cmdtp->usage); -#endif /* CFG_LONGHELP */ - } - else { + for (i = 1; i < argc; ++i) { + if ((cmdtp = find_cmd_tbl (argv[i], cmd_start, cmd_items )) != NULL) { + rcode |= cmd_usage(cmdtp); + } else { printf ("Unknown command '%s' - try 'help'" " without arguments for list of all" - " known commands\n\n", - argv[i] - ); + " known commands\n\n", argv[i] + ); rcode = 1; } } @@ -206,149 +100,364 @@ do_help (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) /*************************************************************************** * find command table entry for a command */ -cmd_tbl_t *find_cmd(const char *cmd) +cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len) { cmd_tbl_t *cmdtp; + cmd_tbl_t *cmdtp_temp = table; /*Init value */ + const char *p; + int len; + int n_found = 0; + + /* + * Some commands allow length modifiers (like "cp.b"); + * compare command name only until first dot. + */ + len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd); + + for (cmdtp = table; + cmdtp != table + table_len; + cmdtp++) { + if (strncmp (cmd, cmdtp->name, len) == 0) { + if (len == strlen (cmdtp->name)) + return cmdtp; /* full match */ - /* Search command table - Use linear search - it's a small table */ - for (cmdtp = &cmd_tbl[0]; cmdtp->name; cmdtp++) { - if (strncmp (cmd, cmdtp->name, cmdtp->lmin) == 0) - return cmdtp; + cmdtp_temp = cmdtp; /* abbreviated command ? */ + n_found++; + } + } + if (n_found == 1) { /* exactly one match */ + return cmdtp_temp; } - return NULL; /* not found */ + + return NULL; /* not found or ambiguous command */ } -/* - * The commands in this table are sorted alphabetically by the - * command name and in descending order by the command name string - * length. This is to prevent conflicts in command name parsing. - * Please ensure that new commands are added according to that rule. - * Please use $(TOPDIR)/doc/README.commands as a reference AND make - * sure it gets updated. - */ +cmd_tbl_t *find_cmd (const char *cmd) +{ + int len = &__u_boot_cmd_end - &__u_boot_cmd_start; + return find_cmd_tbl(cmd, &__u_boot_cmd_start, len); +} + +int cmd_usage(cmd_tbl_t *cmdtp) +{ + printf("%s - %s\n\n", cmdtp->name, cmdtp->usage); + +#ifdef CONFIG_SYS_LONGHELP + printf("Usage:\n%s ", cmdtp->name); + + if (!cmdtp->help) { + puts ("- No additional help available.\n"); + return 1; + } + + puts (cmdtp->help); + putc ('\n'); +#endif /* CONFIG_SYS_LONGHELP */ + return 0; +} + +#ifdef CONFIG_AUTO_COMPLETE + +int var_complete(int argc, char *argv[], char last_char, int maxv, char *cmdv[]) +{ + static char tmp_buf[512]; + int space; -cmd_tbl_t cmd_tbl[] = { - CMD_TBL_ASKENV - CMD_TBL_ASM - CMD_TBL_AUTOSCRIPT - CMD_TBL_BASE - CMD_TBL_BDINFO - CMD_TBL_BMP -#ifdef CONFIG_AMIGAONEG3SE - CMD_TBL_BOOTA + space = last_char == '\0' || last_char == ' ' || last_char == '\t'; + + if (space && argc == 1) + return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf); + + if (!space && argc == 2) + return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf); + + return 0; +} + +static void install_auto_complete_handler(const char *cmd, + int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[])) +{ + cmd_tbl_t *cmdtp; + + cmdtp = find_cmd(cmd); + if (cmdtp == NULL) + return; + + cmdtp->complete = complete; +} + +void install_auto_complete(void) +{ + install_auto_complete_handler("printenv", var_complete); + install_auto_complete_handler("setenv", var_complete); +#if defined(CONFIG_CMD_RUN) + install_auto_complete_handler("run", var_complete); #endif - CMD_TBL_BOOTELF - CMD_TBL_BOOTM - CMD_TBL_BOOTP - CMD_TBL_BOOTVX - CMD_TBL_BOOTD - CMD_TBL_BREAK - CMD_TBL_BRGINFO - CMD_TBL_CARINFO - CMD_TBL_JFFS2_CHPART - CMD_TBL_CMP - CMD_TBL_CONINFO - CMD_TBL_CONTINUE - CMD_TBL_CP - CMD_TBL_CRC - CMD_TBL_DATE - CMD_TBL_DCACHE - CMD_TBL_DHCP - CMD_TBL_DIAG - CMD_TBL_DISK - CMD_TBL_DMAINFO - CMD_TBL_DIS - CMD_TBL_DOCBOOT - CMD_TBL_DOC - CMD_TBL_DTT - CMD_TBL_ECHO - CMD_TBL_EEPROM - CMD_TBL_FCCINFO - CMD_TBL_FLERASE - CMD_TBL_FDC - CMD_TBL_FDOS_BOOT - CMD_TBL_FDOS_LS - CMD_TBL_FLINFO - CMD_TBL_FPGA - CMD_TBL_JFFS2_FSINFO - CMD_TBL_JFFS2_FSLOAD - CMD_TBL_GETDCR - CMD_TBL_GO - CMD_TBL_HELP - CMD_TBL_HWFLOW - CMD_TBL_I2CINFO - CMD_TBL_ICACHE -#ifdef CONFIG_8260 - CMD_TBL_ICINFO +} + +/*************************************************************************************/ + +static int complete_cmdv(int argc, char *argv[], char last_char, int maxv, char *cmdv[]) +{ + cmd_tbl_t *cmdtp; + const char *p; + int len, clen; + int n_found = 0; + const char *cmd; + + /* sanity? */ + if (maxv < 2) + return -2; + + cmdv[0] = NULL; + + if (argc == 0) { + /* output full list of commands */ + for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { + if (n_found >= maxv - 2) { + cmdv[n_found++] = "..."; + break; + } + cmdv[n_found++] = cmdtp->name; + } + cmdv[n_found] = NULL; + return n_found; + } + + /* more than one arg or one but the start of the next */ + if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) { + cmdtp = find_cmd(argv[0]); + if (cmdtp == NULL || cmdtp->complete == NULL) { + cmdv[0] = NULL; + return 0; + } + return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv); + } + + cmd = argv[0]; + /* + * Some commands allow length modifiers (like "cp.b"); + * compare command name only until first dot. + */ + p = strchr(cmd, '.'); + if (p == NULL) + len = strlen(cmd); + else + len = p - cmd; + + /* return the partial matches */ + for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) { + + clen = strlen(cmdtp->name); + if (clen < len) + continue; + + if (memcmp(cmd, cmdtp->name, len) != 0) + continue; + + /* too many! */ + if (n_found >= maxv - 2) { + cmdv[n_found++] = "..."; + break; + } + + cmdv[n_found++] = cmdtp->name; + } + + cmdv[n_found] = NULL; + return n_found; +} + +static int make_argv(char *s, int argvsz, char *argv[]) +{ + int argc = 0; + + /* split into argv */ + while (argc < argvsz - 1) { + + /* skip any white space */ + while ((*s == ' ') || (*s == '\t')) + ++s; + + if (*s == '\0') /* end of s, no more args */ + break; + + argv[argc++] = s; /* begin of argument string */ + + /* find end of string */ + while (*s && (*s != ' ') && (*s != '\t')) + ++s; + + if (*s == '\0') /* end of s, no more args */ + break; + + *s++ = '\0'; /* terminate current arg */ + } + argv[argc] = NULL; + + return argc; +} + +static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char *argv[]) +{ + int ll = leader != NULL ? strlen(leader) : 0; + int sl = sep != NULL ? strlen(sep) : 0; + int len, i; + + if (banner) { + puts("\n"); + puts(banner); + } + + i = linemax; /* force leader and newline */ + while (*argv != NULL) { + len = strlen(*argv) + sl; + if (i + len >= linemax) { + puts("\n"); + if (leader) + puts(leader); + i = ll - sl; + } else if (sep) + puts(sep); + puts(*argv++); + i += len; + } + printf("\n"); +} + +static int find_common_prefix(char *argv[]) +{ + int i, len; + char *anchor, *s, *t; + + if (*argv == NULL) + return 0; + + /* begin with max */ + anchor = *argv++; + len = strlen(anchor); + while ((t = *argv++) != NULL) { + s = anchor; + for (i = 0; i < len; i++, t++, s++) { + if (*t != *s) + break; + } + len = s - anchor; + } + return len; +} + +static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */ + +int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp) +{ + int n = *np, col = *colp; + char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ + char *cmdv[20]; + char *s, *t; + const char *sep; + int i, j, k, len, seplen, argc; + int cnt; + char last_char; + + if (strcmp(prompt, CONFIG_SYS_PROMPT) != 0) + return 0; /* not in normal console */ + + cnt = strlen(buf); + if (cnt >= 1) + last_char = buf[cnt - 1]; + else + last_char = '\0'; + + /* copy to secondary buffer which will be affected */ + strcpy(tmp_buf, buf); + + /* separate into argv */ + argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv); + + /* do the completion and return the possible completions */ + i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv); + + /* no match; bell and out */ + if (i == 0) { + if (argc > 1) /* allow tab for non command */ + return 0; + putc('\a'); + return 1; + } + + s = NULL; + len = 0; + sep = NULL; + seplen = 0; + if (i == 1) { /* one match; perfect */ + k = strlen(argv[argc - 1]); + s = cmdv[0] + k; + len = strlen(s); + sep = " "; + seplen = 1; + } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */ + k = strlen(argv[argc - 1]); + j -= k; + if (j > 0) { + s = cmdv[0] + k; + len = j; + } + } + + if (s != NULL) { + k = len + seplen; + /* make sure it fits */ + if (n + k >= CONFIG_SYS_CBSIZE - 2) { + putc('\a'); + return 1; + } + + t = buf + cnt; + for (i = 0; i < len; i++) + *t++ = *s++; + if (sep != NULL) + for (i = 0; i < seplen; i++) + *t++ = sep[i]; + *t = '\0'; + n += k; + col += k; + puts(t - k); + if (sep == NULL) + putc('\a'); + *np = n; + *colp = col; + } else { + print_argv(NULL, " ", " ", 78, cmdv); + + puts(prompt); + puts(buf); + } + return 1; +} + #endif - CMD_TBL_IMD - CMD_TBL_IMM - CMD_TBL_INM - CMD_TBL_IMW - CMD_TBL_PORTIO_IN - CMD_TBL_ICRC - CMD_TBL_IPROBE - CMD_TBL_ILOOP - CMD_TBL_ISDRAM - CMD_TBL_IDE - CMD_TBL_IMINFO - CMD_TBL_IOPINFO - CMD_TBL_IOPSET - CMD_TBL_IRQINFO - CMD_TBL_KGDB - CMD_TBL_LOADB - CMD_TBL_LOADS - CMD_TBL_LOG - CMD_TBL_LOOP - CMD_TBL_JFFS2_LS - CMD_TBL_MCCINFO - CMD_TBL_MD - CMD_TBL_MEMCINFO -#ifdef CONFIG_AMIGAONEG3SE - CMD_TBL_MENU + +#ifdef CMD_DATA_SIZE +int cmd_get_data_size(char* arg, int default_size) +{ + /* Check for a size specification .b, .w or .l. + */ + int len = strlen(arg); + if (len > 2 && arg[len-2] == '.') { + switch(arg[len-1]) { + case 'b': + return 1; + case 'w': + return 2; + case 'l': + return 4; + case 's': + return -2; + default: + return -1; + } + } + return default_size; +} #endif - CMD_TBL_MII - CMD_TBL_MM - CMD_TBL_MTEST - CMD_TBL_MUXINFO - CMD_TBL_MW - CMD_TBL_NAND - CMD_TBL_NANDBOOT - CMD_TBL_NEXT - CMD_TBL_NM - CMD_TBL_PORTIO_OUT - CMD_TBL_PCI - CMD_TBL_PRINTENV - CMD_TBL_PROTECT - CMD_TBL_RARPB - CMD_TBL_RDUMP - CMD_TBL_PINIT - CMD_TBL_REGINFO - CMD_TBL_RESET - CMD_TBL_RUN - CMD_TBL_SAVEENV - CMD_TBL_SAVES - CMD_TBL_SCCINFO - CMD_TBL_SCSIBOOT - CMD_TBL_SCSI - CMD_TBL_SETDCR - CMD_TBL_SETENV - CMD_TBL_SIINFO - CMD_TBL_SITINFO - CMD_TBL_SIUINFO - CMD_TBL_MISC /* sleep */ - CMD_TBL_SMCINFO - CMD_TBL_SPIINFO - CMD_TBL_SPI - CMD_TBL_STACK - CMD_TBL_STEP - CMD_TBL_TFTPB - CMD_TBL_USBBOOT - CMD_TBL_USB - CMD_TBL_VERS - CMD_TBL_BSP - CMD_TBL_VFD - CMD_TBL_QUES /* keep this ("help") the last entry */ - /* the following entry terminates this table */ - MK_CMD_TBL_ENTRY( NULL, 0, 0, 0, NULL, NULL, NULL ) -};