mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-29 20:04:11 +00:00
lib: parser: add pre-merge varname propagation step
Fills token->varname based on context. WORD tokens use the WORD - if it isn't actually "WORD". Other than that, a preceding constant token is used as name. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
5894e76da7
commit
c09c46ae3c
@ -341,6 +341,7 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
|
|||||||
graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
|
graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
|
||||||
|
|
||||||
cmd_graph_parse (graph, cmd);
|
cmd_graph_parse (graph, cmd);
|
||||||
|
cmd_graph_names (graph);
|
||||||
cmd_graph_merge (cnode->cmdgraph, graph, +1);
|
cmd_graph_merge (cnode->cmdgraph, graph, +1);
|
||||||
graph_delete_graph (graph);
|
graph_delete_graph (graph);
|
||||||
|
|
||||||
@ -387,6 +388,7 @@ uninstall_element (enum node_type ntype, struct cmd_element *cmd)
|
|||||||
graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
|
graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
|
||||||
|
|
||||||
cmd_graph_parse (graph, cmd);
|
cmd_graph_parse (graph, cmd);
|
||||||
|
cmd_graph_names (graph);
|
||||||
cmd_graph_merge (cnode->cmdgraph, graph, -1);
|
cmd_graph_merge (cnode->cmdgraph, graph, -1);
|
||||||
graph_delete_graph (graph);
|
graph_delete_graph (graph);
|
||||||
|
|
||||||
|
@ -81,7 +81,28 @@ cmd_token_dup (struct cmd_token *token)
|
|||||||
void cmd_token_varname_set(struct cmd_token *token, const char *varname)
|
void cmd_token_varname_set(struct cmd_token *token, const char *varname)
|
||||||
{
|
{
|
||||||
XFREE (MTYPE_CMD_VAR, token->varname);
|
XFREE (MTYPE_CMD_VAR, token->varname);
|
||||||
token->varname = varname ? XSTRDUP (MTYPE_CMD_VAR, varname) : NULL;
|
if (!varname)
|
||||||
|
{
|
||||||
|
token->varname = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen (varname), i;
|
||||||
|
token->varname = XMALLOC (MTYPE_CMD_VAR, len + 1);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
switch (varname[i])
|
||||||
|
{
|
||||||
|
case '-':
|
||||||
|
case '+':
|
||||||
|
case '*':
|
||||||
|
case ':':
|
||||||
|
token->varname[i] = '_';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
token->varname[i] = tolower (varname[i]);
|
||||||
|
}
|
||||||
|
token->varname[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -162,6 +183,10 @@ cmd_nodes_equal (struct graph_node *ga, struct graph_node *gb)
|
|||||||
/* one a ..., the other not. */
|
/* one a ..., the other not. */
|
||||||
if (cmd_nodes_link (ga, ga) != cmd_nodes_link (gb, gb))
|
if (cmd_nodes_link (ga, ga) != cmd_nodes_link (gb, gb))
|
||||||
return false;
|
return false;
|
||||||
|
if (!a->varname != !b->varname)
|
||||||
|
return false;
|
||||||
|
if (a->varname && strcmp (a->varname, b->varname))
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (a->type)
|
switch (a->type)
|
||||||
{
|
{
|
||||||
@ -349,3 +374,107 @@ cmd_graph_merge (struct graph *old, struct graph *new, int direction)
|
|||||||
vector_slot (old->nodes, 0), vector_slot (new->nodes, 0),
|
vector_slot (old->nodes, 0), vector_slot (new->nodes, 0),
|
||||||
direction);
|
direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_node_names (struct graph_node *gn, struct graph_node *join,
|
||||||
|
const char *prevname)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
struct cmd_token *tok = gn->data, *jointok;
|
||||||
|
struct graph_node *stop = cmd_loopstop (gn);
|
||||||
|
|
||||||
|
switch (tok->type)
|
||||||
|
{
|
||||||
|
case WORD_TKN:
|
||||||
|
prevname = tok->text;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VARIABLE_TKN:
|
||||||
|
if (!tok->varname
|
||||||
|
&& strcmp (tok->text, "WORD")
|
||||||
|
&& strcmp (tok->text, "NAME"))
|
||||||
|
cmd_token_varname_set (tok, tok->text);
|
||||||
|
/* fallthrough */
|
||||||
|
case RANGE_TKN:
|
||||||
|
case IPV4_TKN:
|
||||||
|
case IPV4_PREFIX_TKN:
|
||||||
|
case IPV6_TKN:
|
||||||
|
case IPV6_PREFIX_TKN:
|
||||||
|
if (!tok->varname && prevname)
|
||||||
|
cmd_token_varname_set (tok, prevname);
|
||||||
|
prevname = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case START_TKN:
|
||||||
|
case END_TKN:
|
||||||
|
case JOIN_TKN:
|
||||||
|
/* "<foo|bar> WORD" -> word is not "bar" or "foo" */
|
||||||
|
prevname = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORK_TKN:
|
||||||
|
/* apply "<A.B.C.D|X:X::X:X>$name" */
|
||||||
|
jointok = tok->forkjoin->data;
|
||||||
|
if (!jointok->varname)
|
||||||
|
break;
|
||||||
|
for (i = 0; i < vector_active (tok->forkjoin->from); i++)
|
||||||
|
{
|
||||||
|
struct graph_node *tail = vector_slot (tok->forkjoin->from, i);
|
||||||
|
struct cmd_token *tailtok = tail->data;
|
||||||
|
if (tail == gn || tailtok->varname)
|
||||||
|
continue;
|
||||||
|
cmd_token_varname_set (tailtok, jointok->varname);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < vector_active (gn->to); i++)
|
||||||
|
{
|
||||||
|
struct graph_node *next = vector_slot (gn->to, i);
|
||||||
|
if (next == stop || next == join)
|
||||||
|
continue;
|
||||||
|
cmd_node_names (next, join, prevname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok->type == FORK_TKN && tok->forkjoin != join)
|
||||||
|
cmd_node_names (tok->forkjoin, join, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cmd_graph_names (struct graph *graph)
|
||||||
|
{
|
||||||
|
struct graph_node *start;
|
||||||
|
|
||||||
|
assert (vector_active (graph->nodes) >= 1);
|
||||||
|
start = vector_slot (graph->nodes, 0);
|
||||||
|
|
||||||
|
/* apply varname on initial "[no]" */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (vector_active (start->to) != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
struct graph_node *first = vector_slot (start->to, 0);
|
||||||
|
struct cmd_token *tok = first->data;
|
||||||
|
/* looking for an option with 2 choices, nothing or "no" */
|
||||||
|
if (tok->type != FORK_TKN || vector_active (first->to) != 2)
|
||||||
|
break;
|
||||||
|
|
||||||
|
struct graph_node *next0 = vector_slot (first->to, 0);
|
||||||
|
struct graph_node *next1 = vector_slot (first->to, 1);
|
||||||
|
/* one needs to be empty */
|
||||||
|
if (next0 != tok->forkjoin && next1 != tok->forkjoin)
|
||||||
|
break;
|
||||||
|
|
||||||
|
struct cmd_token *tok0 = next0->data;
|
||||||
|
struct cmd_token *tok1 = next1->data;
|
||||||
|
/* the other one needs to be "no" (only one will match here) */
|
||||||
|
if ((tok0->type == WORD_TKN && !strcmp(tok0->text, "no")))
|
||||||
|
cmd_token_varname_set (tok0, "no");
|
||||||
|
if ((tok1->type == WORD_TKN && !strcmp(tok1->text, "no")))
|
||||||
|
cmd_token_varname_set (tok1, "no");
|
||||||
|
}
|
||||||
|
while (0);
|
||||||
|
|
||||||
|
cmd_node_names (start, NULL, NULL);
|
||||||
|
}
|
||||||
|
@ -111,6 +111,7 @@ extern void cmd_token_del (struct cmd_token *);
|
|||||||
extern void cmd_token_varname_set(struct cmd_token *token, const char *varname);
|
extern void cmd_token_varname_set(struct cmd_token *token, const char *varname);
|
||||||
|
|
||||||
extern void cmd_graph_parse (struct graph *graph, struct cmd_element *cmd);
|
extern void cmd_graph_parse (struct graph *graph, struct cmd_element *cmd);
|
||||||
|
extern void cmd_graph_names (struct graph *graph);
|
||||||
extern void cmd_graph_merge (struct graph *old, struct graph *new, int direction);
|
extern void cmd_graph_merge (struct graph *old, struct graph *new, int direction);
|
||||||
|
|
||||||
#endif /* _FRR_COMMAND_GRAPH_H */
|
#endif /* _FRR_COMMAND_GRAPH_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user