On 08.08.2013 16:38, Tomas Meszaros wrote: > New completion generators responsible for advances command > and command options completions. > > vshReadlineCommandCompletionGenerator - generator for advanced > command completions. This function will call some vshCmdCompleter > function (e.g. vshDomainCompleter), which will return relevant > data used for autocompletion (e.g. domain names). > > vshReadlineOptionsCompletionGenerator - almost the same as the > vshReadlineCommandCompletionGenerator, but this one completes > cmd options. > > vshReadlineCompletion() has become much more complex because we > now have more generator functions and therefore more states to > choose from. > --- > tools/virsh.c | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 376 insertions(+), 22 deletions(-) > > diff --git a/tools/virsh.c b/tools/virsh.c > index 13d66c7..aec26b4 100644 > --- a/tools/virsh.c > +++ b/tools/virsh.c > @@ -2610,6 +2610,25 @@ cleanup: > * ----------------- > */ > > +static const vshCmdDef * > +vshDetermineCommandName(void) > +{ > + const vshCmdDef *cmd = NULL; > + char *p; > + char *cmdname; > + > + if (!(p = strchr(rl_line_buffer, ' '))) > + return NULL; > + > + cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1); so this is effectively vshMalloc(). > + memcpy(cmdname, rl_line_buffer, p - rl_line_buffer); > + > + cmd = vshCmddefSearch(cmdname); > + VIR_FREE(cmdname); > + > + return cmd; > +} > + > /* > * Generator function for command completion. STATE lets us > * know whether to start from scratch; without any state > @@ -2657,25 +2676,14 @@ vshReadlineCommandGenerator(const char *text, int state) > static char * > vshReadlineOptionsGenerator(const char *text, int state) > { > - static int list_index, len; > static const vshCmdDef *cmd = NULL; > + static int list_index, len; > const char *name; > > if (!state) { > - /* determine command name */ > - char *p; > - char *cmdname; > - > - if (!(p = strchr(rl_line_buffer, ' '))) > - return NULL; > - > - cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1); > - memcpy(cmdname, rl_line_buffer, p - rl_line_buffer); > - > - cmd = vshCmddefSearch(cmdname); > + cmd = vshDetermineCommandName(); > list_index = 0; > len = strlen(text); > - VIR_FREE(cmdname); > } > > if (!cmd) > @@ -2707,22 +2715,368 @@ vshReadlineOptionsGenerator(const char *text, int state) > return NULL; > } > > +/* > + * Generator function for command completion, but unlike > + * the vshRaadlineCommandGenerator which completes command name, this function > + * provides more advanced completion for commands by calling specific command > + * completers (e.g. vshDomainCompleter). > + */ > +static char * > +vshReadlineCommandCompletionGenerator(const char *text, int state) > +{ > + static const vshCmdDef *cmd = NULL; > + static int list_index, len; > + char **completed_names = NULL; > + char *name; > + > + if (!state) { > + cmd = vshDetermineCommandName(); > + list_index = 0; > + len = strlen(text); > + } > + > + if (!cmd) > + return NULL; > + > + if (!cmd->completer) > + return NULL; > + > + completed_names = cmd->completer(cmd->completer_flags); > + > + if (!completed_names) > + return NULL; > + > + while ((name = completed_names[list_index])) { > + char *res; > + list_index++; > + > + if (STRNEQLEN(name, text, len)) > + /* Skip irrelevant names */ > + continue; > + > + res = vshMalloc(NULL, strlen(name) + 1); > + snprintf(res, strlen(name) + 1, "%s", name); Consider using vshStrdup() instead of these two lines. > + VIR_FREE(name); > + return res; > + } > + VIR_FREE(completed_names); > + > + return NULL; > +} > + > +/* > + * Generator function for command option completion. Provides advances > + * completion for command options. > + */ > +static char * > +vshReadlineOptionsCompletionGenerator(const char *text ATTRIBUTE_UNUSED, > + int state ATTRIBUTE_UNUSED) > +{ > + static const vshCmdDef *cmd = NULL; > + static const vshCmdOptDef *opt = NULL; > + static int list_index, len; > + unsigned long int opt_index = 0; > + size_t i; > + char **completed_names = NULL; > + char *name; > + char *ptr = NULL; > + > + if (!state) { > + cmd = vshDetermineCommandName(); > + list_index = 0; > + len = strlen(text); > + } > + > + if (!cmd) > + return NULL; > + > + if (!cmd->opts) > + return NULL; > + > + for (i = 0; cmd->opts[i].name; i++) { > + if ((ptr = strstr(rl_line_buffer, cmd->opts[i].name))) { > + if (opt_index < (ptr - rl_line_buffer)) { These to if's can be joined into one. > + opt_index = ptr - rl_line_buffer; > + opt = &cmd->opts[i]; > + } > + } > + } > + > + if (!opt) > + return NULL; > + > + if (!opt->completer) > + return NULL; > + > + completed_names = opt->completer(opt->completer_flags); > + > + if (!completed_names) > + return NULL; > + > + while ((name = completed_names[list_index])) { > + char *res; > + list_index++; > + > + if (STRNEQLEN(name, text, len)) > + /* Skip irrelevant names */ > + continue; > + > + res = vshMalloc(NULL, strlen(name) + 1); > + snprintf(res, strlen(name) + 1, "%s", name); Again, nice candidate to be replaced by vshStrdup(). > + VIR_FREE(name); > + return res; > + } > + VIR_FREE(completed_names); > + > + return NULL; > +} > + Michal -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list