summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2016-08-01 20:30:14 +0000
committerQuentin Young <qlyoung@cumulusnetworks.com>2016-08-01 20:30:14 +0000
commite1cbb2ff67441cac4a486efdb3b5584bd701cba0 (patch)
tree559caaa0cdddccb492e833baef0fde4a0ca0c96e
parente648e61a747c6c13ccea7d97066dfb07d4461d96 (diff)
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 <qlyoung@cumulusnetworks.com>
-rw-r--r--lib/command_match.c84
-rw-r--r--lib/command_match.h2
-rw-r--r--lib/grammar_sandbox.c6
3 files changed, 45 insertions, 47 deletions
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, "<cr> %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);
}