summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2024-03-05 19:04:10 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2024-03-05 19:04:10 +0100
commit1b064355f752b9bfe4644f775697bbd9b711f762 (patch)
tree8f3995f1b7450ddbc6309a18fc5e80bc25fdb31b
parent114be2af28e5c124bd479a487f89244ba99c272d (diff)
Client: Add support for completion of command options
We can easily extend command completion to handle also keywords for command options. Help for command options is not yet supported.
-rw-r--r--client/commands.c27
-rw-r--r--conf/gen_commands.m43
-rw-r--r--conf/gen_parser.m41
-rw-r--r--nest/config.Y34
-rw-r--r--proto/bfd/config.Y9
-rw-r--r--proto/mrt/config.Y5
-rw-r--r--proto/ospf/config.Y8
7 files changed, 78 insertions, 9 deletions
diff --git a/client/commands.c b/client/commands.c
index fdf2652a..318f0ecd 100644
--- a/client/commands.c
+++ b/client/commands.c
@@ -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))
{
diff --git a/conf/gen_commands.m4 b/conf/gen_commands.m4
index 3ed21f13..daf39da6 100644
--- a/conf/gen_commands.m4
+++ b/conf/gen_commands.m4
@@ -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)')
diff --git a/conf/gen_parser.m4 b/conf/gen_parser.m4
index 80071aef..48c2ca50 100644
--- a/conf/gen_parser.m4
+++ b/conf/gen_parser.m4
@@ -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
diff --git a/nest/config.Y b/nest/config.Y
index 63888a04..20186ece 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -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); }
diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y
index 4edc13d9..1a7474b0 100644
--- a/proto/bfd/config.Y
+++ b/proto/bfd/config.Y
@@ -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; }
diff --git a/proto/mrt/config.Y b/proto/mrt/config.Y
index 4da6777a..d2136ed1 100644
--- a/proto/mrt/config.Y
+++ b/proto/mrt/config.Y
@@ -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; }
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 71d9d05b..7d35304a 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -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));