]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Various minor improvements & bugfixes to CLI backend
authorQuentin Young <qlyoung@cumulusnetworks.com>
Sat, 29 Oct 2016 04:43:04 +0000 (04:43 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Sat, 29 Oct 2016 04:43:04 +0000 (04:43 +0000)
- Do not allow tab-completion on anything except words
- Rewrite cmd_make_strvec to use strsep
- Remove a few trailing whitespaces
- Remove cmd_complete_command_lib

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
lib/command.c
lib/command.h
lib/vty.c

index f9c4107745f298902a71fc4a608c5986e638ce9c..a12591a8bcf0ab1aa96407742d128d8b4dfd38d3 100644 (file)
@@ -240,56 +240,41 @@ install_node (struct cmd_node *node,
   node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
 }
 
-/* Breaking up string into each command piece. I assume given
-   character is separated by a space character. Return value is a
-   vector which includes char ** data element. */
+/**
+ * Tokenizes a string, storing tokens in a vector.
+ * Whitespace is ignored.
+ *
+ * Delimiter string = " \n\r\t".
+ *
+ * @param string to tokenize
+ * @return tokenized string
+ */
 vector
 cmd_make_strvec (const char *string)
 {
-  const char *cp, *start;
-  char *token;
-  int strlen;
-  vector strvec;
+  if (!string) return NULL;
 
-  if (string == NULL)
-    return NULL;
+  char *copy, *copystart;
+  copystart = copy = XSTRDUP (MTYPE_TMP, string);
 
-  cp = string;
+  // skip leading whitespace
+  while (isspace ((int) *copy) && *copy != '\0') copy++;
 
-  /* Skip white spaces. */
-  while (isspace ((int) *cp) && *cp != '\0')
-    cp++;
-
-  /* Return if there is only white spaces */
-  if (*cp == '\0')
-    return NULL;
-
-  if (*cp == '!' || *cp == '#')
+  // if the entire string was whitespace or a comment, return
+  if (*copy == '\0' || *copy == '!' || *copy == '#')
     return NULL;
 
-  /* Prepare return vector. */
-  strvec = vector_init (VECTOR_MIN_SIZE);
-
-  /* Copy each command piece and set into vector. */
-  while (1)
-    {
-      start = cp;
-      while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
-             *cp != '\0')
-        cp++;
-      strlen = cp - start;
-      token = XMALLOC (MTYPE_STRVEC, strlen + 1);
-      memcpy (token, start, strlen);
-      *(token + strlen) = '\0';
-      vector_set (strvec, token);
-
-      while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
-             *cp != '\0')
-        cp++;
+  vector strvec = vector_init (VECTOR_MIN_SIZE);
+  const char *delim = " \n\r\t", *tok = NULL;
+  while (copy)
+  {
+    tok = strsep (&copy, delim);
+    if (*tok != '\0')
+      vector_set (strvec, XSTRDUP (MTYPE_STRVEC, tok));
+  }
 
-      if (*cp == '\0')
-        return strvec;
-    }
+  XFREE (MTYPE_TMP, copystart);
+  return strvec;
 }
 
 /* Free allocated string vector. */
@@ -350,7 +335,7 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
                __func__);
       return;
     }
-  
+
   cnode = vector_slot (cmdvec, ntype);
 
   if (cnode == NULL)
@@ -359,17 +344,17 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
                ntype);
       exit (EXIT_FAILURE);
     }
-  
+
   if (hash_lookup (cnode->cmd_hash, cmd) != NULL)
     {
-      fprintf (stderr, 
+      fprintf (stderr,
                "Multiple command installs to node %d of command:\n%s\n",
                ntype, cmd->string);
       return;
     }
-  
+
   assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern));
-  
+
   command_parse_format (cnode->cmdgraph, cmd);
   vector_set (cnode->cmd_vector, cmd);
 
@@ -570,6 +555,7 @@ completions_to_vec (struct list *completions)
          sizeof (void *),
          &compare_completions);
 
+  // make <cr> the first element, if it is present
   if (cr)
   {
     vector_set_index (comps, vector_active (comps), NULL);
@@ -586,6 +572,7 @@ completions_to_vec (struct list *completions)
  * @param vline the vectorized input line
  * @param vty the vty with the node to match on
  * @param status pointer to matcher status code
+ * @return vector of struct cmd_token * with possible completions
  */
 static vector
 cmd_complete_command_real (vector vline, struct vty *vty, int *status)
@@ -658,8 +645,20 @@ cmd_describe_command (vector vline, struct vty *vty, int *status)
   return cmd_complete_command_real (vline, vty, status);
 }
 
