]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Implement hidden and deprecated commands
authorQuentin Young <qlyoung@cumulusnetworks.com>
Thu, 10 Nov 2016 23:17:07 +0000 (23:17 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Thu, 10 Nov 2016 23:17:07 +0000 (23:17 +0000)
Each token now knows whether it is part of a hidden
or deprecated command. Command completion logic hides
such tokens when generating completions. Command
matching logic works as before and will still match on
hidden and deprecated commands.

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

index 8eee923144f1f1cbfc4e31c7fc58b61e09f7baab..c0b9ee4e10903514adeb801e5b2a10764e527d69 100644 (file)
@@ -235,7 +235,7 @@ install_node (struct cmd_node *node,
   node->cmdgraph = graph_new ();
   node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
   // add start node
-  struct cmd_token *token = new_cmd_token (START_TKN, NULL, NULL);
+  struct cmd_token *token = new_cmd_token (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
   graph_new_node (node->cmdgraph, token, (void (*)(void *)) &del_cmd_token);
   node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
 }
@@ -2383,10 +2383,11 @@ cmd_init (int terminal)
 }
 
 struct cmd_token *
-new_cmd_token (enum cmd_token_type type, char *text, char *desc)
+new_cmd_token (enum cmd_token_type type, u_char attr, char *text, char *desc)
 {
   struct cmd_token *token = XMALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
   token->type = type;
+  token->attr = attr;
   token->text = text;
   token->desc = desc;
   token->arg  = NULL;
@@ -2412,7 +2413,7 @@ del_cmd_token (struct cmd_token *token)
 struct cmd_token *
 copy_cmd_token (struct cmd_token *token)
 {
-  struct cmd_token *copy = new_cmd_token (token->type, NULL, NULL);
+  struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
   copy->max   = token->max;
   copy->min   = token->min;
   copy->text  = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
index 7b1f7d9fb51e068657c1bae3aeb9114bd8a91511..51f7f78085cce4b948db66e742571d5db288bca6 100644 (file)
@@ -182,24 +182,25 @@ enum cmd_token_type
   END_TKN,          // last token in line
 };
 
-/**
- * Token struct.
- */
+/* Command attributes */
+enum
+{
+  CMD_ATTR_NORMAL,
+  CMD_ATTR_DEPRECATED,
+  CMD_ATTR_HIDDEN,
+};
+
+/* Comamand token struct. */
 struct cmd_token
 {
   enum cmd_token_type type;     // token type
+  u_char attr;                  // token attributes
   char *text;                   // token text
   char *desc;                   // token description
   long long min, max;           // for ranges
   char *arg;                    // user input that matches this token
 };
 
-enum
-{
-  CMD_ATTR_DEPRECATED = 1,
-  CMD_ATTR_HIDDEN,
-};
-
 /* Structure of command element. */
 struct cmd_element
 {
@@ -425,7 +426,7 @@ copy_cmd_element(struct cmd_element *cmd);
 
 /* memory management for cmd_token */
 struct cmd_token *
-new_cmd_token (enum cmd_token_type, char *, char *);
+new_cmd_token (enum cmd_token_type, u_char attr, char *, char *);
 void
 del_cmd_token (struct cmd_token *);
 struct cmd_token *
index 42788ecb01d3eecc710d6e6fb278735890d894e2..8fa8da6b1070197c7bef8592d06a3d47c92a1c6f 100644 (file)
@@ -331,6 +331,10 @@ command_complete (struct graph *graph,
       for (ALL_LIST_ELEMENTS_RO (current,node,gn))
         {
           struct cmd_token *token = gn->data;
+
+          if (token->attr == CMD_ATTR_HIDDEN || token->attr == CMD_ATTR_DEPRECATED)
+            continue;
+
           enum match_type minmatch = min_match_level (token->type);
 #ifdef TRACE_MATCHER
           fprintf (stdout, "\"%s\" matches \"%s\" (%d) ? ", input_token, token->text, token->type);
index 680a74ccd2ae4335a4802ac53bf8e7ee97c69a73..3ef0b42ebea2834e396d60bd8bed580c16574537 100644 (file)
   static struct graph_node *
   new_token_node (struct graph *,
                   enum cmd_token_type type,
-                  char *text, char *doc);
+                  u_char attr, char *text,
+                  char *doc);
 
   static void
   terminate_graph (struct graph *,
 
 /* yyparse parameters */
 %parse-param { struct graph *graph }
-%parse-param { struct cmd_element *element }
+%parse-param { struct cmd_element *el }
 
 /* called automatically before yyparse */
 %initial-action {
   startnode = vector_slot (graph->nodes, 0);
 
   /* set string to parse */
-  set_lexer_string (element->string);
+  set_lexer_string (el->string);
 
   /* copy docstring and keep a pointer to the copy */
-  if (element->doc)
+  if (el->doc)
   {
     // allocate a new buffer, making room for a flag
-    size_t length = (size_t) strlen (element->doc) + 2;
+    size_t length = (size_t) strlen (el->doc) + 2;
     docstr = malloc (length);
-    memcpy (docstr, element->doc, strlen (element->doc));
+    memcpy (docstr, el->doc, strlen (el->doc));
     // set the flag so doc_next knows when to print a warning
     docstr[length - 2] = 0x03;
     // null terminate
@@ -167,7 +168,7 @@ start:
   sentence_root cmd_token_seq
 {
   // tack on the command element
-  terminate_graph (graph, currnode, element);
+  terminate_graph (graph, currnode, el);
 }
 | sentence_root cmd_token_seq placeholder_token '.' '.' '.'
 {
@@ -179,14 +180,14 @@ start:
   add_edge_dedup (currnode, currnode);
 
   // tack on the command element
-  terminate_graph (graph, currnode, element);
+  terminate_graph (graph, currnode, el);
 }
 ;
 
 sentence_root: WORD
 {
   struct graph_node *root =
-    new_token_node (graph, WORD_TKN, strdup ($1), doc_next(element));
+    new_token_node (graph, WORD_TKN, el->attr, strdup ($1), doc_next(el));
 
   if ((currnode = add_edge_dedup (startnode, root)) != root)
     graph_delete_node (graph, root);
@@ -227,7 +228,7 @@ compound_token:
 
 literal_token: WORD
 {
-  $$ = new_token_node (graph, WORD_TKN, strdup($1), doc_next(element));
+  $$ = new_token_node (graph, WORD_TKN, el->attr, strdup($1), doc_next(el));
   free ($1);
 }
 ;
@@ -235,32 +236,32 @@ literal_token: WORD
 placeholder_token:
   IPV4
 {
-  $$ = new_token_node (graph, IPV4_TKN, strdup($1), doc_next(element));
+  $$ = new_token_node (graph, IPV4_TKN, el->attr, strdup($1), doc_next(el));
   free ($1);
 }
 | IPV4_PREFIX
 {
-  $$ = new_token_node (graph, IPV4_PREFIX_TKN, strdup($1), doc_next(element));
+  $$ = new_token_node (graph, IPV4_PREFIX_TKN, el->attr, strdup($1), doc_next(el));
   free ($1);
 }
 | IPV6
 {
-  $$ = new_token_node (graph, IPV6_TKN, strdup($1), doc_next(element));
+  $$ = new_token_node (graph, IPV6_TKN, el->attr, strdup($1), doc_next(el));
   free ($1);
 }
 | IPV6_PREFIX
 {
-  $$ = new_token_node (graph, IPV6_PREFIX_TKN, strdup($1), doc_next(element));
+  $$ = new_token_node (graph, IPV6_PREFIX_TKN, el->attr, strdup($1), doc_next(el));
   free ($1);
 }
 | VARIABLE
 {
-  $$ = new_token_node (graph, VARIABLE_TKN, strdup($1), doc_next(element));
+  $$ = new_token_node (graph, VARIABLE_TKN, el->attr, strdup($1), doc_next(el));
   free ($1);
 }
 | RANGE
 {
-  $$ = new_token_node (graph, RANGE_TKN, strdup($1), doc_next(element));
+  $$ = new_token_node (graph, RANGE_TKN, el->attr, strdup($1), doc_next(el));
   struct cmd_token *token = $$->data;
 
   // get the numbers out
@@ -270,7 +271,7 @@ placeholder_token:
   token->max = strtoll (yylval.string, &yylval.string, 10);
 
   // validate range
-  if (token->min > token->max) yyerror (graph, element, "Invalid range.");
+  if (token->min > token->max) yyerror (graph, el, "Invalid range.");
 
   free ($1);
 }
@@ -279,8 +280,8 @@ placeholder_token:
 selector: '<' selector_seq_seq '>'
 {
   $$ = malloc (sizeof (struct subgraph));
-  $$->start = new_token_node (graph, SELECTOR_TKN, NULL, NULL);
-  $$->end   = new_token_node (graph, NUL_TKN, NULL, NULL);
+  $$->start = new_token_node (graph, SELECTOR_TKN, el->attr, NULL, NULL);
+  $$->end   = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL);
   for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
   {
     struct graph_node *sn = vector_slot ($2->start->to, i),
@@ -362,8 +363,8 @@ option: '[' option_token_seq ']'
 {
   // make a new option
   $$ = malloc (sizeof (struct subgraph));
-  $$->start = new_token_node (graph, OPTION_TKN, NULL, NULL);
-  $$->end   = new_token_node (graph, NUL_TKN, NULL, NULL);
+  $$->start = new_token_node (graph, OPTION_TKN, el->attr, NULL, NULL);
+  $$->end   = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL);
   // add a path through the sequence to the end
   graph_add_edge ($$->start, $2->start);
   graph_add_edge ($2->end, $$->end);
@@ -434,13 +435,15 @@ cleanup()
 }
 
 static void
-terminate_graph (struct graph *graph, struct graph_node *finalnode, struct cmd_element *element)
+terminate_graph (struct graph *graph, struct graph_node *finalnode,
+                 struct cmd_element *element)
 {
   // end of graph should look like this
   // * -> finalnode -> END_TKN -> cmd_element
   struct graph_node *end_token_node =
     new_token_node (graph,
                     END_TKN,
+                    element->attr,
                     strdup (CMD_CR_TEXT),
                     strdup (""));
   struct graph_node *end_element_node =
@@ -467,9 +470,10 @@ doc_next (struct cmd_element *el)
 }
 
 static struct graph_node *
-new_token_node (struct graph *graph, enum cmd_token_type type, char *text, char *doc)
+new_token_node (struct graph *graph, enum cmd_token_type type,
+                u_char attr, char *text, char *doc)
 {
-  struct cmd_token *token = new_cmd_token (type, text, doc);
+  struct cmd_token *token = new_cmd_token (type, attr, text, doc);
   return graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token);
 }
 
@@ -507,7 +511,16 @@ static struct graph_node *
 add_edge_dedup (struct graph_node *from, struct graph_node *to)
 {
   struct graph_node *existing = node_adjacent (from, to);
-  return existing ? existing : graph_add_edge (from, to);
+  if (existing)
+  {
+    struct cmd_token *ex_tok = existing->data;
+    struct cmd_token *to_tok = to->data;
+    // NORMAL takes precedence over DEPRECATED takes precedence over HIDDEN
+    ex_tok->attr = (ex_tok->attr < to_tok->attr) ? ex_tok->attr : to_tok->attr;
+    return existing;
+  }
+  else
+    return graph_add_edge (from, to);
 }
 
 /**