]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: parser: add pre-merge varname propagation step
authorDavid Lamparter <equinox@opensourcerouting.org>
Wed, 22 Mar 2017 05:56:17 +0000 (06:56 +0100)
committerQuentin Young <qlyoung@users.noreply.github.com>
Mon, 15 May 2017 14:27:43 +0000 (10:27 -0400)
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>
lib/command.c
lib/command_graph.c
lib/command_graph.h

index 7a53357e7a5302565e7ef80ed8a5eb8850cf2c98..0e19a3dfeefc3c85dc97f330fc8ac8146ddaf72e 100644 (file)
@@ -341,6 +341,7 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
   graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
 
   cmd_graph_parse (graph, cmd);
+  cmd_graph_names (graph);
   cmd_graph_merge (cnode->cmdgraph, graph, +1);
   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);
 
   cmd_graph_parse (graph, cmd);
+  cmd_graph_names (graph);
   cmd_graph_merge (cnode->cmdgraph, graph, -1);
   graph_delete_graph (graph);
 
index 7e611e362284276277ddebc2c2653297490134e0..62d0610e1858e3347189ff88551b5600e37ce3b7 100644 (file)
@@ -81,7 +81,28 @@ cmd_token_dup (struct cmd_token *token)
 void cmd_token_varname_set(struct cmd_token *token, const char *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
@@ -162,6 +183,10 @@ cmd_nodes_equal (struct graph_node *ga, struct graph_node *gb)
   /* one a ..., the other not. */
   if (cmd_nodes_link (ga, ga) != cmd_nodes_link (gb, gb))
     return false;
+  if (!a->varname != !b->varname)
+    return false;
+  if (a->varname && strcmp (a->varname, b->varname))
+    return false;
 
   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),
                    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);
+}
index e6d49f2f5645528068bb3df0fe440ae94020e34f..11cea9bd4289f7c509d9afa19ab115df4e328073 100644 (file)
@@ -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_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);
 
 #endif /* _FRR_COMMAND_GRAPH_H */