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 16:27:43 +0200 |
commit | 7f059ea614bf310015bcb4e9b8dd7b1f6c6e072a (patch) | |
tree | 6fdc433e5c6d8877380874935130f950fa15db3b /vtysh | |
parent | lib: cli: autocomplete variables (diff) | |
download | frr-7f059ea614bf310015bcb4e9b8dd7b1f6c6e072a.tar.xz frr-7f059ea614bf310015bcb4e9b8dd7b1f6c6e072a.zip |
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 c28d57cff..fcae71737 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 ad45abcdf..57151acee 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 2a84847aa..aa003c752 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 (); } |