Client: Online help works (Cisco style: just press `?' at the end of a line).
This commit is contained in:
parent
c51f132d58
commit
0223d4fff1
4 changed files with 156 additions and 3 deletions
|
@ -91,10 +91,43 @@ got_line(char *cmd_buffer)
|
||||||
free(cmd_buffer);
|
free(cmd_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
input_complete(int arg, int key)
|
||||||
|
{
|
||||||
|
ding();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
input_help(int arg, int key)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (rl_point != rl_end || arg != 1)
|
||||||
|
return rl_insert(arg, '?');
|
||||||
|
while (i < rl_end)
|
||||||
|
{
|
||||||
|
if (rl_line_buffer[i++] == '"')
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (i >= rl_end) /* `?' inside quoted string -> insert */
|
||||||
|
return rl_insert(1, '?');
|
||||||
|
}
|
||||||
|
while (rl_line_buffer[i++] != '"');
|
||||||
|
}
|
||||||
|
puts("?");
|
||||||
|
cmd_help(rl_line_buffer, rl_end);
|
||||||
|
rl_on_new_line();
|
||||||
|
rl_redisplay();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_init(void)
|
input_init(void)
|
||||||
{
|
{
|
||||||
rl_readline_name = "birdc";
|
rl_readline_name = "birdc";
|
||||||
|
rl_add_defun("bird-complete", input_complete, '\t');
|
||||||
|
rl_add_defun("bird-help", input_help, '?');
|
||||||
rl_callback_handler_install("bird> ", got_line);
|
rl_callback_handler_install("bird> ", got_line);
|
||||||
input_initialized = 1;
|
input_initialized = 1;
|
||||||
if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
|
if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
|
||||||
|
@ -282,6 +315,7 @@ main(int argc, char **argv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
|
cmd_build_tree();
|
||||||
server_connect();
|
server_connect();
|
||||||
io_loop(0);
|
io_loop(0);
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,8 @@
|
||||||
/* client.c */
|
/* client.c */
|
||||||
|
|
||||||
void cleanup(void);
|
void cleanup(void);
|
||||||
|
|
||||||
|
/* commands.c */
|
||||||
|
|
||||||
|
void cmd_build_tree(void);
|
||||||
|
void cmd_help(char *cmd, int len);
|
||||||
|
|
|
@ -6,15 +6,128 @@
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
|
#include "lib/resource.h"
|
||||||
#include "client/client.h"
|
#include "client/client.h"
|
||||||
|
|
||||||
struct cmd_info {
|
struct cmd_info {
|
||||||
char *command;
|
char *command;
|
||||||
char *args;
|
char *args;
|
||||||
char *help;
|
char *help;
|
||||||
|
int is_real_cmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmd_info command_table[] = {
|
static struct cmd_info command_table[] = {
|
||||||
#include "conf/commands.h"
|
#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);
|
||||||
|
}
|
||||||
|
|
|
@ -7,9 +7,10 @@ m4_divert(-1)m4_dnl
|
||||||
# Can be freely distributed and used under the terms of the GNU GPL.
|
# Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
#
|
#
|
||||||
|
|
||||||
m4_define(CF_CLI, `CF_CLI_HELP($1, $3, $4)')
|
m4_define(CF_CLI, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$3", "$4", 1 },
|
||||||
|
m4_divert(-1)')
|
||||||
|
|
||||||
m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3" },
|
m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 0 },
|
||||||
m4_divert(-1)')
|
m4_divert(-1)')
|
||||||
|
|
||||||
# As we are processing C source, we must access all M4 primitives via
|
# As we are processing C source, we must access all M4 primitives via
|
||||||
|
|
Loading…
Reference in a new issue