Support expansion of command abbreviations.
Client considered finished (modulo bugs).
This commit is contained in:
parent
de30342f97
commit
e69e4ed934
5 changed files with 80 additions and 34 deletions
19
TODO
19
TODO
|
@ -1,7 +1,5 @@
|
||||||
Core
|
Core
|
||||||
~~~~
|
~~~~
|
||||||
- IPv6: router advertisements
|
|
||||||
- IPv6: test it!
|
|
||||||
- IPv6: hashing functions etc.
|
- IPv6: hashing functions etc.
|
||||||
|
|
||||||
- krt-iface: check whether the interface alias hack works
|
- krt-iface: check whether the interface alias hack works
|
||||||
|
@ -36,21 +34,6 @@ Commands
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
- showing of routing table as seen by given protocol
|
- showing of routing table as seen by given protocol
|
||||||
|
|
||||||
Roadmap
|
|
||||||
~~~~~~~
|
|
||||||
- Allocators and data structures
|
|
||||||
- Client
|
|
||||||
- Remaining bits of IPv6 support (radvd)
|
|
||||||
- RIPv6
|
|
||||||
- BGP?
|
|
||||||
|
|
||||||
Client
|
|
||||||
~~~~~~
|
|
||||||
- command completion
|
|
||||||
- online help
|
|
||||||
- builtin command and aliases
|
|
||||||
- access control
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
- write doctool
|
- write doctool
|
||||||
|
@ -74,6 +57,8 @@ Globals
|
||||||
|
|
||||||
Various ideas
|
Various ideas
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
- client: access control
|
||||||
|
- IPv6 router advertisements
|
||||||
- real multipath (doesn't seem to be simple at all :()
|
- real multipath (doesn't seem to be simple at all :()
|
||||||
- fake multipath (even less simple)
|
- fake multipath (even less simple)
|
||||||
- route recalculation timing and flap dampening [see RFC2439 for algorithms]
|
- route recalculation timing and flap dampening [see RFC2439 for algorithms]
|
||||||
|
|
|
@ -79,6 +79,8 @@ extern Function *rl_last_func;
|
||||||
static void
|
static void
|
||||||
got_line(char *cmd_buffer)
|
got_line(char *cmd_buffer)
|
||||||
{
|
{
|
||||||
|
char *cmd;
|
||||||
|
|
||||||
if (!cmd_buffer)
|
if (!cmd_buffer)
|
||||||
{
|
{
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -86,12 +88,22 @@ got_line(char *cmd_buffer)
|
||||||
}
|
}
|
||||||
if (cmd_buffer[0])
|
if (cmd_buffer[0])
|
||||||
{
|
{
|
||||||
add_history(cmd_buffer);
|
cmd = cmd_expand(cmd_buffer);
|
||||||
/* FIXME: Builtin commands: exit, ... */
|
if (cmd)
|
||||||
server_send(cmd_buffer);
|
{
|
||||||
input_hidden = -1;
|
add_history(cmd);
|
||||||
io_loop(0);
|
puts(cmd);
|
||||||
input_hidden = 0;
|
if (!strcmp(cmd, "exit") || !strcmp(cmd, "quit"))
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
server_send(cmd);
|
||||||
|
input_hidden = -1;
|
||||||
|
io_loop(0);
|
||||||
|
input_hidden = 0;
|
||||||
|
free(cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(cmd_buffer);
|
free(cmd_buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,4 @@ void input_stop_list(void);
|
||||||
void cmd_build_tree(void);
|
void cmd_build_tree(void);
|
||||||
void cmd_help(char *cmd, int len);
|
void cmd_help(char *cmd, int len);
|
||||||
int cmd_complete(char *cmd, int len, char *buf, int again);
|
int cmd_complete(char *cmd, int len, char *buf, int again);
|
||||||
|
char *cmd_expand(char *cmd);
|
||||||
|
|
|
@ -25,8 +25,6 @@ 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 {
|
||||||
struct cmd_node *sibling, *son, **plastson;
|
struct cmd_node *sibling, *son, **plastson;
|
||||||
struct cmd_info *cmd, *help;
|
struct cmd_info *cmd, *help;
|
||||||
|
@ -53,7 +51,7 @@ cmd_build_tree(void)
|
||||||
while (*c)
|
while (*c)
|
||||||
{
|
{
|
||||||
char *d = c;
|
char *d = c;
|
||||||
while (*c && *c != ' ')
|
while (*c && !isspace(*c))
|
||||||
c++;
|
c++;
|
||||||
for(new=old->son; new; new=new->sibling)
|
for(new=old->son; new; new=new->sibling)
|
||||||
if (new->len == c-d && !memcmp(new->token, d, c-d))
|
if (new->len == c-d && !memcmp(new->token, d, c-d))
|
||||||
|
@ -70,7 +68,7 @@ cmd_build_tree(void)
|
||||||
memcpy(new->token, d, c-d);
|
memcpy(new->token, d, c-d);
|
||||||
}
|
}
|
||||||
old = new;
|
old = new;
|
||||||
while (*c == ' ')
|
while (isspace(*c))
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
if (cmd->is_real_cmd)
|
if (cmd->is_real_cmd)
|
||||||
|
@ -143,13 +141,13 @@ cmd_help(char *cmd, int len)
|
||||||
n = &cmd_root;
|
n = &cmd_root;
|
||||||
while (cmd < end)
|
while (cmd < end)
|
||||||
{
|
{
|
||||||
if (*cmd == ' ' || *cmd == '\t')
|
if (isspace(*cmd))
|
||||||
{
|
{
|
||||||
cmd++;
|
cmd++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
z = cmd;
|
z = cmd;
|
||||||
while (cmd < end && *cmd != ' ' && *cmd != '\t')
|
while (cmd < end && !isspace(*cmd))
|
||||||
cmd++;
|
cmd++;
|
||||||
m = cmd_find_abbrev(n, z, cmd-z, &ambig);
|
m = cmd_find_abbrev(n, z, cmd-z, &ambig);
|
||||||
if (ambig)
|
if (ambig)
|
||||||
|
@ -213,7 +211,7 @@ cmd_complete(char *cmd, int len, char *buf, int again)
|
||||||
n = &cmd_root;
|
n = &cmd_root;
|
||||||
while (cmd < fin && n->son)
|
while (cmd < fin && n->son)
|
||||||
{
|
{
|
||||||
if (*cmd == ' ' || *cmd == '\t')
|
if (isspace(*cmd))
|
||||||
{
|
{
|
||||||
cmd++;
|
cmd++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -262,3 +260,44 @@ cmd_complete(char *cmd, int len, char *buf, int again)
|
||||||
input_stop_list();
|
input_stop_list();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
cmd_expand(char *cmd)
|
||||||
|
{
|
||||||
|
struct cmd_node *n, *m;
|
||||||
|
char *c, *b, *args;
|
||||||
|
int ambig;
|
||||||
|
|
||||||
|
args = c = cmd;
|
||||||
|
n = &cmd_root;
|
||||||
|
while (*c)
|
||||||
|
{
|
||||||
|
if (isspace(*c))
|
||||||
|
{
|
||||||
|
c++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
b = c;
|
||||||
|
while (*c && !isspace(*c))
|
||||||
|
c++;
|
||||||
|
m = cmd_find_abbrev(n, b, c-b, &ambig);
|
||||||
|
if (!m)
|
||||||
|
{
|
||||||
|
if (!ambig)
|
||||||
|
break;
|
||||||
|
puts("Ambiguous command, possible expansions are:");
|
||||||
|
cmd_list_ambiguous(n, b, c-b);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
args = c;
|
||||||
|
n = m;
|
||||||
|
}
|
||||||
|
if (!n->cmd)
|
||||||
|
{
|
||||||
|
puts("No such command.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
b = malloc(strlen(n->cmd->command) + strlen(args) + 1);
|
||||||
|
sprintf(b, "%s%s", n->cmd->command, args);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
|
@ -12,11 +12,21 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
|
#include "lib/string.h"
|
||||||
#include "client/client.h"
|
#include "client/client.h"
|
||||||
|
|
||||||
/* Client versions of logging functions */
|
/* Client versions of logging functions */
|
||||||
|
|
||||||
/* FIXME: Use bsprintf, so that %m works */
|
static void
|
||||||
|
vlog(char *msg, va_list args)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if (bvsnprintf(buf, sizeof(buf)-1, msg, args) < 0)
|
||||||
|
bsprintf(buf + sizeof(buf) - 100, " ... <too long>");
|
||||||
|
fputs(buf, stderr);
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bug(char *msg, ...)
|
bug(char *msg, ...)
|
||||||
|
@ -26,8 +36,8 @@ bug(char *msg, ...)
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
cleanup();
|
cleanup();
|
||||||
fputs("Internal error: ", stderr);
|
fputs("Internal error: ", stderr);
|
||||||
|
vlog(msg, args);
|
||||||
vfprintf(stderr, msg, args);
|
vfprintf(stderr, msg, args);
|
||||||
fputc('\n', stderr);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +48,6 @@ die(char *msg, ...)
|
||||||
|
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
cleanup();
|
cleanup();
|
||||||
vfprintf(stderr, msg, args);
|
vlog(msg, args);
|
||||||
fputc('\n', stderr);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue