]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Client: Add support for completion of command options
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 5 Mar 2024 18:04:10 +0000 (19:04 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 5 Mar 2024 18:04:10 +0000 (19:04 +0100)
We can easily extend command completion to handle also keywords for
command options. Help for command options is not yet supported.

client/commands.c
conf/gen_commands.m4
conf/gen_parser.m4
nest/config.Y
proto/bfd/config.Y
proto/mrt/config.Y
proto/ospf/config.Y

index fdf2652a068d2bbf331d37a05932ca9e2fb42a63..318f0ecd190d5a3f27890c2dfd675006c364df90 100644 (file)
@@ -20,6 +20,7 @@ struct cmd_info {
   char *args;
   char *help;
   int is_real_cmd;
+  int is_option;
 };
 
 static struct cmd_info command_table[] = {
@@ -30,7 +31,8 @@ struct cmd_node {
   struct cmd_node *sibling, *son, **plastson;
   struct cmd_info *cmd, *help;
   int len;
-  signed char prio;
+  u8 final;
+  s8 prio;
   char token[1];
 };
 
@@ -51,12 +53,13 @@ cmd_build_tree(void)
       struct cmd_node *old, *new;
       char *c = cmd->command;
 
-      old = &cmd_root;
+      new = &cmd_root;
       while (*c)
        {
          char *d = c;
          while (*c && !isspace_(*c))
            c++;
+         old = new;
          for(new=old->son; new; new=new->sibling)
            if (new->len == c-d && !memcmp(new->token, d, c-d))
              break;
@@ -72,14 +75,17 @@ cmd_build_tree(void)
              memcpy(new->token, d, c-d);
              new->prio = (new->len == 3 && (!memcmp(new->token, "roa", 3) || !memcmp(new->token, "rip", 3))) ? 0 : 1; /* Hack */
            }
-         old = new;
          while (isspace_(*c))
            c++;
        }
+
       if (cmd->is_real_cmd)
-       old->cmd = cmd;
+       new->cmd = cmd;
       else
-       old->help = cmd;
+       new->help = cmd;
+
+      if (cmd->is_option)
+       old->final = 1;
     }
 }
 
@@ -147,7 +153,7 @@ cmd_help(char *cmd, int len)
   int ambig;
 
   n = &cmd_root;
-  while (cmd < end)
+  while (cmd < end && !n->final)
     {
       if (isspace_(*cmd))
        {
@@ -168,6 +174,11 @@ cmd_help(char *cmd, int len)
       n = m;
     }
   cmd_display_help(n->cmd, NULL);
+
+  /* Currently no help for options */
+  if (n->final)
+    return;
+
   for (m=n->son; m; m=m->sibling)
     cmd_display_help(m->help, m->cmd);
 }
@@ -229,7 +240,7 @@ cmd_complete(char *cmd, int len, char *buf, int again)
 
   /* Find the context */
   n = &cmd_root;
