]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: Cleanup some memory issues in CLI
authorQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 29 Jul 2016 15:54:03 +0000 (15:54 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 29 Jul 2016 15:54:03 +0000 (15:54 +0000)
Various memory leaks have been fixed and the quagga
memory macros are in use. Also consolidated the argv
and matching code into one graph traversal.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_graph.h
lib/command_lex.l
lib/command_match.c
lib/command_match.h
lib/command_parse.y
lib/grammar_sandbox.c

index 490c2a06901a6857778ac9a9f2323e5a8a763a11..d3c6771248d5157f892748d27ab81d4aa5871cdf 100644 (file)
@@ -4190,6 +4190,30 @@ cmd_terminate_element(struct cmd_element *cmd)
   cmd->tokens = NULL;
 }
 
+void
+free_cmd_element(struct cmd_element *cmd)
+{
+  if (!cmd) return;
+  free ((char*) cmd->string);
+  free ((char*) cmd->doc);
+  cmd_terminate_element(cmd);
+  free (cmd);
+}
+
+struct cmd_element *
+copy_cmd_element(struct cmd_element *cmd)
+{
+  struct cmd_element *el = XMALLOC(MTYPE_CMD_TOKENS, sizeof (struct cmd_element));
+  el->string = cmd->string ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->string) : NULL;
+  el->func = cmd->func;
+  el->doc = cmd->doc ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->doc) : NULL;
+  el->daemon = cmd->daemon;
+  el->tokens = cmd->tokens ? vector_copy(cmd->tokens) : NULL;
+  el->attr = cmd->attr;
+  fprintf(stderr, "successful copy\n");
+  return el;
+}
+
 void
 cmd_terminate ()
 {
index c1ef0e55bd110ce5bb2f1781911b0b9378b27aa5..9a77d3b87c52925926f83d7fd6ea9a2bfc048567 100644 (file)
@@ -571,6 +571,12 @@ extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element
 extern void cmd_init (int);
 extern void cmd_terminate (void);
 
+/* memory management for cmd_element */
+void
+free_cmd_element(struct cmd_element *);
+struct cmd_element *
+copy_cmd_element(struct cmd_element *cmd);
+
 /* Export typical functions. */
 extern struct cmd_element config_end_cmd;
 extern struct cmd_element config_exit_cmd;
index a5880f34a674bb28ca21a6cb732a8297ae2ca1a8..7c09a5cd6c0908ac955ff0295eff5bca2ffa245a 100644 (file)
@@ -22,6 +22,7 @@ add_node(struct graph_node *parent, struct graph_node *child)
       return p_child;
   }
   vector_set(parent->children, child);
+  child->refs++;
   return child;
 }
 
@@ -58,6 +59,7 @@ cmp_node(struct graph_node *first, struct graph_node *second)
      */
     case START_GN:
     case END_GN:
+    case NUL_GN:
     default:
       break;
   }
@@ -73,29 +75,61 @@ new_node(enum graph_node_type type)
 
   node->type = type;
   node->children = vector_init(VECTOR_MIN_SIZE);
-  node->is_start = 0;
   node->end      = NULL;
   node->text     = NULL;
+  node->element  = NULL;
+  node->arg      = NULL;
+  node->is_start = 0;
   node->value    = 0;
   node->min      = 0;
   node->max      = 0;
-  node->element  = NULL;
+  node->refs     = 0;
 
   return node;
 }
 
+struct graph_node *
+copy_node (struct graph_node *node)
+{
+  struct graph_node *new = new_node(node->type);
+  new->children = vector_copy (node->children);
+  new->is_start = node->is_start;
+  new->end      = node->end;
+  new->text     = node->text ? XSTRDUP(MTYPE_CMD_TOKENS, node->text) : NULL;
+  new->value    = node->value;
+  new->min      = node->min;
+  new->max      = node->max;
+  new->element  = node->element ? copy_cmd_element(node->element) : NULL;
+  new->arg      = node->arg ? XSTRDUP(MTYPE_CMD_TOKENS, node->arg) : NULL;
+  new->refs     = 0;
+  return new;
+}
+
 void
 free_node (struct graph_node *node)
 {
   if (!node) return;
-  free_node (node->end);
   vector_free (node->children);
+  free_cmd_element (node->element);
   free (node->text);
   free (node->arg);
-  free (node->element);
   free (node);
 }
 
