| 1 | #                                                          -*- shell-script -*-
 | 
| 2 | #
 | 
| 3 | #   bash_completion - programmable completion functions for bash 4.1+
 | 
| 4 | #
 | 
| 5 | #   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
 | 
| 6 | #             © 2009-2018, Bash Completion Maintainers
 | 
| 7 | #
 | 
| 8 | #   This program is free software; you can redistribute it and/or modify
 | 
| 9 | #   it under the terms of the GNU General Public License as published by
 | 
| 10 | #   the Free Software Foundation; either version 2, or (at your option)
 | 
| 11 | #   any later version.
 | 
| 12 | #
 | 
| 13 | #   This program is distributed in the hope that it will be useful,
 | 
| 14 | #   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
| 15 | #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
| 16 | #   GNU General Public License for more details.
 | 
| 17 | #
 | 
| 18 | #   You should have received a copy of the GNU General Public License
 | 
| 19 | #   along with this program; if not, write to the Free Software Foundation,
 | 
| 20 | #   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
| 21 | #
 | 
| 22 | #   The latest version of this software can be obtained here:
 | 
| 23 | #
 | 
| 24 | #   https://github.com/scop/bash-completion
 | 
| 25 | 
 | 
| 26 | BASH_COMPLETION_VERSINFO=(2 8)
 | 
| 27 | 
 | 
| 28 | if [[ $- == *v* ]]; then
 | 
| 29 |     BASH_COMPLETION_ORIGINAL_V_VALUE="-v"
 | 
| 30 | else
 | 
| 31 |     BASH_COMPLETION_ORIGINAL_V_VALUE="+v"
 | 
| 32 | fi
 | 
| 33 | 
 | 
| 34 | if [[ ${BASH_COMPLETION_DEBUG-} ]]; then
 | 
| 35 |     set -v
 | 
| 36 | else
 | 
| 37 |     set +v
 | 
| 38 | fi
 | 
| 39 | 
 | 
| 40 | # Blacklisted completions, causing problems with our code.
 | 
| 41 | #
 | 
| 42 | _blacklist_glob='@(acroread.sh)'
 | 
| 43 | 
 | 
| 44 | # Turn on extended globbing and programmable completion
 | 
| 45 | shopt -s extglob progcomp
 | 
| 46 | 
 | 
| 47 | # A lot of the following one-liners were taken directly from the
 | 
| 48 | # completion examples provided with the bash 2.04 source distribution
 | 
| 49 | 
 | 
| 50 | # start of section containing compspecs that can be handled within bash
 | 
| 51 | 
 | 
| 52 | # user commands see only users
 | 
| 53 | complete -u groups slay w sux
 | 
| 54 | 
 | 
| 55 | # bg completes with stopped jobs
 | 
| 56 | complete -A stopped -P '"%' -S '"' bg
 | 
| 57 | 
 | 
| 58 | # other job commands
 | 
| 59 | complete -j -P '"%' -S '"' fg jobs disown
 | 
| 60 | 
 | 
| 61 | # readonly and unset complete with shell variables
 | 
| 62 | complete -v readonly unset
 | 
| 63 | 
 | 
| 64 | # set completes with set options
 | 
| 65 | complete -A setopt set
 | 
| 66 | 
 | 
| 67 | # shopt completes with shopt options
 | 
| 68 | complete -A shopt shopt
 | 
| 69 | 
 | 
| 70 | # helptopics
 | 
| 71 | complete -A helptopic help
 | 
| 72 | 
 | 
| 73 | # unalias completes with aliases
 | 
| 74 | complete -a unalias
 | 
| 75 | 
 | 
| 76 | # type and which complete on commands
 | 
| 77 | complete -c command type which
 | 
| 78 | 
 | 
| 79 | # builtin completes on builtins
 | 
| 80 | complete -b builtin
 | 
| 81 | 
 | 
| 82 | # start of section containing completion functions called by other functions
 | 
| 83 | 
 | 
| 84 | # Check if we're running on the given userland
 | 
| 85 | # @param $1 userland to check for
 | 
| 86 | _userland()
 | 
