--- /dev/null
+#!/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
-src := commands.c util.c client.c
+src := commands.c util.c client.c complete.c
obj := $(src-o-files)
$(all-client)
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;
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)
{
server_path = xbasename(server_path);
break;
default:
+ if (complete)
+ exit(0);
usage(argv[0]);
}
interactive = isatty(0);
parse_args(argc, argv);
cmd_build_tree();
+
+ if (complete)
+ return do_complete(init_cmd);
+
server_connect();
select_loop();
return 0;
* 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 */
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))
}
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;
}
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;
}
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;
}
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 */
{
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)
}
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;
}
--- /dev/null
+/*
+ * 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