Browse code

bash: bash_completion support

Change-Id: I4bbd93d1956a9da679be6a7b0f682c2eaa9f444d
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/1307
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Vinay Kulkarni <kulkarniv@vmware.com>

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