mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	Client: Online help works (Cisco style: just press `?' at the end of a line).
This commit is contained in:
		@@ -91,10 +91,43 @@ got_line(char *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
 | 
			
		||||
input_init(void)
 | 
			
		||||
{
 | 
			
		||||
  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);
 | 
			
		||||
  input_initialized = 1;
 | 
			
		||||
  if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
 | 
			
		||||
@@ -282,6 +315,7 @@ main(int argc, char **argv)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  parse_args(argc, argv);
 | 
			
		||||
  cmd_build_tree();
 | 
			
		||||
  server_connect();
 | 
			
		||||
  io_loop(0);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,3 +9,8 @@
 | 
			
		||||
/* client.c */
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,10 @@ m4_divert(-1)m4_dnl
 | 
			
		||||
#	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)')
 | 
			
		||||
 | 
			
		||||
# As we are processing C source, we must access all M4 primitives via
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user