| 87 | {
 | 
| 88 |     local userland=$( uname -s )
 | 
| 89 |     [[ $userland == @(Linux|GNU/*) ]] && userland=GNU
 | 
| 90 |     [[ $userland == $1 ]]
 | 
| 91 | }
 | 
| 92 | 
 | 
| 93 | # This function sets correct SysV init directories
 | 
| 94 | #
 | 
| 95 | _sysvdirs()
 | 
| 96 | {
 | 
| 97 |     sysvdirs=( )
 | 
| 98 |     [[ -d /etc/rc.d/init.d ]] && sysvdirs+=( /etc/rc.d/init.d )
 | 
| 99 |     [[ -d /etc/init.d ]] && sysvdirs+=( /etc/init.d )
 | 
| 100 |     # Slackware uses /etc/rc.d
 | 
| 101 |     [[ -f /etc/slackware-version ]] && sysvdirs=( /etc/rc.d )
 | 
| 102 | }
 | 
| 103 | 
 | 
| 104 | # This function checks whether we have a given program on the system.
 | 
| 105 | #
 | 
| 106 | _have()
 | 
| 107 | {
 | 
| 108 |     # Completions for system administrator commands are installed as well in
 | 
| 109 |     # case completion is attempted via `sudo command ...'.
 | 
| 110 |     PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin type $1 &>/dev/null
 | 
| 111 | }
 | 
| 112 | 
 | 
| 113 | # Backwards compatibility for compat completions that use have().
 | 
| 114 | # @deprecated should no longer be used; generally not needed with dynamically
 | 
| 115 | #             loaded completions, and _have is suitable for runtime use.
 | 
| 116 | have()
 | 
| 117 | {
 | 
| 118 |     unset -v have
 | 
| 119 |     _have $1 && have=yes
 | 
| 120 | }
 | 
| 121 | 
 | 
| 122 | # This function checks whether a given readline variable
 | 
| 123 | # is `on'.
 | 
| 124 | #
 | 
| 125 | _rl_enabled()
 | 
| 126 | {
 | 
| 127 |     [[ "$( bind -v )" == *$1+([[:space:]])on* ]]
 | 
| 128 | }
 | 
| 129 | 
 | 
| 130 | # This function shell-quotes the argument
 | 
| 131 | quote()
 | 
| 132 | {
 | 
| 133 |     local quoted=${1//\'/\'\\\'\'}
 | 
| 134 |     printf "'%s'" "$quoted"
 | 
| 135 | }
 | 
| 136 | 
 | 
| 137 | # @see _quote_readline_by_ref()
 | 
| 138 | quote_readline()
 | 
| 139 | {
 | 
| 140 |     local quoted
 | 
| 141 |     _quote_readline_by_ref "$1" ret
 | 
| 142 |     printf %s "$ret"
 | 
| 143 | } # quote_readline()
 | 
| 144 | 
 | 
| 145 | 
 | 
| 146 | # This function shell-dequotes the argument
 | 
| 147 | dequote()
 | 
| 148 | {
 | 
| 149 |     eval printf %s "$1" 2> /dev/null
 | 
| 150 | }
 | 
| 151 | 
 | 
| 152 | 
 | 
| 153 | # Assign variable one scope above the caller
 | 
| 154 | # Usage: local "$1" && _upvar $1 "value(s)"
 | 
| 155 | # Param: $1  Variable name to assign value to
 | 
| 156 | # Param: $*  Value(s) to assign.  If multiple values, an array is
 | 
| 157 | #            assigned, otherwise a single value is assigned.
 | 
| 158 | # NOTE: For assigning multiple variables, use '_upvars'.  Do NOT
 | 
| 159 | #       use multiple '_upvar' calls, since one '_upvar' call might
 | 
| 160 | #       reassign a variable to be used by another '_upvar' call.
 | 
| 161 | # See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
 | 
| 162 | _upvar()
 | 
| 163 | {
 | 
| 164 |     if unset -v "$1"; then           # Unset & validate varname
 | 
| 165 |         if (( $# == 2 )); then
 | 
| 166 |             eval $1=\"\$2\"          # Return single value
 | 
| 167 |         else
 | 
| 168 |             eval $1=\(\"\${@:2}\"\)  # Return array
 | 
| 169 |         fi
 | 
| 170 |     fi
 | 
| 171 | }
 | 
| 172 | 
 | 
| 173 | 
 | 
| 174 | # Assign variables one scope above the caller
 | 
| 175 | # Usage: local varname [varname ...] &&
 | 
| 176 | #        _upvars [-v varname value] | [-aN varname [value ...]] ...
 | 
| 177 | # Available OPTIONS:
 | 
| 178 | #     -aN  Assign next N values to varname as array
 | 
| 179 | #     -v   Assign single value to varname
 | 
| 180 | # Return: 1 if error occurs
 | 
| 181 | # See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
 | 
| 182 | _upvars()
 | 
| 183 | {
 | 
| 184 |     if ! (( $# )); then
 | 
| 185 |         echo "${FUNCNAME[0]}: usage: ${FUNCNAME[0]} [-v varname"\
 | 
| 186 |             "value] | [-aN varname [value ...]] ..." 1>&2
 | 
| 187 |         return 2
 | 
| 188 |     fi
 | 
| 189 |     while (( $# )); do
 | 
| 190 |         case $1 in
 | 
| 191 |             -a*)
 | 
| 192 |                 # Error checking
 | 
| 193 |                 [[ ${1#-a} ]] || { echo "bash: ${FUNCNAME[0]}: \`$1': missing"\
 | 
| 194 |                     "number specifier" 1>&2; return 1; }
 | 
| 195 |                 printf %d "${1#-a}" &> /dev/null || { echo "bash:"\
 | 
| 196 |                     "${FUNCNAME[0]}: \`$1': invalid number specifier" 1>&2
 | 
| 197 |                     return 1; }
 | 
| 198 |                 # Assign array of -aN elements
 | 
| 199 |                 [[ "$2" ]] && unset -v "$2" && eval $2=\(\"\${@:3:${1#-a}}\"\) &&
 | 
| 200 |                 shift $((${1#-a} + 2)) || { echo "bash: ${FUNCNAME[0]}:"\
 | 
| 201 |                     "\`$1${2+ }$2': missing argument(s)" 1>&2; return 1; }
 | 
| 202 |                 ;;
 | 
| 203 |             -v)
 | 
| 204 |                 # Assign single value
 | 
| 205 |                 [[ "$2" ]] && unset -v "$2" && eval $2=\"\$3\" &&
 | 
| 206 |                 shift 3 || { echo "bash: ${FUNCNAME[0]}: $1: missing"\
 | 
| 207 |                 "argument(s)" 1>&2; return 1; }
 | 
| 208 |                 ;;
 | 
| 209 |             *)
 | 
| 210 |                 echo "bash: ${FUNCNAME[0]}: $1: invalid option" 1>&2
 | 
| 211 |                 return 1 ;;
 | 
| 212 |         esac
 | 
| 213 |     done
 | 
| 214 | }
 | 
| 215 | 
 | 
| 216 | 
 | 
| 217 | # Reassemble command line words, excluding specified characters from the
 | 
| 218 | # list of word completion separators (COMP_WORDBREAKS).
 | 
| 219 | # @param $1 chars  Characters out of $COMP_WORDBREAKS which should
 | 
| 220 | #     NOT be considered word breaks. This is useful for things like scp where
 | 
| 221 | #     we want to return host:path and not only path, so we would pass the
 | 
| 222 | #     colon (:) as $1 here.
 | 
| 223 | # @param $2 words  Name of variable to return words to
 | 
| 224 | # @param $3 cword  Name of variable to return cword to
 | 
| 225 | #
 | 
| 226 | __reassemble_comp_words_by_ref()
 | 
| 227 | {
 | 
| 228 |     local exclude i j line ref
 | 
| 229 |     # Exclude word separator characters?
 | 
| 230 |     if [[ $1 ]]; then
 | 
| 231 |         # Yes, exclude word separator characters;
 | 
| 232 |         # Exclude only those characters, which were really included
 | 
| 233 |         exclude="${1//[^$COMP_WORDBREAKS]}"
 | 
| 234 |     fi
 | 
| 235 | 
 | 
| 236 |     # Default to cword unchanged
 | 
| 237 |     printf -v "$3" %s "$COMP_CWORD"
 | 
| 238 |     # Are characters excluded which were former included?
 | 
| 239 |     if [[ $exclude ]]; then
 | 
| 240 |         # Yes, list of word completion separators has shrunk;
 | 
| 241 |         line=$COMP_LINE
 | 
| 242 |         # Re-assemble words to complete
 | 
| 243 |         for (( i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
 | 
| 244 |             # Is current word not word 0 (the command itself) and is word not
 | 
| 245 |             # empty and is word made up of just word separator characters to
 | 
| 246 |             # be excluded and is current word not preceded by whitespace in
 | 
| 247 |             # original line?
 | 
| 248 |             while [[ $i -gt 0 && ${COMP_WORDS[$i]} == +([$exclude]) ]]; do
 | 
| 249 |                 # Is word separator not preceded by whitespace in original line
 | 
| 250 |                 # and are we not going to append to word 0 (the command
 | 
| 251 |                 # itself), then append to current word.
 | 
| 252 |                 [[ $line != [[:blank:]]* ]] && (( j >= 2 )) && ((j--))
 | 
| 253 |                 # Append word separator to current or new word
 | 
| 254 |                 ref="$2[$j]"
 | 
| 255 |                 printf -v "$ref" %s "${!ref}${COMP_WORDS[i]}"
 | 
| 256 |                 # Indicate new cword
 | 
| 257 |                 [[ $i == $COMP_CWORD ]] && printf -v "$3" %s "$j"
 | 
| 258 |                 # Remove optional whitespace + word separator from line copy
 | 
| 259 |                 line=${line#*"${COMP_WORDS[$i]}"}
 | 
| 260 |                 # Start new word if word separator in original line is
 | 
| 261 |                 # followed by whitespace.
 | 
| 262 |                 [[ $line == [[:blank:]]* ]] && ((j++))
 | 
| 263 |                 # Indicate next word if available, else end *both* while and
 | 
| 264 |                 # for loop
 | 
| 265 |                 (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2
 | 
| 266 |             done
 | 
| 267 |             # Append word to current word
 | 
| 268 |             ref="$2[$j]"
 | 
| 269 |             printf -v "$ref" %s "${!ref}${COMP_WORDS[i]}"
 | 
| 270 |             # Remove optional whitespace + word from line copy
 | 
| 271 |             line=${line#*"${COMP_WORDS[i]}"}
 | 
| 272 |             # Indicate new cword
 | 
| 273 |             [[ $i == $COMP_CWORD ]] && printf -v "$3" %s "$j"
 | 
| 274 |         done
 | 
| 275 |         [[ $i == $COMP_CWORD ]] && printf -v "$3" %s "$j"
 | 
| 276 |     else
 | 
| 277 |         # No, list of word completions separators hasn't changed;
 | 
| 278 |         for i in ${!COMP_WORDS[@]}; do
 | 
| 279 |             printf -v "$2[i]" %s "${COMP_WORDS[i]}"
 | 
| 280 |         done
 | 
| 281 |     fi
 | 
| 282 | } # __reassemble_comp_words_by_ref()
 | 
| 283 | 
 | 
| 284 | 
 | 
| 285 | # @param $1 exclude  Characters out of $COMP_WORDBREAKS which should NOT be
 | 
| 286 | #     considered word breaks. This is useful for things like scp where
 | 
| 287 | #     we want to return host:path and not only path, so we would pass the
 | 
| 288 | #     colon (:) as $1 in this case.
 | 
| 289 | # @param $2 words  Name of variable to return words to
 | 
| 290 | # @param $3 cword  Name of variable to return cword to
 | 
| 291 | # @param $4 cur  Name of variable to return current word to complete to
 | 
| 292 | # @see __reassemble_comp_words_by_ref()
 | 
| 293 | __get_cword_at_cursor_by_ref()
 | 
| 294 | {
 | 
| 295 |     local cword words=()
 | 
| 296 |     __reassemble_comp_words_by_ref "$1" words cword
 | 
| 297 | 
 | 
| 298 |     local i cur index=$COMP_POINT lead=${COMP_LINE:0:$COMP_POINT}
 | 
| 299 |     # Cursor not at position 0 and not leaded by just space(s)?
 | 
| 300 |     if [[ $index -gt 0 && ( $lead && ${lead//[[:space:]]} ) ]]; then
 | 
| 301 |         cur=$COMP_LINE
 | 
| 302 |         for (( i = 0; i <= cword; ++i )); do
 | 
| 303 |             while [[
 | 
| 304 |                 # Current word fits in $cur?
 | 
| 305 |                 ${#cur} -ge ${#words[i]} &&
 | 
| 306 |                 # $cur doesn't match cword?
 | 
| 307 |                 "${cur:0:${#words[i]}}" != "${words[i]}"
 | 
| 308 |             ]]; do
 | 
| 309 |                 # Strip first character
 | 
| 310 |                 cur="${cur:1}"
 | 
| 311 |                 # Decrease cursor position, staying >= 0
 | 
| 312 |                 [[ $index -gt 0 ]] && ((index--))
 | 
| 313 |             done
 | 
| 314 | 
 | 
| 315 |             # Does found word match cword?
 | 
| 316 |             if [[ $i -lt $cword ]]; then
 | 
| 317 |                 # No, cword lies further;
 | 
| 318 |                 local old_size=${#cur}
 | 
| 319 |                 cur="${cur#"${words[i]}"}"
 | 
| 320 |                 local new_size=${#cur}
 | 
| 321 |                 index=$(( index - old_size + new_size ))
 | 
| 322 |             fi
 | 
| 323 |         done
 | 
| 324 |         # Clear $cur if just space(s)
 | 
| 325 |         [[ $cur && ! ${cur//[[:space:]]} ]] && cur=
 | 
| 326 |         # Zero $index if negative
 | 
| 327 |         [[ $index -lt 0 ]] && index=0
 | 
| 328 |     fi
 | 
| 329 | 
 | 
| 330 |     local "$2" "$3" "$4" && _upvars -a${#words[@]} $2 "${words[@]}" \
 | 
| 331 |         -v $3 "$cword" -v $4 "${cur:0:$index}"
 | 
| 332 | }
 | 
| 333 | 
 | 
| 334 | 
 | 
| 335 | # Get the word to complete and optional previous words.
 | 
| 336 | # This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases
 | 
| 337 | # where the user is completing in the middle of a word.
 | 
| 338 | # (For example, if the line is "ls foobar",
 | 
| 339 | # and the cursor is here -------->   ^
 | 
| 340 | # Also one is able to cross over possible wordbreak characters.
 | 
| 341 | # Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES]
 | 
| 342 | # Available VARNAMES:
 | 
| 343 | #     cur         Return cur via $cur
 | 
| 344 | #     prev        Return prev via $prev
 | 
| 345 | #     words       Return words via $words
 | 
| 346 | #     cword       Return cword via $cword
 | 
| 347 | #
 | 
| 348 | # Available OPTIONS:
 | 
| 349 | #     -n EXCLUDE  Characters out of $COMP_WORDBREAKS which should NOT be
 | 
| 350 | #                 considered word breaks. This is useful for things like scp
 | 
| 351 | #                 where we want to return host:path and not only path, so we
 | 
| 352 | #                 would pass the colon (:) as -n option in this case.
 | 
| 353 | #     -c VARNAME  Return cur via $VARNAME
 | 
| 354 | #     -p VARNAME  Return prev via $VARNAME
 | 
| 355 | #     -w VARNAME  Return words via $VARNAME
 | 
| 356 | #     -i VARNAME  Return cword via $VARNAME
 | 
| 357 | #
 | 
| 358 | # Example usage:
 | 
| 359 | #
 | 
| 360 | #    $ _get_comp_words_by_ref -n : cur prev
 | 
| 361 | #
 | 
| 362 | _get_comp_words_by_ref()
 | 
| 363 | {
 | 
| 364 |     local exclude flag i OPTIND=1
 | 
| 365 |     local cur cword words=()
 | 
| 366 |     local upargs=() upvars=() vcur vcword vprev vwords
 | 
| 367 | 
 | 
| 368 |     while getopts "c:i:n:p:w:" flag "$@"; do
 | 
| 369 |         case $flag in
 | 
| 370 |             c) vcur=$OPTARG ;;
 | 
| 371 |             i) vcword=$OPTARG ;;
 | 
| 372 |             n) exclude=$OPTARG ;;
 | 
| 373 |             p) vprev=$OPTARG ;;
 | 
| 374 |             w) vwords=$OPTARG ;;
 | 
| 375 |         esac
 | 
| 376 |     done
 | 
| 377 |     while [[ $# -ge $OPTIND ]]; do
 | 
| 378 |         case ${!OPTIND} in
 | 
| 379 |             cur)   vcur=cur ;;
 | 
| 380 |             prev)  vprev=prev ;;
 | 
| 381 |             cword) vcword=cword ;;
 | 
| 382 |             words) vwords=words ;;
 | 
| 383 |             *) echo "bash: $FUNCNAME(): \`${!OPTIND}': unknown argument" \
 | 
| 384 |                 1>&2; return 1
 | 
| 385 |         esac
 | 
| 386 |         let "OPTIND += 1"
 | 
| 387 |     done
 | 
| 388 | 
 | 
| 389 |     __get_cword_at_cursor_by_ref "$exclude" words cword cur
 | 
| 390 | 
 | 
| 391 |     [[ $vcur   ]] && { upvars+=("$vcur"  ); upargs+=(-v $vcur   "$cur"  ); }
 | 
| 392 |     [[ $vcword ]] && { upvars+=("$vcword"); upargs+=(-v $vcword "$cword"); }
 | 
| 393 |     [[ $vprev && $cword -ge 1 ]] && { upvars+=("$vprev" ); upargs+=(-v $vprev
 | 
| 394 |         "${words[cword - 1]}"); }
 | 
| 395 |     [[ $vwords ]] && { upvars+=("$vwords"); upargs+=(-a${#words[@]} $vwords
 | 
| 396 |         "${words[@]}"); }
 | 
| 397 | 
 | 
| 398 |     (( ${#upvars[@]} )) && local "${upvars[@]}" && _upvars "${upargs[@]}"
 | 
| 399 | }
 | 
| 400 | 
 | 
| 401 | 
 | 
| 402 | # Get the word to complete.
 | 
| 403 | # This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases
 | 
| 404 | # where the user is completing in the middle of a word.
 | 
| 405 | # (For example, if the line is "ls foobar",
 | 
| 406 | # and the cursor is here -------->   ^
 | 
| 407 | # @param $1 string  Characters out of $COMP_WORDBREAKS which should NOT be
 | 
| 408 | #     considered word breaks. This is useful for things like scp where
 | 
| 409 | #     we want to return host:path and not only path, so we would pass the
 | 
| 410 | #     colon (:) as $1 in this case.
 | 
| 411 | # @param $2 integer  Index number of word to return, negatively offset to the
 | 
| 412 | #     current word (default is 0, previous is 1), respecting the exclusions
 | 
| 413 | #     given at $1.  For example, `_get_cword "=:" 1' returns the word left of
 | 
| 414 | #     the current word, respecting the exclusions "=:".
 | 
| 415 | # @deprecated  Use `_get_comp_words_by_ref cur' instead
 | 
| 416 | # @see _get_comp_words_by_ref()
 | 
| 417 | _get_cword()
 | 
| 418 | {
 | 
| 419 |     local LC_CTYPE=C
 | 
| 420 |     local cword words
 | 
| 421 |     __reassemble_comp_words_by_ref "$1" words cword
 | 
| 422 | 
 | 
| 423 |     # return previous word offset by $2
 | 
| 424 |     if [[ ${2//[^0-9]/} ]]; then
 | 
| 425 |         printf "%s" "${words[cword-$2]}"
 | 
| 426 |     elif [[ "${#words[cword]}" -eq 0 || "$COMP_POINT" == "${#COMP_LINE}" ]]; then
 | 
| 427 |         printf "%s" "${words[cword]}"
 | 
| 428 |     else
 | 
| 429 |         local i
 | 
| 430 |         local cur="$COMP_LINE"
 | 
| 431 |         local index="$COMP_POINT"
 | 
| 432 |         for (( i = 0; i <= cword; ++i )); do
 | 
| 433 |             while [[
 | 
| 434 |                 # Current word fits in $cur?
 | 
| 435 |                 "${#cur}" -ge ${#words[i]} &&
 | 
| 436 |                 # $cur doesn't match cword?
 | 
| 437 |                 "${cur:0:${#words[i]}}" != "${words[i]}"
 | 
| 438 |             ]]; do
 | 
| 439 |                 # Strip first character
 | 
| 440 |                 cur="${cur:1}"
 | 
| 441 |                 # Decrease cursor position, staying >= 0
 | 
| 442 |                 [[ $index -gt 0 ]] && ((index--))
 | 
| 443 |             done
 | 
| 444 | 
 | 
| 445 |             # Does found word matches cword?
 | 
| 446 |             if [[ "$i" -lt "$cword" ]]; then
 | 
| 447 |                 # No, cword lies further;
 | 
| 448 |                 local old_size="${#cur}"
 | 
| 449 |                 cur="${cur#${words[i]}}"
 | 
| 450 |                 local new_size="${#cur}"
 | 
| 451 |                 index=$(( index - old_size + new_size ))
 | 
| 452 |             fi
 | 
| 453 |         done
 | 
| 454 | 
 | 
| 455 |         if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then
 | 
| 456 |             # We messed up! At least return the whole word so things
 | 
| 457 |             # keep working
 | 
| 458 |             printf "%s" "${words[cword]}"
 | 
| 459 |         else
 | 
| 460 |             printf "%s" "${cur:0:$index}"
 | 
| 461 |         fi
 | 
| 462 |     fi
 | 
| 463 | } # _get_cword()
 | 
| 464 | 
 | 
| 465 | 
 | 
| 466 | # Get word previous to the current word.
 | 
| 467 | # This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4
 | 
| 468 | # will properly return the previous word with respect to any given exclusions to
 | 
| 469 | # COMP_WORDBREAKS.
 | 
| 470 | # @deprecated  Use `_get_comp_words_by_ref cur prev' instead
 | 
| 471 | # @see _get_comp_words_by_ref()
 | 
| 472 | #
 | 
| 473 | _get_pword()
 | 
| 474 | {
 | 
| 475 |     if [[ $COMP_CWORD -ge 1 ]]; then
 | 
| 476 |         _get_cword "${@:-}" 1
 | 
| 477 |     fi
 | 
| 478 | }
 | 
| 479 | 
 | 
| 480 | 
 | 
| 481 | # If the word-to-complete contains a colon (:), left-trim COMPREPLY items with
 | 
| 482 | # word-to-complete.
 | 
| 483 | # With a colon in COMP_WORDBREAKS, words containing
 | 
| 484 | # colons are always completed as entire words if the word to complete contains
 | 
| 485 | # a colon.  This function fixes this, by removing the colon-containing-prefix
 | 
| 486 | # from COMPREPLY items.
 | 
| 487 | # The preferred solution is to remove the colon (:) from COMP_WORDBREAKS in
 | 
| 488 | # your .bashrc:
 | 
| 489 | #
 | 
| 490 | #    # Remove colon (:) from list of word completion separators
 | 
| 491 | #    COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
 | 
| 492 | #
 | 
| 493 | # See also: Bash FAQ - E13) Why does filename completion misbehave if a colon
 | 
| 494 | # appears in the filename? - http://tiswww.case.edu/php/chet/bash/FAQ
 | 
| 495 | # @param $1 current word to complete (cur)
 | 
| 496 | # @modifies global array $COMPREPLY
 | 
| 497 | #
 | 
| 498 | __ltrim_colon_completions()
 | 
| 499 | {
 | 
| 500 |     if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
 | 
| 501 |         # Remove colon-word prefix from COMPREPLY items
 | 
| 502 |         local colon_word=${1%"${1##*:}"}
 | 
| 503 |         local i=${#COMPREPLY[*]}
 | 
| 504 |         while [[ $((--i)) -ge 0 ]]; do
 | 
| 505 |             COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
 | 
| 506 |         done
 | 
| 507 |     fi
 | 
| 508 | } # __ltrim_colon_completions()
 | 
| 509 | 
 | 
| 510 | 
 | 
| 511 | # This function quotes the argument in a way so that readline dequoting
 | 
| 512 | # results in the original argument.  This is necessary for at least
 | 
| 513 | # `compgen' which requires its arguments quoted/escaped:
 | 
| 514 | #
 | 
| 515 | #     $ ls "a'b/"
 | 
| 516 | #     c
 | 
| 517 | #     $ compgen -f "a'b/"       # Wrong, doesn't return output
 | 
| 518 | #     $ compgen -f "a\'b/"      # Good
 | 
| 519 | #     a\'b/c
 | 
| 520 | #
 | 
| 521 | # See also:
 | 
| 522 | # - http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html
 | 
| 523 | # - http://www.mail-archive.com/bash-completion-devel@lists.alioth.\
 | 
| 524 | #   debian.org/msg01944.html
 | 
| 525 | # @param $1  Argument to quote
 | 
| 526 | # @param $2  Name of variable to return result to
 | 
| 527 | _quote_readline_by_ref()
 | 
| 528 | {
 | 
| 529 |     if [[ $1 == \'* ]]; then
 | 
| 530 |         # Leave out first character
 | 
| 531 |         printf -v $2 %s "${1:1}"
 | 
| 532 |     else
 | 
| 533 |         printf -v $2 %q "$1"
 | 
| 534 |     fi
 | 
| 535 | 
 | 
| 536 |     # If result becomes quoted like this: $'string', re-evaluate in order to
 | 
| 537 |     # drop the additional quoting.  See also: http://www.mail-archive.com/
 | 
| 538 |     # bash-completion-devel@lists.alioth.debian.org/msg01942.html
 | 
| 539 |     [[ ${!2} == \$* ]] && eval $2=${!2}
 | 
| 540 | } # _quote_readline_by_ref()
 | 
| 541 | 
 | 
| 542 | 
 | 
| 543 | # This function performs file and directory completion. It's better than
 | 
| 544 | # simply using 'compgen -f', because it honours spaces in filenames.
 | 
| 545 | # @param $1  If `-d', complete only on directories.  Otherwise filter/pick only
 | 
| 546 | #            completions with `.$1' and the uppercase version of it as file
 | 
| 547 | #            extension.
 | 
| 548 | #
 | 
| 549 | _filedir()
 | 
| 550 | {
 | 
| 551 |     local IFS=$'\n'
 | 
| 552 | 
 | 
| 553 |     _tilde "$cur" || return
 | 
| 554 | 
 | 
| 555 |     local -a toks
 | 
| 556 |     local x reset
 | 
| 557 | 
 | 
| 558 |     reset=$(shopt -po noglob); set -o noglob
 | 
| 559 |     toks=( $( compgen -d -- "$cur" ) )
 | 
| 560 |     IFS=' '; $reset; IFS=$'\n'
 | 
| 561 | 
 | 
| 562 |     if [[ "$1" != -d ]]; then
 | 
| 563 |         local quoted
 | 
| 564 |         _quote_readline_by_ref "$cur" quoted
 | 
| 565 | 
 | 
| 566 |         # Munge xspec to contain uppercase version too
 | 
| 567 |         # http://thread.gmane.org/gmane.comp.shells.bash.bugs/15294/focus=15306
 | 
| 568 |         local xspec=${1:+"!*.@($1|${1^^})"}
 | 
| 569 |         reset=$(shopt -po noglob); set -o noglob
 | 
| 570 |         toks+=( $( compgen -f -X "$xspec" -- $quoted ) )
 | 
| 571 |         IFS=' '; $reset; IFS=$'\n'
 | 
| 572 | 
 | 
| 573 |         # Try without filter if it failed to produce anything and configured to
 | 
| 574 |         [[ -n ${COMP_FILEDIR_FALLBACK:-} && -n "$1" && ${#toks[@]} -lt 1 ]] && {
 | 
| 575 |             reset=$(shopt -po noglob); set -o noglob
 | 
| 576 |             toks+=( $( compgen -f -- $quoted ) )
 | 
| 577 |             IFS=' '; $reset; IFS=$'\n'
 | 
| 578 |         }
 | 
| 579 |     fi
 | 
| 580 | 
 | 
| 581 |     if [[ ${#toks[@]} -ne 0 ]]; then
 | 
| 582 |         # 2>/dev/null for direct invocation, e.g. in the _filedir unit test
 | 
| 583 |         compopt -o filenames 2>/dev/null
 | 
| 584 |         COMPREPLY+=( "${toks[@]}" )
 | 
| 585 |     fi
 | 
| 586 | } # _filedir()
 | 
| 587 | 
 | 
| 588 | 
 | 
| 589 | # This function splits $cur=--foo=bar into $prev=--foo, $cur=bar, making it
 | 
| 590 | # easier to support both "--foo bar" and "--foo=bar" style completions.
 | 
| 591 | # `=' should have been removed from COMP_WORDBREAKS when setting $cur for
 | 
| 592 | # this to be useful.
 | 
| 593 | # Returns 0 if current option was split, 1 otherwise.
 | 
| 594 | #
 | 
| 595 | _split_longopt()
 | 
| 596 | {
 | 
| 597 |     if [[ "$cur" == --?*=* ]]; then
 | 
| 598 |         # Cut also backslash before '=' in case it ended up there
 | 
| 599 |         # for some reason.
 | 
| 600 |         prev="${cur%%?(\\)=*}"
 | 
| 601 |         cur="${cur#*=}"
 | 
| 602 |         return 0
 | 
| 603 |     fi
 | 
| 604 | 
 | 
| 605 |     return 1
 | 
| 606 | }
 | 
| 607 | 
 | 
| 608 | # Complete variables.
 | 
| 609 | # @return  True (0) if variables were completed,
 | 
| 610 | #          False (> 0) if not.
 | 
| 611 | _variables()
 | 
| 612 | {
 | 
| 613 |     if [[ $cur =~ ^(\$(\{[!#]?)?)([A-Za-z0-9_]*)$ ]]; then
 | 
| 614 |         # Completing $var / ${var / ${!var / ${#var
 | 
| 615 |         if [[ $cur == \${* ]]; then
 | 
| 616 |             local arrs vars
 | 
| 617 |             vars=( $( compgen -A variable -P ${BASH_REMATCH[1]} -S '}' -- ${BASH_REMATCH[3]} ) ) && \
 | 
| 618 |             arrs=( $( compgen -A arrayvar -P ${BASH_REMATCH[1]} -S '[' -- ${BASH_REMATCH[3]} ) )
 | 
| 619 |             if [[ ${#vars[@]} -eq 1 && $arrs ]]; then
 | 
| 620 |                 # Complete ${arr with ${array[ if there is only one match, and that match is an array variable
 | 
| 621 |                 compopt -o nospace
 | 
| 622 |                 COMPREPLY+=( ${arrs[*]} )
 | 
| 623 |             else
 | 
| 624 |                 # Complete ${var with ${variable}
 | 
| 625 |                 COMPREPLY+=( ${vars[*]} )
 | 
| 626 |             fi
 | 
| 627 |         else
 | 
| 628 |             # Complete $var with $variable
 | 
| 629 |             COMPREPLY+=( $( compgen -A variable -P '$' -- "${BASH_REMATCH[3]}" ) )
 | 
| 630 |         fi
 | 
| 631 |         return 0
 | 
| 632 |     elif [[ $cur =~ ^(\$\{[#!]?)([A-Za-z0-9_]*)\[([^]]*)$ ]]; then
 | 
| 633 |         # Complete ${array[i with ${array[idx]}
 | 
| 634 |         local IFS=$'\n'
 | 
| 635 |         COMPREPLY+=( $( compgen -W '$(printf %s\\n "${!'${BASH_REMATCH[2]}'[@]}")' \
 | 
| 636 |             -P "${BASH_REMATCH[1]}${BASH_REMATCH[2]}[" -S ']}' -- "${BASH_REMATCH[3]}" ) )
 | 
| 637 |         # Complete ${arr[@ and ${arr[*
 | 
| 638 |         if [[ ${BASH_REMATCH[3]} == [@*] ]]; then
 | 
| 639 |             COMPREPLY+=( "${BASH_REMATCH[1]}${BASH_REMATCH[2]}[${BASH_REMATCH[3]}]}" )
 | 
| 640 |         fi
 | 
| 641 |         __ltrim_colon_completions "$cur"    # array indexes may have colons
 | 
| 642 |         return 0
 | 
| 643 |     elif [[ $cur =~ ^\$\{[#!]?[A-Za-z0-9_]*\[.*\]$ ]]; then
 | 
| 644 |         # Complete ${array[idx] with ${array[idx]}
 | 
| 645 |         COMPREPLY+=( "$cur}" )
 | 
| 646 |         __ltrim_colon_completions "$cur"
 | 
| 647 |         return 0
 | 
| 648 |     else
 | 
| 649 |         case $prev in
 | 
| 650 |             TZ)
 | 
| 651 |                 cur=/usr/share/zoneinfo/$cur
 | 
| 652 |                 _filedir
 | 
| 653 |                 for i in ${!COMPREPLY[@]}; do
 | 
| 654 |                     if [[ ${COMPREPLY[i]} == *.tab ]]; then
 | 
| 655 |                         unset 'COMPREPLY[i]'
 | 
| 656 |                         continue
 | 
| 657 |                     elif [[ -d ${COMPREPLY[i]} ]]; then
 | 
| 658 |                         COMPREPLY[i]+=/
 | 
| 659 |                         compopt -o nospace
 | 
| 660 |                     fi
 | 
| 661 |                     COMPREPLY[i]=${COMPREPLY[i]#/usr/share/zoneinfo/}
 | 
| 662 |                 done
 | 
| 663 |                 return 0
 | 
| 664 |                 ;;
 | 
| 665 |         esac
 | 
| 666 |     fi
 | 
| 667 |     return 1
 | 
| 668 | }
 | 
| 669 | 
 | 
| 670 | # Initialize completion and deal with various general things: do file
 | 
| 671 | # and variable completion where appropriate, and adjust prev, words,
 | 
| 672 | # and cword as if no redirections exist so that completions do not
 | 
| 673 | # need to deal with them.  Before calling this function, make sure
 | 
| 674 | # cur, prev, words, and cword are local, ditto split if you use -s.
 | 
| 675 | #
 | 
| 676 | # Options:
 | 
| 677 | #     -n EXCLUDE  Passed to _get_comp_words_by_ref -n with redirection chars
 | 
| 678 | #     -e XSPEC    Passed to _filedir as first arg for stderr redirections
 | 
| 679 | #     -o XSPEC    Passed to _filedir as first arg for other output redirections
 | 
| 680 | #     -i XSPEC    Passed to _filedir as first arg for stdin redirections
 | 
| 681 | #     -s          Split long options with _split_longopt, implies -n =
 | 
| 682 | # @return  True (0) if completion needs further processing,
 | 
| 683 | #          False (> 0) no further processing is necessary.
 | 
| 684 | #
 | 
| 685 | _init_completion()
 | 
| 686 | {
 | 
| 687 |     local exclude= flag outx errx inx OPTIND=1
 | 
| 688 | 
 | 
| 689 |     while getopts "n:e:o:i:s" flag "$@"; do
 | 
| 690 |         case $flag in
 | 
| 691 |             n) exclude+=$OPTARG ;;
 | 
| 692 |             e) errx=$OPTARG ;;
 | 
| 693 |             o) outx=$OPTARG ;;
 | 
| 694 |             i) inx=$OPTARG ;;
 | 
| 695 |             s) split=false ; exclude+== ;;
 | 
| 696 |         esac
 | 
| 697 |     done
 | 
| 698 | 
 | 
| 699 |     # For some reason completion functions are not invoked at all by
 | 
| 700 |     # bash (at least as of 4.1.7) after the command line contains an
 | 
| 701 |     # ampersand so we don't get a chance to deal with redirections
 | 
| 702 |     # containing them, but if we did, hopefully the below would also
 | 
| 703 |     # do the right thing with them...
 | 
| 704 | 
 | 
| 705 |     COMPREPLY=()
 | 
| 706 |     local redir="@(?([0-9])<|?([0-9&])>?(>)|>&)"
 | 
| 707 |     _get_comp_words_by_ref -n "$exclude<>&" cur prev words cword
 | 
| 708 | 
 | 
| 709 |     # Complete variable names.
 | 
| 710 |     _variables && return 1
 | 
| 711 | 
 | 
| 712 |     # Complete on files if current is a redirect possibly followed by a
 | 
| 713 |     # filename, e.g. ">foo", or previous is a "bare" redirect, e.g. ">".
 | 
| 714 |     if [[ $cur == $redir* || $prev == $redir ]]; then
 | 
| 715 |         local xspec
 | 
| 716 |         case $cur in
 | 
| 717 |             2'>'*) xspec=$errx ;;
 | 
| 718 |             *'>'*) xspec=$outx ;;
 | 
| 719 |             *'<'*) xspec=$inx ;;
 | 
| 720 |             *)
 | 
| 721 |                 case $prev in
 | 
| 722 |                     2'>'*) xspec=$errx ;;
 | 
| 723 |                     *'>'*) xspec=$outx ;;
 | 
| 724 |                     *'<'*) xspec=$inx ;;
 | 
| 725 |                 esac
 | 
| 726 |                 ;;
 | 
| 727 |         esac
 | 
| 728 |         cur="${cur##$redir}"
 | 
| 729 |         _filedir $xspec
 | 
| 730 |         return 1
 | 
| 731 |     fi
 | 
| 732 | 
 | 
| 733 |     # Remove all redirections so completions don't have to deal with them.
 | 
| 734 |     local i skip
 | 
| 735 |     for (( i=1; i < ${#words[@]}; )); do
 | 
| 736 |         if [[ ${words[i]} == $redir* ]]; then
 | 
| 737 |             # If "bare" redirect, remove also the next word (skip=2).
 | 
| 738 |             [[ ${words[i]} == $redir ]] && skip=2 || skip=1
 | 
| 739 |             words=( "${words[@]:0:i}" "${words[@]:i+skip}" )
 | 
| 740 |             [[ $i -le $cword ]] && cword=$(( cword - skip ))
 | 
| 741 |         else
 | 
| 742 |             i=$(( ++i ))
 | 
| 743 |         fi
 | 
| 744 |     done
 | 
| 745 | 
 | 
| 746 |     [[ $cword -le 0 ]] && return 1
 | 
| 747 |     prev=${words[cword-1]}
 | 
| 748 | 
 | 
| 749 |     [[ ${split-} ]] && _split_longopt && split=true
 | 
| 750 | 
 | 
| 751 |     return 0
 | 
| 752 | }
 | 
| 753 | 
 | 
| 754 | # Helper function for _parse_help and _parse_usage.
 | 
| 755 | __parse_options()
 | 
| 756 | {
 | 
| 757 |     local option option2 i IFS=$' \t\n,/|'
 | 
| 758 | 
 | 
| 759 |     # Take first found long option, or first one (short) if not found.
 | 
| 760 |     option=
 | 
| 761 |     local -a array
 | 
| 762 |     read -a array <<<"$1"
 | 
| 763 |     for i in "${array[@]}"; do
 | 
| 764 |         case "$i" in
 | 
| 765 |             ---*) break ;;
 | 
| 766 |             --?*) option=$i ; break ;;
 | 
| 767 |             -?*)  [[ $option ]] || option=$i ;;
 | 
| 768 |             *)    break ;;
 | 
| 769 |         esac
 | 
| 770 |     done
 | 
| 771 |     [[ $option ]] || return
 | 
| 772 | 
 | 
| 773 |     IFS=$' \t\n' # affects parsing of the regexps below...
 | 
| 774 | 
 | 
| 775 |     # Expand --[no]foo to --foo and --nofoo etc
 | 
| 776 |     if [[ $option =~ (\[((no|dont)-?)\]). ]]; then
 | 
| 777 |         option2=${option/"${BASH_REMATCH[1]}"/}
 | 
| 778 |         option2=${option2%%[<{().[]*}
 | 
| 779 |         printf '%s\n' "${option2/=*/=}"
 | 
| 780 |         option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"}
 | 
| 781 |     fi
 | 
| 782 | 
 | 
| 783 |     option=${option%%[<{().[]*}
 | 
| 784 |     printf '%s\n' "${option/=*/=}"
 | 
| 785 | }
 | 
| 786 | 
 | 
| 787 | # Parse GNU style help output of the given command.
 | 
| 788 | # @param $1  command; if "-", read from stdin and ignore rest of args
 | 
| 789 | # @param $2  command options (default: --help)
 | 
| 790 | #
 | 
| 791 | _parse_help()
 | 
| 792 | {
 | 
| 793 |     eval local cmd=$( quote "$1" )
 | 
| 794 |     local line
 | 
| 795 |     { case $cmd in
 | 
| 796 |         -) cat ;;
 | 
| 797 |         *) LC_ALL=C "$( dequote "$cmd" )" ${2:---help} 2>&1 ;;
 | 
| 798 |       esac } \
 | 
| 799 |     | while read -r line; do
 | 
| 800 | 
 | 
| 801 |         [[ $line == *([[:blank:]])-* ]] || continue
 | 
| 802 |         # transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc
 | 
| 803 |         while [[ $line =~ \
 | 
| 804 |             ((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+\]? ]]; do
 | 
| 805 |             line=${line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"}
 | 
| 806 |         done
 | 
| 807 |         __parse_options "${line// or /, }"
 | 
| 808 | 
 | 
| 809 |     done
 | 
| 810 | }
 | 
| 811 | 
 | 
| 812 | # Parse BSD style usage output (options in brackets) of the given command.
 | 
| 813 | # @param $1  command; if "-", read from stdin and ignore rest of args
 | 
| 814 | # @param $2  command options (default: --usage)
 | 
| 815 | #
 | 
| 816 | _parse_usage()
 | 
| 817 | {
 | 
| 818 |     eval local cmd=$( quote "$1" )
 | 
| 819 |     local line match option i char
 | 
| 820 |     { case $cmd in
 | 
| 821 |         -) cat ;;
 | 
| 822 |         *) LC_ALL=C "$( dequote "$cmd" )" ${2:---usage} 2>&1 ;;
 | 
| 823 |       esac } \
 | 
| 824 |     | while read -r line; do
 | 
| 825 | 
 | 
| 826 |         while [[ $line =~ \[[[:space:]]*(-[^]]+)[[:space:]]*\] ]]; do
 | 
| 827 |             match=${BASH_REMATCH[0]}
 | 
| 828 |             option=${BASH_REMATCH[1]}
 | 
| 829 |             case $option in
 | 
| 830 |                 -?(\[)+([a-zA-Z0-9?]))
 | 
| 831 |                     # Treat as bundled short options
 | 
| 832 |                     for (( i=1; i < ${#option}; i++ )); do
 | 
| 833 |                         char=${option:i:1}
 | 
| 834 |                         [[ $char != '[' ]] && printf '%s\n' -$char
 | 
| 835 |                     done
 | 
| 836 |                     ;;
 | 
| 837 |                 *)
 | 
| 838 |                     __parse_options "$option"
 | 
| 839 |                     ;;
 | 
| 840 |             esac
 | 
| 841 |             line=${line#*"$match"}
 | 
| 842 |         done
 | 
| 843 | 
 | 
| 844 |     done
 | 
| 845 | }
 | 
| 846 | 
 | 
| 847 | # This function completes on signal names (minus the SIG prefix)
 | 
| 848 | # @param $1 prefix
 | 
| 849 | _signals()
 | 
| 850 | {
 | 
| 851 |     local -a sigs=( $( compgen -P "$1" -A signal "SIG${cur#$1}" ) )
 | 
| 852 |     COMPREPLY+=( "${sigs[@]/#${1}SIG/${1}}" )
 | 
| 853 | }
 | 
| 854 | 
 | 
| 855 | # This function completes on known mac addresses
 | 
| 856 | #
 | 
| 857 | _mac_addresses()
 | 
| 858 | {
 | 
| 859 |     local re='\([A-Fa-f0-9]\{2\}:\)\{5\}[A-Fa-f0-9]\{2\}'
 | 
| 860 |     local PATH="$PATH:/sbin:/usr/sbin"
 | 
| 861 | 
 | 
| 862 |     # Local interfaces
 | 
| 863 |     # - ifconfig on Linux: HWaddr or ether
 | 
| 864 |     # - ifconfig on FreeBSD: ether
 | 
| 865 |     # - ip link: link/ether
 | 
| 866 |     COMPREPLY+=( $( \
 | 
| 867 |         { LC_ALL=C ifconfig -a || ip link show; } 2>/dev/null | command sed -ne \
 | 
| 868 |         "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]].*/\1/p" -ne \
 | 
| 869 |         "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" -ne \
 | 
| 870 |         "s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($re\)[[:space:]].*|\2|p" -ne \
 | 
| 871 |         "s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($re\)[[:space:]]*$|\2|p"
 | 
| 872 |         ) )
 | 
| 873 | 
 | 
| 874 |     # ARP cache
 | 
| 875 |     COMPREPLY+=( $( { arp -an || ip neigh show; } 2>/dev/null | command sed -ne \
 | 
| 876 |         "s/.*[[:space:]]\($re\)[[:space:]].*/\1/p" -ne \
 | 
| 877 |         "s/.*[[:space:]]\($re\)[[:space:]]*$/\1/p" ) )
 | 
| 878 | 
 | 
| 879 |     # /etc/ethers
 | 
| 880 |     COMPREPLY+=( $( command sed -ne \
 | 
| 881 |         "s/^[[:space:]]*\($re\)[[:space:]].*/\1/p" /etc/ethers 2>/dev/null ) )
 | 
| 882 | 
 | 
| 883 |     COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- "$cur" ) )
 | 
| 884 |     __ltrim_colon_completions "$cur"
 | 
| 885 | }
 | 
| 886 | 
 | 
| 887 | # This function completes on configured network interfaces
 | 
| 888 | #
 | 
| 889 | _configured_interfaces()
 | 
| 890 | {
 | 
| 891 |     if [[ -f /etc/debian_version ]]; then
 | 
| 892 |         # Debian system
 | 
| 893 |         COMPREPLY=( $( compgen -W "$( command sed -ne 's|^iface \([^ ]\{1,\}\).*$|\1|p'\
 | 
| 894 |             /etc/network/interfaces /etc/network/interfaces.d/* 2>/dev/null )" \
 | 
| 895 |             -- "$cur" ) )
 | 
| 896 |     elif [[ -f /etc/SuSE-release ]]; then
 | 
| 897 |         # SuSE system
 | 
| 898 |         COMPREPLY=( $( compgen -W "$( printf '%s\n' \
 | 
| 899 |             /etc/sysconfig/network/ifcfg-* | \
 | 
| 900 |             command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p' )" -- "$cur" ) )
 | 
| 901 |     elif [[ -f /etc/pld-release ]]; then
 | 
| 902 |         # PLD Linux
 | 
| 903 |         COMPREPLY=( $( compgen -W "$( command ls -B \
 | 
| 904 |             /etc/sysconfig/interfaces | \
 | 
| 905 |             command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p' )" -- "$cur" ) )
 | 
| 906 |     else
 | 
| 907 |         # Assume Red Hat
 | 
| 908 |         COMPREPLY=( $( compgen -W "$( printf '%s\n' \
 | 
| 909 |             /etc/sysconfig/network-scripts/ifcfg-* | \
 | 
| 910 |             command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p' )" -- "$cur" ) )
 | 
| 911 |     fi
 | 
| 912 | }
 | 
| 913 | 
 | 
| 914 | # Local IP addresses.
 | 
| 915 | # -4: IPv4 addresses only (default)
 | 
| 916 | # -6: IPv6 addresses only
 | 
| 917 | # -a: All addresses
 | 
| 918 | #
 | 
| 919 | _ip_addresses()
 | 
| 920 | {
 | 
| 921 |     local n
 | 
| 922 |     case $1 in
 | 
| 923 |         -a) n='6\?' ;;
 | 
| 924 |         -6) n='6' ;;
 | 
| 925 |     esac
 | 
| 926 |     local PATH=$PATH:/sbin
 | 
| 927 |     local addrs=$( { LC_ALL=C ifconfig -a || ip addr show; } 2>/dev/null |
 | 
| 928 |         command sed -ne \
 | 
| 929 |             's/.*addr:\([^[:space:]]*\).*/\1/p' -ne \
 | 
| 930 |             "s|.*inet$n[[:space:]]\{1,\}\([^[:space:]/]*\).*|\1|p" )
 | 
| 931 |     COMPREPLY+=( $( compgen -W "$addrs" -- "$cur" ) )
 | 
| 932 | }
 | 
| 933 | 
 | 
| 934 | # This function completes on available kernels
 | 
| 935 | #
 | 
| 936 | _kernel_versions()
 | 
| 937 | {
 | 
| 938 |     COMPREPLY=( $( compgen -W '$( command ls /lib/modules )' -- "$cur" ) )
 | 
| 939 | }
 | 
| 940 | 
 | 
| 941 | # This function completes on all available network interfaces
 | 
| 942 | # -a: restrict to active interfaces only
 | 
| 943 | # -w: restrict to wireless interfaces only
 | 
| 944 | #
 | 
| 945 | _available_interfaces()
 | 
| 946 | {
 | 
| 947 |     local PATH=$PATH:/sbin
 | 
| 948 | 
 | 
| 949 |     COMPREPLY=( $( {
 | 
| 950 |         if [[ ${1:-} == -w ]]; then
 | 
| 951 |             iwconfig
 | 
| 952 |         elif [[ ${1:-} == -a ]]; then
 | 
| 953 |             ifconfig || ip link show up
 | 
| 954 |         else
 | 
| 955 |             ifconfig -a || ip link show
 | 
| 956 |         fi
 | 
| 957 |     } 2>/dev/null | awk \
 | 
| 958 |         '/^[^ \t]/ { if ($1 ~ /^[0-9]+:/) { print $2 } else { print $1 } }' ) )
 | 
| 959 | 
 | 
| 960 |     COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) )
 | 
| 961 | }
 | 
| 962 | 
 | 
| 963 | # Echo number of CPUs, falling back to 1 on failure.
 | 
| 964 | _ncpus()
 | 
| 965 | {
 | 
| 966 |     local var=NPROCESSORS_ONLN
 | 
| 967 |     [[ $OSTYPE == *linux* ]] && var=_$var
 | 
| 968 |     local n=$( getconf $var 2>/dev/null )
 | 
| 969 |     printf %s ${n:-1}
 | 
| 970 | }
 | 
| 971 | 
 | 
| 972 | # Perform tilde (~) completion
 | 
| 973 | # @return  True (0) if completion needs further processing,
 | 
| 974 | #          False (> 0) if tilde is followed by a valid username, completions
 | 
| 975 | #          are put in COMPREPLY and no further processing is necessary.
 | 
| 976 | _tilde()
 | 
| 977 | {
 | 
| 978 |     local result=0
 | 
| 979 |     if [[ $1 == \~* && $1 != */* ]]; then
 | 
| 980 |         # Try generate ~username completions
 | 
| 981 |         COMPREPLY=( $( compgen -P '~' -u -- "${1#\~}" ) )
 | 
| 982 |         result=${#COMPREPLY[@]}
 | 
| 983 |         # 2>/dev/null for direct invocation, e.g. in the _tilde unit test
 | 
| 984 |         [[ $result -gt 0 ]] && compopt -o filenames 2>/dev/null
 | 
| 985 |     fi
 | 
| 986 |     return $result
 | 
| 987 | }
 | 
| 988 | 
 | 
| 989 | 
 | 
| 990 | # Expand variable starting with tilde (~)
 | 
| 991 | # We want to expand ~foo/... to /home/foo/... to avoid problems when
 | 
| 992 | # word-to-complete starting with a tilde is fed to commands and ending up
 | 
| 993 | # quoted instead of expanded.
 | 
| 994 | # Only the first portion of the variable from the tilde up to the first slash
 | 
| 995 | # (~../) is expanded.  The remainder of the variable, containing for example
 | 
| 996 | # a dollar sign variable ($) or asterisk (*) is not expanded.
 | 
| 997 | # Example usage:
 | 
| 998 | #
 | 
| 999 | #    $ v="~"; __expand_tilde_by_ref v; echo "$v"
 | 
| 1000 | #
 | 
| 1001 | # Example output:
 | 
| 1002 | #
 | 
| 1003 | #       v                  output
 | 
| 1004 | #    --------         ----------------
 | 
| 1005 | #    ~                /home/user
 | 
| 1006 | #    ~foo/bar         /home/foo/bar
 | 
| 1007 | #    ~foo/$HOME       /home/foo/$HOME
 | 
| 1008 | #    ~foo/a  b        /home/foo/a  b
 | 
| 1009 | #    ~foo/*           /home/foo/*
 | 
| 1010 | #
 | 
| 1011 | # @param $1  Name of variable (not the value of the variable) to expand
 | 
| 1012 | __expand_tilde_by_ref()
 | 
| 1013 | {
 | 
| 1014 |     if [[ ${!1} == \~* ]]; then
 | 
| 1015 |         eval $1=$(printf ~%q "${!1#\~}")
 | 
| 1016 |     fi
 | 
| 1017 | } # __expand_tilde_by_ref()
 | 
| 1018 | 
 | 
| 1019 | 
 | 
| 1020 | # This function expands tildes in pathnames
 | 
| 1021 | #
 | 
| 1022 | _expand()
 | 
| 1023 | {
 | 
| 1024 |     # Expand ~username type directory specifications.  We want to expand
 | 
| 1025 |     # ~foo/... to /home/foo/... to avoid problems when $cur starting with
 | 
| 1026 |     # a tilde is fed to commands and ending up quoted instead of expanded.
 | 
| 1027 | 
 | 
| 1028 |     if [[ "$cur" == \~*/* ]]; then
 | 
| 1029 |         __expand_tilde_by_ref cur
 | 
| 1030 |     elif [[ "$cur" == \~* ]]; then
 | 
| 1031 |         _tilde "$cur" || eval COMPREPLY[0]=$(printf ~%q "${COMPREPLY[0]#\~}")
 | 
| 1032 |         return ${#COMPREPLY[@]}
 | 
| 1033 |     fi
 | 
| 1034 | }
 | 
| 1035 | 
 | 
| 1036 | # This function completes on process IDs.
 | 
| 1037 | # AIX and Solaris ps prefers X/Open syntax.
 | 
| 1038 | [[ $OSTYPE == *@(solaris|aix)* ]] &&
 | 
| 1039 | _pids()
 | 
| 1040 | {
 | 
| 1041 |     COMPREPLY=( $( compgen -W '$( command ps -efo pid | command sed 1d )' -- "$cur" ))
 | 
| 1042 | } ||
 | 
| 1043 | _pids()
 | 
| 1044 | {
 | 
| 1045 |     COMPREPLY=( $( compgen -W '$( command ps axo pid= )' -- "$cur" ) )
 | 
| 1046 | }
 | 
| 1047 | 
 | 
| 1048 | # This function completes on process group IDs.
 | 
| 1049 | # AIX and SunOS prefer X/Open, all else should be BSD.
 | 
| 1050 | [[ $OSTYPE == *@(solaris|aix)* ]] &&
 | 
| 1051 | _pgids()
 | 
| 1052 | {
 | 
| 1053 |     COMPREPLY=( $( compgen -W '$( command ps -efo pgid | command sed 1d )' -- "$cur" ))
 | 
| 1054 | } ||
 | 
| 1055 | _pgids()
 | 
| 1056 | {
 | 
| 1057 |     COMPREPLY=( $( compgen -W '$( command ps axo pgid= )' -- "$cur" ))
 | 
| 1058 | }
 | 
| 1059 | 
 | 
| 1060 | # This function completes on process names.
 | 
| 1061 | # AIX and SunOS prefer X/Open, all else should be BSD.
 | 
| 1062 | # @param $1 if -s, don't try to avoid truncated command names
 | 
| 1063 | [[ $OSTYPE == *@(solaris|aix)* ]] &&
 | 
| 1064 | _pnames()
 | 
| 1065 | {
 | 
| 1066 |     COMPREPLY=( $( compgen -X '<defunct>' -W '$( command ps -efo comm | \
 | 
| 1067 |         command sed -e 1d -e "s:.*/::" -e "s/^-//" | sort -u )' -- "$cur" ) )
 | 
| 1068 | } ||
 | 
| 1069 | _pnames()
 | 
| 1070 | {
 | 
| 1071 |     if [[ "$1" == -s ]]; then
 | 
| 1072 |         COMPREPLY=( $( compgen -X '<defunct>' \
 | 
| 1073 |             -W '$( command ps axo comm | command sed -e 1d )' -- "$cur" ) )
 | 
| 1074 |     else
 | 
| 1075 |         # FIXME: completes "[kblockd/0]" to "0". Previously it was completed
 | 
| 1076 |         # to "kblockd" which isn't correct either. "kblockd/0" would be
 | 
| 1077 |         # arguably most correct, but killall from psmisc 22 treats arguments
 | 
| 1078 |         # containing "/" specially unless -r is given so that wouldn't quite
 | 
| 1079 |         # work either. Perhaps it'd be best to not complete these to anything
 | 
| 1080 |         # for now.
 | 
| 1081 |         COMPREPLY=( $( compgen -X '<defunct>' -W '$( command ps axo command= | command sed -e \
 | 
| 1082 |             "s/ .*//" -e \
 | 
| 1083 |             "s:.*/::" -e \
 | 
| 1084 |             "s/:$//" -e \
 | 
| 1085 |             "s/^[[(-]//" -e \
 | 
| 1086 |             "s/[])]$//" | sort -u )' -- "$cur" ) )
 | 
| 1087 |     fi
 | 
| 1088 | }
 | 
| 1089 | 
 | 
| 1090 | # This function completes on user IDs
 | 
| 1091 | #
 | 
| 1092 | _uids()
 | 
| 1093 | {
 | 
| 1094 |     if type getent &>/dev/null; then
 | 
| 1095 |         COMPREPLY=( $( compgen -W '$( getent passwd | cut -d: -f3 )' -- "$cur" ) )
 | 
| 1096 |     elif type perl &>/dev/null; then
 | 
| 1097 |         COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($uid) = (getpwent)[2]) { print $uid . "\n" }'"'"' )' -- "$cur" ) )
 | 
| 1098 |     else
 | 
| 1099 |         # make do with /etc/passwd
 | 
| 1100 |         COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/passwd )' -- "$cur" ) )
 | 
| 1101 |     fi
 | 
| 1102 | }
 | 
| 1103 | 
 | 
| 1104 | # This function completes on group IDs
 | 
| 1105 | #
 | 
| 1106 | _gids()
 | 
| 1107 | {
 | 
| 1108 |     if type getent &>/dev/null; then
 | 
| 1109 |         COMPREPLY=( $( compgen -W '$( getent group | cut -d: -f3 )' \
 | 
| 1110 |             -- "$cur" ) )
 | 
| 1111 |     elif type perl &>/dev/null; then
 | 
| 1112 |         COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($gid) = (getgrent)[2]) { print $gid . "\n" }'"'"' )' -- "$cur" ) )
 | 
| 1113 |     else
 | 
| 1114 |         # make do with /etc/group
 | 
| 1115 |         COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/group )' -- "$cur" ) )
 | 
| 1116 |     fi
 | 
| 1117 | }
 | 
