]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/grammar_sandbox.c
lib: Code cleanup, formatting, & headers
[mirror_frr.git] / lib / grammar_sandbox.c
index d1779a9b6e805b4b9f4adf8cdafe21c2c2d1de97..39d4d6b7cd6cc99640383ed57aaddfaed2d7f6c5 100644 (file)
@@ -1,69 +1,86 @@
+/*
+ * Testing shim and API examples for the new CLI backend.
+ *
+ * This unit defines a number of commands in the old engine that can
+ * be used to test and interact with the new engine.
+ *
+ * This shim should be removed upon integration. It is currently hooked in
+ * vtysh/vtysh.c. It has no header, vtysh.c merely includes this entire unit
+ * since it clutters up the makefiles less and this is only a temporary shim.
+ *
+ * --
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
 #include "command.h"
 #include "command_graph.h"
 #include "command_parse.h"
 #include "command_match.h"
-#include "linklist.h"
 
 #define GRAMMAR_STR "CLI grammar sandbox\n"
 
+void
+grammar_sandbox_init(void);
+void
+pretty_print_graph (struct graph_node *start, int level);
+
+/*
+ * Start node for testing command graph.
+ *
+ * Each cmd_node will have one of these that replaces the `cmdvector` member.
+ * The examples below show how to install a command to the graph, calculate
+ * completions for a given input line, and match input against the graph.
+ */
 struct graph_node * nodegraph;
 
+/**
+ * Reference use of parsing / command installation API
+ */
 DEFUN (grammar_test,
        grammar_test_cmd,
        "grammar parse .COMMAND",
        GRAMMAR_STR
        "command to pass to new parser\n")
 {
-  char* command = argv_concat(argv, argc, 0);
-  struct cmd_element *cmd = malloc(sizeof(struct cmd_element));
+  char *command = argv_concat(argv, argc, 0);
+
+  // initialize a pretend cmd_element
+  struct cmd_element *cmd = XCALLOC(MTYPE_CMD_TOKENS, sizeof(struct cmd_element));
   cmd->string = command;
   cmd->doc = NULL;
   cmd->func = NULL;
   cmd->tokens = vector_init(VECTOR_MIN_SIZE);
-  parse_command_format(nodegraph, cmd);
-  return CMD_SUCCESS;
-}
 
-DEFUN (grammar_test_doc,
-       grammar_test_doc_cmd,
-       "grammar test docstring",
-       GRAMMAR_STR
-       "Test function for docstring\n"
-       "Command end\n")
-{
-  struct cmd_element *cmd = malloc(sizeof(struct cmd_element));
-  cmd->string = "test docstring <example|selector follow> (1-255) end VARIABLE [OPTION|set lol] . VARARG";
-  cmd->doc = "Test stuff\n"
-             "docstring thing\n"
-             "first example\n"
-             "second example\n"
-             "follow\n"
-             "random range\n"
-             "end thingy\n"
-             "variable\n"
-             "optional variable\n"
-             "optional set\n"
-             "optional lol\n"
-             "vararg!\n";
-  cmd->func = NULL;
-  cmd->tokens = vector_init(VECTOR_MIN_SIZE);
-  parse_command_format(nodegraph, cmd);
-  return CMD_SUCCESS;
-}
+  // parse the command and install it into the command graph
+  parse_command_format (nodegraph, cmd);
+
+  // free resources
+  free (command);
 
-DEFUN (grammar_test_show,
-       grammar_test_show_cmd,
-       "grammar tree",
-       GRAMMAR_STR
-       "print current accumulated DFA\n")
-{
-  if (!nodegraph)
-    fprintf(stderr, "!nodegraph\n");
-  else
-    walk_graph(nodegraph, 0);
   return CMD_SUCCESS;
 }
 
