From: David Woodhouse Date: Wed, 8 Apr 2020 14:15:00 +0000 (+0100) Subject: Fix autocompletion a bit more, add tests X-Git-Tag: v8.09~25 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=8b83e3714697afae0740884ac332debe074d17f9;p=users%2Fdwmw2%2Fopenconnect.git Fix autocompletion a bit more, add tests Signed-off-by: David Woodhouse --- diff --git a/bash/openconnect.bash b/bash/openconnect.bash index 89d55ee7..2424fe41 100644 --- a/bash/openconnect.bash +++ b/bash/openconnect.bash @@ -76,7 +76,7 @@ _complete_openconnect () { export COMP_LINE COMP_POINT COMP_CWORD COMP_KEY COMP_TYPE COMP_WORDS[0]="--autocomplete" local IFS=$'\n' - COMPREPLY=( $(/home/dwmw/git/openconnect/gtls-ibm/openconnect "${COMP_WORDS[@]}") ) + COMPREPLY=( $(openconnect "${COMP_WORDS[@]}") ) case "${COMPREPLY[0]}" in FILENAME) if [ "${COMPREPLY[1]}" != "" ]; then diff --git a/main.c b/main.c index 366c5770..20744397 100644 --- a/main.c +++ b/main.c @@ -1139,14 +1139,24 @@ static int autocomplete(int argc, char **argv) opterr = 0; - while (1) { - int match_opt = (argv[optind] == comp_opt); + while (argv[optind]) { + int thisind = optind; /* Don't let getopt_long() assume it's a separator; instead * assume they want to tab-complete to a real long option. */ - if (match_opt && !strcmp(comp_opt, "--")) + if (argv[thisind] == comp_opt) goto empty_opt; + /* Skip over non-option elements, in an attempt to prevent + * getopt_long() from reordering the array as we go. The problem + * is that we've seen it *delay* the reordering. So it processes + * the argv element *after* the non-option, but argv[optind] is + * still pointing to the non-option. */ + if (argv[thisind][0] != '-') { + optind++; + continue; + } + opt = getopt_long(argc, argv, #ifdef _WIN32 "C:c:Dde:F:g:hi:k:m:P:p:Q:qs:u:Vvx:", @@ -1158,23 +1168,41 @@ static int autocomplete(int argc, char **argv) if (opt == -1) break; - if (match_opt) { + if (argv[thisind] == comp_opt) { + char *matcher = NULL; empty_opt: - /* No autocompletion for short options */ - if (!strncmp(comp_opt, "--", 2)) { - int complen = strlen(comp_opt + 2); + if (!strncmp(comp_opt, "--", 2)) + matcher = comp_opt + 2; + else if (!strcmp(comp_opt, "-")) + matcher = comp_opt + 1; + + if (matcher) { + int matchlen = strlen(matcher); const struct option *p = long_options; while (p->name) { - if (!strncmp(comp_opt + 2, p->name, complen)) + if (!strncmp(matcher, p->name, matchlen)) printf("--%s\n", p->name); p++; } - } + } else if (comp_opt[0] == '-') { + if (comp_opt[1] && !comp_opt[2]) { + /* Single-char -X option. */ + const struct option *longopt = long_options; + while (longopt->name) { + if (comp_opt[1] == longopt->val) { + printf("--%s\n", longopt->name); + break; + } + longopt++; + } + } + } else + printf("HOSTNAME\n"); + return 0; } - if (optarg == comp_opt) { switch (opt) { case 'k': /* --sslkey */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 14f51c5a..bcc91212 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -45,7 +45,7 @@ EXTRA_DIST = certs/ca.pem certs/ca-key.pem certs/user-cert.pem $(USER_KEYS) $(US configs/user-cert.prm softhsm2.conf.in softhsm ns.sh configs/test-dtls-psk.config \ scripts/vpnc-script scripts/vpnc-script-detect-disconnect -dist_check_SCRIPTS = +dist_check_SCRIPTS = autocompletion if HAVE_NETNS dist_check_SCRIPTS += dtls-psk sigterm diff --git a/tests/autocompletion b/tests/autocompletion new file mode 100755 index 00000000..d2f0ae68 --- /dev/null +++ b/tests/autocompletion @@ -0,0 +1,68 @@ +#!/bin/sh +# +# Bash completion for OpenConnect +# +# Copyright © David Woodhouse +# +# Author: David Woodhouse +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# version 2.1, as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + + +# Consider a command line like the following: +# +# openconnect -c --authenticate\ -k -k "'"'"'.pem --authgroup 'foo +# bar' --o\s linux-64 myserver + + +OPENCONNECT="${OPENCONNECT:-${top_builddir}/openconnect}" + +do_test() +{ + if [ "$(COMP_CWORD=$WORD $OPENCONNECT --autocomplete "$@")" != "$RESULT" ]; then + echo "Autocomplete failed (word $WORD) for '$@'" + exit 1 + fi + echo "Autocomplete OK (word $WORD) for '$@'" +} + +WORD=1 +RESULT="HOSTNAME" +do_test "" + +WORD=1 +RESULT="--certificate" +do_test -c + +WORD=3 +RESULT="FILENAME +!*.@(pem|der|p12|crt)" +do_test foo -k '' + +WORD=2 +RESULT="--protocol" +do_test somehost --proto + +WORD=1 +RESULT="HOSTNAME" +do_test somehost --proto + +WORD=3 +RESULT="FILENAME +!*.@(pem|der|crt)" +do_test foo --cafile '' + +WORD=4 +RESULT="none +off +all +stateless" +do_test -k foo --compr '' +