+void
+free_graph (struct graph_node *start)
+{
+  if (start && start->children && vector_active(start->children) > 0) {
+    for (unsigned int i = 0; i < vector_active(start->children); i++) {
+      free_graph (vector_slot(start->children, i));
+      vector_unset(start->children, i);
+    }
+  }
+
+  if (--(start->refs) == 0)
+    free_node (start);
+}
+
 char *
 describe_node(struct graph_node *node, char* buffer, unsigned int bufsize)
 {
@@ -166,3 +200,18 @@ walk_graph(struct graph_node *start, int level)
     fprintf(stderr, "\n");
 }
 
+void
+dump_node (struct graph_node *node)
+{
+  char buf[50];
+  describe_node(node, buf, 50);
+  fprintf(stderr, "%s[%d]\n", buf, node->type);
+  fprintf(stderr, "\t->text: %s\n", node->text);
+  fprintf(stderr, "\t->value: %ld\n", node->value);
+  fprintf(stderr, "\t->is_start: %d\n", node->is_start);
+  fprintf(stderr, "\t->element: %p\n", node->element);
+  fprintf(stderr, "\t->min: %ld\n->max: %ld\n", node->min, node->max);
+  fprintf(stderr, "\t->arg: %s\n", node->arg);
+  fprintf(stderr, "\t->refs: %d\n", node->refs);
+  fprintf(stderr, "\tnum children: %d\n", vector_active(node->children));
+}
index a9ffe0f7b6e0aa5c78311fd5e61dbe97a9c27363..dc78475ca6bb43a86287287c94bf7200d4a241cc 100644 (file)
@@ -35,6 +35,9 @@ struct graph_node
   struct cmd_element *element;
   /* used for passing arguments to command functions */
   char *arg;
+
+  /* refcount for node parents */
+  int refs;
 };
 
 /*
@@ -47,7 +50,7 @@ struct graph_node
  * @param[in] child node
  * @return pointer to child if it is added, pointer to existing child otherwise
  */
-extern struct graph_node *
+struct graph_node *
 add_node(struct graph_node *, struct graph_node *);
 
 /*
@@ -61,7 +64,7 @@ add_node(struct graph_node *, struct graph_node *);
  * @param[in] second node to compare
  * @return 1 if equal, zero otherwise.
  */
-extern int
+int
 cmp_node(struct graph_node *, struct graph_node *);
 
 /*
@@ -71,9 +74,36 @@ cmp_node(struct graph_node *, struct graph_node *);
  * @param[in] node type
  * @return pointer to the newly allocated node
  */
-extern struct graph_node *
+struct graph_node *
 new_node(enum graph_node_type);
 
+/**
+ * Copies a node.
+ * The children vector is copied, but the pointers the vector
+ * holds point to the same data as the original vector.
+ * The element, if it exists, is copied.
+ *
+ * @param[in] pointer to node to copy
+ * @return pointer to copied node
+ */
+struct graph_node *
+copy_node(struct graph_node *);
+
+/**
+ * Frees the data associated with a graph_node.
+ * @param[out] pointer to graph_node to free
+ */
+void
+free_node(struct graph_node *);
+
+/**
+ * Recursively calls free_node on a graph node
+ * and all its children.
+ * @param[out] graph to free
+ */
+void
+free_graph(struct graph_node *);
+
 /**
  * Walks a command DFA, printing structure to stdout.
  * For debugging.
@@ -81,7 +111,7 @@ new_node(enum graph_node_type);
  * @param[in] start node of graph to walk
  * @param[in] graph depth for recursion, caller passes 0
  */
-extern void
+void
 walk_graph(struct graph_node *, int);
 
 /**
@@ -90,13 +120,9 @@ walk_graph(struct graph_node *, int);
  * @param[out] the buffer to write the description into
  * @return pointer to description string
  */
-extern char *
+char *
 describe_node(struct graph_node *, char *, unsigned int);
 
