]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Add matching and argv support
authorQuentin Young <qlyoung@cumulusnetworks.com>
Wed, 27 Jul 2016 01:35:46 +0000 (01:35 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Wed, 27 Jul 2016 01:35:46 +0000 (01:35 +0000)
Queries may be run against DFA's to find matching
cmd_element, and argument lists may be constructed.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
lib/command_graph.c
lib/command_graph.h
lib/command_match.c
lib/command_match.h
lib/command_new.h [deleted file]
lib/command_parse.y
lib/grammar_sandbox.c

index b81e35ac9a053872ad5c3e8cadfe35920d6aa94e..38baa802c36fb74df0f734712dbb6495b7c1d4d2 100644 (file)
@@ -6,8 +6,8 @@
  * @author Quentin Young <qlyoung@cumulusnetworks.com>
  */
 
-#include <zebra.h>
 #include "command_graph.h"
+#include <zebra.h>
 #include "memory.h"
 
 struct graph_node *
@@ -100,7 +100,7 @@ describe_node(struct graph_node *node, char* buffer, unsigned int bufsize)
       snprintf(buffer, bufsize, node->text);
       break;
     case NUMBER_GN:
-      snprintf(buffer, bufsize, "%d", node->value);
+      snprintf(buffer, bufsize, "%ld", node->value);
       break;
     case SELECTOR_GN:
       snprintf(buffer, bufsize, "<>");
index e57c0786885dc39974ddf655600dcdf499e9c0fc..f0ded212624c6806642435a77dc5c9688f250b96 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef COMMAND_GRAPH_H
 #define COMMAND_GRAPH_H
 
-#include "vty.h"
-#include "vector.h"
+#include "command.h"
 
 enum graph_node_type
 {
@@ -22,18 +21,19 @@ enum graph_node_type
 
 struct graph_node
 {
-  enum graph_node_type type;
-  vector children;
-  int is_root;              // true if first token in command
+  enum graph_node_type type;// data type this node matches or holds
+  int is_start;             // whether this node is a start node
+  vector children;          // this node's children
   struct graph_node * end;  // pointer to end for SELECTOR_GN & OPTION_GN
 
-  // cmd_element struct pointer, only valid for END_GN
-  struct cmd_element *element;
-
-  /* various data fields for nodes */
   char* text;       // for WORD_GN and VARIABLE_GN
-  long value;        // for NUMBER_GN
-  long min, max;     // for RANGE_GN
+  long value;       // for NUMBER_GN
+  long min, max;    // for RANGE_GN
+
+  /* cmd_element struct pointer, only valid for END_GN */
+  struct cmd_element *element;
+  /* used for passing arguments to command functions */
+  char *arg;
 };
 
 /*
@@ -91,4 +91,11 @@ walk_graph(struct graph_node *, int);
  */
 extern char *
 describe_node(struct graph_node *, char *, unsigned int);
+
+/**
+ * Frees the data associated with a graph_node.
+ * @param[out] pointer to graph_node to free
+ */
+void
+free_node(struct graph_node *);
 #endif
index fd515726521b8d6600fdcd66ae31849a6dc56074..dc44f1b824de9f69e6a2f64bd1fbadee6b6a1979 100644 (file)
@@ -1,56 +1,55 @@
+#include "command_match.h"
+#include "command_parse.h"
 #include <zebra.h>
 #include "memory.h"
-#include "vector.h"
-#include "command_match.h"
 
-/* prototypes */
+/* matcher helper prototypes */
 static int
 add_nexthops(struct list *, struct graph_node *);
 
+static struct list *
+match_build_argv_r (struct graph_node *start, vector vline, unsigned int n);
+
+/* token matcher prototypes */
+static enum match_type
+match_ipv4 (const char *);
+
 static enum match_type
-cmd_ipv4_match (const char *);
+match_ipv4_prefix (const char *);
 
 static enum match_type
-cmd_ipv4_prefix_match (const char *);
+match_ipv6 (const char *);
 
 static enum match_type
-cmd_ipv6_match (const char *);
+match_ipv6_prefix (const char *);
 
 static enum match_type
-cmd_ipv6_prefix_match (const char *);
+match_range (struct graph_node *, const char *str);
 
 static enum match_type
-cmd_range_match (struct graph_node *, const char *str);
+match_word (struct graph_node *, enum filter_type, const char *);
 
 static enum match_type
-cmd_word_match (struct graph_node *, enum filter_type, const char *);
+match_number (struct graph_node *, const char *);
 
-static vector
-cmd_make_strvec (const char *);
+static enum match_type
+match_variable (struct graph_node *, const char *);
 
 static enum match_type
 match_token (struct graph_node *, char *, enum filter_type);
 
-static vector
-cmd_make_strvec (const char *);
-
 /* matching functions */
 
-/**
- * Attempt to find an exact command match for a line of user input.
- *
- * @return cmd_element found, or NULL if there is no match.
- */
-struct cmd_element
-match_command (struct graph_node *start, vector *command, enum filter_type filter)
+struct cmd_element *
+match_command (struct graph_node *start, const char *line, enum filter_type filter)
 {
   // get all possible completions
-  struct list completions = match_command_complete (start, command, filter);
+  struct list *completions = match_command_complete (start, line, filter);
 
   // one of them should be END_GN if this command matches
   struct graph_node *gn;
   struct listnode *node;
-  for (ALL_LIST_ELEMENTS_RO(current,node,gn))
+  for (ALL_LIST_ELEMENTS_RO(completions,node,gn))
   {
     if (gn->type == END_GN)
       break;
@@ -59,32 +58,11 @@ match_command (struct graph_node *start, vector *command, enum filter_type filte
   return gn ? gn->element : NULL;
 }
 
-/**
- * Compiles next-hops for a given line of user input.
- *
- * Given a string of input and a start node for a matching DFA, runs the input
- * against the DFA until the input is exhausted or a mismatch is encountered.
- *
- * This function returns all valid next hops away from the current node.
- *  - If the input is a valid prefix to a longer command(s), the set of next
- *    hops determines what tokens are valid to follow the prefix. In other words,
- *    the returned list is a list of possible completions.
- *  - If the input matched a full command, exactly one of the next hops will be
- *    a node of type END_GN and its function pointer will be set.
- *  - If the input did not match any valid token sequence, the returned list
- *    will be empty (there are no transitions away from a nonexistent state).
- *
- * @param[in] start the start node of the DFA to match against
- * @param[in] filter the filtering method
- * @param[in] input the input string
- * @return pointer to linked list with all possible next hops from the last
- *         matched token. If this is empty, the input did not match any command.
- */
 struct list *
-match_command_complete (struct graph_node *start, const char *input, enum filter_type filter)
+match_command_complete (struct graph_node *start, const char *line, enum filter_type filter)
 {
-  // break command
-  vector command = cmd_make_strvec (input);
+  // vectorize command line
+  vector vline = cmd_make_strvec (line);
 
   // pointer to next input token to match
   char *token;
@@ -101,13 +79,13 @@ match_command_complete (struct graph_node *start, const char *input, enum filter
   add_nexthops(next, start);
 
   unsigned int idx;
-  for (idx = 0; idx < vector_active(command) && next->count > 0; idx++)
+  for (idx = 0; idx < vector_active(vline) && next->count > 0; idx++)
   {
     list_free (current);
     current = next;
     next = list_new();
 
-    token = vector_slot(command, idx);
+    token = vector_slot(vline, idx);
 
     list_delete_all_node(matched);
 
@@ -131,14 +109,15 @@ match_command_complete (struct graph_node *start, const char *input, enum filter
   list_free (current);
   list_free (matched);
 
+  cmd_free_strvec(vline);
+
   return next;
 }
 
 /**
  * Adds all children that are reachable by one parser hop
  * to the given list. NUL_GN, SELECTOR_GN, and OPTION_GN
- * nodes are treated as though their children are attached
- * to their parent.
+ * nodes are treated as transparent.
  *
  * @param[out] l the list to add the children to
  * @param[in] node the node to get the children of
@@ -166,24 +145,73 @@ add_nexthops(struct list *l, struct graph_node *node)
   return added;
 }
 
-/**
- * Build the appropriate argv for a matched command.
- *
- * @param[in] command the command element
- * @param[in] the input line matching this command
- * @param[out] argv
- * @return argc
- *
-int
-match_build_argv (struct cmd_element *command, vector *input, char *argv)
+struct list *
+match_build_argv (const char *line, struct cmd_element *element)
 {
-  // build individual command graph
+  struct list *argv = NULL;
+
+  // parse command
   struct graph_node *start = new_node(NUL_GN);
-  cmd_parse_format(start, command->string);
-  
+  parse_command_format(start, element);
+
+  vector vline = cmd_make_strvec (line);
+
+  for (unsigned int i = 0; i < vector_active(start->children); i++)
+  {
+    // call recursive builder on each starting child
+    argv = match_build_argv_r (vector_slot(start->children, i), vline, 0);
+    // if any of them succeed, return their argv (there should only be one)
+    if (argv) break;
+  }
+
+  return argv;
 }
-*/
 
+static struct list *
+match_build_argv_r (struct graph_node *start, vector vline, unsigned int n)
+{
+  // if we don't match this node, die
+  if (match_token(start, vector_slot(vline, n), FILTER_STRICT) == no_match)
+    return NULL;
+
+  // some stuffs we need
+  struct list *argv = list_new();
+  struct graph_node *gn;
+  struct listnode   *ln;
+
+  // append current arg
+  start->arg = strdup(vector_slot(vline, n));
+  listnode_add(argv, start);
+
+  // get all possible nexthops
+  struct list *next = list_new();
+  add_nexthops(next, start);
+
+  // check if one of them is END_GN
+  for (ALL_LIST_ELEMENTS_RO(next,ln,gn))
+  {
+    if (gn->type == END_GN){
+      fprintf(stderr, "Hit END_GN while searching next set of node with text %s\n", start->text);
+      return argv;
+    }
+  }
+
+  // if we have no more input, why even live?
+  if (n+1 >= vector_active(vline)) return NULL;
+
+  // otherwise recurse on all nexthops
+  for (ALL_LIST_ELEMENTS_RO(next,ln,gn))
+  {
+    for (unsigned int i = 0; i < n; i++) fprintf(stderr, "\t");
+    fprintf(stderr, "Recursing on node %s for token %s\n", gn->text, (char*) vector_slot(vline, n+1));
+    struct list *result = match_build_argv_r (gn, vline, n+1);
+    if (result != NULL) {
+      list_add_list (argv, result);
+      return argv;
+    }
+  }
+  return NULL;
+}
 
 /* matching utility functions */
 
@@ -192,21 +220,22 @@ match_token (struct graph_node *node, char *token, enum filter_type filter)
 {
   switch (node->type) {
     case WORD_GN:
-      return cmd_word_match (node, filter, token);
+      return match_word (node, filter, token);
     case IPV4_GN:
-      return cmd_ipv4_match (token);
+      return match_ipv4 (token);
     case IPV4_PREFIX_GN:
-      return cmd_ipv4_prefix_match (token);
+      return match_ipv4_prefix (token);
     case IPV6_GN:
-      return cmd_ipv6_match (token);
+      return match_ipv6 (token);
     case IPV6_PREFIX_GN:
-      return cmd_ipv6_prefix_match (token);
+      return match_ipv6_prefix (token);
     case RANGE_GN:
-      return cmd_range_match (node, token);
+      return match_range (node, token);
     case NUMBER_GN:
-      return cmd_number_match (node, token);
+      return match_number (node, token);
     case VARIABLE_GN:
-      return cmd_variable_match (node, token);
+      return match_variable (node, token);
+    case END_GN:
     default:
       return no_match;
   }
@@ -216,7 +245,7 @@ match_token (struct graph_node *node, char *token, enum filter_type filter)
 #define IPV4_PREFIX_STR "0123456789./"
 
 static enum match_type
-cmd_ipv4_match (const char *str)
+match_ipv4 (const char *str)
 {
   struct sockaddr_in sin_dummy;
 
@@ -233,7 +262,7 @@ cmd_ipv4_match (const char *str)
 }
 
 static enum match_type
-cmd_ipv4_prefix_match (const char *str)
+match_ipv4_prefix (const char *str)
 {
   struct sockaddr_in sin_dummy;
   const char *delim = "/\0";
@@ -274,7 +303,7 @@ cmd_ipv4_prefix_match (const char *str)
 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
 
 static enum match_type
-cmd_ipv6_match (const char *str)
+match_ipv6 (const char *str)
 {
   struct sockaddr_in6 sin6_dummy;
   int ret;
@@ -294,7 +323,7 @@ cmd_ipv6_match (const char *str)
 }
 
 static enum match_type
-cmd_ipv6_prefix_match (const char *str)
+match_ipv6_prefix (const char *str)
 {
   struct sockaddr_in6 sin6_dummy;
   const char *delim = "/\0";
@@ -332,10 +361,10 @@ cmd_ipv6_prefix_match (const char *str)
 #endif
 
 static enum match_type
-cmd_range_match (struct graph_node *rangenode, const char *str)
+match_range (struct graph_node *rangenode, const char *str)
 {
   char *endptr = NULL;
-  signed long long val;
+  signed long val;
 
   if (str == NULL)
     return 1;
@@ -352,11 +381,10 @@ cmd_range_match (struct graph_node *rangenode, const char *str)
 }
 
 static enum match_type
-cmd_word_match(struct graph_node *wordnode,
-               enum filter_type filter,
-               const char *word)
+match_word(struct graph_node *wordnode,
+           enum filter_type filter,
+           const char *word)
 {
-
   if (filter == FILTER_RELAXED)
   {
     if (!word || !strlen(word))
@@ -375,7 +403,8 @@ cmd_word_match(struct graph_node *wordnode,
   }
 }
 
-cmd_number_match(struct graph_node *numnode, const char *word)
+static enum match_type
+match_number(struct graph_node *numnode, const char *word)
 {
   if (!strcmp("\0", word)) return no_match;
   char *endptr;
@@ -384,57 +413,11 @@ cmd_number_match(struct graph_node *numnode, const char *word)
   return num == numnode->value ? exact_match : no_match;
 }
 
-cmd_variable_match(struct graph_node *varnode, const char *word)
-{
-  // I guess this matches whatever?
-  return exact_match;
-}
+#define VARIABLE_ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"
 
-static vector
-cmd_make_strvec (const char *string)
+static enum match_type
+match_variable(struct graph_node *varnode, const char *word)
 {
-  const char *cp, *start;
-  char *token;
-  int strlen;
-  vector strvec;
-
-  if (string == NULL)
-    return NULL;
-
-  cp = string;
-
-  /* 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 == '#')
-    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++;
-
-      if (*cp == '\0')
-        return strvec;
-    }
+  return strlen(word) == strspn(word, VARIABLE_ALPHABET) && isalpha(word[0]) ?
+     exact_match : no_match;
 }
index 695dda2827d39e913ea266bc1b7473051e1884db..24cd1287e6bccf1ef81d97a03fa8dd340fd319b2 100644 (file)
@@ -1,22 +1,21 @@
 #ifndef COMMAND_MATCH_H
 #define COMMAND_MATCH_H
 
+#include "command.h"
 #include "command_graph.h"
 #include "linklist.h"
 
-/**
- * Filter types. These tell the parser whether to allow
- * partial matching on tokens.
- */
+
+/** These definitions exist in command.c in
+ * the current engine but will be relocated
+ * here in the new engine*/
 enum filter_type
 {
   FILTER_RELAXED,
   FILTER_STRICT
 };
 
-/**
- * Command matcher result value.
- */
+/* matcher result value. */
 enum matcher_rv
 {
   MATCHER_OK,
@@ -34,8 +33,8 @@ enum match_type
   partly_match,
   exact_match
 };
-/**
- * Defines which matcher_rv values constitute
+
+/* Defines which matcher_rv values constitute
  * an error. Should be used against matcher_rv
  * return values to do basic error checking.
  */
@@ -46,7 +45,46 @@ enum match_type
    || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
   )
 
+/**
+ * Attempt to find an exact command match for a line of user input.
+ *
+ * @return cmd_element found, or NULL if there is no match.
+ */
+struct cmd_element *
+match_command (struct graph_node *, const char *, enum filter_type);
+
+/**
+ * Compiles next-hops for a given line of user input.
+ *
+ * Given a string of input and a start node for a matching DFA, runs the input
+ * against the DFA until the input is exhausted or a mismatch is encountered.
+ *
+ * This function returns all valid next hops away from the current node.
+ *  - If the input is a valid prefix to a longer command(s), the set of next
+ *    hops determines what tokens are valid to follow the prefix. In other words,
+ *    the returned list is a list of possible completions.
+ *  - If the input matched a full command, exactly one of the next hops will be
+ *    a node of type END_GN and its function pointer will be set.
+ *  - If the input did not match any valid token sequence, the returned list
+ *    will be empty (there are no transitions away from a nonexistent state).
+ *
+ * @param[in] start the start node of the DFA to match against
+ * @param[in] filter the filtering method
+ * @param[in] input the input string
+ * @return pointer to linked list with all possible next hops from the last
+ *         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);
+
+/**
+ * Builds an argument list given a cmd_element and a matching input line.
+ *
+ * @param[in] input line
+ * @param[in] cmd_element struct
+ * @return pointer to argument linked list
+ */
 struct list *
-match_command (struct graph_node *, enum filter_type, const char *);
+match_build_argv (const char *, struct cmd_element *);
 
 #endif
diff --git a/lib/command_new.h b/lib/command_new.h
deleted file mode 100644 (file)
index 87f453d..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Zebra configuration command interface routine
- * Copyright (C) 1997, 98 Kunihiro Ishiguro
- *
- * 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.
- */
-
-#ifndef _ZEBRA_COMMAND_H
-#define _ZEBRA_COMMAND_H
-
-#include "vector.h"
-#include "vty.h"
-#include "lib/route_types.h"
-
-/* Host configuration variable */
-struct host
-{
-  /* Host name of this router. */
-  char *name;
-
-  /* Password for vty interface. */
-  char *password;
-  char *password_encrypt;
-
-  /* Enable password */
-  char *enable;
-  char *enable_encrypt;
-
-  /* System wide terminal lines. */
-  int lines;
-
-  /* Log filename. */
-  char *logfile;
-
-  /* config file name of this host */
-  char *config;
-
-  /* Flags for services */
-  int advanced;
-  int encrypt;
-
-  /* Banner configuration. */
-  const char *motd;
-  char *motdfile;
-};
-
-/* There are some command levels which called from command node. */
-enum node_type
-{
-  AUTH_NODE,            /* Authentication mode of vty interface. */
-  RESTRICTED_NODE,      /* Restricted view mode */
-  VIEW_NODE,            /* View node. Default mode of vty interface. */
-  AUTH_ENABLE_NODE,     /* Authentication mode for change enable. */
-  ENABLE_NODE,          /* Enable node. */
-  CONFIG_NODE,          /* Config node. Default mode of config file. */
-  SERVICE_NODE,         /* Service node. */
-  DEBUG_NODE,           /* Debug node. */
-  VRF_DEBUG_NODE,       /* Vrf Debug node. */
-  AAA_NODE,             /* AAA node. */
-  KEYCHAIN_NODE,        /* Key-chain node. */
-  KEYCHAIN_KEY_NODE,    /* Key-chain key node. */
-  VRF_NODE,             /* VRF mode node. */
-  INTERFACE_NODE,       /* Interface mode node. */
-  ZEBRA_NODE,           /* zebra connection node. */
-  TABLE_NODE,           /* rtm_table selection node. */
-  RIP_NODE,             /* RIP protocol mode node. */
-  RIPNG_NODE,           /* RIPng protocol mode node. */
-  BGP_NODE,             /* BGP protocol mode which includes BGP4+ */
-  BGP_VPNV4_NODE,       /* BGP MPLS-VPN PE exchange. */
-  BGP_VPNV6_NODE,       /* BGP MPLS-VPN PE exchange. */
-  BGP_IPV4_NODE,        /* BGP IPv4 unicast address family.  */
-  BGP_IPV4M_NODE,       /* BGP IPv4 multicast address family.  */
-  BGP_IPV6_NODE,        /* BGP IPv6 address family */
-  BGP_IPV6M_NODE,       /* BGP IPv6 multicast address family. */
-  BGP_ENCAP_NODE,       /* BGP ENCAP SAFI */
-  BGP_ENCAPV6_NODE,     /* BGP ENCAP SAFI */
-  OSPF_NODE,            /* OSPF protocol mode */
-  OSPF6_NODE,           /* OSPF protocol for IPv6 mode */
-  ISIS_NODE,            /* ISIS protocol mode */
-  PIM_NODE,             /* PIM protocol mode */
-  MASC_NODE,            /* MASC for multicast.  */
-  IRDP_NODE,            /* ICMP Router Discovery Protocol mode. */
-  IP_NODE,              /* Static ip route node. */
-  ACCESS_NODE,          /* Access list node. */
-  PREFIX_NODE,          /* Prefix list node. */
-  ACCESS_IPV6_NODE,     /* Access list node. */
-  PREFIX_IPV6_NODE,     /* Prefix list node. */
-  AS_LIST_NODE,         /* AS list node. */
-  COMMUNITY_LIST_NODE,  /* Community list node. */
-  RMAP_NODE,            /* Route map node. */
-  SMUX_NODE,            /* SNMP configuration node. */
-  DUMP_NODE,            /* Packet dump node. */
-  FORWARDING_NODE,      /* IP forwarding node. */
-  PROTOCOL_NODE,        /* protocol filtering node */
-  VTY_NODE,             /* Vty node. */
-};
-
-/* Node which has some commands and prompt string and configuration
-   function pointer . */
-struct cmd_node
-{
-  /* Node index. */
-  enum node_type node;
-
-  /* Prompt character at vty interface. */
-  const char *prompt;
-
-  /* Is this node's configuration goes to vtysh ? */
-  int vtysh;
-
-  /* Node's configuration write function */
-  int (*func) (struct vty *);
-
-  /* Start of this node's command graph */
-  struct graph_node * cmd_graph;
-};
-
-enum
-{
-  CMD_ATTR_DEPRECATED = 1,
-  CMD_ATTR_HIDDEN,
-};
-
-/* Structure of command element. */
-struct cmd_element
-{
-  const char *string;   // command format string
-  const char *doc;      // command doc string
-  int daemon;           // daemon associated with command
-  u_char attr;          // Command attributes
-
-  // function for this command
-  int (*func) (struct cmd_element *, struct vty *, int, const char *[]);
-};
-
-/* argument to be recorded on argv[] if it's not a literal */
-#define TERMINAL_RECORD(t) ((t) >= TERMINAL_OPTION)
-
-/* Return value of the commands. */
-#define CMD_SUCCESS              0
-#define CMD_WARNING              1
-#define CMD_ERR_NO_MATCH         2
-#define CMD_ERR_AMBIGUOUS        3
-#define CMD_ERR_INCOMPLETE       4
-#define CMD_ERR_EXEED_ARGC_MAX   5
-#define CMD_ERR_NOTHING_TODO     6
-#define CMD_COMPLETE_FULL_MATCH  7
-#define CMD_COMPLETE_MATCH       8
-#define CMD_COMPLETE_LIST_MATCH  9
-#define CMD_SUCCESS_DAEMON      10
-#define CMD_ERR_NO_FILE         11
-
-/* Argc max counts. */
-#define CMD_ARGC_MAX   25
-
-/* Turn off these macros when uisng cpp with extract.pl */
-#ifndef VTYSH_EXTRACT_PL
-
-/* helper defines for end-user DEFUN* macros */
-#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
-  struct cmd_element cmdname = \
-  { \
-    .string = cmdstr,   \
-    .doc    = helpstr,  \
-    .daemon = dnum,     \
-    .attr   = attrs,    \
-    .func   = funcname, \
-  };
-
-#define DEFUN_CMD_FUNC_DECL(funcname) \
-  static int funcname (struct cmd_element *, struct vty *, int, const char *[]);
-
-#define DEFUN_CMD_FUNC_TEXT(funcname) \
-  static int funcname \
-    (struct cmd_element *self __attribute__ ((unused)), \
-     struct vty *vty __attribute__ ((unused)), \
-     int argc __attribute__ ((unused)), \
-     const char *argv[] __attribute__ ((unused)) )
-
-/* DEFUN for vty command interface.
- *
- * DEFUN(funcname, cmdname, cmdstr, helpstr)
- *
- * funcname
- * ========
- * Name of the function that will be defined.
- *
- * cmdname
- * =======
- * Name of the struct that will be defined for the command.
- *
- * cmdstr
- * ======
- * The cmdstr defines the command syntax. It is used by the vty subsystem
- * and vtysh to perform matching and completion in the CLI.
- *
- * Syntax Summary
- * ----------------
- * <summary>
- *
- * Abbreviated BNF
- * ----------------
- * <bnf>
- *
- *
- * helpstr
- * =======
- *
- * The helpstr is used to show a short explantion for the commands that
- * are available when the user presses '?' on the CLI. It is the concatenation
- * of the helpstrings for all the tokens that make up the command.
- *
- * There should be one helpstring for each token in the cmdstr except those
- * containing other tokens, like Multiple or Keyword Tokens. For those, there
- * will only be the helpstrings of the contained tokens.
- *
- * The individual helpstrings are expected to be in the same order as their
- * respective Tokens appear in the cmdstr. They should each be terminated with
- * a linefeed. The last helpstring should be terminated with a linefeed as well.
- *
- * Care should also be taken to avoid having similar tokens with different
- * helpstrings. Imagine e.g. the commands "show ip ospf" and "show ip bgp".
- * they both contain a helpstring for "show", but only one will be displayed
- * when the user enters "sh?". If those two helpstrings differ, it is not
- * defined which one will be shown and the behavior is therefore unpredictable.
- */
-#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-#define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
-
-#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \
-
-/* DEFUN_NOSH for commands that vtysh should ignore */
-#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN(funcname, cmdname, cmdstr, helpstr)
-
-/* DEFSH for vtysh. */
-#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) \
-
-#define DEFSH_HIDDEN(daemon, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon) \
-
-/* DEFUN + DEFSH */
-#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-/* DEFUN + DEFSH with attributes */
-#define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \
-  DEFUN_CMD_FUNC_DECL(funcname) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \
-  DEFUN_CMD_FUNC_TEXT(funcname)
-
-#define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
-
-#define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED)
-
-/* ALIAS macro which define existing command's alias. */
-#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
-
-#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0)
-
-#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0)
-
-#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0)
-
-#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon)
-
-#define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon)
-
-#define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
-  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, daemon)
-
-#endif /* VTYSH_EXTRACT_PL */
-
-/* Some macroes */
-
-/*
- * Sometimes #defines create maximum values that
- * need to have strings created from them that
- * allow the parser to match against them.
- * These macros allow that.
- */
-#define CMD_CREATE_STR(s)  CMD_CREATE_STR_HELPER(s)
-#define CMD_CREATE_STR_HELPER(s) #s
-#define CMD_RANGE_STR(a,s) "<" CMD_CREATE_STR(a) "-" CMD_CREATE_STR(s) ">"
-
-/* Common descriptions. */
-#define SHOW_STR "Show running system information\n"
-#define IP_STR "IP information\n"
-#define IPV6_STR "IPv6 information\n"
-#define NO_STR "Negate a command or set its defaults\n"
-#define REDIST_STR "Redistribute information from another routing protocol\n"
-#define CLEAR_STR "Reset functions\n"
-#define RIP_STR "RIP information\n"
-#define BGP_STR "BGP information\n"
-#define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n"
-#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
-#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
-#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
-#define OSPF_STR "OSPF information\n"
-#define NEIGHBOR_STR "Specify neighbor router\n"
-#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
-#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
-#define ROUTER_STR "Enable a routing process\n"
-#define AS_STR "AS number\n"
-#define MBGP_STR "MBGP information\n"
-#define MATCH_STR "Match values from routing table\n"
-#define SET_STR "Set values in destination routing protocol\n"
-#define OUT_STR "Filter outgoing routing updates\n"
-#define IN_STR  "Filter incoming routing updates\n"
-#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
-#define OSPF6_NUMBER_STR "Specify by number\n"
-#define INTERFACE_STR "Interface infomation\n"
-#define IFNAME_STR "Interface name(e.g. ep0)\n"
-#define IP6_STR "IPv6 Information\n"
-#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
-#define OSPF6_ROUTER_STR "Enable a routing process\n"
-#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
-#define SECONDS_STR "<1-65535> Seconds\n"
-#define ROUTE_STR "Routing Table\n"
-#define PREFIX_LIST_STR "Build a prefix list\n"
-#define OSPF6_DUMP_TYPE_LIST \
-"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
-#define ISIS_STR "IS-IS information\n"
-#define AREA_TAG_STR "[area tag]\n"
-#define COMMUNITY_AANN_STR "Community number where AA and NN are <0-65535>\n"
-#define COMMUNITY_VAL_STR  "Community number in AA:NN format (where AA and NN are <0-65535>) or local-AS|no-advertise|no-export|internet or additive\n"
-
-#define CONF_BACKUP_EXT ".sav"
-
-/* IPv4 only machine should not accept IPv6 address for peer's IP
-   address.  So we replace VTY command string like below. */
-#ifdef HAVE_IPV6
-#define NEIGHBOR_CMD       "neighbor (A.B.C.D|X:X::X:X) "
-#define NO_NEIGHBOR_CMD    "no neighbor (A.B.C.D|X:X::X:X) "
-#define NEIGHBOR_ADDR_STR  "Neighbor address\nIPv6 address\n"
-#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|X:X::X:X|WORD) "
-#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|X:X::X:X|WORD) "
-#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nInterface name or neighbor tag\n"
-#define NEIGHBOR_ADDR_STR3 "Neighbor address\nIPv6 address\nInterface name\n"
-#else
-#define NEIGHBOR_CMD       "neighbor A.B.C.D "
-#define NO_NEIGHBOR_CMD    "no neighbor A.B.C.D "
-#define NEIGHBOR_ADDR_STR  "Neighbor address\n"
-#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|WORD) "
-#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|WORD) "
-#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
-#endif /* HAVE_IPV6 */
-
-/* Dynamic neighbor (listen range) configuration */
-#ifdef HAVE_IPV6
-#define LISTEN_RANGE_CMD      "bgp listen range (A.B.C.D/M|X:X::X:X/M) "
-#define LISTEN_RANGE_ADDR_STR "Neighbor address\nNeighbor IPv6 address\n"
-#else
-#define LISTEN_RANGE_CMD      "bgp listen range A.B.C.D/M "
-#define LISTEN_RANGE_ADDR_STR "Neighbor address\n"
-#endif /* HAVE_IPV6 */
-
-/* Prototypes. */
-extern void install_node (struct cmd_node *, int (*) (struct vty *));
-extern void install_default (enum node_type);
-extern void install_element (enum node_type, struct cmd_element *);
-
-/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
-   string with a space between each element (allocated using
-   XMALLOC(MTYPE_TMP)).  Returns NULL if shift >= argc. */
-extern char *argv_concat (const char **argv, int argc, int shift);
-
-extern vector cmd_make_strvec (const char *);
-extern void cmd_free_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);
-extern enum node_type node_parent (enum node_type);
-extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int);
-extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **);
-extern void cmd_init (int);
-extern void cmd_terminate (void);
-
-/* Export typical functions. */
-extern struct cmd_element config_end_cmd;
-extern struct cmd_element config_exit_cmd;
-extern struct cmd_element config_quit_cmd;
-extern struct cmd_element config_help_cmd;
-extern struct cmd_element config_list_cmd;
-extern char *host_config_file (void);
-extern void host_config_set (const char *);
-
-extern void print_version (const char *);
-
-extern int cmd_banner_motd_file (const char *);
-
-/* struct host global, ick */
-extern struct host host;
-
-/* "<cr>" global */
-extern char *command_cr;
-#endif /* _ZEBRA_COMMAND_H */
index 1cef6766ae39d45b28a27fcc8507f9752c7241b8..7b56aec952b4573b9b696daf04de4aa9233f4cd4 100644 (file)
@@ -9,22 +9,24 @@
  */
 
 %{
-#include "command_graph.h"
-#include "command_new.h"
-
 extern int yylex(void);
 extern void yyerror(const char *);
 
 // compile with debugging facilities
 #define YYDEBUG 1
 %}
+%code requires {
+  #include "command.h"
+  #include "command_graph.h"
+}
 %code provides {
-extern struct
-graph_node *cmd_parse_format(const char *, const char *, struct graph_node *);
-extern void
-set_buffer_string(const char *);
+  extern void
+  set_buffer_string(const char *);
+  struct graph_node *
+  parse_command_format(struct graph_node *, struct cmd_element *);
 }
 
+
 /* valid types for tokens */
 %union{
   int integer;
@@ -45,7 +47,7 @@ struct graph_node *optnode_start,   // start node for option set
 struct graph_node *selnode_start,   // start node for selector set
                   *selnode_end;     // end node for selector set
 
-const struct cmd_element *command;  // command we're parsing
+struct cmd_element *command;        // command we're parsing
 %}
 
 %token <node> WORD
@@ -86,12 +88,16 @@ start: sentence_root
   struct graph_node *end = new_node(END_GN);
   end->element = command;
 
+  // ensure there are no END_GN children
+  for (unsigned int i = 0; i < vector_active(currnode->children); i++)
+  {
+    struct graph_node *child = vector_slot(currnode->children, i);
+    if (child->type == END_GN)
+      yyerror("Duplicate command.");
+  }
+
   // add node
   end = add_node(currnode, end);
-
-  // check that we did not get back an existing node
-  if (!strcmp(command->string, end->element->string)
-    yyerror("Duplicate command.");
 }
 
 sentence_root: WORD
@@ -166,12 +172,7 @@ placeholder_token:
   // get the numbers out
   strsep(&yylval.string, "(-)");
   $$->min = atoi( strsep(&yylval.string, "(-)") );
-  strsep(&yylval.string, "(-)");
   $$->max = atoi( strsep(&yylval.string, "(-)") );
-
-  // we could do this a variety of ways with either
-  // the lexer or the parser, but this is the simplest
-  // and involves the least amount of free()
 }
 ;
 
@@ -304,9 +305,9 @@ void yyerror(char const *message) {
 }
 
 struct graph_node *
-cmd_parse_format(struct graph_node *start, struct cmd_element *cmd)
+parse_command_format(struct graph_node *start, struct cmd_element *cmd)
 {
-  fprintf(stderr, "parsing: %s\n", string);
+  fprintf(stderr, "parsing: %s\n", cmd->string);
 
   /* clear state pointers */
   startnode = currnode = seqhead = NULL;
@@ -318,7 +319,7 @@ cmd_parse_format(struct graph_node *start, struct cmd_element *cmd)
   // command string
   command = cmd;
   // make flex read from a string
-  set_buffer_string(input);
+  set_buffer_string(command->string);
   // initialize the start node of this command dfa
   startnode = start;
   // parse command into DFA
index 24f882c89f57e27c7883fe780df9a4588539ea76..6eee9c8b657e22b45153e5954c3f97333bf6f786 100644 (file)
@@ -14,11 +14,11 @@ DEFUN (grammar_test,
        GRAMMAR_STR
        "command to pass to new parser\n")
 {
-
-  const char* command = argv_concat(argv, argc, 0);
-  cmd_parse_format(command, "lol", nodegraph);
+  char* command = argv_concat(argv, argc, 0);
+  struct cmd_element *cmd = malloc(sizeof(struct cmd_element));
+  cmd->string = command;
+  parse_command_format(nodegraph, cmd);
   walk_graph(nodegraph, 0);
-
   return CMD_SUCCESS;
 }
 
@@ -32,15 +32,15 @@ DEFUN (grammar_test_show,
   return CMD_SUCCESS;
 }
 
-DEFUN (grammar_test_match,
-       grammar_test_match_cmd,
-       "grammar match .COMMAND",
+DEFUN (grammar_test_complete,
+       grammar_test_complete_cmd,
+       "grammar complete .COMMAND",
        GRAMMAR_STR
-       "attempt to match input on DFA\n"
-       "command to match")
+       "attempt to complete input on DFA\n"
+       "command to complete")
 {
   const char* command = argv_concat(argv, argc, 0);
-  struct list *result = match_command(nodegraph, FILTER_STRICT, command);
+  struct list *result = match_command_complete (nodegraph, command, FILTER_STRICT);
 
   if (result->count == 0) // invalid command
     fprintf(stderr, "%% Unknown command\n");
@@ -53,7 +53,7 @@ DEFUN (grammar_test_match,
     // print possible next hops, if any
     for (ALL_LIST_ELEMENTS_RO(result,node,cnode)) {
       if (cnode->type == END_GN)
-        fprintf(stderr, "<cr>");
+        fprintf(stderr, "<cr>\n");
       else
         fprintf(stderr, "%s\n", describe_node(cnode, desc, 50));
     }
@@ -64,6 +64,39 @@ DEFUN (grammar_test_match,
   return CMD_SUCCESS;
 }
 
+DEFUN (grammar_test_match,
+       grammar_test_match_cmd,
+       "grammar match .COMMAND",
+       GRAMMAR_STR
+       "attempt to match input on DFA\n"
+       "command to match")
+{
+  const char* command = argv_concat(argv, argc, 0);
+  struct cmd_element *element = match_command (nodegraph, command, FILTER_STRICT);
+
+  if (element)
+    fprintf(stderr, "Matched: %s\n", element->string);
+  else {
+    fprintf(stderr, "Returned NULL\n");
+    return CMD_SUCCESS;
+  }
+
+  struct list *argvv = match_build_argv (command, element);
+  fprintf(stderr, "num args: %d\n", argvv->count);
+
+  struct listnode *ln;
+  struct graph_node *gn;
+  for (ALL_LIST_ELEMENTS_RO(argvv,ln,gn)) {
+    fprintf(stderr, "node text: %s\n", gn->text);
+    if (gn->arg)
+      fprintf(stderr, "node arg: %s\n", gn->arg);
+    else
+      fprintf(stderr, "No arg.\n");
+  }
+
+  return CMD_SUCCESS;
+}
+
 
 void grammar_sandbox_init(void);
 void grammar_sandbox_init() {
@@ -72,4 +105,5 @@ void grammar_sandbox_init() {
   install_element (ENABLE_NODE, &grammar_test_cmd);
   install_element (ENABLE_NODE, &grammar_test_show_cmd);
   install_element (ENABLE_NODE, &grammar_test_match_cmd);
+  install_element (ENABLE_NODE, &grammar_test_complete_cmd);
 }