diff options
| -rw-r--r-- | lib/command.c | 24 | ||||
| -rw-r--r-- | lib/command.h | 6 | ||||
| -rw-r--r-- | lib/command_graph.c | 57 | ||||
| -rw-r--r-- | lib/command_graph.h | 46 | ||||
| -rw-r--r-- | lib/command_lex.l | 14 | ||||
| -rw-r--r-- | lib/command_match.c | 326 | ||||
| -rw-r--r-- | lib/command_match.h | 15 | ||||
| -rw-r--r-- | lib/command_parse.y | 3 | ||||
| -rw-r--r-- | 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 @@ -4191,6 +4191,30 @@ cmd_terminate_element(struct cmd_element *cmd) } 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 () { unsigned int i, j; 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,17 +74,44 @@ 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. * * @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; } |
