]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Clean up completions code, fix segfault on no match
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 3 Oct 2016 23:21:11 +0000 (23:21 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 3 Oct 2016 23:21:11 +0000 (23:21 +0000)
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
lib/command.c

index 405cf6de665df399f0f88ad0cb8f851ad86e04cb..35b13fe8e0364579c9cc9043e0aa2ee18a386dbc 100644 (file)
@@ -597,57 +597,47 @@ cmd_describe_command (vector vline, struct vty *vty, int *status)
 char **
 cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
 {
-  char **ret;
-
-  if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
-    {
-      enum node_type onode;
-      vector shifted_vline;
-      unsigned int index;
-
-      onode = vty->node;
-      vty->node = ENABLE_NODE;
-      /* We can try it on enable node, cos' the vty is authenticated */
-
-      shifted_vline = vector_init (vector_count(vline));
-      /* use memcpy? */
-      for (index = 1; index < vector_active (vline); index++)
-        {
-          vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
-        }
+  char **ret = NULL;
+  int original_node = vty->node;
+  vector input_line = vector_init (vector_count (vline));
+
+  // if the first token is 'do' we'll want to execute the command in the enable node
+  int do_shortcut = cmd_try_do_shortcut (vty->node, vector_slot (vline, 0));
+  vty->node = do_shortcut ? ENABLE_NODE : original_node;
+
+  // construct the input line we'll be matching on
+  unsigned int offset = (do_shortcut) ? 1 : 0;
+  for (unsigned index = 0; index + offset < vector_active (vline); index++)
+    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);
+  if (!MATCHER_ERROR (*status))
+  {
+    // copy completions text into an array of char*
+    ret = XMALLOC (MTYPE_TMP, vector_active (comps) * sizeof (char *) + 1);
+    unsigned int i;
+    for (i = 0; i < vector_active (comps); i++)
+      {
+        struct cmd_token *token = vector_slot (comps, i);
+        ret[i] = XSTRDUP (MTYPE_TMP, token->text);
+        vector_unset (comps, i);
+        del_cmd_token (token);
+      }
+    // set the last element to NULL, which vty/vtysh uses as a sentinel value
+    ret[i] = NULL;
+    vector_free (comps);
+    comps = NULL;
+  }
 
-      // get token completions
-      vector comps = cmd_complete_command_real (shifted_vline, vty, status);
-      ret = XMALLOC (MTYPE_TMP, vector_active (comps) * sizeof (char *) + 1);
-      unsigned int i;
-      for (i = 0; i < vector_active (comps); i++)
-        {
-          struct cmd_token *token = vector_slot (comps, i);
-          ret[i] = XSTRDUP (MTYPE_TMP, token->text);
-          vector_unset (comps, i);
-          del_cmd_token (token);
-        }
-      vector_free (comps);
-      ret[i] = NULL;
+  // comps should always be null here
+  assert (!comps);
 
-      vector_free(shifted_vline);
-      vty->node = onode;
-      return ret;
-  }
+  // free the adjusted input line
+  vector_free (input_line);
 
-  // get token completions
-  vector comps = cmd_complete_command_real (vline, vty, status);
-  ret = XMALLOC (MTYPE_TMP, vector_active (comps) * sizeof (char *) + 1);
-  unsigned int i;
-  for (i = 0; i < vector_active (comps); i++)
-    {
-      struct cmd_token *token = vector_slot (comps, i);
-      ret[i] = XSTRDUP (MTYPE_TMP, token->text);
-      vector_unset (comps, i);
-      del_cmd_token (token);
-    }
-  ret[i] = NULL;
-  vector_free (comps);
+  // reset vty->node to its original value
+  vty->node = original_node;
 
   return ret;
 }