mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 13:33:15 +00:00
lib: Implement hidden and deprecated commands
Each token now knows whether it is part of a hidden or deprecated command. Command completion logic hides such tokens when generating completions. Command matching logic works as before and will still match on hidden and deprecated commands. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
4c4ff4c136
commit
ce882f8168
@ -235,7 +235,7 @@ install_node (struct cmd_node *node,
|
|||||||
node->cmdgraph = graph_new ();
|
node->cmdgraph = graph_new ();
|
||||||
node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
|
node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
|
||||||
// add start node
|
// add start node
|
||||||
struct cmd_token *token = new_cmd_token (START_TKN, NULL, NULL);
|
struct cmd_token *token = new_cmd_token (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
||||||
graph_new_node (node->cmdgraph, token, (void (*)(void *)) &del_cmd_token);
|
graph_new_node (node->cmdgraph, token, (void (*)(void *)) &del_cmd_token);
|
||||||
node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
|
node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
|
||||||
}
|
}
|
||||||
@ -2383,10 +2383,11 @@ cmd_init (int terminal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct cmd_token *
|
struct cmd_token *
|
||||||
new_cmd_token (enum cmd_token_type type, char *text, char *desc)
|
new_cmd_token (enum cmd_token_type type, u_char attr, char *text, char *desc)
|
||||||
{
|
{
|
||||||
struct cmd_token *token = XMALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
|
struct cmd_token *token = XMALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
|
||||||
token->type = type;
|
token->type = type;
|
||||||
|
token->attr = attr;
|
||||||
token->text = text;
|
token->text = text;
|
||||||
token->desc = desc;
|
token->desc = desc;
|
||||||
token->arg = NULL;
|
token->arg = NULL;
|
||||||
@ -2412,7 +2413,7 @@ del_cmd_token (struct cmd_token *token)
|
|||||||
struct cmd_token *
|
struct cmd_token *
|
||||||
copy_cmd_token (struct cmd_token *token)
|
copy_cmd_token (struct cmd_token *token)
|
||||||
{
|
{
|
||||||
struct cmd_token *copy = new_cmd_token (token->type, NULL, NULL);
|
struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
|
||||||
copy->max = token->max;
|
copy->max = token->max;
|
||||||
copy->min = token->min;
|
copy->min = token->min;
|
||||||
copy->text = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
|
copy->text = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
|
||||||
|
@ -182,24 +182,25 @@ enum cmd_token_type
|
|||||||
END_TKN, // last token in line
|
END_TKN, // last token in line
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/* Command attributes */
|
||||||
* Token struct.
|
enum
|
||||||
*/
|
{
|
||||||
|
CMD_ATTR_NORMAL,
|
||||||
|
CMD_ATTR_DEPRECATED,
|
||||||
|
CMD_ATTR_HIDDEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Comamand token struct. */
|
||||||
struct cmd_token
|
struct cmd_token
|
||||||
{
|
{
|
||||||
enum cmd_token_type type; // token type
|
enum cmd_token_type type; // token type
|
||||||
|
u_char attr; // token attributes
|
||||||
char *text; // token text
|
char *text; // token text
|
||||||
char *desc; // token description
|
char *desc; // token description
|
||||||
long long min, max; // for ranges
|
long long min, max; // for ranges
|
||||||
char *arg; // user input that matches this token
|
char *arg; // user input that matches this token
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
CMD_ATTR_DEPRECATED = 1,
|
|
||||||
CMD_ATTR_HIDDEN,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Structure of command element. */
|
/* Structure of command element. */
|
||||||
struct cmd_element
|
struct cmd_element
|
||||||
{
|
{
|
||||||
@ -425,7 +426,7 @@ copy_cmd_element(struct cmd_element *cmd);
|
|||||||
|
|
||||||
/* memory management for cmd_token */
|
/* memory management for cmd_token */
|
||||||
struct cmd_token *
|
struct cmd_token *
|
||||||
new_cmd_token (enum cmd_token_type, char *, char *);
|
new_cmd_token (enum cmd_token_type, u_char attr, char *, char *);
|
||||||
void
|
void
|
||||||
del_cmd_token (struct cmd_token *);
|
del_cmd_token (struct cmd_token *);
|
||||||
struct cmd_token *
|
struct cmd_token *
|
||||||
|
@ -331,6 +331,10 @@ command_complete (struct graph *graph,
|
|||||||
for (ALL_LIST_ELEMENTS_RO (current,node,gn))
|
for (ALL_LIST_ELEMENTS_RO (current,node,gn))
|
||||||
{
|
{
|
||||||
struct cmd_token *token = gn->data;
|
struct cmd_token *token = gn->data;
|
||||||
|
|
||||||
|
if (token->attr == CMD_ATTR_HIDDEN || token->attr == CMD_ATTR_DEPRECATED)
|
||||||
|
continue;
|
||||||
|
|
||||||
enum match_type minmatch = min_match_level (token->type);
|
enum match_type minmatch = min_match_level (token->type);
|
||||||
#ifdef TRACE_MATCHER
|
#ifdef TRACE_MATCHER
|
||||||
fprintf (stdout, "\"%s\" matches \"%s\" (%d) ? ", input_token, token->text, token->type);
|
fprintf (stdout, "\"%s\" matches \"%s\" (%d) ? ", input_token, token->text, token->type);
|
||||||
|
@ -121,7 +121,8 @@
|
|||||||
static struct graph_node *
|
static struct graph_node *
|
||||||
new_token_node (struct graph *,
|
new_token_node (struct graph *,
|
||||||
enum cmd_token_type type,
|
enum cmd_token_type type,
|
||||||
char *text, char *doc);
|
u_char attr, char *text,
|
||||||
|
char *doc);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
terminate_graph (struct graph *,
|
terminate_graph (struct graph *,
|
||||||
@ -134,7 +135,7 @@
|
|||||||
|
|
||||||
/* yyparse parameters */
|
/* yyparse parameters */
|
||||||
%parse-param { struct graph *graph }
|
%parse-param { struct graph *graph }
|
||||||
%parse-param { struct cmd_element *element }
|
%parse-param { struct cmd_element *el }
|
||||||
|
|
||||||
/* called automatically before yyparse */
|
/* called automatically before yyparse */
|
||||||
%initial-action {
|
%initial-action {
|
||||||
@ -144,15 +145,15 @@
|
|||||||
startnode = vector_slot (graph->nodes, 0);
|
startnode = vector_slot (graph->nodes, 0);
|
||||||
|
|
||||||
/* set string to parse */
|
/* set string to parse */
|
||||||
set_lexer_string (element->string);
|
set_lexer_string (el->string);
|
||||||
|
|
||||||
/* copy docstring and keep a pointer to the copy */
|
/* copy docstring and keep a pointer to the copy */
|
||||||
if (element->doc)
|
if (el->doc)
|
||||||
{
|
{
|
||||||
// allocate a new buffer, making room for a flag
|
// allocate a new buffer, making room for a flag
|
||||||
size_t length = (size_t) strlen (element->doc) + 2;
|
size_t length = (size_t) strlen (el->doc) + 2;
|
||||||
docstr = malloc (length);
|
docstr = malloc (length);
|
||||||
memcpy (docstr, element->doc, strlen (element->doc));
|
memcpy (docstr, el->doc, strlen (el->doc));
|
||||||
// set the flag so doc_next knows when to print a warning
|
// set the flag so doc_next knows when to print a warning
|
||||||
docstr[length - 2] = 0x03;
|
docstr[length - 2] = 0x03;
|
||||||
// null terminate
|
// null terminate
|
||||||
@ -167,7 +168,7 @@ start:
|
|||||||
sentence_root cmd_token_seq
|
sentence_root cmd_token_seq
|
||||||
{
|
{
|
||||||
// tack on the command element
|
// tack on the command element
|
||||||
terminate_graph (graph, currnode, element);
|
terminate_graph (graph, currnode, el);
|
||||||
}
|
}
|
||||||
| sentence_root cmd_token_seq placeholder_token '.' '.' '.'
|
| sentence_root cmd_token_seq placeholder_token '.' '.' '.'
|
||||||
{
|
{
|
||||||
@ -179,14 +180,14 @@ start:
|
|||||||
add_edge_dedup (currnode, currnode);
|
add_edge_dedup (currnode, currnode);
|
||||||
|
|
||||||
// tack on the command element
|
// tack on the command element
|
||||||
terminate_graph (graph, currnode, element);
|
terminate_graph (graph, currnode, el);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
sentence_root: WORD
|
sentence_root: WORD
|
||||||
{
|
{
|
||||||
struct graph_node *root =
|
struct graph_node *root =
|
||||||
new_token_node (graph, WORD_TKN, strdup ($1), doc_next(element));
|
new_token_node (graph, WORD_TKN, el->attr, strdup ($1), doc_next(el));
|
||||||
|
|
||||||
if ((currnode = add_edge_dedup (startnode, root)) != root)
|
if ((currnode = add_edge_dedup (startnode, root)) != root)
|
||||||
graph_delete_node (graph, root);
|
graph_delete_node (graph, root);
|
||||||
@ -227,7 +228,7 @@ compound_token:
|
|||||||
|
|
||||||
literal_token: WORD
|
literal_token: WORD
|
||||||
{
|
{
|
||||||
$$ = new_token_node (graph, WORD_TKN, strdup($1), doc_next(element));
|
$$ = new_token_node (graph, WORD_TKN, el->attr, strdup($1), doc_next(el));
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -235,32 +236,32 @@ literal_token: WORD
|
|||||||
placeholder_token:
|
placeholder_token:
|
||||||
IPV4
|
IPV4
|
||||||
{
|
{
|
||||||
$$ = new_token_node (graph, IPV4_TKN, strdup($1), doc_next(element));
|
$$ = new_token_node (graph, IPV4_TKN, el->attr, strdup($1), doc_next(el));
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
| IPV4_PREFIX
|
| IPV4_PREFIX
|
||||||
{
|
{
|
||||||
$$ = new_token_node (graph, IPV4_PREFIX_TKN, strdup($1), doc_next(element));
|
$$ = new_token_node (graph, IPV4_PREFIX_TKN, el->attr, strdup($1), doc_next(el));
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
| IPV6
|
| IPV6
|
||||||
{
|
{
|
||||||
$$ = new_token_node (graph, IPV6_TKN, strdup($1), doc_next(element));
|
$$ = new_token_node (graph, IPV6_TKN, el->attr, strdup($1), doc_next(el));
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
| IPV6_PREFIX
|
| IPV6_PREFIX
|
||||||
{
|
{
|
||||||
$$ = new_token_node (graph, IPV6_PREFIX_TKN, strdup($1), doc_next(element));
|
$$ = new_token_node (graph, IPV6_PREFIX_TKN, el->attr, strdup($1), doc_next(el));
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
| VARIABLE
|
| VARIABLE
|
||||||
{
|
{
|
||||||
$$ = new_token_node (graph, VARIABLE_TKN, strdup($1), doc_next(element));
|
$$ = new_token_node (graph, VARIABLE_TKN, el->attr, strdup($1), doc_next(el));
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
| RANGE
|
| RANGE
|
||||||
{
|
{
|
||||||
$$ = new_token_node (graph, RANGE_TKN, strdup($1), doc_next(element));
|
$$ = new_token_node (graph, RANGE_TKN, el->attr, strdup($1), doc_next(el));
|
||||||
struct cmd_token *token = $$->data;
|
struct cmd_token *token = $$->data;
|
||||||
|
|
||||||
// get the numbers out
|
// get the numbers out
|
||||||
@ -270,7 +271,7 @@ placeholder_token:
|
|||||||
token->max = strtoll (yylval.string, &yylval.string, 10);
|
token->max = strtoll (yylval.string, &yylval.string, 10);
|
||||||
|
|
||||||
// validate range
|
// validate range
|
||||||
if (token->min > token->max) yyerror (graph, element, "Invalid range.");
|
if (token->min > token->max) yyerror (graph, el, "Invalid range.");
|
||||||
|
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
@ -279,8 +280,8 @@ placeholder_token:
|
|||||||
selector: '<' selector_seq_seq '>'
|
selector: '<' selector_seq_seq '>'
|
||||||
{
|
{
|
||||||
$$ = malloc (sizeof (struct subgraph));
|
$$ = malloc (sizeof (struct subgraph));
|
||||||
$$->start = new_token_node (graph, SELECTOR_TKN, NULL, NULL);
|
$$->start = new_token_node (graph, SELECTOR_TKN, el->attr, NULL, NULL);
|
||||||
$$->end = new_token_node (graph, NUL_TKN, NULL, NULL);
|
$$->end = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL);
|
||||||
for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
|
for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
|
||||||
{
|
{
|
||||||
struct graph_node *sn = vector_slot ($2->start->to, i),
|
struct graph_node *sn = vector_slot ($2->start->to, i),
|
||||||
@ -362,8 +363,8 @@ option: '[' option_token_seq ']'
|
|||||||
{
|
{
|
||||||
// make a new option
|
// make a new option
|
||||||
$$ = malloc (sizeof (struct subgraph));
|
$$ = malloc (sizeof (struct subgraph));
|
||||||
$$->start = new_token_node (graph, OPTION_TKN, NULL, NULL);
|
$$->start = new_token_node (graph, OPTION_TKN, el->attr, NULL, NULL);
|
||||||
$$->end = new_token_node (graph, NUL_TKN, NULL, NULL);
|
$$->end = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL);
|
||||||
// add a path through the sequence to the end
|
// add a path through the sequence to the end
|
||||||
graph_add_edge ($$->start, $2->start);
|
graph_add_edge ($$->start, $2->start);
|
||||||
graph_add_edge ($2->end, $$->end);
|
graph_add_edge ($2->end, $$->end);
|
||||||
@ -434,13 +435,15 @@ cleanup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
terminate_graph (struct graph *graph, struct graph_node *finalnode, struct cmd_element *element)
|
terminate_graph (struct graph *graph, struct graph_node *finalnode,
|
||||||
|
struct cmd_element *element)
|
||||||
{
|
{
|
||||||
// end of graph should look like this
|
// end of graph should look like this
|
||||||
// * -> finalnode -> END_TKN -> cmd_element
|
// * -> finalnode -> END_TKN -> cmd_element
|
||||||
struct graph_node *end_token_node =
|
struct graph_node *end_token_node =
|
||||||
new_token_node (graph,
|
new_token_node (graph,
|
||||||
END_TKN,
|
END_TKN,
|
||||||
|
element->attr,
|
||||||
strdup (CMD_CR_TEXT),
|
strdup (CMD_CR_TEXT),
|
||||||
strdup (""));
|
strdup (""));
|
||||||
struct graph_node *end_element_node =
|
struct graph_node *end_element_node =
|
||||||
@ -467,9 +470,10 @@ doc_next (struct cmd_element *el)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct graph_node *
|
static struct graph_node *
|
||||||
new_token_node (struct graph *graph, enum cmd_token_type type, char *text, char *doc)
|
new_token_node (struct graph *graph, enum cmd_token_type type,
|
||||||
|
u_char attr, char *text, char *doc)
|
||||||
{
|
{
|
||||||
struct cmd_token *token = new_cmd_token (type, text, doc);
|
struct cmd_token *token = new_cmd_token (type, attr, text, doc);
|
||||||
return graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token);
|
return graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +511,16 @@ static struct graph_node *
|
|||||||
add_edge_dedup (struct graph_node *from, struct graph_node *to)
|
add_edge_dedup (struct graph_node *from, struct graph_node *to)
|
||||||
{
|
{
|
||||||
struct graph_node *existing = node_adjacent (from, to);
|
struct graph_node *existing = node_adjacent (from, to);
|
||||||
return existing ? existing : graph_add_edge (from, to);
|
if (existing)
|
||||||
|
{
|
||||||
|
struct cmd_token *ex_tok = existing->data;
|
||||||
|
struct cmd_token *to_tok = to->data;
|
||||||
|
// NORMAL takes precedence over DEPRECATED takes precedence over HIDDEN
|
||||||
|
ex_tok->attr = (ex_tok->attr < to_tok->attr) ? ex_tok->attr : to_tok->attr;
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return graph_add_edge (from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user