-  while (cmd < fin && n->son)
+  while (cmd < fin && n->son && !n->final)
     {
       if (isspace_(*cmd))
        {
@@ -290,7 +301,7 @@ cmd_expand(char *cmd)
 
   args = c = cmd;
   n = &cmd_root;
-  while (*c)
+  while (*c && !n->final)
     {
       if (isspace_(*c))
        {
index 3ed21f135bc310d6b32bb29e810546159d7e49aa..daf39da6ff662c292cec435ac606ea33685955c5 100644 (file)
@@ -13,6 +13,9 @@ m4_divert(-1)')
 m4_define(CF_CLI_CMD, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 1 },
 m4_divert(-1)')
 
+m4_define(CF_CLI_OPT, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 1, .is_option = 1 },
+m4_divert(-1)')
+
 m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 0 },
 m4_divert(-1)')
 
index 80071aefa19bce7287288dcf04c2e73a0b403a2f..48c2ca5085f03b86c837f512d9a8db53c348d643 100644 (file)
@@ -48,6 +48,7 @@ m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
 m4_divert(3)cli_cmd: CF_cmd
 CF_cmd: $1 $2 END')
 m4_define(CF_CLI_CMD, `')
+m4_define(CF_CLI_OPT, `')
 m4_define(CF_CLI_HELP, `')
 
 # ENUM declarations are ignored
index 63888a04a5212dd19ff026d121f3cc6b8dea8219..20186ece66a4bb2e992bc9e819d85ba15576eb87 100644 (file)
@@ -650,6 +650,23 @@ CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]])
 CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>|in <prefix>] [table <t>] [(import|export) table <p>.<c>] [filter <f>|where <cond>] [all] [primary] [filtered] [(export|preexport|noexport) <p>] [protocol <p>] [stats|count]]], [[Show routing table]])
 { rt_show($3); } ;
 
+CF_CLI_OPT(SHOW ROUTE FOR, <ip>|<prefix>)
+CF_CLI_OPT(SHOW ROUTE IN, <prefix>)
+CF_CLI_OPT(SHOW ROUTE TABLE, <t>)
+CF_CLI_OPT(SHOW ROUTE FILTER, <f>)
+CF_CLI_OPT(SHOW ROUTE WHERE, <cond>)
+CF_CLI_OPT(SHOW ROUTE ALL)
+CF_CLI_OPT(SHOW ROUTE PRIMARY)
+CF_CLI_OPT(SHOW ROUTE FILTERED)
+CF_CLI_OPT(SHOW ROUTE IMPORT, <p>[.<c>])
+CF_CLI_OPT(SHOW ROUTE EXPORT, <p>[.<c>])
+CF_CLI_OPT(SHOW ROUTE EXPORTED, <p>[.<c>])
+CF_CLI_OPT(SHOW ROUTE PREEXPORT, <p>[.<c>])
+CF_CLI_OPT(SHOW ROUTE NOEXPORT, <p>[.<c>])
+CF_CLI_OPT(SHOW ROUTE PROTOCOL, <p>)
+CF_CLI_OPT(SHOW ROUTE STATS)
+CF_CLI_OPT(SHOW ROUTE COUNT)
+
 r_args:
    /* empty */ {
      $$ = cfg_allocz(sizeof(struct rt_show_data));
@@ -841,13 +858,19 @@ CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]])
 CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])
 { cmd_show_symbols($3); } ;
 
+CF_CLI_OPT(SHOW SYMBOLS TABLE)
+CF_CLI_OPT(SHOW SYMBOLS FILTER)
+CF_CLI_OPT(SHOW SYMBOLS FUNCTION)
+CF_CLI_OPT(SHOW SYMBOLS PROTOCOL)
+CF_CLI_OPT(SHOW SYMBOLS TEMPLATE)
+
 sym_args:
    /* empty */ {
      $$ = cfg_allocz(sizeof(struct sym_show_data));
    }
  | sym_args TABLE { $$ = $1; $$->type = SYM_TABLE; }
- | sym_args FUNCTION { $$ = $1; $$->type = SYM_FUNCTION; }
  | sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
+ | sym_args FUNCTION { $$ = $1; $$->type = SYM_FUNCTION; }
  | sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
  | sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
  | sym_args CF_SYM_KNOWN { $$ = $1; $$->sym = $2; }
@@ -914,6 +937,15 @@ CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
 CF_CLI(DEBUG, debug_args, (<protocol> | <channel> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
 { /* Done in debug_args */  };
 
+CF_CLI_OPT(DEBUG ALL)
+CF_CLI_OPT(DEBUG OFF)
+CF_CLI_OPT(DEBUG STATES)
+CF_CLI_OPT(DEBUG ROUTES)
+CF_CLI_OPT(DEBUG FILTERS)
+CF_CLI_OPT(DEBUG INTERFACES)
+CF_CLI_OPT(DEBUG EVENTS)
+CF_CLI_OPT(DEBUG PACKETS)
+
 debug_args:
    proto_patt debug_mask { proto_apply_cmd($1, proto_cmd_debug, 1, $2);  }
  | channel_arg debug_mask { channel_cmd_debug($1, $2); }
index 4edc13d94b5e1e30e650301b74bed53488288867..1a7474b0b18ddf328e8ce1a14fe77ad09a4f7cfc 100644 (file)
@@ -189,6 +189,15 @@ CF_CLI_HELP(SHOW BFD SESSIONS, ..., [[Show information about BFD sessions]]);
 CF_CLI(SHOW BFD SESSIONS, bfd_show_sessions_args, [<name>] [address <ip|prefix>] [(interface|dev) \"<name>\"] [ipv4|ipv6] [direct|multihop] [all], [[Show information about BFD sessions]])
 { PROTO_WALK_CMD($4->name, &proto_bfd, p) bfd_show_sessions(p, $4); };
 
+CF_CLI_OPT(SHOW BFD SESSIONS ADDRESS, <ip>|<prefix>)
+CF_CLI_OPT(SHOW BFD SESSIONS INTERFACE, \"<name>\")
+CF_CLI_OPT(SHOW BFD SESSIONS DEV, \"<name>\")
+CF_CLI_OPT(SHOW BFD SESSIONS ALL)
+CF_CLI_OPT(SHOW BFD SESSIONS IPV4)
+CF_CLI_OPT(SHOW BFD SESSIONS IPV6)
+CF_CLI_OPT(SHOW BFD SESSIONS DIRECT)
+CF_CLI_OPT(SHOW BFD SESSIONS MULTIHOP)
+
 bfd_show_sessions_args:
    /* empty */ { $$ = cfg_allocz(sizeof(struct bfd_show_sessions_cmd)); }
  | bfd_show_sessions_args CF_SYM_KNOWN { cf_assert_symbol($2, SYM_PROTO); $$->name = $2; }
index 4da6777ac426ca8d1073fbba259238548731118e..d2136ed16f39bc7038660895174a27014615c689 100644 (file)
@@ -53,6 +53,11 @@ CF_CLI_HELP(MRT DUMP, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filt
 CF_CLI(MRT DUMP, mrt_dump_args, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filter>|where <where filter>], [[Save mrt table dump v2 of table name <t> right now]])
 { mrt_dump_cmd($3); } ;
 
+CF_CLI_OPT(MRT DUMP TABLE, <name>|\"<pattern>\")
+CF_CLI_OPT(MRT DUMP TO, \"<file>\")
+CF_CLI_OPT(MRT DUMP FILTER, <filter>)
+CF_CLI_OPT(MRT DUMP WHERE, <where filter>)
+
 mrt_dump_args:
    /* empty */ { $$ = cfg_allocz(sizeof(struct mrt_dump_data)); }
  | mrt_dump_args TABLE rtable  { $$ = $1; $$->table_ptr = $3->table; }
index 71d9d05bfa366182dd33a491524b657508e84888..7d35304a6bbf92cbc771c189f56155796ca98a29 100644 (file)
@@ -546,6 +546,14 @@ CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area <id> | link] [type <num>] [ls
   ospf_sh_lsadb($4);
 };
 
+CF_CLI_OPT(SHOW OSPF LSADB GLOBAL)
+CF_CLI_OPT(SHOW OSPF LSADB AREA, <id>)
+CF_CLI_OPT(SHOW OSPF LSADB LINK)
+CF_CLI_OPT(SHOW OSPF LSADB TYPE, <num>)
+CF_CLI_OPT(SHOW OSPF LSADB LSID, <id>)
+CF_CLI_OPT(SHOW OSPF LSADB SELF)
+CF_CLI_OPT(SHOW OSPF LSADB ROUTER, <id>)
+
 lsadb_args:
    /* empty */ {
      $$ = cfg_allocz(sizeof(struct lsadb_show_data));