diff options
| author | David Lamparter <equinox@opensourcerouting.org> | 2017-05-10 16:38:48 +0200 | 
|---|---|---|
| committer | Quentin Young <qlyoung@users.noreply.github.com> | 2017-05-15 10:27:43 -0400 | 
| commit | 7f059ea614bf310015bcb4e9b8dd7b1f6c6e072a (patch) | |
| tree | 6fdc433e5c6d8877380874935130f950fa15db3b /vtysh | |
| parent | 70d44c5cd4f28f9d08a24f519d859885d92e2a13 (diff) | |
vtysh: autocomplete variables
This asks the connected daemons for their variable completions through a
hidden CLI command.
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'vtysh')
| -rw-r--r-- | vtysh/vtysh.c | 73 | ||||
| -rw-r--r-- | vtysh/vtysh.h | 2 | ||||
| -rw-r--r-- | vtysh/vtysh_config.c | 8 | 
3 files changed, 67 insertions, 16 deletions
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index c28d57cff2..fcae717374 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -107,12 +107,9 @@ begins_with(const char *str, const char *prefix)    return strncmp(str, prefix, lenprefix) == 0;  } -/* NB: multiplexed function: - *  if fp == NULL, this calls vtysh_config_parse_line - *  if fp != NULL, this prints lines to fp - */  static int -vtysh_client_run (struct vtysh_client *vclient, const char *line, FILE *fp) +vtysh_client_run (struct vtysh_client *vclient, const char *line, FILE *fp, +                  void (*callback)(void *, const char *), void *cbarg)  {    int ret;    char stackbuf[4096]; @@ -178,8 +175,8 @@ vtysh_client_run (struct vtysh_client *vclient, const char *line, FILE *fp)                fputs (buf, fp);                fputc ('\n', fp);              } -          else -            vtysh_config_parse_line (buf); +          if (callback) +            callback(cbarg, buf);            if (eol == end)              /* \n\0\0\0 */ @@ -223,14 +220,15 @@ out:  static int  vtysh_client_run_all (struct vtysh_client *head_client, const char *line, -                      int continue_on_err, FILE *fp) +                      int continue_on_err, FILE *fp, +                      void (*callback)(void *, const char *), void *cbarg)  {    struct vtysh_client *client;    int rc, rc_all = CMD_SUCCESS;    for (client = head_client; client; client = client->next)      { -      rc = vtysh_client_run(client, line, fp); +      rc = vtysh_client_run(client, line, fp, callback, cbarg);        if (rc != CMD_SUCCESS)          {            if (!continue_on_err) @@ -245,13 +243,13 @@ static int  vtysh_client_execute (struct vtysh_client *head_client, const char *line,                        FILE *fp)  { -  return vtysh_client_run_all (head_client, line, 0, fp); +  return vtysh_client_run_all (head_client, line, 0, fp, NULL, NULL);  }  static void  vtysh_client_config (struct vtysh_client *head_client, char *line)  { -  vtysh_client_run_all (head_client, line, 1, NULL); +  vtysh_client_run_all (head_client, line, 1, NULL, vtysh_config_parse_line, NULL);  }  void @@ -796,6 +794,27 @@ vtysh_rl_describe (void)  		   width,  		   token->text,  		   token->desc); + +        if (IS_VARYING_TOKEN(token->type)) +          { +            const char *ref = vector_slot(vline, vector_active(vline) - 1); + +            vector varcomps = vector_init (VECTOR_MIN_SIZE); +            cmd_variable_complete (token, ref, varcomps); + +            if (vector_active (varcomps) > 0) +              { +                fprintf(stdout, "     "); +                for (size_t j = 0; j < vector_active (varcomps); j++) +                  { +                    char *item = vector_slot (varcomps, j); +                    fprintf (stdout, " %s", item); +                    XFREE (MTYPE_COMPLETION, item); +                  } +                vty_out (vty, "%s", VTY_NEWLINE); +              } +            vector_free (varcomps); +          }        }    cmd_free_strvec (vline); @@ -838,6 +857,7 @@ command_generator (const char *text, int state)      }    if (matched && matched[index]) +    /* this is free()'d by readline, but we leak 1 count of MTYPE_COMPLETION */      return matched[index++];    XFREE (MTYPE_TMP, matched); @@ -3193,6 +3213,36 @@ vtysh_prompt (void)    return buf;  } +static void vtysh_ac_line(void *arg, const char *line) +{ +  vector comps = arg; +  size_t i; +  for (i = 0; i < vector_active(comps); i++) +    if (!strcmp(line, (char *)vector_slot(comps, i))) +      return; +  vector_set(comps, XSTRDUP(MTYPE_COMPLETION, line)); +} + +static void vtysh_autocomplete(vector comps, struct cmd_token *token) +{ +  char accmd[256]; +  size_t i; + +  snprintf(accmd, sizeof(accmd), "autocomplete %d %s %s", token->type, +           token->text, token->varname ? token->varname : "-"); + +  for (i = 0; i < array_size(vtysh_client); i++) +    vtysh_client_run_all (&vtysh_client[i], accmd, 1, NULL, +                          vtysh_ac_line, comps); +} + +static const struct cmd_variable_handler vtysh_var_handler = { +        /* match all */ +        .tokenname = NULL, +        .varname = NULL, +        .completions = vtysh_autocomplete +}; +  void  vtysh_init_vty (void)  { @@ -3203,6 +3253,7 @@ vtysh_init_vty (void)    /* Initialize commands. */    cmd_init (0); +  cmd_variable_handler_register(&vtysh_var_handler);    /* Install nodes. */    install_node (&bgp_node, NULL); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index ad45abcdf3..57151aceed 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -85,7 +85,7 @@ int vtysh_mark_file(const char *filename);  int vtysh_read_config (const char *);  int vtysh_write_config_integrated (void); -void vtysh_config_parse_line (const char *); +void vtysh_config_parse_line (void *, const char *);  void vtysh_config_dump (FILE *); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 2a84847aaa..aa003c7528 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -145,7 +145,7 @@ config_add_line_uniq (struct list *config, const char *line)  }  void -vtysh_config_parse_line (const char *line) +vtysh_config_parse_line (void *arg, const char *line)  {    char c;    static struct config *config = NULL; @@ -418,12 +418,12 @@ vtysh_config_write ()    if (host.name)      {        sprintf (line, "hostname %s", host.name); -      vtysh_config_parse_line(line); +      vtysh_config_parse_line(NULL, line);      }    if (vtysh_write_integrated == WRITE_INTEGRATED_NO) -    vtysh_config_parse_line ("no service integrated-vtysh-config"); +    vtysh_config_parse_line (NULL, "no service integrated-vtysh-config");    if (vtysh_write_integrated == WRITE_INTEGRATED_YES) -    vtysh_config_parse_line ("service integrated-vtysh-config"); +    vtysh_config_parse_line (NULL, "service integrated-vtysh-config");    user_config_write ();  }  | 
