]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Client: Online help works (Cisco style: just press `?' at the end of a line).
authorMartin Mares <mj@ucw.cz>
Thu, 17 Feb 2000 22:00:13 +0000 (22:00 +0000)
committerMartin Mares <mj@ucw.cz>
Thu, 17 Feb 2000 22:00:13 +0000 (22:00 +0000)
client/client.c
client/client.h
client/commands.c
conf/gen_commands.m4

index 50335e4fb8deeb9f87c41d3af71ba6da449145ac..b9e3ab8184a2d987ecf68245cef6551271837874 100644 (file)
@@ -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);
 
index f0edeeb531361b9d23175db5299e319269e86729..a9c990357a99fa3239cc3d3dfbdc1a0dd21e23c5 100644 (file)
@@ -9,3 +9,8 @@
 /* client.c */
 
 void cleanup(void);
+
+/* commands.c */
+
+void cmd_build_tree(void);
+void cmd_help(char *cmd, int len);
index ea9358d83cbc2c0f19622b717863eacff88b8820..ceb036b1c769e987f6e9af40e5034c572e002560 100644 (file)
  *     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);
+}
index cba10b40b9dc1f5f42715de4ca8d8c72af36caff..a88ba014c5c3862d9cad23afd5b3a366186fd761 100644 (file)
@@ -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