In bgpctl I am constantly hitting this annoying edgecase where adding detail to a show rib command errors out: bgpctl show rib 192.0.2.1 detail unknown argument: detail valid commands/args: <cr> all longer-prefixes or-longer or-shorter
The problem is that the t_show_prefix token table can not fall back to t_show_rib if an unknown token is seen. This diff solves this issue with the introduction of ANYTOKEN. ANYTOKEN matches if nothing previously matched and then redirects the call to the next table (which is pointing back up). To make show_valid_args() work nicely dump store the first table on ANYTOKEN and dump the help for that one first. I don't think there is a need to have a stack of tables since ANYTOKEN should be used sparingly. With this 'bgpctl show rib 192.0.2.1 detail' works. -- :wq Claudio Index: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v retrieving revision 1.124 diff -u -p -r1.124 parser.c --- parser.c 13 Apr 2023 11:52:43 -0000 1.124 +++ parser.c 15 Apr 2023 08:34:25 -0000 @@ -34,8 +34,9 @@ #include "parser.h" enum token_type { - NOTOKEN, ENDTOKEN, + NOTOKEN, + ANYTOKEN, KEYWORD, ADDRESS, PEERADDRESS, @@ -72,6 +73,8 @@ struct token { const struct token *next; }; +static const struct token *prevtable; + static const struct token t_main[]; static const struct token t_show[]; static const struct token t_show_summary[]; @@ -320,11 +323,11 @@ static const struct token t_show_mrt_as[ }; static const struct token t_show_prefix[] = { - { NOTOKEN, "", NONE, NULL}, - { FLAG, "all", F_LONGER, NULL}, - { FLAG, "longer-prefixes", F_LONGER, NULL}, - { FLAG, "or-longer", F_LONGER, NULL}, - { FLAG, "or-shorter", F_SHORTER, NULL}, + { FLAG, "all", F_LONGER, t_show_rib}, + { FLAG, "longer-prefixes", F_LONGER, t_show_rib}, + { FLAG, "or-longer", F_LONGER, t_show_rib}, + { FLAG, "or-shorter", F_SHORTER, t_show_rib}, + { ANYTOKEN, "", NONE, t_show_rib}, { ENDTOKEN, "", NONE, NULL} }; @@ -533,6 +536,12 @@ parse(int argc, char *argv[]) show_valid_args(table); return (NULL); } + if (match->type == ANYTOKEN) { + if (prevtable == NULL) + prevtable = table; + table = match->next; + continue; + } argc--; argv++; @@ -571,6 +580,13 @@ match_token(int *argc, char **argv[], co t = &table[i]; } break; + case ANYTOKEN: + /* match anything if nothing else matched before */ + if (match == 0) { + match++; + t = &table[i]; + } + break; case KEYWORD: if (word != NULL && strncmp(word, table[i].keyword, wordlen) == 0) { @@ -842,10 +858,19 @@ show_valid_args(const struct token table { int i; + if (prevtable != NULL) { + const struct token *t = prevtable; + prevtable = NULL; + show_valid_args(t); + fprintf(stderr, "or any of\n"); + } + for (i = 0; table[i].type != ENDTOKEN; i++) { switch (table[i].type) { case NOTOKEN: fprintf(stderr, " <cr>\n"); + break; + case ANYTOKEN: break; case KEYWORD: case FLAG: