From: Quentin Young Date: Mon, 1 Aug 2016 20:30:14 +0000 (+0000) Subject: lib: Add partial completion support X-Git-Tag: frr-3.0-branchpoint~129^2~271 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=e1cbb2ff67441cac4a486efdb3b5584bd701cba0;p=matthieu%2Ffrr.git lib: Add partial completion support Completions now include nodes that the input partially matches as well as the children of nodes those that the input exactly matches. Also some minor cleanup and bugfixes. Signed-off-by: Quentin Young --- diff --git a/lib/command_match.c b/lib/command_match.c index 13dee51fef..af506591ed 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -33,7 +33,7 @@ static enum match_type match_range (struct graph_node *, const char *str); static enum match_type -match_word (struct graph_node *, const char *, enum filter_type); +match_word (struct graph_node *, const char *); static enum match_type match_number (struct graph_node *, const char *); @@ -42,7 +42,7 @@ static enum match_type match_variable (struct graph_node *, const char *); static enum match_type -match_token (struct graph_node *, char *, enum filter_type); +match_token (struct graph_node *, char *); /* matching functions */ @@ -66,7 +66,7 @@ copy_node (struct graph_node *node) /* Linked list data deletion callback */ static void -free_nodelist (void *node) { +delete_nodelist (void *node) { free_node ((struct graph_node *) node); } @@ -161,8 +161,11 @@ match_command_r (struct graph_node *start, vector vline, unsigned int n) // get the minimum match level that can count as a full match enum match_type minmatch = min_match_level(start->type); + // get the current operating token + char *token = vector_slot(vline, n); + // if we don't match this node, die - if (match_token(start, vector_slot(vline, n), FILTER_RELAXED) < minmatch) + if (match_token(start, token) < minmatch) return NULL; // pointers for iterating linklist @@ -177,14 +180,14 @@ match_command_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) { - struct graph_node *curr = copy_node(start); - curr->arg = XSTRDUP(MTYPE_CMD_TOKENS, vector_slot(vline, n)); - // initialize a new argument list + // we have a match, so build an argv and pass it back up the chain struct list *argv = list_new(); - argv->del = &free_nodelist; + argv->del = &delete_nodelist; + struct graph_node *curr = copy_node(start); + curr->arg = XSTRDUP(MTYPE_CMD_TOKENS, token); // add the current node - listnode_add(argv, copy_node(curr)); - // push the end node + listnode_add(argv, curr); + // add the end node listnode_add(argv, copy_node(gn)); // clean up list_delete (next); @@ -230,8 +233,10 @@ match_command_r (struct graph_node *start, vector vline, unsigned int n) } if (bestmatch) { + // if we have a best match, prepend this node + matching token + // to argv and pass it up the chain struct graph_node *curr = copy_node(start); - curr->arg = XSTRDUP(MTYPE_CMD_TOKENS, vector_slot(vline, n)); + curr->arg = XSTRDUP(MTYPE_CMD_TOKENS, token); list_add_node_prev (bestmatch, bestmatch->head, curr); // cleanup list_delete (next); @@ -242,10 +247,8 @@ match_command_r (struct graph_node *start, vector vline, unsigned int n) } struct list * -match_command_complete (struct graph_node *start, const char *line, enum filter_type filter) +match_command_complete (struct graph_node *start, const char *line) { - enum match_type minmatch = filter + 1; - // vectorize command line vector vline = cmd_make_strvec (line); @@ -253,7 +256,6 @@ match_command_complete (struct graph_node *start, const char *line, enum filter_ 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 @@ -272,13 +274,17 @@ match_command_complete (struct graph_node *start, const char *line, enum filter_ 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); + switch (match_token(gn, token)) { + case partly_match: // if it's a partial match, add this node to possible next hops + listnode_add(next, gn); + break; + case exact_match: // if it's an exact match, add this node's children to next hops + add_nexthops(next, gn); + break; + default: // otherwise do nothing + break; } } } @@ -292,7 +298,6 @@ match_command_complete (struct graph_node *start, const char *line, enum filter_ * next = set of all nodes reachable from all nodes in `matched` */ list_free (current); - list_free (matched); cmd_free_strvec(vline); @@ -374,11 +379,11 @@ score_precedence (struct graph_node *node) } static enum match_type -match_token (struct graph_node *node, char *token, enum filter_type filter) +match_token (struct graph_node *node, char *token) { switch (node->type) { case WORD_GN: - return match_word (node, token, filter); + return match_word (node, token); case IPV4_GN: return match_ipv4 (token); case IPV4_PREFIX_GN: @@ -621,26 +626,21 @@ match_range (struct graph_node *rangenode, const char *str) } static enum match_type -match_word(struct graph_node *wordnode, - const char *word, - enum filter_type filter) +match_word(struct graph_node *wordnode, const char *word) { - if (filter == FILTER_RELAXED) - { - if (!word || !strlen(word)) - return partly_match; - else if (!strncmp(wordnode->text, word, strlen(word))) - return !strcmp(wordnode->text, word) ? exact_match : partly_match; - else - return no_match; - } - else - { - if (!word) - return no_match; - else - return !strcmp(wordnode->text, word) ? exact_match : no_match; - } + // if the passed token is null or 0 length, partly match + if (!word || !strlen(word)) + return partly_match; + + // if the passed token is strictly a prefix of the full word, partly match + if (strlen(word) < strlen(wordnode->text)) + return !strncmp(wordnode->text, word, strlen(word)) ? partly_match : no_match; + + // if they are the same length and exactly equal, exact match + else if (strlen(word) == strlen(wordnode->text)) + return !strncmp(wordnode->text, word, strlen(word)) ? exact_match : no_match; + + return no_match; } static enum match_type diff --git a/lib/command_match.h b/lib/command_match.h index a102ba9484..8ad7ab0556 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -78,6 +78,6 @@ match_command (struct graph_node *, const char *, struct list **); * matched token. If this is empty, the input did not match any command. */ struct list * -match_command_complete (struct graph_node *, const char *, enum filter_type); +match_command_complete (struct graph_node *, const char *); #endif diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index 90aadc6a9f..c53811e062 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -19,6 +19,7 @@ DEFUN (grammar_test, cmd->string = command; cmd->doc = NULL; cmd->func = NULL; + cmd->tokens = vector_init(VECTOR_MIN_SIZE); parse_command_format(nodegraph, cmd); return CMD_SUCCESS; } @@ -45,7 +46,7 @@ DEFUN (grammar_test_complete, "command to complete") { const char* command = argv_concat(argv, argc, 0); - struct list *result = match_command_complete (nodegraph, command, FILTER_STRICT); + struct list *result = match_command_complete (nodegraph, command); if (result->count == 0) // invalid command fprintf(stderr, "%% Unknown command\n"); @@ -61,9 +62,6 @@ DEFUN (grammar_test_complete, fprintf(stderr, " %p\n", cnode->element->func); else fprintf(stderr, "%s\n", describe_node(cnode, desc, 50)); - - if (cnode->type == RANGE_GN) - fprintf(stderr, "%lld - %lld\n", cnode->min, cnode->max); } free(desc); }