[libvirt] [PATCH 5/8] virsh: Improve readline generators and readline completion
Michal Privoznik
mprivozn at redhat.com
Mon Aug 19 14:45:12 UTC 2013
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
More information about the libvir-list
mailing list