[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