diff options
author | Martin Mares <mj@ucw.cz> | 2000-02-17 22:00:13 +0000 |
---|---|---|
committer | Martin Mares <mj@ucw.cz> | 2000-02-17 22:00:13 +0000 |
commit | 0223d4fff11badc03470b4320fa9dfe28afd1bed (patch) | |
tree | b4281ed75395e0f219c3dc7fb2cc97f6282769db /client/commands.c | |
parent | c51f132d582632037b4ef064fbd32d785af245fc (diff) |
Client: Online help works (Cisco style: just press `?' at the end of a line).
Diffstat (limited to 'client/commands.c')
-rw-r--r-- | client/commands.c | 115 |
1 files changed, 114 insertions, 1 deletions
diff --git a/client/commands.c b/client/commands.c index ea9358d8..ceb036b1 100644 --- a/client/commands.c +++ b/client/commands.c @@ -6,15 +6,128 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +#include <stdio.h> + #include "nest/bird.h" +#include "lib/resource.h" #include "client/client.h" struct cmd_info { char *command; char *args; char *help; + int is_real_cmd; }; -struct cmd_info command_table[] = { +static struct cmd_info command_table[] = { #include "conf/commands.h" }; + +/* FIXME: There should exist some system of aliases, so that `show' can be abbreviated as `s' etc. */ + +struct cmd_node { + struct cmd_node *sibling, *son, **plastson; + struct cmd_info *cmd; + int len; + char token[1]; +}; + +static struct cmd_node cmd_root; + +void +cmd_build_tree(void) +{ + unsigned int i; + + cmd_root.plastson = &cmd_root.son; + + for(i=0; i<sizeof(command_table) / sizeof(struct cmd_info); i++) + { + struct cmd_info *cmd = &command_table[i]; + struct cmd_node *old, *new; + char *c = cmd->command; + + old = &cmd_root; + while (*c) + { + char *d = c; + while (*c && *c != ' ') + c++; + for(new=old->son; new; new=new->sibling) + if (new->len == c-d && !memcmp(new->token, d, c-d)) + break; + if (!new) + { + new = xmalloc(sizeof(struct cmd_node) + c-d); + *old->plastson = new; + old->plastson = &new->sibling; + new->sibling = new->son = NULL; + new->plastson = &new->son; + new->cmd = NULL; + new->len = c-d; + memcpy(new->token, d, c-d); + new->token[c-d] = 0; + } + old = new; + while (*c == ' ') + c++; + } + old->cmd = cmd; + } +} + +static void +cmd_display_help(struct cmd_info *c) +{ + char buf[strlen(c->command) + strlen(c->args) + 4]; + + sprintf(buf, "%s %s", c->command, c->args); + printf("%-45s %s\n", buf, c->help); +} + +static struct cmd_node * +cmd_find_abbrev(struct cmd_node *root, char *cmd, int len) +{ + struct cmd_node *m, *best = NULL, *best2 = NULL; + + for(m=root->son; m; m=m->sibling) + { + if (m->len == len && !memcmp(m->token, cmd, len)) + return m; + if (m->len > len && !memcmp(m->token, cmd, len)) + { + best2 = best; + best = m; + } + } + return best2 ? NULL : best; +} + +void +cmd_help(char *cmd, int len) +{ + char *end = cmd + len; + struct cmd_node *n, *m; + char *z; + + n = &cmd_root; + while (cmd < end) + { + if (*cmd == ' ' || *cmd == '\t') + { + cmd++; + continue; + } + z = cmd; + while (cmd < end && *cmd != ' ' && *cmd != '\t') + cmd++; + m = cmd_find_abbrev(n, z, cmd-z); + if (!m) + break; + n = m; + } + if (n->cmd && n->cmd->is_real_cmd) + cmd_display_help(n->cmd); + for (m=n->son; m; m=m->sibling) + cmd_display_help(m->cmd); +} |