diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2008-03-01 21:08:14 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2008-03-01 21:08:14 +0100 |
commit | df31bb46be18edbaca1adbef3dcb16d2033942b9 (patch) | |
tree | 98ca794cf8d8753c47135c9b3189a49fd5cb7ea2 /common/command.c | |
parent | a1a747af7f7bd816af73d808e1c750f536873c3d (diff) | |
download | barebox-df31bb46be18edbaca1adbef3dcb16d2033942b9.tar.gz barebox-df31bb46be18edbaca1adbef3dcb16d2033942b9.tar.xz |
implement TAB completion
Diffstat (limited to 'common/command.c')
-rw-r--r-- | common/command.c | 286 |
1 files changed, 1 insertions, 285 deletions
diff --git a/common/command.c b/common/command.c index fdd7444e6d..94a8f28787 100644 --- a/common/command.c +++ b/common/command.c @@ -32,6 +32,7 @@ #include <environment.h> #include <list.h> #include <init.h> +#include <complete.h> LIST_HEAD(command_list); EXPORT_SYMBOL(command_list); @@ -176,10 +177,6 @@ int register_command(cmd_tbl_t *cmd) debug("register command %s\n", cmd->name); - /* - * Would be nice to have some kind of list_add_sort - * to keep the command list in order - */ list_add_sort(&cmd->list, &command_list, compare); if (cmd->aliases) { @@ -256,284 +253,3 @@ static int init_command_list(void) late_initcall(init_command_list); -#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 (CONFIG_COMMANDS & CFG_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_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_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_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; - putchar('\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_CBSIZE - 2) { - putchar('\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) - putchar('\a'); - *np = n; - *colp = col; - } else { - print_argv(NULL, " ", " ", 78, cmdv); - - puts(prompt); - puts(buf); - } - return 1; -} - -#endif |