summaryrefslogtreecommitdiffstats
path: root/utils/ipset_list
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ipset_list')
-rw-r--r--utils/ipset_list/README.md4
-rwxr-xr-xutils/ipset_list/ipset_list77
-rw-r--r--utils/ipset_list/ipset_list_bash_completion359
3 files changed, 278 insertions, 162 deletions
diff --git a/utils/ipset_list/README.md b/utils/ipset_list/README.md
index fad617e..4806252 100644
--- a/utils/ipset_list/README.md
+++ b/utils/ipset_list/README.md
@@ -6,7 +6,6 @@ ipset set listing wrapper script
Features:
==========
-(in addition to the native ipset options)
- Calculate sum of set members (and match on that count).
- List only members of a specified set.
@@ -21,6 +20,7 @@ Features:
- Calculate the amount of matching, excluded and traversed sets.
- Colorize the output.
- Operate on a single, selected, or all sets.
+- Programmable completion is included to make usage easier and faster.
Examples:
@@ -46,9 +46,9 @@ Examples:
- `ipset_list -Xs setA -Xs setB` - show all set names, but exclude setA and setB.
- `ipset_list -Xs "set[AB]"` - show all set names, but exclude setA and setB.
- `ipset_list -Mc 0` - show sets with zero members
-- `ipset_list -Mc '>=100'` - show sets with a member count greater or equal to 100
- `ipset_list -Hr \>=1 -Hv 0 -Hs \>10000` - find sets with at least one reference, revision of 0 and size in memory greater than 10000
- `ipset_list -i -Fr "^210\..*" setA` - show only members of setA matching the regex "^210\\..*"
+- `ipset_list -Mc \>=100 -Mc \<=150` - show sets with a member count greater or equal to 100 and not greater than 150.
- `ipset_list -a -c -Fh "Type:hash:ip" -Fr "^210\..*"` - show all information of sets with type hash:ip, matching the regex "^210\\..*", show match and members sum
- `ipset_list -Fh Type:hash:ip -Fh "Header:family inet *"` - show all set names, which are of type hash:ip and header of ipv4.
- `ipset_list -t -Xh "Revision:*" -Xh "References:*"` - show all sets headers, but exclude Revision and References entries.
diff --git a/utils/ipset_list/ipset_list b/utils/ipset_list/ipset_list
index b5f1dab..18743a5 100755
--- a/utils/ipset_list/ipset_list
+++ b/utils/ipset_list/ipset_list
@@ -59,7 +59,6 @@
# $0 -Ts - show all set names and total count of sets.
# $0 -Tm - calculate total size in memory of all sets.
# $0 -Mc 0 - show sets with zero members
-# $0 -Mc '>=100' - show sets with a member count greater or equal to 100
# $0 -Fi References:0 - show all sets with 0 references
# $0 -Hr 0 - shortcut for `-Fi References:0'
# $0 -Xs setA -Xs setB - show all set names, but exclude setA and setB.
@@ -68,6 +67,8 @@
# $0 -Ht "!(hash:ip)" - show sets which are not of type hash:ip
# $0 -Ht "!(bitmap:*)" - show sets wich are not of any bitmap type
# $0 -i -Fr "^210\..*" setA - show only members of setA matching the regex "^210\..*"
+# $0 -Mc \>=100 -Mc \<=150 - show sets with a member count greater or equal to 100
+#+ and not greater than 150.
# $0 -a -c -Fh "Type:hash:ip" -Fr "^210\..*"
#+ - show all information of sets with type hash:ip,
#+ matching the regex "^210\..*", show match and members sum.
@@ -197,15 +198,16 @@ set +u
# variables
export LC_ALL=C
-readonly version=2.6
+readonly version=2.7
readonly me="${0//*\//}"
readonly oIFS="$IFS"
-declare ips_version="" str_search="" str_match_on_msum="" str_xclude="" opt str_hval str_op
+declare ips_version="" str_search="" str_xclude="" opt str_hval str_op
declare -i show_all=show_count=show_members=headers_only=names_only=isolate=calc_mem=count_sets=sets_total=0
declare -i match_on_header=glob_search=regex_search=member_count=match_count=do_count=0
declare -i exclude_header=glob_xclude_element=glob_xclude_element=exclude_set=0
declare -i in_header=found_set=found_hxclude=found_sxclude=xclude_count=mem_total=mem_tmp=set_count=sets_sum=i=x=idx=0
-declare -a arr_sets arr_par arr_hcache arr_mcache arr_hsearch arr_hsearch_int arr_hxclude arr_sxclude
+declare -a arr_sets=() arr_par=() arr_hcache=() arr_mcache=() arr_hsearch=()
+declare -a arr_hsearch_int=() arr_hxclude=() arr_sxclude=() arr_match_on_msum=()
# functions
ex_miss_optarg() {
@@ -239,24 +241,25 @@ while (($#)); do
printf '%s [option [opt-arg]] [set-name] [...]\n\n' "$me"
printf '%s %s\n' "$me" "{-?|-h} | -n"
printf '%s %s\n\t%s\n' "$me" "[-i|-r|-s|-Co] [-d char] [-To value]"\
- "[{-Fg|-Fr}|{-Xg|-Xr} pattern] set-name"
- printf '%s %s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n' "$me"\
- "[-t|-c|-Co|-Cs|-Tm|-Ts] [-Fh header-glob:value-glob] [...]"\
+ "[{-Fg|-Fr}|{-Xg|-Xr} pattern] -- set-name"
+ printf '%s %s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n' "$me"\
+ "[-t|-c|-Ca|-Co|-Cs|-Tm|-Ts]"\
+ "[-Fh header-glob:value-glob] [...]"\
"[-Fi header-glob:[!|<|>|<=|>=]value] [...]"\
"[-Fg|-Fr pattern] [-Ht type-glob]"\
"[-Hr|-Hs|-Hv [!|<|>|<=|>=]value]"\
- "[-Mc [!|<|>|<=|>=]value] [-To value]"\
+ "[-Mc [!|<|>|<=|>=]value] [...] [-To value]"\
"[-Xh header-glob:value-glob] [...]"\
- "[-Xs setname-glob] [...] [set-name] [...]"
+ "[-Xs setname-glob] [...] -- [set-name] [...]"
printf '%s %s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n' "$me"\
- "[-a|-c|-m|-r|-s|-Co|-Cs|-Tm|-Ts] [-d char]"\
+ "[-a|-c|-m|-r|-s|-Ca|-Co|-Cs|-Tm|-Ts] [-d char]"\
"[-Fh header-glob:value-glob] [...]"\
"[-Fi header-glob:[!|<|>|<=|>=]value] [...]"\
"[-Fg|-Fr pattern] [-Ht type-glob]"\
"[-Hr|-Hs|-Hv [!|<|>|<=|>=]value]"\
- "[-Mc [!|<|>|<=|>=]value] [-To value]"\
+ "[-Mc [!|<|>|<=|>=]value] [...] [-To value]"\
"[-Xh header-glob:value-glob] [...]"\
- "[-Xg|-Xr pattern] [-Xs setname-glob] [...] [set-name] [...]"
+ "[-Xg|-Xr pattern] [-Xs setname-glob] [...] -- [set-name] [...]"
printf 'options:\n'
printf '%-13s%s\n' '-a' 'show all information but with default delim (whitespace).'\
'-c' 'calculate members and match (-Fg|-Fr) sum.'\
@@ -269,6 +272,7 @@ while (($#)); do
'-s' 'print elements sorted (if supported by the set type).'\
'-t' 'show set headers only.'\
'-v' 'version information.'\
+ '-Ca' "shortcut for -c -Cs -Ts -Tm (enable all counters)."\
'-Co' "colorize output (requires \`cl')."\
'-Cs' 'count amount of matching sets.'\
'-Fg pattern' 'match on members using a [ext]glob pattern.'\
@@ -280,8 +284,8 @@ while (($#)); do
printf '%-24s%s\n' '-Ht set-type-glob' 'match on set type.'\
'-Hr [!|<|>|<=|>=]value' 'match on number of references (value=int).'\
'-Hs [!|<|>|<=|>=]value' 'match on size in memory (value=int).'\
- '-Hv [!|<|>|<=|>=]value' 'match on revision number (value=int).'\
- '-Mc [!|<|>|<=|>=]value' 'match on member count (value=int).'
+ '-Hv [!|<|>|<=|>=]value' 'match on revision number (value=int).'
+ printf '%-30s%s\n' '-Mc [!|<|>|<=|>=]value [...]' 'match on member count (value=int).'
printf '%-13s%s\n' '-Tm' 'calculate total memory usage of all matching sets.'\
'-To' 'set timeout value (int) for read (listing sets).'\
'-Ts' 'count amount of traversed sets.'
@@ -290,6 +294,7 @@ while (($#)); do
printf '%-13s%s\n' '-Xg pattern' 'exclude members matching a [ext]glob pattern.'\
'-Xr pattern' 'exclude members matching a regex pattern.'\
'-Xs pattern' 'exclude sets matching a [ext]glob pattern.'
+ printf '%-13s%s\n' '--' 'stop further option processing.'
exit 0
;;
-a) show_all=1 # like `ipset list', but with $delim as delim
@@ -327,6 +332,10 @@ while (($#)); do
shift 2
fi
;;
+ -Ca) # shortcut for -c -Cs -Ts -Tm
+ show_count=1 count_sets=1 calc_mem=1 sets_total=1
+ shift
+ ;;
-Cs) count_sets=1 # calculate total count of matching sets
shift
;;
@@ -400,7 +409,7 @@ while (($#)); do
-Mc) do_count=1 # match on the count of members
[[ $2 ]] || ex_miss_optarg $1 "value pattern"
if is_compare_str "$2"; then
- str_match_on_msum="$2"
+ arr_match_on_msum[${#arr_match_on_msum[@]}]="$2"
shift 2
else
ex_invalid_usage "invalid format of match on member count value. expecting: \`[!|<|>|<=|>=]value'"
@@ -446,6 +455,8 @@ while (($#)); do
-v) printf "%s version %s\n" "$me" "$version"
exit 0
;;
+ --) shift; break
+ ;;
*) break
esac
done
@@ -456,7 +467,7 @@ declare -i i=x=idx=0
printf "ipset binary \`%s' does not exist, or is not executable. check \`ipset' variable\n" "$ipset" >&2
exit 1
}
-ips_version="$("$ipset" --version)"
+ips_version="$("$ipset" version)"
ips_version="${ips_version#ipset v}"
ips_version="${ips_version%%.*}"
if ! is_int "$ips_version"; then
@@ -518,7 +529,11 @@ if ((glob_xclude_element || regex_xclude_element)); then
fi
if ((colorize)); then
if ! [[ -x ${cl:=/usr/local/bin/cl} ]]; then
- printf "cl program \`%s' does not exist, or is not executable. check \`cl' variable\n" "$cl" >&2
+ printf "\ncl program \`%s' does not exist, or is not executable.\ncheck \`cl' variable.\n\n" "$cl" >&2
+ printf "If you do not have the program, you can download it from:\n"
+ printf "%s\n" "http://sourceforge.net/projects/colorize-shell/" \
+ "https://github.com/AllKind/cl" >&2
+ printf "\n"
exit 1
fi
# set color defaults if unset
@@ -704,6 +719,11 @@ for idx in "${!arr_sets[@]}"; do found_set=0 arr_hcache=() arr_mcache=()
if ((show_members || show_all || isolate)); then
arr_mcache[i++]="$REPLY"
fi
+ else
+ if (($? == 2)); then
+ printf "Invalid regex pattern \`%s'.\n" "$str_search"
+ exit 1
+ fi
fi
else
if ((glob_xclude_element)); then # exclude matching members
@@ -712,9 +732,14 @@ for idx in "${!arr_sets[@]}"; do found_set=0 arr_hcache=() arr_mcache=()
else let xclude_count+=1
fi
elif ((regex_xclude_element)); then # exclude matching members
- if ! [[ $REPLY =~ $str_xclude ]]; then
+ if [[ $REPLY =~ $str_xclude ]]; then
+ let xclude_count+=1
+ else
+ if (($? == 2)); then
+ printf "Invalid regex pattern \`%s'.\n" "$str_xclude"
+ exit 1
+ fi
arr_mcache[i++]="$REPLY"
- else let xclude_count+=1
fi
else
arr_mcache[i++]="$REPLY"
@@ -733,12 +758,14 @@ for idx in "${!arr_sets[@]}"; do found_set=0 arr_hcache=() arr_mcache=()
if ((glob_search || regex_search)) && ((match_count == 0)); then
continue # glob or regex search didn't match
fi
- if [[ $str_match_on_msum ]]; then # match on member sum
- str_op="${str_match_on_msum//[[:digit:]]}"
- [[ ${str_op:===} = \! ]] && str_op='!='
- if ! (($member_count $str_op ${str_match_on_msum//[[:punct:]]})); then
- continue # does not match
- fi
+ if ((${#arr_match_on_msum[@]} > 0)); then # match on member sum
+ for i in ${!arr_match_on_msum[@]}; do
+ str_op="${arr_match_on_msum[i]//[[:digit:]]}"
+ [[ ${str_op:===} = \! ]] && str_op='!='
+ if ! (($member_count $str_op ${arr_match_on_msum[i]//[[:punct:]]})); then
+ continue 2 # does not match
+ fi
+ done
fi
let set_count+=1 # count amount of matching sets
if ((calc_mem)); then
diff --git a/utils/ipset_list/ipset_list_bash_completion b/utils/ipset_list/ipset_list_bash_completion
index 2580009..e4faf7f 100644
--- a/utils/ipset_list/ipset_list_bash_completion
+++ b/utils/ipset_list/ipset_list_bash_completion
@@ -40,164 +40,253 @@ ipset_list=ipset_list
shopt -s extglob
-_remove_reply_entry() {
+# -----------------------------------------------------------------
+# Functions
+# -----------------------------------------------------------------
+
+_ipset_list_show_sets() {
+COMPREPLY=( $( compgen -W '${sets[@]}' -- "$cur" ) )
+# dedupe sets listing
+for ((i=set_index; i < ${#words[@]}-1; i++)); do
+ _ipset_list_remove_reply_entry "${words[i]}"
+done
+}
+
+_ipset_list_remove_reply_entry() {
local -i x
while (($#)); do
- for x in ${!COMPREPLY[@]}; do
- if [[ ${COMPREPLY[x]} = $1 ]]; then
- unset COMPREPLY[x]
- break
- fi
- done
- shift
+ for x in ${!COMPREPLY[@]}; do
+ if [[ ${COMPREPLY[x]} = $1 ]]; then
+ if [[ $_DEBUG_NF_COMPLETION ]]; then
+ printf "removing dupe entry COMPREPLY[$x]: %s\n" \
+ "${COMPREPLY[x]}"
+ fi
+ unset COMPREPLY[x]
+ break
+ fi
+ done
+ shift
done
}
+# -----------------------------------------------------------------
+# Main
+# -----------------------------------------------------------------
+
_ipset_list_complete() {
-local -i i=x=show_all=isolate=show_members=resolve=headers_only=0
-local cur prev
-local sets=()
-sets=( $("$ipset_list" -n ) )
-local opts=(-? -a -c -d -h -i -m -n -r -s -t -v)
-local Copts=(-Cs -Co)
+local -i i=x=got_bashcompl=0
+local -i show_all=isolate=show_members=resolve=headers_only=set_index=0
+local cur prev cword words str_tmp
+local sets=( $("$ipset_list" -n ) )
+local opts=(-- -? -a -c -d -h -i -m -n -r -s -t -v)
+local Copts=(-Ca -Cs -Co)
local Fopts=(-Fh -Fi -Fg -Fr)
local Hopts=(-Hr -Hs -Ht -Hv)
local Topts=(-Tm -To -Ts)
local Xopts=(-Xh -Xg -Xr -Xs)
+local arr_types=()
: ${PATH:=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin}
COMPREPLY=()
-_get_comp_words_by_ref cur || return
-_get_comp_words_by_ref prev || return
-
-#DEBUG=Y
-if [[ $DEBUG ]]; then
- printf "\ncur: <%s> prev: <%s>\n" "$cur" "$prev"
- printf "COMP_WORDS:\n"
- printf "<%s>\n" "${COMP_WORDS[@]}"
+
+# expecting _get_comp_words_by_ref() to exist from bash_completion
+if declare -f _get_comp_words_by_ref &>/dev/null; then got_bashcompl=1
+ _get_comp_words_by_ref -n : cur prev cword words || return
+else got_bashcompl=0 # not so neat, but a workaround
+ COMP_WORDBREAKS="${COMP_WORDBREAKS//:/}"
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ cword=$COMP_CWORD
+ for i in ${!COMP_WORDS[@]}; do words[i]="${COMP_WORDS[i]}"; done
fi
-# dont' allow an option after the set name(s)
-if [[ $cur = -* ]]; then
- for i in ${!sets[@]}; do
- [[ ${sets[i]} = $prev ]] && return 0
- done
+#_DEBUG_NF_COMPLETION=Y
+if [[ $_DEBUG_NF_COMPLETION ]]; then
+ printf "\nCOMP_WORDBREAKS: <%s>\n" "$COMP_WORDBREAKS"
+ printf "COMP_LINE: <%s>\n" "$COMP_LINE"
+ printf "COMP_TYPE: <%s>\n" "$COMP_TYPE"
+ printf "COMP_POINT: <%s>\n" "$COMP_POINT"
+ printf "COMP_KEY: <%s>\n" "$COMP_KEY"
+ printf "COMP_CWORD: <%s>\n" "$COMP_CWORD"
+ printf "\ncur: <%s> prev: <%s>\n" "$cur" "$prev"
+ printf "words:\n"
+ printf "<%s>\n" "${words[@]}"
fi
-# some options allow only a subset of other options
-for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do
- case "${COMP_WORDS[i]}" in
- -a) show_all=1 ;;
- -i) isolate=1 ;;
- -m) show_members=1 ;;
- -r) resolve=1 ;;
- -t) headers_only=1 ;;
- -\?|-h|-n|-v)
- return 0
- ;;
- esac
+
+# collect info of cmdline
+for ((i=1; i < ${#words[@]}-1; i++)); do
+ case "${words[i]}" in
+ -a) ((set_index)) && break || show_all=1 ;;
+ -i) ((set_index)) && break || isolate=1 Copts=(-Co) ;;
+ -m) ((set_index)) && break || show_members=1 ;;
+ -r) ((set_index)) && break || resolve=1 ;;
+ -t) ((set_index)) && break || headers_only=1 ;;
+ --) ((set_index)) && break || set_index=$((i+1)) ;;
+ -\?|-h|-n|-v)
+ ((set_index)) || return 0
+ ;;
+ @(-Fh|-Fi|-Xh)) ((set_index)) && break || header_operation=1 ;;
+ *)
+ ((set_index)) && break
+ # options expecting an opt arg
+ str_tmp="@(-@(d|Fg|Fh|Fi|Fr|Ht|Hr|Hs|Hv|Mc|To|Xg|Xh|Xr|Xs))"
+ if [[ ${words[i-1]} = $str_tmp ]]; then
+ continue
+ fi
+ # if not an option, register set index
+ str_tmp="@(-@(-|?|a|c|d|h|i|m|n|r|s|t|v|Ca|Cs|Co|Fg|Fh|Fi|Fr|Ht|Hr|Hs|Hv|Mc|To|Tm|Ts|Xg|Xh|Xr))"
+ if [[ ${words[i]} != $str_tmp ]]; then
+ for x in ${!sets[@]}; do
+ if [[ ${sets[x]} = ${words[i]} ]]; then
+ set_index=$i
+ break
+ fi
+ done
+ fi
+ esac
done
+
# invalid combinations of options
if ((headers_only)); then
- if ((show_all || show_members || isolate || resolve)); then
- return 0
- fi
-elif ((isolate && show_all)); then
- return 0
+ if ((show_all || show_members || isolate || resolve)); then
+ return 0
+ fi
+elif ((isolate)); then
+ if ((show_all || header_operation)); then
+ return 0
+ fi
fi
-case "$cur" in
- -C) COMPREPLY=( ${Copts[@]} $cur )
- for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do # no set counting on -i
- if [[ ${COMP_WORDS[i]} = -i ]]; then
- COMPREPLY=( -Co )
- break
- fi
- done
- ;;
- -F) COMPREPLY=( ${Fopts[@]} ) ;;
- -H) COMPREPLY=( ${Hopts[@]} ) ;;
- -M) COMPREPLY=( -Mc ) ;;
- -T) COMPREPLY=( ${Topts[@]} ) ;;
- -X) COMPREPLY=( ${Xopts[@]} ) ;;
- -*) # any option is requested
- case "$prev" in # options that exclude any other option, or need a value we can't predict
- @(-@(\?|d|h|n|v|Fg|Fh|Fi|Fr|Ht|Hr|Hs|Hv|Mc|To|Xg|Xh|Xr)))
- return 0
- ;;
- esac
- if ((${#COMP_WORDS[@]} > 2)); then # these options don't allow any other
- opts=("${opts[@]/@(-n|-h|-\?)/}")
- fi
- # some options allow only a subset of other options
- if ((isolate)); then
- COMPREPLY=( -Co -d -r -s $cur )
- elif ((headers_only)); then
- COMPREPLY=( -c ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
- elif ((show_members)); then
- COMPREPLY=( -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} )
- elif ((show_all)); then
- COMPREPLY=( -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
- elif ((resolve)); then
- COMPREPLY=( -a -c -d -s -m ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
- else
- COMPREPLY=( ${opts[@]} ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]} )
- fi
- ;;
- *) # not an option was requested
- COMPREPLY=( $( compgen -W '${sets[@]}' -- $cur ) )
- case "$prev" in
- -Xh) # retrieve list of headers
- COMPREPLY=()
- while read -r; do
- [[ $REPLY = Name ]] && continue
- COMPREPLY[${#COMPREPLY[@]}]="$REPLY"
- done < <( "$ipset_list" -t "${sets[0]}" | command awk -F: '{ print $1 }' )
- compopt -o nospace
- local IFS=$'\n'
- COMPREPLY=( $( compgen -P '"' -S ':*"' -W '${COMPREPLY[@]}' -- $cur ) )
- ;;
- @(-@(Hr|Hs|Hv|Mc))) # options making use of arithmetic comparison
- compopt -o nospace
- COMPREPLY=( '\!' '\<' '\>' '\<=' '\>=' )
- ;;
- @(-@(\?|d|h|n|v|Fg|Fh|Fi|Fr|Ht|To|Xg|Xr))) COMPREPLY=() ;;
- esac
- if ((isolate)); then # allow only one set with isolate
- for i in ${!sets[@]}; do
- if [[ ${sets[i]} = $prev ]]; then
- COMPREPLY=()
- break
- fi
- done
- fi
-esac
-if ((${#COMPREPLY[@]})); then # post process the reply
- for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do # mutual exclusive options
- case "${COMP_WORDS[i]}" in
- -Fg) _remove_reply_entry "-Fr" "-Xg" "-Xr" ;;
- -Fr) _remove_reply_entry "-Fg" "-Xg" "-Xr" ;;
- -Xg) _remove_reply_entry "-Fg" "-Fr" "-Xr" ;;
- -Xr) _remove_reply_entry "-Fg" "-Fr" "-Xg" ;;
- esac
- done
- for ((i=1; i <= ${#COMP_WORDS[@]}; i++)); do # remove options that can only be used once
- if [[ ${COMP_WORDS[i]} = @(""|-|-@(Fh|Fi|Xh|Xs)) ]]; then
- continue
- else
- for x in ${!COMPREPLY[@]}; do
- if [[ ${COMP_WORDS[i]} = ${COMPREPLY[x]} ]]; then
- unset COMPREPLY[$x]
- break
- fi
- done
- fi
- done
+# start setting compreply
+# all depends on $set_index
+if ((set_index)); then
+ if ((isolate && cword > set_index)); then
+ return 0 # allow only one set with isolate
+ fi
+ # dont' allow an option after the set name(s)
+ # allows to list sets which start with an hyphen
+ # and also handles those who have the name of ipset_list options
+ _ipset_list_show_sets
+else
+if [[ $prev = @(-@(\?|d|h|n|v|Fg|Fi|Fr|Ht|To|Xg|Xr)) ]]; then
+ return 0
+elif [[ $prev = -Xs ]]; then
+ # list sets if user does not want to enter a glob
+ _ipset_list_show_sets
+elif [[ $prev = -Ht ]]; then i=0
+ # show supported set types
+ while read -r; do
+ [[ $REPLY = "Supported set types:"* ]] && ((!i)) && \
+ i=1 && continue
+ ((i)) || continue
+ if [[ $REPLY = *:* ]]; then
+ set -- $REPLY
+ arr_types[${#arr_types[@]}]="$1"
+ fi
+ done < <(ipset help)
+ for i in ${!arr_types[@]}; do # remove dupe entries
+ for ((x=i+1; x < ${#arr_types[@]}; x++)); do
+ if [[ ${arr_types[i]} = ${arr_types[x]} ]]; then
+ unset arr_types[x]
+ fi
+ done
+ done
+ COMPREPLY=( $( compgen -W '${arr_types[@]}' -- "$cur" ) )
+elif [[ $prev = @(-Fh|-Xh) ]]; then
+ # retrieve list of headers
+ if ((${#sets[*]} > 0)); then
+ while read -r; do
+ [[ $REPLY = Name ]] && continue
+ COMPREPLY[${#COMPREPLY[@]}]="$REPLY"
+ done < <("$ipset_list" -t "${sets[0]}"|command awk -F: '{print $1}')
+ compopt -o nospace
+ local IFS=$'\n'
+ if [[ $prev = -Xh ]]; then
+ COMPREPLY=( $( compgen -P '"' -S ':*"' \
+ -W '${COMPREPLY[@]}' -- "$cur" ) )
+ elif [[ $prev = -Fh ]]; then
+ COMPREPLY=( $( compgen -P '"' -S ':"' \
+ -W '${COMPREPLY[@]}' -- "$cur" ) )
+ fi
+ fi
+elif [[ $prev = @(-@(Hr|Hs|Hv|Mc)) ]]; then
+ # options making use of arithmetic comparison
+ compopt -o nospace
+ COMPREPLY=( $( compgen -P '\' -W '\! \< \> \<= \>=' -- "$cur" ) )
+elif [[ $cur = -* ]]; then
+ # any option is requested
+ case "$prev" in
+ @(-@(\?|d|h|n|v|Fg|Fh|Fi|Fr|Ht|Hr|Hs|Hv|Mc|To|Xg|Xh|Xr)))
+ # options that exclude any other option,
+ # or need a value we can't predict
+ return 0
+ ;;
+ esac
+ # these options don't allow any other
+ if ((${#words[@]} > 2)); then
+ opts=("${opts[@]/@(-n|-h|-\?)/}")
+ fi
+ # some options allow only a subset of other options
+ if ((isolate)); then
+ COMPREPLY=( $(compgen -W '-- -Co -d -r -s' -- $cur ) )
+ elif ((headers_only)); then
+ COMPREPLY=( $(compgen -W \
+ '-- -c ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \
+ -- $cur ) )
+ elif ((show_members)); then
+ COMPREPLY=( $(compgen -W \
+ '-- -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]}' \
+ -- $cur ) )
+ elif ((show_all)); then
+ COMPREPLY=( $(compgen -W \
+ '-- -c -d -r -s ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \
+ -- $cur ) )
+ elif ((resolve)); then
+ COMPREPLY=( $(compgen -W \
+ '-- -a -c -d -s -m ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \
+ -- $cur ) )
+ elif ((header_operation)); then
+ COMPREPLY=( $(compgen -W \
+ '-- -a -c -d -s -m -t ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \
+ -- $cur ) )
+ else
+ COMPREPLY=( $(compgen -W \
+ '${opts[@]} ${Copts[@]} ${Fopts[@]} ${Hopts[@]} -Mc ${Topts[@]} ${Xopts[@]}' \
+ -- $cur ) )
+ fi
+ # post process the reply
+ if ((${#COMPREPLY[@]})); then
+ x=$((set_index ? set_index : ${#words[*]}-1))
+ # mutual exclusive options
+ for ((i=1; i < x; i++)); do
+ case "${words[i]}" in
+ -Fg) _ipset_list_remove_reply_entry "-Fr" "-Xg" "-Xr" ;;
+ -Fr) _ipset_list_remove_reply_entry "-Fg" "-Xg" "-Xr" ;;
+ -Xg) _ipset_list_remove_reply_entry "-Fg" "-Fr" "-Xr" ;;
+ -Xr) _ipset_list_remove_reply_entry "-Fg" "-Fr" "-Xg" ;;
+ esac
+ # options allowed multiple times
+ if [[ ${words[i]} = @(""|-|-@(Fh|Fi|Mc|Xh|Xs)) ]]; then
+ continue
+ else # remove dupe
+ _ipset_list_remove_reply_entry "${words[i]}"
+ fi
+ done
+ fi
+elif [[ $cur = * ]]; then
+ # non option request
+ # default to sets listing
+ _ipset_list_show_sets
fi
-if [[ $DEBUG ]]; then
- printf "COMPREPLY:\n"
- printf "<%s>\n" "${COMPREPLY[@]}"
+fi
+
+((got_bashcompl)) && __ltrim_colon_completions "$cur"
+
+if [[ $_DEBUG_NF_COMPLETION ]]; then
+ printf "COMPREPLY:\n"
+ printf "<%s>\n" "${COMPREPLY[@]}"
fi
}
-complete -F _ipset_list_complete "$ipset_list"
+complete -F _ipset_list_complete "${ipset_list:-ipset_list}"