-/**
- * Frees the data associated with a graph_node.
- * @param[out] pointer to graph_node to free
- */
 void
-free_node(struct graph_node *);
+dump_node (struct graph_node *);
 #endif
index 45f8f8e63691df1d2d5445c0fc1c12304d6faf7e..5a0e76d418a5bb0391daa624894b95ebf9533d98 100644 (file)
@@ -22,14 +22,14 @@ RANGE           \({NUMBER}\-{NUMBER}\)
 
 %%
 [ /t]           /* ignore whitespace */;
-{WORD}          {yylval.string = strdup(yytext); return WORD;}
-{IPV4}          {yylval.string = strdup(yytext); return IPV4;}
-{IPV4_PREFIX}   {yylval.string = strdup(yytext); return IPV4_PREFIX;}
-{IPV6}          {yylval.string = strdup(yytext); return IPV6;}
-{IPV6_PREFIX}   {yylval.string = strdup(yytext); return IPV6_PREFIX;}
-{VARIABLE}      {yylval.string = strdup(yytext); return VARIABLE;}
+{WORD}          {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
+{IPV4}          {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
+{IPV4_PREFIX}   {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
+{IPV6}          {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV6;}
+{IPV6_PREFIX}   {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV6_PREFIX;}
+{VARIABLE}      {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return VARIABLE;}
 {NUMBER}        {yylval.integer = atoi(yytext); return NUMBER;}
-{RANGE}         {yylval.string = strdup(yytext); return RANGE;}
+{RANGE}         {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return RANGE;}
 .               {return yytext[0];}
 %%
 
index 023faafade4e15aa971185acb357c490a6b97643..91b6069b1a496a4cafd60720daa0ee58733e0253 100644 (file)
@@ -8,7 +8,7 @@ static int
 add_nexthops(struct list *, struct graph_node *);
 
 static struct list *
-match_build_argv_r (struct graph_node *, vector, unsigned int);
+match_command_r (struct graph_node *, vector, unsigned int);
 
 static int
 score_precedence (struct graph_node *);
@@ -43,176 +43,86 @@ match_token (struct graph_node *, char *, enum filter_type);
 
 /* matching functions */
 
-struct cmd_element *
-match_command (struct graph_node *start, const char *line, enum filter_type filter)
-{
-  // get all possible completions
-  struct list *completions = match_command_complete (start, line, filter);
-
-  // one of them should be END_GN if this command matches
-  struct graph_node *gn;
-  struct listnode *node;
-  for (ALL_LIST_ELEMENTS_RO(completions,node,gn))
-  {
-    if (gn->type == END_GN)
-      break;
-    gn = NULL;
-  }
-  return gn ? gn->element : NULL;
+static void
+free_nodelist (void *node) {
+  free_node ((struct graph_node *) node);
 }
 
-struct list *
-match_command_complete (struct graph_node *start, const char *line, enum filter_type filter)
-{
-  // vectorize command line
-  vector vline = cmd_make_strvec (line);
-
-  // pointer to next input token to match
-  char *token;
-
-  struct list *current  = list_new(), // current nodes to match input token against
-              *matched  = list_new(), // current nodes that match the input token
-              *next     = list_new(); // possible next hops to current input token
-
-  // pointers used for iterating lists
-  struct graph_node *gn;
-  struct listnode *node;
-
-  // add all children of start node to list
-  add_nexthops(next, start);
-
-  unsigned int idx;
-  for (idx = 0; idx < vector_active(vline) && next->count > 0; idx++)
-  {
-    list_free (current);
-    current = next;
-    next = list_new();
-
-    token = vector_slot(vline, idx);
-
-    list_delete_all_node(matched);
-
-    for (ALL_LIST_ELEMENTS_RO(current,node,gn))
-    {
-      if (match_token(gn, token, filter) == exact_match) {
-        listnode_add(matched, gn);
-        add_nexthops(next, gn);
-      }
-    }
-  }
-
-  /* Variable summary
-   * -----------------------------------------------------------------
-   * token    = last input token processed
-   * idx      = index in `command` of last token processed
-   * current  = set of all transitions from the previous input token
-   * matched  = set of all nodes reachable with current input
-   * next     = set of all nodes reachable from all nodes in `matched`
-   */
-  list_free (current);
-  list_free (matched);
-
-  cmd_free_strvec(vline);
-
-  return next;
-}
-
-/**
- * Adds all children that are reachable by one parser hop
- * to the given list. NUL_GN, SELECTOR_GN, and OPTION_GN
- * nodes are treated as transparent.
- *
- * @param[out] l the list to add the children to
- * @param[in] node the node to get the children of
- * @return the number of children added to the list
- */
-static int
-add_nexthops(struct list *l, struct graph_node *node)
-{
-  int added = 0;
-  struct graph_node *child;
-  for (unsigned int i = 0; i < vector_active(node->children); i++)
-  {
-    child = vector_slot(node->children, i);
-    switch (child->type) {
-      case OPTION_GN:
-      case SELECTOR_GN:
-      case NUL_GN:
-        added += add_nexthops(l, child);
-        break;
-      default:
-        listnode_add(l, child);
-        added++;
-    }
-  }
-  return added;
-}
-
-struct list *
-match_build_argv (const char *line, struct cmd_element *element)
+struct cmd_element *
+match_command (struct graph_node *start, const char *line, struct list **argv)
 {
-  struct list *argv = NULL;
-
   // parse command
-  struct graph_node *start = new_node(NUL_GN);
-  parse_command_format(start, element);
-
   vector vline = cmd_make_strvec (line);
 
   for (unsigned int i = 0; i < vector_active(start->children); i++)
   {
     // call recursive builder on each starting child
-    argv = match_build_argv_r (vector_slot(start->children, i), vline, 0);
+    *argv = match_command_r(vector_slot(start->children, i), vline, 0);
     // if any of them succeed, return their argv
-    // since all command DFA's must begin with a word and these are deduplicated,
-    // no need to check precedence
-    if (argv) break;
+    // since all command DFA's must begin with a word, there can only be
+    // one valid return value
+    if (*argv) break;
+  }
+
+  if (*argv) {
+    // copy the nodes we need
+    struct listnode *ln;
+    struct graph_node *gn;
+    char buf[50];
+    for (ALL_LIST_ELEMENTS_RO(*argv,ln,gn)) {
+      describe_node(gn, buf, 50);
+      fprintf(stderr, "%s[%d]\n", buf, gn->type);
+      if (gn->type == END_GN)
+        return gn->element;
+    }
+    assert(0);
   }
 
-  return argv;
+  return NULL;
 }
 
 /**
- * Builds an argument list given a DFA and a matching input line.
- * This function should be passed the start node of the DFA, a matching
- * input line, and the index of the first input token in the input line.
+ * Matches a given input line against a DFA.
+ *
+ * Builds an argument list given a DFA and a matching input line. This function
+ * should be passed the start node of the DFA, a matching input line, and the
+ * index of the first token in the input line.
  *
- * First the function determines if the node it is passed matches the
- * first token of input. If it does not, it returns NULL. If it does
- * match, then it saves the input token as the head of an argument list.
+ * First the function determines if the node it is passed matches the first
+ * token of input. If it does not, it returns NULL. If it does match, then it
+ * saves the input token as the head of an argument list.
  *
- * The next step is to see if there is further input in the input line.
- * If there is not, the current node's children are searched to see if
- * any of them are leaves (type END_GN). If this is the case, then the
- * bottom of the recursion stack has been reached, and the argument list
- * (with one node) is returned. If it is not the case, NULL is returned,
- * indicating that there is no match for the input along this path.
+ * The next step is to see if there is further input in the input line. If
+ * there is not, the current node's children are searched to see if any of them
+ * are leaves (type END_GN). If this is the case, then the bottom of the
+ * recursion stack has been reached, and the argument list (with one node) is
+ * returned. If it is not the case, NULL is returned, indicating that there is
+ * no match for the input along this path.
  *
- * If there is further input, then the function recurses on each of the
- * current node's children, passing them the input line minus the token
- * that was just matched. For each child, the return value of the recursive
- * call is inspected. If it is null, then there is no match for the input along
- * the subgraph headed by that child. If it is not null, then there is at least
- * one input match in that subgraph (more on this in a moment).
+ * If there is further input, then the function recurses on each of the current
+ * node's children, passing them the input line minus the token that was just
+ * matched. For each child, the return value of the recursive call is
+ * inspected. If it is null, then there is no match for the input along the
+ * subgraph headed by that child. If it is not null, then there is at least one
+ * input match in that subgraph (more on this in a moment).
  *
  * If a recursive call on a child returns a non-null value, then it has matched
  * the input given it on the subgraph that starts with that child. However, due
  * to the flexibility of the grammar, it is sometimes the case that two or more
  * child graphs match the same input (two or more of the recursive calls have
- * non-NULL return values). This is not a valid state, since only one
- * true match is possible. In order to resolve this conflict, the function
- * keeps a reference to the child node that most specifically matches the
- * input. This is done by assigning each node type a precedence. If a child is
- * found to match the remaining input, then the precedence values of the
- * current best-matching child and this new match are compared. The node with
- * higher precedence is kept, and the other match is discarded. Due to the
- * recursive nature of this function, it is only necessary to compare the
- * precedence of immediate children, since all subsequent children will already
- * have been disambiguated in this way.
+ * non-NULL return values). This is not a valid state, since only one true
+ * match is possible. In order to resolve this conflict, the function keeps a
+ * reference to the child node that most specifically matches the input. This
+ * is done by assigning each node type a precedence. If a child is found to
+ * match the remaining input, then the precedence values of the current
+ * best-matching child and this new match are compared. The node with higher
+ * precedence is kept, and the other match is discarded. Due to the recursive
+ * nature of this function, it is only necessary to compare the precedence of
+ * immediate children, since all subsequent children will already have been
+ * disambiguated in this way.
  *
  * In the event that two children are found to match with the same precedence,
- * then this command is totally ambiguous (how did you even match it in the first
- * place?) and NULL is returned.
+ * then the input is ambiguous for the passed cmd_element and NULL is returned.
  *
  * The ultimate return value is an ordered linked list of nodes that comprise
  * the best match for the command, each with their `arg` fields pointing to the
@@ -224,22 +134,19 @@ match_build_argv (const char *line, struct cmd_element *element)
  * callers.
  */
 static struct list *
-match_build_argv_r (struct graph_node *start, vector vline, unsigned int n)
+match_command_r (struct graph_node *start, vector vline, unsigned int n)
 {
   // if we don't match this node, die
   if (match_token(start, vector_slot(vline, n), FILTER_STRICT) != exact_match)
     return NULL;
 
   // arg list for this subgraph
-  struct list *argv = list_new();
+  struct list *argv;
 
   // pointers for iterating linklist
   struct graph_node *gn;
   struct listnode   *ln;
 
-  // append current arg
-  listnode_add(argv, start);
-
   // get all possible nexthops
   struct list *next = list_new();
   add_nexthops(next, start);
@@ -248,14 +155,22 @@ match_build_argv_r (struct graph_node *start, vector vline, unsigned int n)
   if (n+1 == vector_active (vline)) {
     for (ALL_LIST_ELEMENTS_RO(next,ln,gn)) {
       if (gn->type == END_GN) {
+        // delete nexthops, we don't need them
         list_delete (next);
-        start->arg = XSTRDUP(MTYPE_CMD_TOKENS, vector_slot(vline, n));
-        if (start->type == VARIABLE_GN)
-          fprintf(stderr, "Setting variable %s->arg with text %s\n", start->text, start->arg);
+        // dupe current node, set arg field, and return
+        struct graph_node *curr = copy_node(start);
+        curr->arg = XSTRDUP(MTYPE_CMD_TOKENS, vector_slot(vline, n));
+        fprintf(stderr, ">> Matched END_GN on node %s for token %s\n", curr->text, curr->arg);
+        // initialize a new argument list
+        argv = list_new();
+        argv->del = &free_nodelist;
+        listnode_add(argv, curr);
+        listnode_add(argv, copy_node(gn));
         return argv;
       }
     }
-    list_free (next);
+    // no END_GN found, free resources and return null
+    list_delete (next);
     return NULL;
   }
 
@@ -269,7 +184,7 @@ match_build_argv_r (struct graph_node *start, vector vline, unsigned int n)
       // get the result of the next node
       for (unsigned int i = 0; i < n; i++) fprintf(stderr, "\t");
       fprintf(stderr, "Recursing on node %s for token %s\n", gn->text, (char*) vector_slot(vline, n+1));
-      struct list *result = match_build_argv_r (gn, vline, n+1);
+      struct list *result = match_command_r (gn, vline, n+1);
 
       // compare to our current best match, and save if it's better
       if (result) {
@@ -288,7 +203,7 @@ match_build_argv_r (struct graph_node *start, vector vline, unsigned int n)
             fprintf(stderr, ">> Ambiguous match. Abort.\n");
             list_delete (bestmatch);
             list_delete (result);
-            list_delete (argv);
+            list_delete (next);
             return NULL;
           }
         }
@@ -301,19 +216,110 @@ match_build_argv_r (struct graph_node *start, vector vline, unsigned int n)
     }
 
   if (bestmatch) {
+    argv = list_new();
+    listnode_add(argv, start);
     list_add_list(argv, bestmatch);
-    list_delete (bestmatch);
+    list_free (bestmatch);
+    list_delete (next);
     start->arg = XSTRDUP(MTYPE_CMD_TOKENS, vector_slot(vline, n));
     if (start->type == VARIABLE_GN)
       fprintf(stderr, "Setting variable %s->arg with text %s\n", start->text, start->arg);
     return argv;
   }
-  else {
-    list_delete (argv);
+  else
     return NULL;
+}
+
+struct list *
+match_command_complete (struct graph_node *start, const char *line, enum filter_type filter)
+{
+  enum match_type minmatch = filter + 1;
+
+  // vectorize command line
+  vector vline = cmd_make_strvec (line);
+
+  // pointer to next input token to match
+  char *token;
+
+  struct list *current  = list_new(), // current nodes to match input token against
+              *matched  = list_new(), // current nodes that match the input token
+              *next     = list_new(); // possible next hops to current input token
+
+  // pointers used for iterating lists
+  struct graph_node *gn;
+  struct listnode *node;
+
+  // add all children of start node to list
+  add_nexthops(next, start);
+
+  unsigned int idx;
+  for (idx = 0; idx < vector_active(vline) && next->count > 0; idx++)
+  {
+    list_free (current);
+    current = next;
+    next = list_new();
+
+    token = vector_slot(vline, idx);
+
+    list_delete_all_node(matched);
+
+    for (ALL_LIST_ELEMENTS_RO(current,node,gn))
+    {
+      if (match_token(gn, token, filter) >= minmatch) {
+        listnode_add(matched, gn);
+        add_nexthops(next, gn);
+      }
+    }
   }
+
+  /* Variable summary
+   * -----------------------------------------------------------------
+   * token    = last input token processed
+   * idx      = index in `command` of last token processed
+   * current  = set of all transitions from the previous input token
+   * matched  = set of all nodes reachable with current input
+   * next     = set of all nodes reachable from all nodes in `matched`
+   */
+  list_free (current);
+  list_free (matched);
+
+  cmd_free_strvec(vline);
+
+  return next;
 }
 
+/**
+ * Adds all children that are reachable by one parser hop
+ * to the given list. NUL_GN, SELECTOR_GN, and OPTION_GN
+ * nodes are treated as transparent.
+ *
+ * @param[out] l the list to add the children to
+ * @param[in] node the node to get the children of
+ * @return the number of children added to the list
+ */
+static int
+add_nexthops(struct list *l, struct graph_node *node)
+{
+  int added = 0;
+  struct graph_node *child;
+  for (unsigned int i = 0; i < vector_active(node->children); i++)
+  {
+    child = vector_slot(node->children, i);
+    switch (child->type) {
+      case OPTION_GN:
+      case SELECTOR_GN:
+      case NUL_GN:
+        added += add_nexthops(l, child);
+        break;
+      default:
+        listnode_add(l, child);
+        added++;
+    }
+  }
+  return added;
+}
+
+
 /* matching utility functions */
 
 static int
index 24cd1287e6bccf1ef81d97a03fa8dd340fd319b2..a102ba9484ea68c907a8c1da8d1c10de5f0025aa 100644 (file)
@@ -48,10 +48,13 @@ enum match_type
 /**
  * Attempt to find an exact command match for a line of user input.
  *
+ * @param DFA to match against
+ * @param input string
+ * @param pointer to argv pointer
  * @return cmd_element found, or NULL if there is no match.
  */
 struct cmd_element *
-match_command (struct graph_node *, const char *, enum filter_type);
+match_command (struct graph_node *, const char *, struct list **);
 
 /**
  * Compiles next-hops for a given line of user input.
@@ -77,14 +80,4 @@ match_command (struct graph_node *, const char *, enum filter_type);
 struct list *
 match_command_complete (struct graph_node *, const char *, enum filter_type);
 
-/**
- * Builds an argument list given a cmd_element and a matching input line.
- *
- * @param[in] input line
- * @param[in] cmd_element struct
- * @return pointer to argument linked list
- */
-struct list *
-match_build_argv (const char *, struct cmd_element *);
-
 #endif
index 8c0584facdbaa4356ddc586ff4786e1f2fe4b723..cf87ca1042d3d265e3bec18db961a197595cbdcc 100644 (file)
@@ -91,6 +91,7 @@ start: sentence_root
     yyerror("Duplicate command.");
     YYABORT;
   }
+  fprintf(stderr, "Added END_GN with active children: %d\n", vector_active(end->children));
 }
 
 sentence_root: WORD
@@ -323,7 +324,7 @@ parse_command_format(struct graph_node *start, struct cmd_element *cmd)
   optnode_start = optnode_end = NULL;
 
   // trace parser
-  yydebug = 1;
+  yydebug = 0;
   // command string
   command = cmd;
   // make flex read from a string
index e4617969afbbfa0ee6cd1335820e7d36eb3b425a..2443b8471c5a16bf53f74ccfe4bfea72c37af98d 100644 (file)
@@ -18,7 +18,6 @@ DEFUN (grammar_test,
   struct cmd_element *cmd = malloc(sizeof(struct cmd_element));
   cmd->string = command;
   parse_command_format(nodegraph, cmd);
-  walk_graph(nodegraph, 0);
   return CMD_SUCCESS;
 }
 
@@ -28,6 +27,10 @@ DEFUN (grammar_test_show,
        GRAMMAR_STR
        "print current accumulated DFA\n")
 {
+  if (!nodegraph)
+    fprintf(stderr, "!nodegraph\n");
+  fprintf(stderr, "trying to print nodegraph->type\n");
+  fprintf(stderr, "%d\n", nodegraph->type);
   walk_graph(nodegraph, 0);
   return CMD_SUCCESS;
 }
@@ -59,7 +62,7 @@ DEFUN (grammar_test_complete,
     }
     free(desc);
   }