| 1118 | 
 | 
| 1119 | # Glob for matching various backup files.
 | 
| 1120 | #
 | 
| 1121 | _backup_glob='@(#*#|*@(~|.@(bak|orig|rej|swp|dpkg*|rpm@(orig|new|save))))'
 | 
| 1122 | 
 | 
| 1123 | # Complete on xinetd services
 | 
| 1124 | #
 | 
| 1125 | _xinetd_services()
 | 
| 1126 | {
 | 
| 1127 |     local xinetddir=/etc/xinetd.d
 | 
| 1128 |     if [[ -d $xinetddir ]]; then
 | 
| 1129 |         local IFS=$' \t\n' reset=$(shopt -p nullglob); shopt -s nullglob
 | 
| 1130 |         local -a svcs=( $( printf '%s\n' $xinetddir/!($_backup_glob) ) )
 | 
| 1131 |         $reset
 | 
| 1132 |         COMPREPLY+=( $( compgen -W '${svcs[@]#$xinetddir/}' -- "$cur" ) )
 | 
| 1133 |     fi
 | 
| 1134 | }
 | 
| 1135 | 
 | 
| 1136 | # This function completes on services
 | 
| 1137 | #
 | 
| 1138 | _services()
 | 
| 1139 | {
 | 
| 1140 |     local sysvdirs
 | 
| 1141 |     _sysvdirs
 | 
| 1142 | 
 | 
| 1143 |     local IFS=$' \t\n' reset=$(shopt -p nullglob); shopt -s nullglob
 | 
| 1144 |     COMPREPLY=( \
 | 
| 1145 |         $( printf '%s\n' ${sysvdirs[0]}/!($_backup_glob|functions|README) ) )
 | 
| 1146 |     $reset
 | 
| 1147 | 
 | 
| 1148 |     COMPREPLY+=( $( { systemctl list-units --full --all || \
 | 
| 1149 |                       systemctl list-unit-files; } 2>/dev/null | \
 | 
| 1150 |         awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' ) )
 | 
| 1151 | 
 | 
| 1152 |     if [[ -x /sbin/upstart-udev-bridge ]]; then
 | 
| 1153 |         COMPREPLY+=( $( initctl list 2>/dev/null | cut -d' ' -f1 ) )
 | 
| 1154 |     fi
 | 
| 1155 | 
 | 
| 1156 |     COMPREPLY=( $( compgen -W '${COMPREPLY[@]#${sysvdirs[0]}/}' -- "$cur" ) )
 | 
| 1157 | }
 | 
| 1158 | 
 | 
| 1159 | # This completes on a list of all available service scripts for the
 | 
| 1160 | # 'service' command and/or the SysV init.d directory, followed by
 | 
| 1161 | # that script's available commands
 | 
| 1162 | #
 | 
| 1163 | _service()
 | 
| 1164 | {
 | 
| 1165 |     local cur prev words cword
 | 
| 1166 |     _init_completion || return
 | 
| 1167 | 
 | 
| 1168 |     # don't complete past 2nd token
 | 
| 1169 |     [[ $cword -gt 2 ]] && return
 | 
| 1170 | 
 | 
| 1171 |     if [[ $cword -eq 1 && $prev == ?(*/)service ]]; then
 | 
| 1172 |         _services
 | 
| 1173 |         [[ -e /etc/mandrake-release ]] && _xinetd_services
 | 
| 1174 |     else
 | 
| 1175 |         local sysvdirs
 | 
| 1176 |         _sysvdirs
 | 
| 1177 |         COMPREPLY=( $( compgen -W '`command sed -e "y/|/ /" \
 | 
| 1178 |             -ne "s/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\2/p" \
 | 
| 1179 |             ${sysvdirs[0]}/${prev##*/} 2>/dev/null` start stop' -- "$cur" ) )
 | 
| 1180 |     fi
 | 
| 1181 | } &&
 | 
| 1182 | complete -F _service service
 | 
| 1183 | _sysvdirs
 | 
| 1184 | for svcdir in ${sysvdirs[@]}; do
 | 
| 1185 |     for svc in $svcdir/!($_backup_glob); do
 | 
| 1186 |         [[ -x $svc ]] && complete -F _service $svc
 | 
| 1187 |     done
 | 
| 1188 | done
 | 
| 1189 | unset svc svcdir sysvdirs
 | 
| 1190 | 
 | 
| 1191 | # This function completes on modules
 | 
| 1192 | #
 | 
| 1193 | _modules()
 | 
| 1194 | {
 | 
| 1195 |     local modpath
 | 
| 1196 |     modpath=/lib/modules/$1
 | 
| 1197 |     COMPREPLY=( $( compgen -W "$( command ls -RL $modpath 2>/dev/null | \
 | 
| 1198 |         command sed -ne 's/^\(.*\)\.k\{0,1\}o\(\.[gx]z\)\{0,1\}$/\1/p' )" -- "$cur" ) )
 | 
| 1199 | }
 | 
| 1200 | 
 | 
| 1201 | # This function completes on installed modules
 | 
| 1202 | #
 | 
| 1203 | _installed_modules()
 | 
| 1204 | {
 | 
| 1205 |     COMPREPLY=( $( compgen -W "$( PATH="$PATH:/sbin" lsmod | \
 | 
| 1206 |         awk '{if (NR != 1) print $1}' )" -- "$1" ) )
 | 
| 1207 | }
 | 
| 1208 | 
 | 
| 1209 | # This function completes on user or user:group format; as for chown and cpio.
 | 
| 1210 | #
 | 
| 1211 | # The : must be added manually; it will only complete usernames initially.
 | 
| 1212 | # The legacy user.group format is not supported.
 | 
| 1213 | #
 | 
| 1214 | # @param $1  If -u, only return users/groups the user has access to in
 | 
| 1215 | #            context of current completion.
 | 
| 1216 | _usergroup()
 | 
| 1217 | {
 | 
| 1218 |     if [[ $cur == *\\\\* || $cur == *:*:* ]]; then
 | 
| 1219 |         # Give up early on if something seems horribly wrong.
 | 
| 1220 |         return
 | 
| 1221 |     elif [[ $cur == *\\:* ]]; then
 | 
| 1222 |         # Completing group after 'user\:gr<TAB>'.
 | 
| 1223 |         # Reply with a list of groups prefixed with 'user:', readline will
 | 
| 1224 |         # escape to the colon.
 | 
| 1225 |         local prefix
 | 
| 1226 |         prefix=${cur%%*([^:])}
 | 
| 1227 |         prefix=${prefix//\\}
 | 
| 1228 |         local mycur="${cur#*[:]}"
 | 
| 1229 |         if [[ $1 == -u ]]; then
 | 
| 1230 |             _allowed_groups "$mycur"
 | 
| 1231 |         else
 | 
| 1232 |             local IFS=$'\n'
 | 
| 1233 |             COMPREPLY=( $( compgen -g -- "$mycur" ) )
 | 
| 1234 |         fi
 | 
| 1235 |         COMPREPLY=( $( compgen -P "$prefix" -W "${COMPREPLY[@]}" ) )
 | 
| 1236 |     elif [[ $cur == *:* ]]; then
 | 
| 1237 |         # Completing group after 'user:gr<TAB>'.
 | 
| 1238 |         # Reply with a list of unprefixed groups since readline with split on :
 | 
| 1239 |         # and only replace the 'gr' part
 | 
| 1240 |         local mycur="${cur#*:}"
 | 
| 1241 |         if [[ $1 == -u ]]; then
 | 
| 1242 |             _allowed_groups "$mycur"
 | 
| 1243 |         else
 | 
| 1244 |             local IFS=$'\n'
 | 
| 1245 |             COMPREPLY=( $( compgen -g -- "$mycur" ) )
 | 
| 1246 |         fi
 | 
| 1247 |     else
 | 
| 1248 |         # Completing a partial 'usernam<TAB>'.
 | 
| 1249 |         #
 | 
| 1250 |         # Don't suffix with a : because readline will escape it and add a
 | 
| 1251 |         # slash. It's better to complete into 'chown username ' than 'chown
 | 
| 1252 |         # username\:'.
 | 
| 1253 |         if [[ $1 == -u ]]; then
 | 
| 1254 |             _allowed_users "$cur"
 | 
| 1255 |         else
 | 
| 1256 |             local IFS=$'\n'
 | 
| 1257 |             COMPREPLY=( $( compgen -u -- "$cur" ) )
 | 
| 1258 |         fi
 | 
| 1259 |     fi
 | 
| 1260 | }
 | 
| 1261 | 
 | 
| 1262 | _allowed_users()
 | 
| 1263 | {
 | 
| 1264 |     if _complete_as_root; then
 | 
| 1265 |         local IFS=$'\n'
 | 
| 1266 |         COMPREPLY=( $( compgen -u -- "${1:-$cur}" ) )
 | 
| 1267 |     else
 | 
| 1268 |         local IFS=$'\n '
 | 
| 1269 |         COMPREPLY=( $( compgen -W \
 | 
| 1270 |             "$( id -un 2>/dev/null || whoami 2>/dev/null )" -- "${1:-$cur}" ) )
 | 
| 1271 |     fi
 | 
| 1272 | }
 | 
| 1273 | 
 | 
| 1274 | _allowed_groups()
 | 
| 1275 | {
 | 
| 1276 |     if _complete_as_root; then
 | 
| 1277 |         local IFS=$'\n'
 | 
| 1278 |         COMPREPLY=( $( compgen -g -- "$1" ) )
 | 
| 1279 |     else
 | 
| 1280 |         local IFS=$'\n '
 | 
| 1281 |         COMPREPLY=( $( compgen -W \
 | 
| 1282 |             "$( id -Gn 2>/dev/null || groups 2>/dev/null )" -- "$1" ) )
 | 
| 1283 |     fi
 | 
| 1284 | }
 | 
| 1285 | 
 | 
| 1286 | # This function completes on valid shells
 | 
| 1287 | #
 | 
| 1288 | _shells()
 | 
| 1289 | {
 | 
| 1290 |     local shell rest
 | 
| 1291 |     while read -r shell rest; do
 | 
| 1292 |         [[ $shell == /* && $shell == "$cur"* ]] && COMPREPLY+=( $shell )
 | 
| 1293 |     done 2>/dev/null < /etc/shells
 | 
| 1294 | }
 | 
| 1295 | 
 | 
| 1296 | # This function completes on valid filesystem types
 | 
| 1297 | #
 | 
| 1298 | _fstypes()
 | 
| 1299 | {
 | 
| 1300 |     local fss
 | 
| 1301 | 
 | 
| 1302 |     if [[ -e /proc/filesystems ]]; then
 | 
| 1303 |         # Linux
 | 
| 1304 |         fss="$( cut -d$'\t' -f2 /proc/filesystems )
 | 
| 1305 |             $( awk '! /\*/ { print $NF }' /etc/filesystems 2>/dev/null )"
 | 
| 1306 |     else
 | 
| 1307 |         # Generic
 | 
| 1308 |         fss="$( awk '/^[ \t]*[^#]/ { print $3 }' /etc/fstab 2>/dev/null )
 | 
| 1309 |             $( awk '/^[ \t]*[^#]/ { print $3 }' /etc/mnttab 2>/dev/null )
 | 
| 1310 |             $( awk '/^[ \t]*[^#]/ { print $4 }' /etc/vfstab 2>/dev/null )
 | 
| 1311 |             $( awk '{ print $1 }' /etc/dfs/fstypes 2>/dev/null )
 | 
| 1312 |             $( [[ -d /etc/fs ]] && command ls /etc/fs )"
 | 
| 1313 |     fi
 | 
| 1314 | 
 | 
| 1315 |     [[ -n $fss ]] && COMPREPLY+=( $( compgen -W "$fss" -- "$cur" ) )
 | 
| 1316 | }
 | 
| 1317 | 
 | 
| 1318 | # Get real command.
 | 
| 1319 | # - arg: $1  Command
 | 
| 1320 | # - stdout:  Filename of command in PATH with possible symbolic links resolved.
 | 
| 1321 | #            Empty string if command not found.
 | 
| 1322 | # - return:  True (0) if command found, False (> 0) if not.
 | 
| 1323 | _realcommand()
 | 
| 1324 | {
 | 
| 1325 |     type -P "$1" > /dev/null && {
 | 
| 1326 |         if type -p realpath > /dev/null; then
 | 
| 1327 |             realpath "$(type -P "$1")"
 | 
| 1328 |         elif type -p greadlink > /dev/null; then
 | 
| 1329 |             greadlink -f "$(type -P "$1")"
 | 
| 1330 |         elif type -p readlink > /dev/null; then
 | 
| 1331 |             readlink -f "$(type -P "$1")"
 | 
| 1332 |         else
 | 
| 1333 |             type -P "$1"
 | 
| 1334 |         fi
 | 
| 1335 |     }
 | 
| 1336 | }
 | 
| 1337 | 
 | 
| 1338 | # This function returns the first argument, excluding options
 | 
| 1339 | # @param $1 chars  Characters out of $COMP_WORDBREAKS which should
 | 
| 1340 | #     NOT be considered word breaks. See __reassemble_comp_words_by_ref.
 | 
| 1341 | _get_first_arg()
 | 
| 1342 | {
 | 
| 1343 |     local i
 | 
| 1344 | 
 | 
| 1345 |     arg=
 | 
| 1346 |     for (( i=1; i < COMP_CWORD; i++ )); do
 | 
| 1347 |         if [[ "${COMP_WORDS[i]}" != -* ]]; then
 | 
| 1348 |             arg=${COMP_WORDS[i]}
 | 
| 1349 |             break
 | 
| 1350 |         fi
 | 
| 1351 |     done
 | 
| 1352 | }
 | 
| 1353 | 
 | 
| 1354 | 
 | 
| 1355 | # This function counts the number of args, excluding options
 | 
| 1356 | # @param $1 chars  Characters out of $COMP_WORDBREAKS which should
 | 
| 1357 | #     NOT be considered word breaks. See __reassemble_comp_words_by_ref.
 | 
| 1358 | # @param $2 glob   Options whose following argument should not be counted
 | 
| 1359 | _count_args()
 | 
| 1360 | {
 | 
| 1361 |     local i cword words
 | 
| 1362 |     __reassemble_comp_words_by_ref "$1" words cword
 | 
| 1363 | 
 | 
| 1364 |     args=1
 | 
| 1365 |     for (( i=1; i < cword; i++ )); do
 | 
| 1366 |         if [[ ${words[i]} != -* && ${words[i-1]} != $2 ]]; then
 | 
| 1367 |            args=$(($args+1))
 | 
| 1368 |         fi
 | 
| 1369 |     done
 | 
| 1370 | }
 | 
| 1371 | 
 | 
| 1372 | # This function completes on PCI IDs
 | 
| 1373 | #
 | 
| 1374 | _pci_ids()
 | 
| 1375 | {
 | 
| 1376 |     COMPREPLY+=( $( compgen -W \
 | 
| 1377 |         "$( PATH="$PATH:/sbin" lspci -n | awk '{print $3}')" -- "$cur" ) )
 | 
| 1378 | }
 | 
| 1379 | 
 | 
| 1380 | # This function completes on USB IDs
 | 
| 1381 | #
 | 
| 1382 | _usb_ids()
 | 
| 1383 | {
 | 
| 1384 |     COMPREPLY+=( $( compgen -W \
 | 
| 1385 |         "$( PATH="$PATH:/sbin" lsusb | awk '{print $6}' )" -- "$cur" ) )
 | 
| 1386 | }
 | 
| 1387 | 
 | 
| 1388 | # CD device names
 | 
| 1389 | _cd_devices()
 | 
| 1390 | {
 | 
| 1391 |     COMPREPLY+=( $( compgen -f -d -X "!*/?([amrs])cd*" -- "${cur:-/dev/}" ) )
 | 
| 1392 | }
 | 
| 1393 | 
 | 
| 1394 | # DVD device names
 | 
| 1395 | _dvd_devices()
 | 
| 1396 | {
 | 
| 1397 |     COMPREPLY+=( $( compgen -f -d -X "!*/?(r)dvd*" -- "${cur:-/dev/}" ) )
 | 
| 1398 | }
 | 
| 1399 | 
 | 
| 1400 | # TERM environment variable values
 | 
| 1401 | _terms()
 | 
| 1402 | {
 | 
| 1403 |     COMPREPLY+=( $( compgen -W \
 | 
| 1404 |         "$( command sed -ne 's/^\([^[:space:]#|]\{2,\}\)|.*/\1/p' /etc/termcap \
 | 
| 1405 |             2>/dev/null )" -- "$cur" ) )
 | 
| 1406 |     COMPREPLY+=( $( compgen -W "$( { toe -a 2>/dev/null || toe 2>/dev/null; } \
 | 
| 1407 |         | awk '{ print $1 }' | sort -u )" -- "$cur" ) )
 | 
| 1408 | }
 | 
| 1409 | 
 | 
| 1410 | # a little help for FreeBSD ports users
 | 
| 1411 | [[ $OSTYPE == *freebsd* ]] && complete -W 'index search fetch fetch-list
 | 
| 1412 |     extract patch configure build install reinstall deinstall clean
 | 
| 1413 |     clean-depends kernel buildworld' make
 | 
| 1414 | 
 | 
| 1415 | # This function provides simple user@host completion
 | 
| 1416 | #
 | 
| 1417 | _user_at_host()
 | 
| 1418 | {
 | 
| 1419 |     local cur prev words cword
 | 
| 1420 |     _init_completion -n : || return
 | 
| 1421 | 
 | 
| 1422 |     if [[ $cur == *@* ]]; then
 | 
| 1423 |         _known_hosts_real "$cur"
 | 
| 1424 |     else
 | 
| 1425 |         COMPREPLY=( $( compgen -u -S @ -- "$cur" ) )
 | 
| 1426 |         compopt -o nospace
 | 
| 1427 |     fi
 | 
| 1428 | }
 | 
| 1429 | shopt -u hostcomplete && complete -F _user_at_host talk ytalk finger
 | 
| 1430 | 
 | 
| 1431 | # NOTE: Using this function as a helper function is deprecated.  Use
 | 
| 1432 | #       `_known_hosts_real' instead.
 | 
| 1433 | _known_hosts()
 | 
| 1434 | {
 | 
| 1435 |     local cur prev words cword
 | 
| 1436 |     _init_completion -n : || return
 | 
| 1437 | 
 | 
| 1438 |     # NOTE: Using `_known_hosts' as a helper function and passing options
 | 
| 1439 |     #       to `_known_hosts' is deprecated: Use `_known_hosts_real' instead.
 | 
| 1440 |     local options
 | 
| 1441 |     [[ "$1" == -a || "$2" == -a ]] && options=-a
 | 
| 1442 |     [[ "$1" == -c || "$2" == -c ]] && options+=" -c"
 | 
| 1443 |     _known_hosts_real $options -- "$cur"
 | 
| 1444 | } # _known_hosts()
 | 
| 1445 | 
 | 
| 1446 | # Helper function to locate ssh included files in configs
 | 
| 1447 | # This function look for the "Include" keyword in ssh config files and include
 | 
| 1448 | # them recursively adding each result to the config variable
 | 
| 1449 | _included_ssh_config_files()
 | 
| 1450 | {
 | 
| 1451 |     [[ $# -lt 1 ]] && echo "error: $FUNCNAME: missing mandatory argument CONFIG"
 | 
| 1452 |     local configfile i f
 | 
| 1453 |     configfile=$1
 | 
| 1454 |     local included=$( command sed -ne 's/^[[:blank:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:blank:]]\{1,\}\([^#%]*\)\(#.*\)\{0,1\}$/\1/p' "${configfile}" )
 | 
| 1455 |     for i in ${included[@]}; do
 | 
| 1456 |         # Check the origin of $configfile to complete relative included paths on included
 | 
| 1457 |         # files according to ssh_config(5):
 | 
| 1458 |         #  "[...] Files without absolute paths are assumed to be in ~/.ssh if included in a user
 | 
| 1459 |         #   configuration file or /etc/ssh if included from the system configuration file.[...]"
 | 
| 1460 |         if ! [[ "$i" =~ ^\~.*|^\/.* ]]; then
 | 
| 1461 |             if [[ "$configfile" =~ ^\/etc\/ssh.* ]]; then
 | 
| 1462 |                 i="/etc/ssh/$i"
 | 
| 1463 |             else
 | 
| 1464 |                 i="$HOME/.ssh/$i"
 | 
| 1465 |             fi
 | 
| 1466 |         fi
 | 
| 1467 |         __expand_tilde_by_ref i
 | 
| 1468 |         # In case the expanded variable contains multiple paths
 | 
| 1469 |         for f in ${i}; do
 | 
| 1470 |             if [ -r $f ]; then
 | 
| 1471 |                 config+=( "$f" )
 | 
| 1472 |                 # The Included file is processed to look for Included files in itself
 | 
| 1473 |                 _included_ssh_config_files $f
 | 
| 1474 |             fi
 | 
| 1475 |         done
 | 
| 1476 |     done
 | 
| 1477 | } # _included_ssh_config_files()
 | 
| 1478 | 
 | 
| 1479 | # Helper function for completing _known_hosts.
 | 
| 1480 | # This function performs host completion based on ssh's config and known_hosts
 | 
| 1481 | # files, as well as hostnames reported by avahi-browse if
 | 
| 1482 | # COMP_KNOWN_HOSTS_WITH_AVAHI is set to a non-empty value.  Also hosts from
 | 
| 1483 | # HOSTFILE (compgen -A hostname) are added, unless
 | 
| 1484 | # COMP_KNOWN_HOSTS_WITH_HOSTFILE is set to an empty value.
 | 
| 1485 | # Usage: _known_hosts_real [OPTIONS] CWORD
 | 
| 1486 | # Options:  -a             Use aliases from ssh config files
 | 
| 1487 | #           -c             Use `:' suffix
 | 
| 1488 | #           -F configfile  Use `configfile' for configuration settings
 | 
| 1489 | #           -p PREFIX      Use PREFIX
 | 
| 1490 | #           -4             Filter IPv6 addresses from results
 | 
| 1491 | #           -6             Filter IPv4 addresses from results
 | 
| 1492 | # Return: Completions, starting with CWORD, are added to COMPREPLY[]
 | 
| 1493 | _known_hosts_real()
 | 
| 1494 | {
 | 
| 1495 |     local configfile flag prefix OIFS=$IFS
 | 
| 1496 |     local cur user suffix aliases i host ipv4 ipv6
 | 
| 1497 |     local -a kh tmpkh khd config
 | 
| 1498 | 
 | 
| 1499 |     # TODO remove trailing %foo from entries
 | 
| 1500 | 
 | 
| 1501 |     local OPTIND=1
 | 
| 1502 |     while getopts "ac46F:p:" flag "$@"; do
 | 
| 1503 |         case $flag in
 | 
| 1504 |             a) aliases='yes' ;;
 | 
| 1505 |             c) suffix=':' ;;
 | 
| 1506 |             F) configfile=$OPTARG ;;
 | 
| 1507 |             p) prefix=$OPTARG ;;
 | 
| 1508 |             4) ipv4=1 ;;
 | 
| 1509 |             6) ipv6=1 ;;
 | 
| 1510 |         esac
 | 
| 1511 |     done
 | 
| 1512 |     [[ $# -lt $OPTIND ]] && echo "error: $FUNCNAME: missing mandatory argument CWORD"
 | 
| 1513 |     cur=${!OPTIND}; let "OPTIND += 1"
 | 
| 1514 |     [[ $# -ge $OPTIND ]] && echo "error: $FUNCNAME("$@"): unprocessed arguments:"\
 | 
| 1515 |     $(while [[ $# -ge $OPTIND ]]; do printf '%s\n' ${!OPTIND}; shift; done)
 | 
| 1516 | 
 | 
| 1517 |     [[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@}
 | 
| 1518 |     kh=()
 | 
| 1519 | 
 | 
| 1520 |     # ssh config files
 | 
| 1521 |     if [[ -n $configfile ]]; then
 | 
| 1522 |         [[ -r $configfile ]] && config+=( "$configfile" )
 | 
| 1523 |     else
 | 
| 1524 |         for i in /etc/ssh/ssh_config ~/.ssh/config ~/.ssh2/config; do
 | 
| 1525 |             [[ -r $i ]] && config+=( "$i" )
 | 
| 1526 |         done
 | 
| 1527 |     fi
 | 
| 1528 | 
 | 
| 1529 |     # "Include" keyword in ssh config files
 | 
| 1530 |     for i in "${config[@]}"; do
 | 
| 1531 |         _included_ssh_config_files "$i"
 | 
| 1532 |     done
 | 
| 1533 | 
 | 
| 1534 |     # Known hosts files from configs
 | 
| 1535 |     if [[ ${#config[@]} -gt 0 ]]; then
 | 
| 1536 |         local IFS=$'\n' j
 | 
| 1537 |         # expand paths (if present) to global and user known hosts files
 | 
| 1538 |         # TODO(?): try to make known hosts files with more than one consecutive
 | 
| 1539 |         #          spaces in their name work (watch out for ~ expansion
 | 
| 1540 |         #          breakage! Alioth#311595)
 | 
| 1541 |         tmpkh=( $( awk 'sub("^[ \t]*([Gg][Ll][Oo][Bb][Aa][Ll]|[Uu][Ss][Ee][Rr])[Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][ \t]+", "") { print $0 }' "${config[@]}" | sort -u ) )
 | 
| 1542 |         IFS=$OIFS
 | 
| 1543 |         for i in "${tmpkh[@]}"; do
 | 
| 1544 |             # First deal with quoted entries...
 | 
| 1545 |             while [[ $i =~ ^([^\"]*)\"([^\"]*)\"(.*)$ ]]; do
 | 
| 1546 |                 i=${BASH_REMATCH[1]}${BASH_REMATCH[3]}
 | 
| 1547 |                 j=${BASH_REMATCH[2]}
 | 
| 1548 |                 __expand_tilde_by_ref j # Eval/expand possible `~' or `~user'
 | 
| 1549 |                 [[ -r $j ]] && kh+=( "$j" )
 | 
| 1550 |             done
 | 
| 1551 |             # ...and then the rest.
 | 
| 1552 |             for j in $i; do
 | 
| 1553 |                 __expand_tilde_by_ref j # Eval/expand possible `~' or `~user'
 | 
| 1554 |                 [[ -r $j ]] && kh+=( "$j" )
 | 
| 1555 |             done
 | 
| 1556 |         done
 | 
| 1557 |     fi
 | 
| 1558 | 
 | 
| 1559 |     if [[ -z $configfile ]]; then
 | 
| 1560 |         # Global and user known_hosts files
 | 
| 1561 |         for i in /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2 \
 | 
| 1562 |             /etc/known_hosts /etc/known_hosts2 ~/.ssh/known_hosts \
 | 
| 1563 |             ~/.ssh/known_hosts2; do
 | 
| 1564 |             [[ -r $i ]] && kh+=( "$i" )
 | 
| 1565 |         done
 | 
| 1566 |         for i in /etc/ssh2/knownhosts ~/.ssh2/hostkeys; do
 | 
| 1567 |             [[ -d $i ]] && khd+=( "$i"/*pub )
 | 
| 1568 |         done
 | 
| 1569 |     fi
 | 
| 1570 | 
 | 
| 1571 |     # If we have known_hosts files to use
 | 
| 1572 |     if [[ ${#kh[@]} -gt 0 || ${#khd[@]} -gt 0 ]]; then
 | 
| 1573 |         if [[ ${#kh[@]} -gt 0 ]]; then
 | 
| 1574 |             # https://man.openbsd.org/sshd.8#SSH_KNOWN_HOSTS_FILE_FORMAT
 | 
| 1575 |             for i in "${kh[@]}"; do
 | 
| 1576 |                 while read -ra tmpkh; do
 | 
| 1577 |                     set -- "${tmpkh[@]}"
 | 
| 1578 |                     # Skip entries starting with | (hashed) and # (comment)
 | 
| 1579 |                     [[ $1 == [\|\#]* ]] && continue
 | 
| 1580 |                     # Ignore leading @foo (markers)
 | 
| 1581 |                     [[ $1 == @* ]] && shift
 | 
| 1582 |                     # Split entry on commas
 | 
| 1583 |                     local IFS=,
 | 
| 1584 |                     for host in $1; do
 | 
| 1585 |                         # Skip hosts containing wildcards
 | 
| 1586 |                         [[ $host == *[*?]* ]] && continue
 | 
| 1587 |                         # Remove leading [
 | 
| 1588 |                         host="${host#[}"
 | 
| 1589 |                         # Remove trailing ] + optional :port
 | 
| 1590 |                         host="${host%]?(:+([0-9]))}"
 | 
| 1591 |                         # Add host to candidates
 | 
| 1592 |                         COMPREPLY+=( $host )
 | 
| 1593 |                     done
 | 
| 1594 |                     IFS=$OIFS
 | 
| 1595 |                 done < "$i"
 | 
| 1596 |             done
 | 
| 1597 |             COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- "$cur" ) )
 | 
| 1598 |         fi
 | 
| 1599 |         if [[ ${#khd[@]} -gt 0 ]]; then
 | 
| 1600 |             # Needs to look for files called
 | 
| 1601 |             # .../.ssh2/key_22_<hostname>.pub
 | 
| 1602 |             # dont fork any processes, because in a cluster environment,
 | 
| 1603 |             # there can be hundreds of hostkeys
 | 
| 1604 |             for i in "${khd[@]}" ; do
 | 
| 1605 |                 if [[ "$i" == *key_22_$cur*.pub && -r "$i" ]]; then
 | 
| 1606 |                     host=${i/#*key_22_/}
 | 
| 1607 |                     host=${host/%.pub/}
 | 
| 1608 |                     COMPREPLY+=( $host )
 | 
| 1609 |                 fi
 | 
| 1610 |             done
 | 
| 1611 |         fi
 | 
| 1612 | 
 | 
| 1613 |         # apply suffix and prefix
 | 
| 1614 |         for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
 | 
| 1615 |             COMPREPLY[i]=$prefix$user${COMPREPLY[i]}$suffix
 | 
| 1616 |         done
 | 
| 1617 |     fi
 | 
| 1618 | 
 | 
| 1619 |     # append any available aliases from ssh config files
 | 
| 1620 |     if [[ ${#config[@]} -gt 0 && -n "$aliases" ]]; then
 | 
| 1621 |         local hosts=$( command sed -ne 's/^[[:blank:]]*[Hh][Oo][Ss][Tt][[:blank:]]\{1,\}\([^#*?%]*\)\(#.*\)\{0,1\}$/\1/p' "${config[@]}" )
 | 
| 1622 |         COMPREPLY+=( $( compgen -P "$prefix$user" \
 | 
| 1623 |             -S "$suffix" -W "$hosts" -- "$cur" ) )
 | 
| 1624 |     fi
 | 
| 1625 | 
 | 
| 1626 |     # Add hosts reported by avahi-browse, if desired and it's available.
 | 
| 1627 |     if [[ ${COMP_KNOWN_HOSTS_WITH_AVAHI:-} ]] && \
 | 
| 1628 |         type avahi-browse &>/dev/null; then
 | 
| 1629 |         # The original call to avahi-browse also had "-k", to avoid lookups
 | 
| 1630 |         # into avahi's services DB. We don't need the name of the service, and
 | 
| 1631 |         # if it contains ";", it may mistify the result. But on Gentoo (at
 | 
| 1632 |         # least), -k wasn't available (even if mentioned in the manpage) some
 | 
| 1633 |         # time ago, so...
 | 
| 1634 |         COMPREPLY+=( $( compgen -P "$prefix$user" -S "$suffix" -W \
 | 
| 1635 |             "$( avahi-browse -cpr _workstation._tcp 2>/dev/null | \
 | 
| 1636 |                 awk -F';' '/^=/ { print $7 }' | sort -u )" -- "$cur" ) )
 | 
| 1637 |     fi
 | 
| 1638 | 
 | 
| 1639 |     # Add hosts reported by ruptime.
 | 
| 1640 |     COMPREPLY+=( $( compgen -W \
 | 
| 1641 |         "$( ruptime 2>/dev/null | awk '!/^ruptime:/ { print $1 }' )" \
 | 
| 1642 |         -- "$cur" ) )
 | 
| 1643 | 
 | 
| 1644 |     # Add results of normal hostname completion, unless
 | 
| 1645 |     # `COMP_KNOWN_HOSTS_WITH_HOSTFILE' is set to an empty value.
 | 
| 1646 |     if [[ -n ${COMP_KNOWN_HOSTS_WITH_HOSTFILE-1} ]]; then
 | 
| 1647 |         COMPREPLY+=(
 | 
| 1648 |             $( compgen -A hostname -P "$prefix$user" -S "$suffix" -- "$cur" ) )
 | 
| 1649 |     fi
 | 
| 1650 | 
 | 
| 1651 |     if [[ $ipv4 ]]; then
 | 
| 1652 |         COMPREPLY=( "${COMPREPLY[@]/*:*$suffix/}" )
 | 
| 1653 |     fi
 | 
| 1654 |     if [[ $ipv6 ]]; then
 | 
| 1655 |         COMPREPLY=( "${COMPREPLY[@]/+([0-9]).+([0-9]).+([0-9]).+([0-9])$suffix/}" )
 | 
| 1656 |     fi
 | 
| 1657 |     if [[ $ipv4 || $ipv6 ]]; then
 | 
| 1658 |         for i in ${!COMPREPLY[@]}; do
 | 
| 1659 |             [[ ${COMPREPLY[i]} ]] || unset -v COMPREPLY[i]
 | 
| 1660 |         done
 | 
| 1661 |     fi
 | 
| 1662 | 
 | 
| 1663 |     __ltrim_colon_completions "$prefix$user$cur"
 | 
| 1664 | 
 | 
| 1665 | } # _known_hosts_real()
 | 
| 1666 | complete -F _known_hosts traceroute traceroute6 \
 | 
| 1667 |     fping fping6 telnet rsh rlogin ftp dig mtr ssh-installkeys showmount
 | 
| 1668 | 
 | 
| 1669 | # This meta-cd function observes the CDPATH variable, so that cd additionally
 | 
| 1670 | # completes on directories under those specified in CDPATH.
 | 
| 1671 | #
 | 
| 1672 | _cd()
 | 
| 1673 | {
 | 
| 1674 |     local cur prev words cword
 | 
| 1675 |     _init_completion || return
 | 
| 1676 | 
 | 
| 1677 |     local IFS=$'\n' i j k
 | 
| 1678 | 
 | 
| 1679 |     compopt -o filenames
 | 
| 1680 | 
 | 
| 1681 |     # Use standard dir completion if no CDPATH or parameter starts with /,
 | 
| 1682 |     # ./ or ../
 | 
| 1683 |     if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then
 | 
| 1684 |         _filedir -d
 | 
| 1685 |         return
 | 
| 1686 |     fi
 | 
| 1687 | 
 | 
| 1688 |     local -r mark_dirs=$(_rl_enabled mark-directories && echo y)
 | 
| 1689 |     local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y)
 | 
| 1690 | 
 | 
| 1691 |     # we have a CDPATH, so loop on its contents
 | 
| 1692 |     for i in ${CDPATH//:/$'\n'}; do
 | 
| 1693 |         # create an array of matched subdirs
 | 
| 1694 |         k="${#COMPREPLY[@]}"
 | 
| 1695 |         for j in $( compgen -d -- $i/$cur ); do
 | 
| 1696 |             if [[ ( $mark_symdirs && -h $j || $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then
 | 
| 1697 |                 j+="/"
 | 
| 1698 |             fi
 | 
| 1699 |             COMPREPLY[k++]=${j#$i/}
 | 
| 1700 |         done
 | 
| 1701 |     done
 | 
| 1702 | 
 | 
| 1703 |     _filedir -d
 | 
| 1704 | 
 | 
| 1705 |     if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
 | 
| 1706 |         i=${COMPREPLY[0]}
 | 
| 1707 |         if [[ "$i" == "$cur" && $i != "*/" ]]; then
 | 
| 1708 |             COMPREPLY[0]="${i}/"
 | 
| 1709 |         fi
 | 
| 1710 |     fi
 | 
| 1711 | 
 | 
| 1712 |     return
 | 
| 1713 | }
 | 
| 1714 | if shopt -q cdable_vars; then
 | 
| 1715 |     complete -v -F _cd -o nospace cd pushd
 | 
| 1716 | else
 | 
| 1717 |     complete -F _cd -o nospace cd pushd
 | 
| 1718 | fi
 | 
| 1719 | 
 | 
| 1720 | # a wrapper method for the next one, when the offset is unknown
 | 
| 1721 | _command()
 | 
| 1722 | {
 | 
| 1723 |     local offset i
 | 
| 1724 | 
 | 
| 1725 |     # find actual offset, as position of the first non-option
 | 
| 1726 |     offset=1
 | 
| 1727 |     for (( i=1; i <= COMP_CWORD; i++ )); do
 | 
| 1728 |         if [[ "${COMP_WORDS[i]}" != -* ]]; then
 | 
| 1729 |             offset=$i
 | 
| 1730 |             break
 | 
| 1731 |         fi
 | 
| 1732 |     done
 | 
| 1733 |     _command_offset $offset
 | 
| 1734 | }
 | 
| 1735 | 
 | 
| 1736 | # A meta-command completion function for commands like sudo(8), which need to
 | 
| 1737 | # first complete on a command, then complete according to that command's own
 | 
| 1738 | # completion definition.
 | 
| 1739 | #
 | 
| 1740 | _command_offset()
 | 
| 1741 | {
 | 
| 1742 |     # rewrite current completion context before invoking
 | 
| 1743 |     # actual command completion
 | 
| 1744 | 
 | 
| 1745 |     # find new first word position, then
 | 
| 1746 |     # rewrite COMP_LINE and adjust COMP_POINT
 | 
| 1747 |     local word_offset=$1 i j
 | 
| 1748 |     for (( i=0; i < $word_offset; i++ )); do
 | 
| 1749 |         for (( j=0; j <= ${#COMP_LINE}; j++ )); do
 | 
| 1750 |             [[ "$COMP_LINE" == "${COMP_WORDS[i]}"* ]] && break
 | 
| 1751 |             COMP_LINE=${COMP_LINE:1}
 | 
| 1752 |             ((COMP_POINT--))
 | 
| 1753 |         done
 | 
| 1754 |         COMP_LINE=${COMP_LINE#"${COMP_WORDS[i]}"}
 | 
| 1755 |         ((COMP_POINT-=${#COMP_WORDS[i]}))
 | 
| 1756 |     done
 | 
| 1757 | 
 | 
| 1758 |     # shift COMP_WORDS elements and adjust COMP_CWORD
 | 
| 1759 |     for (( i=0; i <= COMP_CWORD - $word_offset; i++ )); do
 | 
| 1760 |         COMP_WORDS[i]=${COMP_WORDS[i+$word_offset]}
 | 
| 1761 |     done
 | 
| 1762 |     for (( i; i <= COMP_CWORD; i++ )); do
 | 
| 1763 |         unset 'COMP_WORDS[i]'
 | 
| 1764 |     done
 | 
| 1765 |     ((COMP_CWORD -= $word_offset))
 | 
| 1766 | 
 | 
| 1767 |     COMPREPLY=()
 | 
| 1768 |     local cur
 | 
| 1769 |     _get_comp_words_by_ref cur
 | 
| 1770 | 
 | 
| 1771 |     if [[ $COMP_CWORD -eq 0 ]]; then
 | 
| 1772 |         local IFS=$'\n'
 | 
| 1773 |         compopt -o filenames
 | 
| 1774 |         COMPREPLY=( $( compgen -d -c -- "$cur" ) )
 | 
| 1775 |     else
 | 
| 1776 |         local cmd=${COMP_WORDS[0]} compcmd=${COMP_WORDS[0]}
 | 
| 1777 |         local cspec=$( complete -p $cmd 2>/dev/null )
 | 
| 1778 | 
 | 
| 1779 |         # If we have no completion for $cmd yet, see if we have for basename
 | 
| 1780 |         if [[ ! $cspec && $cmd == */* ]]; then
 | 
| 1781 |             cspec=$( complete -p ${cmd##*/} 2>/dev/null )
 | 
| 1782 |             [[ $cspec ]] && compcmd=${cmd##*/}
 | 
| 1783 |         fi
 | 
| 1784 |         # If still nothing, just load it for the basename
 | 
| 1785 |         if [[ ! $cspec ]]; then
 | 
| 1786 |             compcmd=${cmd##*/}
 | 
| 1787 |             _completion_loader $compcmd
 | 
| 1788 |             cspec=$( complete -p $compcmd 2>/dev/null )
 | 
| 1789 |         fi
 | 
| 1790 | 
 | 
| 1791 |         if [[ -n $cspec ]]; then
 | 
| 1792 |             if [[ ${cspec#* -F } != $cspec ]]; then
 | 
| 1793 |                 # complete -F <function>
 | 
| 1794 | 
 | 
| 1795 |                 # get function name
 | 
| 1796 |                 local func=${cspec#*-F }
 | 
| 1797 |                 func=${func%% *}
 | 
| 1798 | 
 | 
| 1799 |                 if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then
 | 
| 1800 |                     $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}"
 | 
| 1801 |                 else
 | 
| 1802 |                     $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}"
 | 
| 1803 |                 fi
 | 
| 1804 | 
 | 
| 1805 |                 # restore initial compopts
 | 
| 1806 |                 local opt
 | 
| 1807 |                 while [[ $cspec == *" -o "* ]]; do
 | 
| 1808 |                     # FIXME: should we take "+o opt" into account?
 | 
| 1809 |                     cspec=${cspec#*-o }
 | 
| 1810 |                     opt=${cspec%% *}
 | 
| 1811 |                     compopt -o $opt
 | 
| 1812 |                     cspec=${cspec#$opt}
 | 
| 1813 |                 done
 | 
| 1814 |             else
 | 
| 1815 |                 cspec=${cspec#complete}
 | 
| 1816 |                 cspec=${cspec%%$compcmd}
 | 
| 1817 |                 COMPREPLY=( $( eval compgen "$cspec" -- '$cur' ) )
 | 
| 1818 |             fi
 | 
| 1819 |         elif [[ ${#COMPREPLY[@]} -eq 0 ]]; then
 | 
| 1820 |             # XXX will probably never happen as long as completion loader loads
 | 
| 1821 |             #     *something* for every command thrown at it ($cspec != empty)
 | 
| 1822 |             _minimal
 | 
| 1823 |         fi
 | 
| 1824 |     fi
 | 
| 1825 | }
 | 
| 1826 | complete -F _command aoss command do else eval exec ltrace nice nohup padsp \
 | 
| 1827 |     then time tsocks vsound xargs
 | 
| 1828 | 
 | 
| 1829 | _root_command()
 | 
| 1830 | {
 | 
| 1831 |     local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin
 | 
| 1832 |     local root_command=$1
 | 
| 1833 |     _command
 | 
| 1834 | }
 | 
| 1835 | complete -F _root_command fakeroot gksu gksudo kdesudo really
 | 
| 1836 | 
 | 
| 1837 | # Return true if the completion should be treated as running as root
 | 
| 1838 | _complete_as_root()
 | 
| 1839 | {
 | 
| 1840 |     [[ $EUID -eq 0 || ${root_command:-} ]]
 | 
| 1841 | }
 | 
| 1842 | 
 | 
| 1843 | _longopt()
 | 
| 1844 | {
 | 
| 1845 |     local cur prev words cword split
 | 
| 1846 |     _init_completion -s || return
 | 
| 1847 | 
 | 
| 1848 |     case "${prev,,}" in
 | 
| 1849 |         --help|--usage|--version)
 | 
| 1850 |             return
 | 
| 1851 |             ;;
 | 
| 1852 |         --*dir*)
 | 
| 1853 |             _filedir -d
 | 
| 1854 |             return
 | 
| 1855 |             ;;
 | 
| 1856 |         --*file*|--*path*)
 | 
| 1857 |             _filedir
 | 
| 1858 |             return
 | 
| 1859 |             ;;
 | 
| 1860 |         --+([-a-z0-9_]))
 | 
| 1861 |             local argtype=$( LC_ALL=C $1 --help 2>&1 | command sed -ne \
 | 
| 1862 |                 "s|.*$prev\[\{0,1\}=[<[]\{0,1\}\([-A-Za-z0-9_]\{1,\}\).*|\1|p" )
 | 
| 1863 |             case ${argtype,,} in
 | 
| 1864 |                 *dir*)
 | 
| 1865 |                     _filedir -d
 | 
| 1866 |                     return
 | 
| 1867 |                     ;;
 | 
| 1868 |                 *file*|*path*)
 | 
| 1869 |                     _filedir
 | 
| 1870 |                     return
 | 
| 1871 |                     ;;
 | 
| 1872 |             esac
 | 
| 1873 |             ;;
 | 
| 1874 |     esac
 | 
| 1875 | 
 | 
| 1876 |     $split && return
 | 
| 1877 | 
 | 
| 1878 |     if [[ "$cur" == -* ]]; then
 | 
| 1879 |         COMPREPLY=( $( compgen -W "$( LC_ALL=C $1 --help 2>&1 | \
 | 
| 1880 |             command sed -ne 's/.*\(--[-A-Za-z0-9]\{1,\}=\{0,1\}\).*/\1/p' | sort -u )" \
 | 
| 1881 |             -- "$cur" ) )
 | 
| 1882 |         [[ $COMPREPLY == *= ]] && compopt -o nospace
 | 
| 1883 |     elif [[ "$1" == @(rmdir|chroot) ]]; then
 | 
| 1884 |         _filedir -d
 | 
| 1885 |     else
 | 
| 1886 |         [[ "$1" == mkdir ]] && compopt -o nospace
 | 
| 1887 |         _filedir
 | 
| 1888 |     fi
 | 
| 1889 | }
 | 
| 1890 | # makeinfo and texi2dvi are defined elsewhere.
 | 
| 1891 | complete -F _longopt a2ps awk base64 bash bc bison cat chroot colordiff cp \
 | 
| 1892 |     csplit cut date df diff dir du enscript env expand fmt fold gperf \
 | 
| 1893 |     grep grub head irb ld ldd less ln ls m4 md5sum mkdir mkfifo mknod \
 | 
| 1894 |     mv netstat nl nm objcopy objdump od paste pr ptx readelf rm rmdir \
 | 
| 1895 |     sed seq sha{,1,224,256,384,512}sum shar sort split strip sum tac tail tee \
 | 
| 1896 |     texindex touch tr uname unexpand uniq units vdir wc who
 | 
| 1897 | 
 | 
| 1898 | # declare only knows -g in bash >= 4.2.
 | 
| 1899 | if [[ ${BASH_VERSINFO[0]} -gt 4 ||
 | 
| 1900 |       ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 2 ]]; then
 | 
| 1901 |     declare -Ag _xspecs
 | 
| 1902 | else
 | 
| 1903 |     declare -A _xspecs
 | 
| 1904 | fi
 | 
| 1905 | _filedir_xspec()
 | 
| 1906 | {
 | 
| 1907 |     local cur prev words cword
 | 
| 1908 |     _init_completion || return
 | 
| 1909 | 
 | 
| 1910 |     _tilde "$cur" || return
 | 
| 1911 | 
 | 
| 1912 |     local IFS=$'\n' xspec=${_xspecs[${1##*/}]} tmp
 | 
| 1913 |     local -a toks
 | 
| 1914 | 
 | 
| 1915 |     toks=( $(
 | 
| 1916 |         compgen -d -- "$(quote_readline "$cur")" | {
 | 
| 1917 |         while read -r tmp; do
 | 
| 1918 |             printf '%s\n' $tmp
 | 
| 1919 |         done
 | 
| 1920 |         }
 | 
| 1921 |         ))
 | 
| 1922 | 
 | 
| 1923 |     # Munge xspec to contain uppercase version too
 | 
| 1924 |     # http://thread.gmane.org/gmane.comp.shells.bash.bugs/15294/focus=15306
 | 
| 1925 |     eval xspec="${xspec}"
 | 
| 1926 |     local matchop=!
 | 
| 1927 |     if [[ $xspec == !* ]]; then
 | 
| 1928 |         xspec=${xspec#!}
 | 
| 1929 |         matchop=@
 | 
| 1930 |     fi
 | 
| 1931 |     xspec="$matchop($xspec|${xspec^^})"
 | 
| 1932 | 
 | 
| 1933 |     toks+=( $(
 | 
| 1934 |         eval compgen -f -X "'!$xspec'" -- "\$(quote_readline "\$cur")" | {
 | 
| 1935 |         while read -r tmp; do
 | 
| 1936 |             [[ -n $tmp ]] && printf '%s\n' $tmp
 | 
| 1937 |         done
 | 
| 1938 |         }
 | 
| 1939 |         ))
 | 
| 1940 | 
 | 
| 1941 |     # Try without filter if it failed to produce anything and configured to
 | 
| 1942 |     [[ -n ${COMP_FILEDIR_FALLBACK:-} && ${#toks[@]} -lt 1 ]] && {
 | 
| 1943 |         local reset=$(shopt -po noglob); set -o noglob
 | 
| 1944 |         toks+=( $( compgen -f -- "$(quote_readline "$cur")" ) )
 | 
| 1945 |         IFS=' '; $reset; IFS=$'\n'
 | 
| 1946 |     }
 | 
| 1947 | 
 | 
| 1948 |     if [[ ${#toks[@]} -ne 0 ]]; then
 | 
| 1949 |         compopt -o filenames
 | 
| 1950 |         COMPREPLY=( "${toks[@]}" )
 | 
| 1951 |     fi
 | 
| 1952 | }
 | 
| 1953 | 
 | 
| 1954 | _install_xspec()
 | 
| 1955 | {
 | 
| 1956 |     local xspec=$1 cmd
 | 
| 1957 |     shift
 | 
| 1958 |     for cmd in $@; do
 | 
| 1959 |         _xspecs[$cmd]=$xspec
 | 
| 1960 |     done
 | 
| 1961 | }
 | 
| 1962 | # bzcmp, bzdiff, bz*grep, bzless, bzmore intentionally not here, see Debian: #455510
 | 
| 1963 | _install_xspec '!*.?(t)bz?(2)' bunzip2 bzcat pbunzip2 pbzcat lbunzip2 lbzcat
 | 
| 1964 | _install_xspec '!*.@(zip|[egjswx]ar|exe|pk3|wsz|zargo|xpi|s[tx][cdiw]|sx[gm]|o[dt][tspgfc]|od[bm]|oxt|epub|apk|ipa|do[ct][xm]|p[op]t[mx]|xl[st][xm]|pyz|whl)' unzip zipinfo
 | 
| 1965 | _install_xspec '*.Z' compress znew
 | 
| 1966 | # zcmp, zdiff, z*grep, zless, zmore intentionally not here, see Debian: #455510
 | 
| 1967 | _install_xspec '!*.@(Z|[gGd]z|t[ag]z)' gunzip zcat
 | 
| 1968 | _install_xspec '!*.@(Z|[gGdz]z|t[ag]z)' unpigz
 | 
| 1969 | _install_xspec '!*.Z' uncompress
 | 
| 1970 | # lzcmp, lzdiff intentionally not here, see Debian: #455510
 | 
| 1971 | _install_xspec '!*.@(tlz|lzma)' lzcat lzegrep lzfgrep lzgrep lzless lzmore unlzma
 | 
| 1972 | _install_xspec '!*.@(?(t)xz|tlz|lzma)' unxz xzcat
 | 
| 1973 | _install_xspec '!*.lrz' lrunzip
 | 
| 1974 | _install_xspec '!*.@(gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx)' ee
 | 
| 1975 | _install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|svg)' qiv
 | 
| 1976 | _install_xspec '!*.@(gif|jp?(e)g?(2)|j2[ck]|jp[2f]|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|?(e)ps)' xv
 | 
| 1977 | _install_xspec '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv kghostview
 | 
| 1978 | _install_xspec '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi kdvi
 | 
| 1979 | _install_xspec '!*.dvi' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx
 | 
| 1980 | _install_xspec '!*.[pf]df' acroread gpdf xpdf
 | 
| 1981 | _install_xspec '!*.@(?(e)ps|pdf)' kpdf
 | 
| 1982 | _install_xspec '!*.@(okular|@(?(e|x)ps|?(E|X)PS|[pf]df|[PF]DF|dvi|DVI|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|epub|EPUB|odt|ODT|fb?(2)|FB?(2)|mobi|MOBI|g3|G3|chm|CHM)?(.?(gz|GZ|bz2|BZ2|xz|XZ)))' okular
 | 
| 1983 | _install_xspec '!*.pdf' epdfview pdfunite
 | 
| 1984 | _install_xspec '!*.@(cb[rz7t]|djv?(u)|?(e)ps|pdf)' zathura
 | 
| 1985 | _install_xspec '!*.@(?(e)ps|pdf)' ps2pdf ps2pdf12 ps2pdf13 ps2pdf14 ps2pdfwr
 | 
| 1986 | _install_xspec '!*.texi*' makeinfo texi2html
 | 
| 1987 | _install_xspec '!*.@(?(la)tex|texi|dtx|ins|ltx|dbj)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi xetex xelatex luatex lualatex
 | 
| 1988 | _install_xspec '!*.mp3' mpg123 mpg321 madplay
 | 
| 1989 | _install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wm[av]|WM[AV]|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|web[am]|WEB[AM]|mp[234]|MP[234]|m?(p)4[av]|M?(P)4[AV]|mkv|MKV|og[agmv]|OG[AGMV]|t[ps]|T[PS]|m2t?(s)|M2T?(S)|mts|MTS|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM)|+([0-9]).@(vdr|VDR))?(.@(crdownload|part))' xine aaxine fbxine
 | 
| 1990 | _install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wm[av]|WM[AV]|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|web[am]|WEB[AM]|mp[234]|MP[234]|m?(p)4[av]|M?(P)4[AV]|mkv|MKV|og[agmv]|OG[AGMV]|t[ps]|T[PS]|m2t?(s)|M2T?(S)|mts|MTS|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM|iso|ISO)|+([0-9]).@(vdr|VDR))?(.@(crdownload|part))' kaffeine dragon
 | 
| 1991 | _install_xspec '!*.@(avi|asf|wmv)' aviplay
 | 
| 1992 | _install_xspec '!*.@(rm?(j)|ra?(m)|smi?(l))' realplay
 | 
| 1993 | _install_xspec '!*.@(mpg|mpeg|avi|mov|qt)' xanim
 | 
| 1994 | _install_xspec '!*.@(og[ag]|m3u|flac|spx)' ogg123
 | 
| 1995 | _install_xspec '!*.@(mp3|ogg|pls|m3u)' gqmpeg freeamp
 | 
| 1996 | _install_xspec '!*.fig' xfig
 | 
| 1997 | _install_xspec '!*.@(mid?(i)|cmf)' playmidi
 | 
| 1998 | _install_xspec '!*.@(mid?(i)|rmi|rcp|[gr]36|g18|mod|xm|it|x3m|s[3t]m|kar)' timidity
 | 
| 1999 | _install_xspec '!*.@(669|abc|am[fs]|d[bs]m|dmf|far|it|mdl|m[eo]d|mid?(i)|mt[2m]|oct|okt?(a)|p[st]m|s[3t]m|ult|umx|wav|xm)' modplugplay modplug123
 | 
| 2000 | _install_xspec '*.@([ao]|so|so.!(conf|*/*)|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite
 | 
| 2001 | _install_xspec '!*.@(zip|z|gz|tgz)' bzme
 | 
| 2002 | # konqueror not here on purpose, it's more than a web/html browser
 | 
| 2003 | _install_xspec '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx galeon dillo elinks amaya epiphany
 | 
| 2004 | _install_xspec '!*.@(sxw|stw|sxg|sgl|doc?([mx])|dot?([mx])|rtf|txt|htm|html|?(f)odt|ott|odm|pdf)' oowriter lowriter
 | 
| 2005 | _install_xspec '!*.@(sxi|sti|pps?(x)|ppt?([mx])|pot?([mx])|?(f)odp|otp)' ooimpress loimpress
 | 
| 2006 | _install_xspec '!*.@(sxc|stc|xls?([bmx])|xlw|xlt?([mx])|[ct]sv|?(f)ods|ots)' oocalc localc
 | 
| 2007 | _install_xspec '!*.@(sxd|std|sda|sdd|?(f)odg|otg)' oodraw lodraw
 | 
| 2008 | _install_xspec '!*.@(sxm|smf|mml|odf)' oomath lomath
 | 
| 2009 | _install_xspec '!*.odb' oobase lobase
 | 
| 2010 | _install_xspec '!*.[rs]pm' rpm2cpio
 | 
| 2011 | _install_xspec '!*.aux' bibtex
 | 
| 2012 | _install_xspec '!*.po' poedit gtranslator kbabel lokalize
 | 
| 2013 | _install_xspec '!*.@([Pp][Rr][Gg]|[Cc][Ll][Pp])' harbour gharbour hbpp
 | 
| 2014 | _install_xspec '!*.[Hh][Rr][Bb]' hbrun
 | 
| 2015 | _install_xspec '!*.ly' lilypond ly2dvi
 | 
| 2016 | _install_xspec '!*.@(dif?(f)|?(d)patch)?(.@([gx]z|bz2|lzma))' cdiff
 | 
| 2017 | _install_xspec '!@(*.@(ks|jks|jceks|p12|pfx|bks|ubr|gkr|cer|crt|cert|p7b|pkipath|pem|p10|csr|crl)|cacerts)' portecle
 | 
| 2018 | _install_xspec '!*.@(mp[234c]|og[ag]|@(fl|a)ac|m4[abp]|spx|tta|w?(a)v|wma|aif?(f)|asf|ape)' kid3 kid3-qt
 | 
| 2019 | unset -f _install_xspec
 | 
| 2020 | 
 | 
| 2021 | # Minimal completion to use as fallback in _completion_loader.
 | 
| 2022 | _minimal()
 | 
| 2023 | {
 | 
| 2024 |     local cur prev words cword split
 | 
| 2025 |     _init_completion -s || return
 | 
| 2026 |     $split && return
 | 
| 2027 |     _filedir
 | 
| 2028 | }
 | 
| 2029 | # Complete the empty string to allow completion of '>', '>>', and '<' on < 4.3
 | 
| 2030 | # http://lists.gnu.org/archive/html/bug-bash/2012-01/msg00045.html
 | 
| 2031 | complete -F _minimal ''
 | 
| 2032 | 
 | 
| 2033 | 
 | 
| 2034 | __load_completion()
 | 
| 2035 | {
 | 
| 2036 |     local -a dirs=( ${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions )
 | 
| 2037 |     local OIFS=$IFS IFS=: dir cmd="${1##*/}" compfile
 | 
| 2038 |     [[ -n $cmd ]] || return 1
 | 
| 2039 |     for dir in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do
 | 
| 2040 |         dirs+=( $dir/bash-completion/completions )
 | 
| 2041 |     done
 | 
| 2042 |     IFS=$OIFS
 | 
| 2043 | 
 | 
| 2044 |     if [[ $BASH_SOURCE == */* ]]; then
 | 
| 2045 |         dirs+=( "${BASH_SOURCE%/*}/completions" )
 | 
| 2046 |     else
 | 
| 2047 |         dirs+=( ./completions )
 | 
| 2048 |     fi
 | 
| 2049 | 
 | 
| 2050 |     for dir in "${dirs[@]}"; do
 | 
| 2051 |         [[ -d "$dir" ]] || continue
 | 
| 2052 |         for compfile in "$cmd" "$cmd.bash" "_$cmd"; do
 | 
| 2053 |             compfile="$dir/$compfile"
 | 
| 2054 |             # Avoid trying to source dirs; https://bugzilla.redhat.com/903540
 | 
| 2055 |             [[ -f "$compfile" ]] && . "$compfile" &>/dev/null && return 0
 | 
| 2056 |         done
 | 
| 2057 |     done
 | 
| 2058 | 
 | 
| 2059 |     # Look up simple "xspec" completions
 | 
| 2060 |     [[ "${_xspecs[$cmd]}" ]] && complete -F _filedir_xspec "$cmd" && return 0
 | 
| 2061 | 
 | 
| 2062 |     return 1
 | 
| 2063 | }
 | 
| 2064 | 
 | 
| 2065 | # set up dynamic completion loading
 | 
| 2066 | _completion_loader()
 | 
| 2067 | {
 | 
| 2068 |     # $1=_EmptycmD_ already for empty cmds in bash 4.3, set to it for earlier
 | 
| 2069 |     local cmd="${1:-_EmptycmD_}"
 | 
| 2070 | 
 | 
| 2071 |     __load_completion "$cmd" && return 124
 | 
| 2072 | 
 | 
| 2073 |     # Need to define *something*, otherwise there will be no completion at all.
 | 
| 2074 |     complete -F _minimal -- "$cmd" && return 124
 | 
| 2075 | } &&
 | 
| 2076 | complete -D -F _completion_loader
 | 
| 2077 | 
 | 
| 2078 | # Function for loading and calling functions from dynamically loaded
 | 
| 2079 | # completion files that may not have been sourced yet.
 | 
| 2080 | # @param $1 completion file to load function from in case it is missing
 | 
| 2081 | # @param $2... function and its arguments
 | 
| 2082 | _xfunc()
 | 
| 2083 | {
 | 
| 2084 |     set -- "$@"
 | 
| 2085 |     local srcfile=$1
 | 
| 2086 |     shift
 | 
| 2087 |     declare -F $1 &>/dev/null || {
 | 
| 2088 |         __load_completion "$srcfile"
 | 
| 2089 |     }
 | 
| 2090 |     "$@"
 | 
| 2091 | }
 | 
| 2092 | 
 | 
| 2093 | # source compat completion directory definitions
 | 
| 2094 | compat_dir=${BASH_COMPLETION_COMPAT_DIR:-/etc/bash_completion.d}
 | 
| 2095 | if [[ -d $compat_dir && -r $compat_dir && -x $compat_dir ]]; then
 | 
| 2096 |     for i in "$compat_dir"/*; do
 | 
| 2097 |         [[ ${i##*/} != @($_backup_glob|Makefile*|$_blacklist_glob) \
 | 
| 2098 |             && -f $i && -r $i ]] && . "$i"
 | 
| 2099 |     done
 | 
| 2100 | fi
 | 
| 2101 | unset compat_dir i _blacklist_glob
 | 
| 2102 | 
 | 
| 2103 | # source user completion file
 | 
| 2104 | user_completion=${BASH_COMPLETION_USER_FILE:-~/.bash_completion}
 | 
| 2105 | [[ ${BASH_SOURCE[0]} != $user_completion && -r $user_completion ]] \
 | 
| 2106 |     && . $user_completion
 | 
| 2107 | unset user_completion
 | 
| 2108 | 
 | 
| 2109 | unset -f have
 | 
| 2110 | unset have
 | 
| 2111 | 
 | 
| 2112 | set $BASH_COMPLETION_ORIGINAL_V_VALUE
 | 
| 2113 | unset BASH_COMPLETION_ORIGINAL_V_VALUE
 | 
| 2114 | 
 | 
| 2115 | # ex: filetype=sh
 |