Guest User

/usr/share/bash-completion/bash_completion

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