-  list_free(result);
+  list_delete(result);
 
   return CMD_SUCCESS;
 }
@@ -71,24 +74,22 @@ DEFUN (grammar_test_match,
        "attempt to match input on DFA\n"
        "command to match")
 {
-  const char* command = argv_concat(argv, argc, 0);
-  struct cmd_element *element = match_command (nodegraph, command, FILTER_STRICT);
+  struct list *argvv = NULL;
+  const char *command = argv_concat(argv, argc, 0);
+  struct cmd_element *element = match_command (nodegraph, command, &argvv);
 
-  if (element)
+  if (element) {
     fprintf(stderr, "Matched: %s\n", element->string);
-  else {
-    fprintf(stderr, "Returned NULL\n");
-    return CMD_SUCCESS;
-  }
-
-  struct list *argvv = match_build_argv (command, element);
-  if (!argvv) fprintf(stderr, "Failed to build argv.\n");
-  else {
     struct listnode *ln;
     struct graph_node *gn;
     for (ALL_LIST_ELEMENTS_RO(argvv,ln,gn))
       fprintf(stderr, "%s -- %s\n", gn->text, gn->arg);
   }
+  else {
+    fprintf(stderr, "Returned NULL\n");
+    return CMD_SUCCESS;
+  }
+
   return CMD_SUCCESS;
 }