+
+/**
+ * Reference use of completions API
+ */
 DEFUN (grammar_test_complete,
        grammar_test_complete_cmd,
        "grammar complete .COMMAND",
@@ -71,31 +88,42 @@ DEFUN (grammar_test_complete,
        "attempt to complete input on DFA\n"
        "command to complete")
 {
-  const char* command = argv_concat(argv, argc, 0);
-  struct list *result = match_command_complete (nodegraph, command);
+  char *cmdstr = argv_concat (argv, argc, 0);
+  vector command = cmd_make_strvec (cmdstr);
+
+  struct list *completions;
+  enum matcher_rv result = match_command_complete (nodegraph, command, &completions);
 
-  if (result->count == 0) // invalid command
-    fprintf(stderr, "%% Unknown command\n");
+  // print completions or relevant error message
+  if (completions)
+    {
+      struct listnode *ln;
+      struct graph_node *gn;
+      for (ALL_LIST_ELEMENTS_RO(completions,ln,gn))
+        {
+          if (gn->type == END_GN)
+            zlog_info ("<cr> (%p)", gn->element->func);
+          else
+            zlog_info ("%-30s%s", gn->text, gn->doc);
+        }
+      list_delete (completions);
+    }
   else
-  {
-    fprintf(stderr, "%% Matched full input, possible completions:\n");
-    char* desc = malloc(30);
-    struct listnode *node;
-    struct graph_node *cnode;
-    // print possible next hops, if any
-    for (ALL_LIST_ELEMENTS_RO(result,node,cnode)) {
-      if (cnode->type == END_GN)
-        fprintf(stderr, "<cr> %p\n", cnode->element->func);
-      else
-        fprintf(stderr, "%-30s%s\n", describe_node(cnode, desc, 30), cnode->doc);
+    {
+      assert(MATCHER_ERROR(result));
+      zlog_info ("%% No match for \"%s\"", cmdstr);
     }
-    free(desc);
-  }
-  list_delete(result);
+
+  // free resources
+  cmd_free_strvec (command);
+  free (cmdstr);
 
   return CMD_SUCCESS;
 }
 
+/**
+ * Reference use of matching API
+ */
 DEFUN (grammar_test_match,
        grammar_test_match_cmd,
        "grammar match .COMMAND",
@@ -103,43 +131,105 @@ DEFUN (grammar_test_match,
        "attempt to match input on DFA\n"
        "command to match")
 {
-  const char *line = argv_concat(argv, argc, 0);
+  char *cmdstr = argv_concat(argv, argc, 0);
+  vector command = cmd_make_strvec (cmdstr);
 
   struct list *argvv = NULL;
   struct cmd_element *element = NULL;
-  enum matcher_rv result = match_command (nodegraph, line, &argvv, &element);
-
-  if (element) {
-    fprintf(stderr, "Matched: %s\n", element->string);
-    struct listnode *ln;
-    struct graph_node *gn;
-    for (ALL_LIST_ELEMENTS_RO(argvv,ln,gn))
-      fprintf(stderr, "%s -- %s\n", gn->text, gn->arg);
-  }
+  enum matcher_rv result = match_command (nodegraph, command, &argvv, &element);
+
+  // print completions or relevant error message
+  if (element)
+    {
+      zlog_info ("Matched: %s", element->string);
+      struct listnode *ln;
+      struct graph_node *gn;
+      for (ALL_LIST_ELEMENTS_RO(argvv,ln,gn))
+        if (gn->type != END_GN)
+          zlog_info ("func: %p", gn->element->func);
+        else
+          zlog_info ("%s -- %s", gn->text, gn->arg);
+
+      list_delete (argvv);
+    }
   else {
+     assert(MATCHER_ERROR(result));
      switch (result) {
        case MATCHER_NO_MATCH:
-          fprintf(stderr, "%% Unknown command\n");
+          zlog_info ("%% Unknown command");
           break;
        case MATCHER_INCOMPLETE:
-          fprintf(stderr, "%% Incomplete command\n");
+          zlog_info ("%% Incomplete command");
           break;
        case MATCHER_AMBIGUOUS:
-          fprintf(stderr, "%% Ambiguous command\n");
+          zlog_info ("%% Ambiguous command");
           break;
        default:
-          fprintf(stderr, "%% Unknown error\n");
+          zlog_info ("%% Unknown error");
           break;
      }
   }
 
+  // free resources
+  cmd_free_strvec(command);
+  free(cmdstr);
+
   return CMD_SUCCESS;
 }
 
+/**
+ * Testing shim to test docstrings
+ */
+DEFUN (grammar_test_doc,
+       grammar_test_doc_cmd,
+       "grammar test docstring",
+       GRAMMAR_STR
+       "Test function for docstring\n"
+       "Command end\n")
+{
+  // create cmd_element with docstring
+  struct cmd_element *cmd = XCALLOC(MTYPE_CMD_TOKENS, sizeof(struct cmd_element));
+  cmd->string = "test docstring <example|selector follow> (1-255) end VARIABLE [OPTION|set lol] . VARARG";
+  cmd->doc = "Test stuff\n"
+             "docstring thing\n"
+             "first example\n"
+             "second example\n"
+             "follow\n"
+             "random range\n"
+             "end thingy\n"
+             "variable\n"
+             "optional variable\n"
+             "optional set\n"
+             "optional lol\n"
+             "vararg!\n";
+  cmd->func = NULL;
+  cmd->tokens = vector_init (VECTOR_MIN_SIZE);
+
+  // parse element
+  parse_command_format (nodegraph, cmd);
+
+  return CMD_SUCCESS;
+}
+
+/**
+ * Debugging command to print command graph
+ */
+DEFUN (grammar_test_show,
+       grammar_test_show_cmd,
+       "grammar show graph",
+       GRAMMAR_STR
+       "print current accumulated DFA\n")
+{
+  if (!nodegraph)
+    zlog_info("nodegraph uninitialized");
+  else
+    pretty_print_graph (nodegraph, 0);
+  return CMD_SUCCESS;
+}
 
-void grammar_sandbox_init(void);
+/* this is called in vtysh.c to set up the testing shim */
 void grammar_sandbox_init() {
-  fprintf(stderr, "reinitializing graph\n");
+  zlog_info ("Initializing grammar testing shim");
   nodegraph = new_node(START_GN);
   install_element (ENABLE_NODE, &grammar_test_cmd);
   install_element (ENABLE_NODE, &grammar_test_show_cmd);
@@ -147,3 +237,30 @@ void grammar_sandbox_init() {
   install_element (ENABLE_NODE, &grammar_test_complete_cmd);
   install_element (ENABLE_NODE, &grammar_test_doc_cmd);
 }
+
+/* recursive pretty-print for command graph */
+void
+pretty_print_graph (struct graph_node *start, int level)
+{
+  // print this node
+  fprintf (stdout, "%s[%d] ", start->text, vector_active (start->children));
+
+  if (vector_active (start->children))
+    {
+      if (vector_active (start->children) == 1)
+        pretty_print_graph (vector_slot (start->children, 0), level);
+      else
+        {
+          fprintf(stdout, "\n");
+          for (unsigned int i = 0; i < vector_active (start->children); i++)
+            {
+              struct graph_node *r = vector_slot (start->children, i);
+              for (int j = 0; j < level+1; j++)
+                fprintf (stdout, "    ");
+              pretty_print_graph (r, level+1);
+            }
+        }
+    }
+  else
+    fprintf(stdout, "\n");
+}