X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=common%2Fcommand.c;h=a4a978c5fdc676249bc6f73c7e639acfc1b9dc72;hb=6d0f6bcf337c5261c08fabe12982178c2c489d76;hp=059da7c96c34239b34957424dc5cce4109e4d4a7;hpb=9d2b18a0f9df38cfe15e10766b1302f10d426355;p=oweals%2Fu-boot.git diff --git a/common/command.c b/common/command.c index 059da7c96c..a4a978c5fd 100644 --- a/common/command.c +++ b/common/command.c @@ -36,6 +36,14 @@ do_version (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } +U_BOOT_CMD( + version, 1, 1, do_version, + "version - print monitor version\n", + NULL +); + +#if defined(CONFIG_CMD_ECHO) + int do_echo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { @@ -61,6 +69,166 @@ do_echo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } +U_BOOT_CMD( + echo, CONFIG_SYS_MAXARGS, 1, do_echo, + "echo - echo args to console\n", + "[args..]\n" + " - echo args to console; \\c suppresses newline\n" +); + +#endif + +#ifdef CONFIG_SYS_HUSH_PARSER + +int +do_test (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char **ap; + int left, adv, expr, last_expr, neg, last_cmp; + + /* args? */ + if (argc < 3) + return 1; + +#if 0 + { + printf("test:"); + left = 1; + while (argv[left]) + printf(" %s", argv[left++]); + } +#endif + + last_expr = 0; + left = argc - 1; ap = argv + 1; + if (left > 0 && strcmp(ap[0], "!") == 0) { + neg = 1; + ap++; + left--; + } else + neg = 0; + + expr = -1; + last_cmp = -1; + last_expr = -1; + while (left > 0) { + + if (strcmp(ap[0], "-o") == 0 || strcmp(ap[0], "-a") == 0) + adv = 1; + else if (strcmp(ap[0], "-z") == 0 || strcmp(ap[0], "-n") == 0) + adv = 2; + else + adv = 3; + + if (left < adv) { + expr = 1; + break; + } + + if (adv == 1) { + if (strcmp(ap[0], "-o") == 0) { + last_expr = expr; + last_cmp = 0; + } else if (strcmp(ap[0], "-a") == 0) { + last_expr = expr; + last_cmp = 1; + } else { + expr = 1; + break; + } + } + + if (adv == 2) { + if (strcmp(ap[0], "-z") == 0) + expr = strlen(ap[1]) == 0 ? 1 : 0; + else if (strcmp(ap[0], "-n") == 0) + expr = strlen(ap[1]) == 0 ? 0 : 1; + else { + expr = 1; + break; + } + + if (last_cmp == 0) + expr = last_expr || expr; + else if (last_cmp == 1) + expr = last_expr && expr; + last_cmp = -1; + } + + if (adv == 3) { + if (strcmp(ap[1], "=") == 0) + expr = strcmp(ap[0], ap[2]) == 0; + else if (strcmp(ap[1], "!=") == 0) + expr = strcmp(ap[0], ap[2]) != 0; + else if (strcmp(ap[1], ">") == 0) + expr = strcmp(ap[0], ap[2]) > 0; + else if (strcmp(ap[1], "<") == 0) + expr = strcmp(ap[0], ap[2]) < 0; + else if (strcmp(ap[1], "-eq") == 0) + expr = simple_strtol(ap[0], NULL, 10) == simple_strtol(ap[2], NULL, 10); + else if (strcmp(ap[1], "-ne") == 0) + expr = simple_strtol(ap[0], NULL, 10) != simple_strtol(ap[2], NULL, 10); + else if (strcmp(ap[1], "-lt") == 0) + expr = simple_strtol(ap[0], NULL, 10) < simple_strtol(ap[2], NULL, 10); + else if (strcmp(ap[1], "-le") == 0) + expr = simple_strtol(ap[0], NULL, 10) <= simple_strtol(ap[2], NULL, 10); + else if (strcmp(ap[1], "-gt") == 0) + expr = simple_strtol(ap[0], NULL, 10) > simple_strtol(ap[2], NULL, 10); + else if (strcmp(ap[1], "-ge") == 0) + expr = simple_strtol(ap[0], NULL, 10) >= simple_strtol(ap[2], NULL, 10); + else { + expr = 1; + break; + } + + if (last_cmp == 0) + expr = last_expr || expr; + else if (last_cmp == 1) + expr = last_expr && expr; + last_cmp = -1; + } + + ap += adv; left -= adv; + } + + if (neg) + expr = !expr; + + expr = !expr; + + debug (": returns %d\n", expr); + + return expr; +} + +U_BOOT_CMD( + test, CONFIG_SYS_MAXARGS, 1, do_test, + "test - minimal test like /bin/sh\n", + "[args..]\n" + " - test functionality\n" +); + +int +do_exit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int r; + + r = 0; + if (argc > 1) + r = simple_strtoul(argv[1], NULL, 10); + + return -r - 2; +} + +U_BOOT_CMD( + exit, 2, 1, do_exit, + "exit - exit script\n", + " - exit functionality\n" +); + + +#endif + /* * Use puts() instead of printf() to avoid printf buffer overflow * for long help messages @@ -118,7 +286,7 @@ int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) */ for (i = 1; i < argc; ++i) { if ((cmdtp = find_cmd (argv[i])) != NULL) { -#ifdef CFG_LONGHELP +#ifdef CONFIG_SYS_LONGHELP /* found - print (long) help info */ puts (cmdtp->name); putc (' '); @@ -132,7 +300,7 @@ int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) #else /* no long help available */ if (cmdtp->usage) puts (cmdtp->usage); -#endif /* CFG_LONGHELP */ +#endif /* CONFIG_SYS_LONGHELP */ } else { printf ("Unknown command '%s' - try 'help'" " without arguments for list of all" @@ -145,43 +313,38 @@ int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } -cmd_tbl_t U_BOOT_CMD(HELP) = MK_CMD_ENTRY( - "help", 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" +U_BOOT_CMD( + help, CONFIG_SYS_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" ); -cmd_tbl_t U_BOOT_CMD(QUES) = MK_CMD_ENTRY( - "?", CFG_MAXARGS, 1, do_help, - "? - alias for 'help'\n", +/* This do not ust the U_BOOT_CMD macro as ? can't be used in symbol names */ +#ifdef CONFIG_SYS_LONGHELP +cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = { + "?", CONFIG_SYS_MAXARGS, 1, do_help, + "? - alias for 'help'\n", NULL -); - -cmd_tbl_t U_BOOT_CMD(VERS) = MK_CMD_ENTRY( - "version", 1, 1, do_version, - "version - print monitor version\n", - NULL -); - -cmd_tbl_t U_BOOT_CMD(ECHO) = MK_CMD_ENTRY( - "echo", CFG_MAXARGS, 1, do_echo, - "echo - echo args to console\n", - "[args..]\n" - " - echo args to console; \\c suppresses newline\n" -); +}; +#else +cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = { + "?", CONFIG_SYS_MAXARGS, 1, do_help, + "? - alias for 'help'\n" +}; +#endif /* CONFIG_SYS_LONGHELP */ /*************************************************************************** * 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 = &__u_boot_cmd_start; /*Init value */ + cmd_tbl_t *cmdtp_temp = table; /*Init value */ const char *p; int len; int n_found = 0; @@ -192,8 +355,8 @@ cmd_tbl_t *find_cmd (const char *cmd) */ len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd); - for (cmdtp = &__u_boot_cmd_start; - cmdtp != &__u_boot_cmd_end; + for (cmdtp = table; + cmdtp != table + table_len; cmdtp++) { if (strncmp (cmd, cmdtp->name, len) == 0) { if (len == strlen (cmdtp->name)) @@ -209,3 +372,315 @@ cmd_tbl_t *find_cmd (const char *cmd) return NULL; /* not found or ambiguous command */ } + +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); +} + +#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; + + 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 +} + +/*************************************************************************************/ + +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 + +#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