]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Bash completion for Bird client and daemon.
authorJan Moskyto Matejka <mq@ucw.cz>
Wed, 17 May 2017 15:15:42 +0000 (17:15 +0200)
committerJan Moskyto Matejka <mq@ucw.cz>
Wed, 17 May 2017 15:17:00 +0000 (17:17 +0200)
bird-complete.bash [new file with mode: 0644]
client/Makefile
client/client.c
client/client.h
client/commands.c
client/complete.c [new file with mode: 0644]

diff --git a/bird-complete.bash b/bird-complete.bash
new file mode 100644 (file)
index 0000000..16795da
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+function _bird_complete {
+  CMD=$1
+  NOW=$2
+  PREV=$3
+
+  case $PREV in
+    -c|-D|-P|-s)
+      COMPREPLY=( $(compgen -f -- $NOW) )
+      ;;
+    -g)
+      COMPREPLY=( $(compgen -g -- $NOW) )
+      ;;
+    -u)
+      COMPREPLY=( $(compgen -u -- $NOW) )
+      ;;
+    *)
+      COMPREPLY=( $(compgen -W '-c -d -D -f -g -h -l -p -P -R -s -u --help --version' -- $NOW) )
+      ;;
+  esac
+}
+
+function _birdc_complete {
+  CMD=$1
+  NOW=$2
+  PREV=$3
+
+  echo "bagr" >>xxb
+
+  case $PREV in
+    -*([lvr])s)
+      COMPREPLY=( $(compgen -W "$(find -maxdepth 1 -type s)" -- $NOW) )
+      return
+      ;;
+  esac
+  
+  case $NOW in
+    -*([lvr])s)
+      COMPREPLY=( $(compgen -W "$(find -maxdepth 1 -type s | sed 's#^#'$NOW'#') ${NOW}l ${NOW}r ${NOW}v" -- $NOW) )
+      return
+      ;;
+    -*)
+      COMPREPLY=( $(compgen -W "${NOW}l ${NOW}v ${NOW}r ${NOW}s") )
+      return
+      ;;
+  esac
+
+  COMPREPLY=( $($CMD -C "$NOW" "$COMP_TYPE" "$COMP_CWORD" "$COMP_POINT" "${COMP_WORDS[@]}") )
+}
+
+complete -F _bird_complete bird
+complete -F _birdc_complete birdc
+complete -F _birdc_complete birdcl
index fccb83463a18fdaa0cf77d5dbeb65dbe0315c906..0584c206e778c7d9fd866d06faafb721b3e4ae50 100644 (file)
@@ -1,4 +1,4 @@
-src := commands.c util.c client.c
+src := commands.c util.c client.c complete.c
 obj := $(src-o-files)
 
 $(all-client)
index 0d4bdf3e54f17065d3d9b553b37caf00530f173e..032c7fe2e941846f09f97f9447f376701706f3ea 100644 (file)
@@ -49,6 +49,7 @@ static byte *server_read_pos = server_read_buf;
 int init = 1;          /* During intial sequence */
 int busy = 1;          /* Executing BIRD command */
 int interactive;       /* Whether stdin is terminal */
+int complete = 0;
 
 static int num_lines, skip_input;
 int term_lns, term_cls;
@@ -69,6 +70,13 @@ parse_args(int argc, char **argv)
   int server_changed = 0;
   int c;
 
+  if ((argc > 1) && !strcmp(argv[1], "-C")) {
+    complete_init(argc-2, argv+2);
+    argv += 6;
+    argc -= 6;
+    complete = 1;
+  }
+
   while ((c = getopt(argc, argv, opt_list)) >= 0)
     switch (c)
       {
@@ -87,6 +95,8 @@ parse_args(int argc, char **argv)
          server_path = xbasename(server_path);
        break;
       default:
+       if (complete)
+         exit(0);
        usage(argv[0]);
       }
 
@@ -442,6 +452,10 @@ main(int argc, char **argv)
   interactive = isatty(0);
   parse_args(argc, argv);
   cmd_build_tree();
+
+  if (complete)
+    return do_complete(init_cmd);
+
   server_connect();
   select_loop();
   return 0;
index f9693def0491ce56bc6ea23cec6dc116b21ff51c..7e2c438a8a6f75964e7378de9541b68e5978bc8e 100644 (file)
@@ -6,8 +6,7 @@
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
 
-
-extern int init, busy, interactive;
+extern int init, busy, interactive, complete;
 extern int term_lns, term_cls;
 
 /* birdc.c / birdcl.c */
@@ -24,16 +23,21 @@ void more_end(void);
 
 void cleanup(void);
 
+/* client.c */
+
+void submit_command(char *cmd_raw);
+
 /* 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);
+void cmd_help(const char *cmd, int len);
+int cmd_complete(const char *cmd, int len, char *buf, int again);
 char *cmd_expand(char *cmd);
 
-/* client.c */
+/* complete.c */
 
-void submit_command(char *cmd_raw);
+void complete_init(int argc, char **argv);
+int do_complete(char *cmd);
 
 /* die() with system error messages */
 #define DIE(x, y...) die(x ": %s", ##y, strerror(errno))
index f2134c1bb98a465d8043894c557f7f546cb00b30..84fcc89d23027079eb3dcd6247281520d5b079f3 100644 (file)
@@ -100,7 +100,7 @@ cmd_display_help(struct cmd_info *c1, struct cmd_info *c2)
 }
 
 static struct cmd_node *
-cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
+cmd_find_abbrev(struct cmd_node *root, const char *cmd, int len, int *pambiguous)
 {
   struct cmd_node *m, *best = NULL, *best2 = NULL;
 
@@ -127,21 +127,24 @@ cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
 }
 
 static void
-cmd_list_ambiguous(struct cmd_node *root, char *cmd, int len)
+cmd_list_ambiguous(struct cmd_node *root, const 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);
+    if (m->len > len && !memcmp(m->token, cmd, len))
+      if (complete)
+       printf("%s\n", m->token);
+      else
+       cmd_display_help(m->help, m->cmd);
 }
 
 void
-cmd_help(char *cmd, int len)
+cmd_help(const char *cmd, int len)
 {
-  char *end = cmd + len;
+  const char *end = cmd + len;
   struct cmd_node *n, *m;
-  char *z;
+  const char *z;
   int ambig;
 
   n = &cmd_root;
@@ -171,7 +174,7 @@ cmd_help(char *cmd, int len)
 }
 
 static int
-cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, char *buf)
+cmd_find_common_match(struct cmd_node *root, const char *cmd, int len, int *pcount, char *buf)
 {
   struct cmd_node *m;
   int best, best_prio, i;
@@ -212,13 +215,13 @@ cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, ch
 }
 
 int
-cmd_complete(char *cmd, int len, char *buf, int again)
+cmd_complete(const char *cmd, int len, char *buf, int again)
 {
-  char *start = cmd;
-  char *end = cmd + len;
-  char *fin;
+  const char *start = cmd;
+  const char *end = cmd + len;
+  const char *fin;
   struct cmd_node *n, *m;
-  char *z;
+  const char *z;
   int ambig, cnt = 0, common;
 
   /* Find the last word we want to complete */
@@ -242,9 +245,11 @@ cmd_complete(char *cmd, int len, char *buf, int again)
        {
          if (!again)
            return -1;
-         input_start_list();
+         if (!complete)
+           input_start_list();
          cmd_list_ambiguous(n, z, cmd-z);
-         input_stop_list();
+         if (!complete)
+           input_stop_list();
          return 0;
        }
       if (!m)
@@ -273,9 +278,11 @@ cmd_complete(char *cmd, int len, char *buf, int again)
     }
   if (!again)
     return -1;
-  input_start_list();
+  if (!complete)
+    input_start_list();
   cmd_list_ambiguous(n, fin, end-fin);
-  input_stop_list();
+  if (!complete)
+    input_stop_list();
   return 0;
 }
 
diff --git a/client/complete.c b/client/complete.c
new file mode 100644 (file)
index 0000000..4e478b9
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *     BIRD Client Bash Expansion
+ *
+ *     (c) 2017       Jan Moskyto Matejka <mq@jmq.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nest/bird.h"
+#include "client/client.h"
+
+static const char *c_now;
+static int comp_type, comp_cword, comp_point;
+
+void complete_init(int argc, char **argv) {
+  /* In argv, there are:
+   * $NOW
+   * $COMP_TYPE
+   * $COMP_CWORD
+   * $COMP_POINT
+   * ${COMP_WORDS[@]}
+   */
+
+  c_now = argv[0];
+
+  if (argc < 4)
+    die("Not enough args.");
+
+  if (sscanf(argv[1], "%d", &comp_type) != 1)
+    die("Strange COMP_TYPE=\"%s\".", argv[1]);
+
+  if (sscanf(argv[2], "%d", &comp_cword) != 1)
+    die("Strange COMP_CWORD=\"%s\".", argv[2]);
+
+  if (sscanf(argv[3], "%d", &comp_point) != 1)
+    die("Strange COMP_POINT=\"%s\".", argv[3]);
+
+  return;
+}
+
+int do_complete(char *cmd) {
+  if ((*cmd == 0) && (comp_type == 63))
+    printf("-s\n-l\n-v\n-r\n");
+
+  char buf[256];
+  int res = cmd_complete(cmd, strlen(cmd), buf, (comp_type == 63));
+  if (res == 1)
+    printf("%s%s\n", c_now, buf);
+
+    
+  return 0;
+}
+
+#if 0
+
+  /* Environment and input check */
+  if (!comp_line || !index(comp_line, ' '))
+    die("Environment variable COMP_LINE not found.");
+
+  /* Drop the command name */
+  comp_line = index(comp_line, ' ') + 1;
+
+  /* StrTok copy */
+  char *clt = strdup(comp_line);
+  char *tok = strtok(clt, " ");
+  do {
+    if (!tok)
+      break;
+    if (!tok[0])
+      goto next;
+
+    if (want_socket) {
+      opt_s = tok;
+      goto next;
+    }
+
+    if (tok[0] == '-')
+      switch(tok[1]) {
+       case 's':
+         if (tok[2])
+           opt_s = tok+2;
+         else
+           want_socket = 1;
+         goto next;
+       case 'v':
+         opt_v++;
+         goto next;
+       case 'r':
+         opt_r++;
+         goto next;
+       case 'l':
+         opt_l++;
+         goto next;
+       default:
+         return 0;
+      }
+
+next:
+    tok = strtok(NULL, " ");
+  } while (tok);
+  
+
+
+  fprintf(stderr, "KEY \"%s\"\nLINE \"%s\"\nPOINT \"%s\"\nTYPE \"%s\"\n",
+      comp_key, comp_line, comp_point, comp_type);
+
+  char buf[256];
+  int result = cmd_complete(comp_line, atoi(comp_point), buf, 0);
+
+  if (result < 0)
+    return 0;
+
+  puts(buf);
+
+  return 0;
+}
+#endif