]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Completion works. Unfortunately, we have to access a couple of internal
authorMartin Mares <mj@ucw.cz>
Thu, 17 Feb 2000 23:37:16 +0000 (23:37 +0000)
committerMartin Mares <mj@ucw.cz>
Thu, 17 Feb 2000 23:37:16 +0000 (23:37 +0000)
symbols of libreadline :-(

client/client.c
client/client.h
client/commands.c
nest/config.Y

index b9e3ab8184a2d987ecf68245cef6551271837874..9c6b4ae901fb14690e00fd3ab046c810d5cc925a 100644 (file)
@@ -71,6 +71,11 @@ parse_args(int argc, char **argv)
 static void server_send(char *);
 static void io_loop(int);
 
+/* HACK: libreadline internals we need to access */
+extern int _rl_vis_botlin;
+extern void _rl_move_vert(int);
+extern Function *rl_last_func;
+
 static void
 got_line(char *cmd_buffer)
 {
@@ -91,10 +96,40 @@ got_line(char *cmd_buffer)
   free(cmd_buffer);
 }
 
+void
+input_start_list(void)                 /* Leave the currently edited line and make space for listing */
+{
+  _rl_move_vert(_rl_vis_botlin);
+  crlf();
+}
+
+void
+input_stop_list(void)                  /* Reprint the currently edited line after listing */
+{
+  rl_on_new_line();
+  rl_redisplay();
+}
+
 static int
 input_complete(int arg, int key)
 {
-  ding();
+  static int complete_flag;
+  char buf[256];
+
+  if (rl_last_func != input_complete)
+    complete_flag = 0;
+  switch (cmd_complete(rl_line_buffer, rl_point, buf, complete_flag))
+    {
+    case 0:
+      complete_flag = 1;
+      break;
+    case 1:
+      rl_insert_text(buf);
+      break;
+    default:
+      complete_flag = 1;
+      ding();
+    }
   return 0;
 }
 
@@ -103,22 +138,26 @@ input_help(int arg, int key)
 {
   int i = 0;
 
-  if (rl_point != rl_end || arg != 1)
+  if (arg != 1)
     return rl_insert(arg, '?');
-  while (i < rl_end)
+  while (i < rl_point)
     {
       if (rl_line_buffer[i++] == '"')
        do
          {
-           if (i >= rl_end)            /* `?' inside quoted string -> insert */
+           if (i >= rl_point)          /* `?' 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_begin_undo_group();               /* HACK: We want to display `?' at point position */
+  rl_insert_text("?");
   rl_redisplay();
+  rl_end_undo_group();
+  input_start_list();
+  cmd_help(rl_line_buffer, rl_point);
+  rl_undo_command(1, 0);
+  input_stop_list();
   return 0;
 }
 
index a9c990357a99fa3239cc3d3dfbdc1a0dd21e23c5..f63c75c3f75536b81d6355cc97785e6bc8343ad4 100644 (file)
@@ -9,8 +9,11 @@
 /* client.c */
 
 void cleanup(void);
+void input_start_list(void);
+void input_stop_list(void);
 
 /* commands.c */
 
 void cmd_build_tree(void);
 void cmd_help(char *cmd, int len);
+int cmd_complete(char *cmd, int len, char *buf, int again);
index ceb036b1c769e987f6e9af40e5034c572e002560..09c5c344369ac5ca069ec71e0ada906bf12b9252 100644 (file)
@@ -7,6 +7,8 @@
  */
 
 #include <stdio.h>
+#include <string.h>
+#include <ctype.h>
 
 #include "nest/bird.h"
 #include "lib/resource.h"
@@ -27,7 +29,7 @@ static struct cmd_info command_table[] = {
 
 struct cmd_node {
   struct cmd_node *sibling, *son, **plastson;
-  struct cmd_info *cmd;
+  struct cmd_info *cmd, *help;
   int len;
   char token[1];
 };
@@ -58,26 +60,28 @@ cmd_build_tree(void)
              break;
          if (!new)
            {
-             new = xmalloc(sizeof(struct cmd_node) + c-d);
+             int size = sizeof(struct cmd_node) + c-d;
+             new = xmalloc(size);
+             bzero(new, size);
              *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;
+      if (cmd->is_real_cmd)
+       old->cmd = cmd;
+      else
+       old->help = cmd;
     }
 }
 
 static void
-cmd_display_help(struct cmd_info *c)
+cmd_do_display_help(struct cmd_info *c)
 {
   char buf[strlen(c->command) + strlen(c->args) + 4];
 
@@ -85,11 +89,21 @@ cmd_display_help(struct cmd_info *c)
   printf("%-45s  %s\n", buf, c->help);
 }
 
+static void
+cmd_display_help(struct cmd_info *c1, struct cmd_info *c2)
+{
+  if (c1)
+    cmd_do_display_help(c1);
+  else if (c2)
+    cmd_do_display_help(c2);
+}
+
 static struct cmd_node *
-cmd_find_abbrev(struct cmd_node *root, char *cmd, int len)
+cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
 {
   struct cmd_node *m, *best = NULL, *best2 = NULL;
 
+  *pambiguous = 0;
   for(m=root->son; m; m=m->sibling)
     {
       if (m->len == len && !memcmp(m->token, cmd, len))
@@ -100,7 +114,22 @@ cmd_find_abbrev(struct cmd_node *root, char *cmd, int len)
          best = m;
        }
     }
-  return best2 ? NULL : best;
+  if (best2)
+    {
+      *pambiguous = 1;
+      return NULL;
+    }
+  return best;
+}
+
+static void
+cmd_list_ambiguous(struct cmd_node *root, char *cmd, int len)
+{
+  struct cmd_node *m;
+
+  for(m=root->son; m; m=m->sibling)
+    if (m->len > len && !memcmp(m->token, cmd, len))   
+      cmd_display_help(m->help, m->cmd);
 }
 
 void
@@ -109,6 +138,7 @@ cmd_help(char *cmd, int len)
   char *end = cmd + len;
   struct cmd_node *n, *m;
   char *z;
+  int ambig;
 
   n = &cmd_root;
   while (cmd < end)
@@ -121,13 +151,114 @@ cmd_help(char *cmd, int len)
       z = cmd;
       while (cmd < end && *cmd != ' ' && *cmd != '\t')
        cmd++;
-      m = cmd_find_abbrev(n, z, cmd-z);
+      m = cmd_find_abbrev(n, z, cmd-z, &ambig);
+      if (ambig)
+       {
+         cmd_list_ambiguous(n, z, cmd-z);
+         return;
+       }
       if (!m)
        break;
       n = m;
     }
-  if (n->cmd && n->cmd->is_real_cmd)
-    cmd_display_help(n->cmd);
+  cmd_display_help(n->cmd, NULL);
   for (m=n->son; m; m=m->sibling)
-    cmd_display_help(m->cmd);
+    cmd_display_help(m->help, m->cmd);
+}
+
+static int
+cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, char *buf)
+{
+  struct cmd_node *m;
+  int best, i;
+
+  *pcount = 0;
+  best = -1;
+  for(m=root->son; m; m=m->sibling)
+    {
+      if (m->len < len || memcmp(m->token, cmd, len))
+       continue;
+      (*pcount)++;
+      if (best < 0)
+       {
+         strcpy(buf, m->token + len);
+         best = m->len - len;
+       }
+      else
+       {
+         i = 0;
+         while (i < best && i < m->len - len && buf[i] == m->token[len+i])
+           i++;
+         best = i;
+       }
+    }
+  return best;
+}
+
+int
+cmd_complete(char *cmd, int len, char *buf, int again)
+{
+  char *start = cmd;
+  char *end = cmd + len;
+  char *fin;
+  struct cmd_node *n, *m;
+  char *z;
+  int ambig, cnt = 0, common;
+
+  /* Find the last word we want to complete */
+  for(fin=end; fin > start && !isspace(fin[-1]); fin--)
+    ;
+
+  /* Find the context */
+  n = &cmd_root;
+  while (cmd < fin && n->son)
+    {
+      if (*cmd == ' ' || *cmd == '\t')
+       {
+         cmd++;
+         continue;
+       }
+      z = cmd;
+      while (cmd < fin && !isspace(*cmd))
+       cmd++;
+      m = cmd_find_abbrev(n, z, cmd-z, &ambig);
+      if (ambig)
+       {
+         if (!again)
+           return -1;
+         input_start_list();
+         cmd_list_ambiguous(n, z, cmd-z);
+         input_stop_list();
+         return 0;
+       }
+      if (!m)
+       return -1;
+      n = m;
+    }
+
+  /* Completion of parameters is not yet supported */
+  if (!n->son)
+    return -1;
+
+  /* We know the context, let's try to complete */
+  common = cmd_find_common_match(n, fin, end-fin, &cnt, buf);
+  if (!cnt)
+    return -1;
+  if (cnt == 1)
+    {
+      buf[common++] = ' ';
+      buf[common] = 0;
+      return 1;
+    }
+  if (common > 0)
+    {
+      buf[common] = 0;
+      return 1;
+    }
+  if (!again)
+    return -1;
+  input_start_list();
+  cmd_list_ambiguous(n, fin, end-fin);
+  input_stop_list();
+  return 0;
 }
index d5fdc4e1d68128307c1b580de62bfaad3f514d72..bc2a3fec438e27da41e1d6fc45cad43b3a18e41f 100644 (file)
@@ -192,7 +192,7 @@ password_list:
 
 /* Core commands */
 
-CF_CLI_HELP(SHOW,,[[Show status information]])
+CF_CLI_HELP(SHOW, ..., [[Show status information]])
 
 CF_CLI(SHOW STATUS,,, [[Show router status]])
 { cmd_show_status(); }
@@ -255,7 +255,7 @@ r_args:
 CF_CLI(SHOW SYMBOLS, optsym, [<symbol>], [[Show all known symbolic names]])
 { cmd_show_symbols($3); } ;
 
-CF_CLI_HELP(DEBUG, <subsystem>, [[Show debugging information]])
+CF_CLI_HELP(DEBUG, ..., [[Show debugging information]])
 CF_CLI(DEBUG RESOURCES,,, [[Show all allocated resource]])
 { rdump(&root_pool); cli_msg(0, ""); } ;
 CF_CLI(DEBUG SOCKETS,,, [[Show open sockets]])