From de9d7e4f3ccb1b199602c1a1ce884df37e54f834 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 29 Jul 2016 15:54:03 +0000 Subject: [PATCH] lib: Cleanup some memory issues in CLI 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 --- lib/command.c | 24 ++++ lib/command.h | 6 + lib/command_graph.c | 57 +++++++- lib/command_graph.h | 46 ++++-- lib/command_lex.l | 14 +- lib/command_match.c | 326 +++++++++++++++++++++--------------------- lib/command_match.h | 15 +- lib/command_parse.y | 3 +- lib/grammar_sandbox.c | 27 ++-- 9 files changed, 312 insertions(+), 206 deletions(-) diff --git a/lib/command.c b/lib/command.c index 490c2a0690..d3c6771248 100644 --- a/lib/command.c +++ b/lib/command.c @@ -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 () { diff --git a/lib/command.h b/lib/command.h index c1ef0e55bd..9a77d3b87c 100644 --- a/lib/command.h +++ b/lib/command.h @@ -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; diff --git a/lib/command_graph.c b/lib/command_graph.c index a5880f34a6..7c09a5cd6c 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -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)); +} diff --git a/lib/command_graph.h b/lib/command_graph.h index a9ffe0f7b6..dc78475ca6 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -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 diff --git a/lib/command_lex.l b/lib/command_lex.l index 45f8f8e636..5a0e76d418 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -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];} %% diff --git a/lib/command_match.c b/lib/command_match.c index 023faafade..91b6069b1a 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -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 diff --git a/lib/command_match.h b/lib/command_match.h index 24cd1287e6..a102ba9484 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -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 diff --git a/lib/command_parse.y b/lib/command_parse.y index 8c0584facd..cf87ca1042 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -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 diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index e4617969af..2443b8471c 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -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; } -- 2.39.5