]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Add partial completion support
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 1 Aug 2016 20:30:14 +0000 (20:30 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 1 Aug 2016 20:30:14 +0000 (20:30 +0000)
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>
lib/command_match.c
lib/command_match.h
lib/grammar_sandbox.c

index 13dee51fefdc641707a3e4d88ec0b9c67b89e4e2..af506591edb1ecf94dd34cc41caedc0d58048a6f 100644 (file)
@@ -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
index a102ba9484ea68c907a8c1da8d1c10de5f0025aa..8ad7ab05568ec2075fddd46af1a8415acaf6c249 100644 (file)
@@ -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
index 90aadc6a9f092f621c049a7a7c5a4e0fa3d337c3..c53811e0629b29f418a331761977468a18a4bdbb 100644 (file)
@@ -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);
   }