+/**
+ * Generate possible tab-completions for the given input. This function only
+ * returns results that would result in a valid command if used as Readline
+ * completions (as is the case in vtysh). For instance, if the passed vline ends
+ * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
+ *
+ * @param vline vectorized input line
+ * @param vty the vty
+ * @param status location to store matcher status code in
+ * @return set of valid strings for use with Readline as tab-completions.
+ */
+
 char **
-cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
+cmd_complete_command (vector vline, struct vty *vty, int *status)
 {
   char **ret = NULL;
   int original_node = vty->node;
@@ -675,7 +674,21 @@ cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
     vector_set_index (input_line, index + offset, vector_lookup (vline, index));
 
   // get token completions -- this is a copying operation
-  vector comps = cmd_complete_command_real (input_line, vty, status);
+  vector comps, initial_comps;
+  initial_comps = cmd_complete_command_real (input_line, vty, status);
+
+  // filter out everything that is not suitable for a tab-completion
+  comps = vector_init (VECTOR_MIN_SIZE);
+  for (unsigned int i = 0; i < vector_active(initial_comps); i++)
+  {
+    struct cmd_token *token = vector_slot (initial_comps, i);
+    if (token->type == WORD_TKN)
+      vector_set (comps, token);
+    else
+      del_cmd_token (token);
+  }
+  vector_free (initial_comps);
+
   if (!MATCHER_ERROR (*status))
   {
     // copy completions text into an array of char*
@@ -688,7 +701,9 @@ cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
         vector_unset (comps, i);
         del_cmd_token (token);
       }
-    // set the last element to NULL, which vty/vtysh uses as a sentinel value
+    // set the last element to NULL, because this array is used in
+    // a Readline completion_generator function which expects NULL
+    // as a sentinel value
     ret[i] = NULL;
     vector_free (comps);
     comps = NULL;
@@ -706,12 +721,6 @@ cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
   return ret;
 }
 
-char **
-cmd_complete_command (vector vline, struct vty *vty, int *status)
-{
-  return cmd_complete_command_lib (vline, vty, status, 0);
-}
-
 /* return parent node */
 /* MUST eventually converge on CONFIG_NODE */
 enum node_type
@@ -1578,7 +1587,6 @@ DEFUN (config_enable_password,
        "Modify enable password parameters\n"
        "Assign the privileged level password\n"
        "Specifies a HIDDEN password will follow\n"
-       "dummy string \n"
        "The HIDDEN 'enable' password string\n")
 {
   int idx_8 = 2;
index 4d60c5b4fe30ea4045d4fe1f8df3511fc0e45e52..bdf30b6f3c10b0b371a90eb7ceb943df725d59c2 100644 (file)
@@ -187,13 +187,10 @@ enum cmd_token_type
  */
 struct cmd_token
 {
-  enum cmd_token_type type;   // token type
-
+  enum cmd_token_type type;     // token type
   char *text;                   // token text
   char *desc;                   // token description
-
   long long min, max;           // for ranges
-
   char *arg;                    // user input that matches this token
 };
 
@@ -419,7 +416,6 @@ extern void cmd_free_strvec (vector);
 extern char *cmd_concat_strvec (vector);
 extern vector cmd_describe_command (vector, struct vty *, int *status);
 extern char **cmd_complete_command (vector, struct vty *, int *status);
-extern char **cmd_complete_command_lib (vector, struct vty *, int *status, int islib);
 extern const char *cmd_prompt (enum node_type);
 extern int command_config_read_one_line (struct vty *vty, struct cmd_element **, int use_config_node);
 extern int config_from_file (struct vty *, FILE *, unsigned int *line_num);
index 78bf0e720db803c8d1ab448bf4e343a96aa0fcd0..53a04851d57a67205c5e2042c4855974249beb42 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -923,7 +923,7 @@ vty_complete_command (struct vty *vty)
   if (isspace ((int) vty->buf[vty->length - 1]))
     vector_set (vline, NULL);
 
-  matched = cmd_complete_command_lib (vline, vty, &ret, 1);
+  matched = cmd_complete_command (vline, vty, &ret);
 
   cmd_free_strvec (vline);