diff options
Diffstat (limited to 'common/complete.c')
-rw-r--r-- | common/complete.c | 126 |
1 files changed, 91 insertions, 35 deletions
diff --git a/common/complete.c b/common/complete.c index e504b75606..3911535621 100644 --- a/common/complete.c +++ b/common/complete.c @@ -14,17 +14,39 @@ #include <command.h> #include <environment.h> -static int file_complete(struct string_list *sl, char *instr, int exec) +static bool is_valid_escape(const char *str) +{ + return str[0] == '\\' && (str[1] == ' ' || str[1] == '\\'); +} + +static bool strstarts_escaped(const char *whole, const char *prefix_escaped) +{ + if (!prefix_escaped) + return true; + + while (*prefix_escaped) { + if (is_valid_escape(prefix_escaped)) + prefix_escaped++; + + if (*whole++ != *prefix_escaped++) + return false; + } + + return true; +} + +static int file_complete(struct string_list *sl, char *instr, + const char *dirn, int exec) { char *path = strdup(instr); struct stat s; DIR *dir; struct dirent *d; char tmp[PATH_MAX]; - char *base, *dirn; + char *base; base = basename(instr); - dirn = dirname(path); + dirn = dirn ?: dirname(path); dir = opendir(dirn); if (!dir) @@ -34,7 +56,7 @@ static int file_complete(struct string_list *sl, char *instr, int exec) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; - if (strncmp(base, d->d_name, strlen(base))) + if (!strstarts_escaped(d->d_name, base)) continue; strcpy(tmp, instr); @@ -93,7 +115,7 @@ static int path_command_complete(struct string_list *sl, char *instr) !strcmp(d->d_name, "..")) continue; - if (!strncmp(instr, d->d_name, strlen(instr))) { + if (strstarts_escaped(d->d_name, instr)) { strcpy(tmp, d->d_name); if (!stat(tmp, &s) && S_ISDIR(s.st_mode)) @@ -134,16 +156,10 @@ EXPORT_SYMBOL(command_complete); int device_complete(struct string_list *sl, char *instr) { - struct device_d *dev; - int len; - - if (!instr) - instr = ""; - - len = strlen(instr); + struct device *dev; for_each_device(dev) { - if (strncmp(instr, dev_name(dev), len)) + if (!strstarts_escaped(dev_name(dev), instr)) continue; string_list_add_asprintf(sl, "%s ", dev_name(dev)); @@ -153,26 +169,38 @@ int device_complete(struct string_list *sl, char *instr) } EXPORT_SYMBOL(device_complete); -static int device_param_complete(struct device_d *dev, struct string_list *sl, - char *instr, int eval) +static int device_param_complete(struct device *dev, const char *devname, + struct string_list *sl, char *instr, int eval) { struct param_d *param; - int len; - - len = strlen(instr); list_for_each_entry(param, &dev->parameters, list) { - if (strncmp(instr, param->name, len)) + if (!strstarts_escaped(param->name, instr)) continue; string_list_add_asprintf(sl, "%s%s.%s%c", - eval ? "$" : "", dev_name(dev), param->name, + eval ? "$" : "", devname, param->name, eval ? ' ' : '='); } return 0; } +int driver_complete(struct string_list *sl, char *instr) +{ + struct driver_d *drv; + + for_each_driver(drv) { + if (!strstarts_escaped(drv->name, instr)) + continue; + + string_list_add_asprintf(sl, "%s ", drv->name); + } + + return COMPLETE_CONTINUE; +} +EXPORT_SYMBOL(driver_complete); + int empty_complete(struct string_list *sl, char *instr) { return COMPLETE_END; @@ -229,7 +257,7 @@ int devicetree_nodepath_complete(struct string_list *sl, char *instr) for_each_child_of_node(node, child) { if (strncmp(base, child->name, strlen(base))) continue; - string_list_add_asprintf(sl, "%s/", child->full_name); + string_list_add_asprintf(sl, "%pOF/", child); } out: free(path); @@ -250,15 +278,23 @@ EXPORT_SYMBOL(devicetree_complete); int devicetree_file_complete(struct string_list *sl, char *instr) { devicetree_complete(sl, instr); - file_complete(sl, instr, 0); + file_complete(sl, instr, NULL, 0); return 0; } EXPORT_SYMBOL(devicetree_file_complete); +int tutorial_complete(struct string_list *sl, char *instr) +{ + file_complete(sl, instr, "/env/data/tutorial", 0); + + return 0; +} +EXPORT_SYMBOL(tutorial_complete); + static int env_param_complete(struct string_list *sl, char *instr, int eval) { - struct device_d *dev; + struct device *dev; struct variable_d *var; struct env_context *c; int len; @@ -299,14 +335,12 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval) char *devname; devname = xstrndup(instr, dot - instr); - - dev = get_device_by_name(devname); - free(devname); if (dev) - device_param_complete(dev, sl, dot + 1, eval); + device_param_complete(dev, devname, sl, dot + 1, eval); + free(devname); pos = dot + 1; } @@ -314,7 +348,7 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval) for_each_device(dev) { if (!strncmp(instr, dev_name(dev), len)) - device_param_complete(dev, sl, "", eval); + device_param_complete(dev, dev_name(dev), sl, "", eval); } return 0; @@ -333,21 +367,43 @@ void complete_reset(void) tab_pressed = 0; } +static char *skip_to_last_unescaped_space(char *instr) +{ + char *t; + + t = strrchr(instr, ' '); + if (t && (instr == t || t[-1] != '\\')) + return t + 1; + + return instr; +} + +static size_t strlen_escaped(char *instr) +{ + size_t count = 0; + + for (; *instr; instr++) { + if (is_valid_escape(instr)) + instr++; + + count++; + } + + return count; +} + static char* cmd_complete_lookup(struct string_list *sl, char *instr) { struct command *cmdtp; int len; int ret = COMPLETE_END; char *res = NULL; - char *t; for_each_command(cmdtp) { len = strlen(cmdtp->name); if (!strncmp(instr, cmdtp->name, len) && instr[len] == ' ') { instr += len + 1; - t = strrchr(instr, ' '); - if (t) - instr = t + 1; + instr = skip_to_last_unescaped_space(instr); if (cmdtp->complete) { ret = cmdtp->complete(sl, instr); @@ -392,11 +448,11 @@ int complete(char *instr, char **outstr) if (!instr) { instr = t; if (t && (t[0] == '/' || !strncmp(t, "./", 2))) { - file_complete(&sl, t, 1); + file_complete(&sl, t, NULL, 1); instr = t; } else if ((t = strrchr(t, ' '))) { t++; - file_complete(&sl, t, 0); + file_complete(&sl, t, NULL, 0); instr = t; } else { command_complete(&sl, instr); @@ -407,7 +463,7 @@ int complete(char *instr, char **outstr) env_param_complete(&sl, instr + 1, 1); } - pos = strlen(instr); + pos = strlen_escaped(instr); *outstr = ""; if (list_empty(&sl.list)) |