mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
Bash completion for Bird client and daemon.
This commit is contained in:
parent
d19617f06b
commit
5b8eb44c14
54
bird-complete.bash
Normal file
54
bird-complete.bash
Normal file
@ -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
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/* 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);
|
||||
char *cmd_expand(char *cmd);
|
||||
|
||||
/* client.c */
|
||||
|
||||
void submit_command(char *cmd_raw);
|
||||
|
||||
/* commands.c */
|
||||
|
||||
void cmd_build_tree(void);
|
||||
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);
|
||||
|
||||
/* complete.c */
|
||||
|
||||
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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
122
client/complete.c
Normal file
122
client/complete.c
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user