#   bash_completion - some programmable completion functions for bash 2.05
#
#   <![CDATA[
#
#   $Id: bash_completion,v 1.26 2001/11/05 00:11:48 ianmacd Exp $
#
#   Copyright (C) Ian Macdonald <ian@caliban.org>
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2, or (at your option)
#   any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software Foundation,
#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# Set a couple of useful vars
#
OS=$( uname -s )
RELEASE=$( uname -r )

# Turn on extended globbing and programmable completion
shopt -s extglob progcomp

# A lot of the following one-liners were taken directly from the
# completion examples provided with the bash 2.04 source distribution

# Make directory commands see only directories
complete -d cd mkdir rmdir pushd

# Make file commands see only files
complete -f cat less more ln strip
complete -f -X '*.bz2' bzip2
complete -f -X '!*.bz2' bunzip2
complete -f -X '!*.zip' unzip
complete -f -X '*.gz' gzip
complete -f -X '*.Z' compress
complete -f -X '!*.+(Z|gz|tgz|Gz)' gunzip zcat zmore
complete -f -X '!*.Z' uncompress zmore zcat
complete -f -X '!*.+(gif|jpg|jpeg|GIF|JPG|bmp)' ee xv
complete -f -X '!*.+(ps|PS|ps.gz)' gv
complete -f -X '!*.+(dvi|DVI)' dvips xdvi dviselect dvitype
complete -f -X '!*.+(pdf|PDF)' acroread xpdf
complete -f -X '!*.texi*' makeinfo texi2dvi texi2html
complete -f -X '!*.+(tex|TEX)' tex latex slitex

# kill sees only signals
complete -A signal kill -P '%'

# user commands see only users
complete -u finger su usermod userdel passwd

# bg completes with stopped jobs
complete -A stopped -P '%' bg

# other job commands
complete -j -P '%' fg jobs disown

# network commands complete with hostname
complete -A hostname ssh rsh telnet rlogin ftp ping fping host traceroute \
	    nslookup

# export and others complete with shell variables
complete -v export local readonly unset

# set completes with set options
complete -A setopt set

# shopt completes with shopt options
complete -A shopt shopt

# helptopics
complete -A helptopic help

# unalias completes with aliases
complete -a unalias

# bind completes with readline bindings (make this more intelligent)
complete -A binding bind

# Now we get to the meat of the file, the functions themselves. Some
# of these are works in progress. Most assume GNU versions of the
# tools in question and may require modifications for use on vanilla
# UNIX systems.
#
# A couple of functions may have non-portable, Linux specific code in
# them, but this will be noted where applicable

# This function is handy for checking whether we have certain programs
# on the system. No need for bulky functions in memory if we don't.
#
have()
{
	unset -v have
	which $1 &> /dev/null
	[ $? = 0 ] && have="yes"
}


# GNU chown(1) completion. This should be expanded to allow the use of
# ':' as well as '.' as the user.group separator.
#
_chown()
{
	local cur prev user group

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	# do not attempt completion if we're specifying an option
	[ "$cur" == -* ] && return 0

	# first parameter on line or first since an option?
	if [ $COMP_CWORD -eq 1 ] || [[ "$prev" == -* ]]; then
		if [[ "$cur" == [a-zA-Z]*.* ]]; then
			user=${cur%.*}
			group=${cur#*.}
			COMPREPLY=( $( awk 'BEGIN {FS=":"} \
					{if ($1 ~ /^'$group'/) print $1}' \
					/etc/group ) )
			for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
				COMPREPLY[i]=$user.${COMPREPLY[i]}
			done
		else
			COMPREPLY=( $( compgen -u $cur -S '.' ) )
		fi
	fi

	return 0
}
complete -F _chown -o default chown

# umount(8) completion. This relies on the mount point being the third
# space-delimited field in the output of mount(8)
#
_umount()
{
	local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	# could rewrite the cut | grep to be a sed command, but this is
	# clearer and doesn't result in much overhead
	COMPREPLY=( $( mount | cut -d' ' -f 3 | grep ^$cur) )

	return 0
}
complete -F _umount -o filenames umount

# GID completion. This will get a list of all valid group names from
# /etc/group and should work anywhere.
#
_gid_func()
{
	local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
	COMPREPLY=( $( awk 'BEGIN {FS=":"} {if ($1 ~ /^'$cur'/) print $1}' \
			   /etc/group ) )
	return 0
}
complete -F _gid_func groupdel groupmod

# mount(8) completion. This will pull a list of possible mounts out of
# /etc/fstab, unless the word being completed contains a ':', which
# would indicate the specification of an NFS server. In that case, we
# query the server for a list of all available exports and complete on
# that instead.
#
_mount()

{       local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	if [ -x /usr/sbin/showmount ] && [[ "$cur" == *:* ]]; then
		COMPREPLY=( $( /usr/sbin/showmount -e --no-headers ${cur%%:*} |\
			       grep ^${cur#*:} | awk '{print $1}' ) )
	else
		COMPREPLY=( $( awk '{if ($2 ~ /\//) print $2}' /etc/fstab | \
			       grep ^$cur ) )
	fi

	return 0
}
complete -F _mount -o default mount

# Linux rmmod(1) completion. This completes on a list of all currently
# installed kernel modules.
#
[ $OS = Linux ] &&
_rmmod()
{
	local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	COMPREPLY=( $( /sbin/lsmod | \
		       awk '{if (NR != 1 && $1 ~ /^'$cur'/) print $1}' ) )
	return 0
}
[ $OS = Linux ] && complete -F _rmmod rmmod

# Linux insmod(8) & modprobe(8) completion. This completes on a list of all
# available modules for the version of the kernel currently running.
#
[ $OS = Linux ] &&
_insmod()
{
	local cur prev modpath

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}
	modpath=/lib/modules/`uname -r`

	# behave like lsmod for modprobe -r
	if [ ${COMP_WORDS[0]} = "modprobe" ] && [ "${COMP_WORDS[1]}" = "-r" ]; then
		COMPREPLY=( $( /sbin/lsmod | \
				awk '{if (NR != 1 && $1 ~ /^'$cur'/) print $1}' ) )
		return 0
	fi

	# do filename completion if we're giving a path to a module
        if [[ "$cur" == /* ]]; then
                COMPREPLY=( $( compgen -f $cur ) )
                return 0
        fi

	if [ $COMP_CWORD -gt 1 ]; then
		# do module parameter completion
		COMPREPLY=( $( /sbin/modinfo -p ${COMP_WORDS[1]} | \
		       awk '{if ($1 ~ /^'$cur'/) print $1}' ) )
	else
		# do module name completion
		COMPREPLY=( $( ls -R $modpath | sed -ne 's/^\('$cur'.*\)\.o$/\1/p') )
	fi

	return 0
}
[ $OS = Linux ] && complete -F _insmod -o filenames insmod modprobe

# man(1) completion. This relies on the security enhanced version of
# GNU locate(1). UNIX variants having non-numeric man page sections
# other than l, m and n should add the appropriate sections to the
# first clause of the case statement.
#
# This is Linux specific, in that 'man <section> <page>' is the
# expected syntax. This allows one to do something like
# 'man 3 str<tab>' to obtain a list of all string handling syscalls on
# the system.
#
[ $OS = Linux ] &&
_man()
{
        local cur prev cmd

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

        # default completion if parameter contains / or we have no man.config
        [[ "$cur" == /* ]] || [ ! -f /etc/man.config ] && return 0

        if [[ "$prev" == [0-9ln] ]]; then
                # churn out a string of paths to search, with * appended to $cur
                cmd=`awk '{if ($1 ~ /^MANPATH/) \
                     print $(NF)"/man'$prev'/'$cur'*"}' /etc/man.config | \
                     sort -u`
                # strip off * from paths ending in /*
                cmd=${cmd//\/\\*/\/}
                # redirect stderr for when path doesn't exist
                cmd="ls $cmd 2>/dev/null"
                COMPREPLY=( $( eval $cmd ) )
                # get basename of man pages
                COMPREPLY=( ${COMPREPLY[@]##*/} )
                # strip suffix from man pages
                COMPREPLY=( ${COMPREPLY[@]%.gz} )
                COMPREPLY=( ${COMPREPLY[@]%.*} )
	else
                cmd=`awk '{if ($1 ~ /^MANPATH/) \
                     print $(NF)"/man?/'$cur'*"}' /etc/man.config | sort -u`
                cmd=${cmd//\/\\*/\/}
                cmd="ls $cmd 2>/dev/null"
                COMPREPLY=( $( eval $cmd ) )
                COMPREPLY=( ${COMPREPLY[@]##*/} )
                COMPREPLY=( ${COMPREPLY[@]%.gz} )
                COMPREPLY=( ${COMPREPLY[@]%.*} $( compgen -G $cur\*.[0-9ln] ) )
        fi

	return 0
}
[ $OS = Linux ] && complete -F _man -o default man

# Linux killall(1) completion. This wouldn't be much use on, say,
# Solaris, where killall does exactly that: kills ALL processes.
#
# This could be improved. For example, it currently doesn't take
# command line options into account
#
_killall()
{
	local cur prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	if [[ "$prev" == -[A-Z0-9]* ]]; then
		# get a list of processes (the gensub() in the awk takes care
		# of getting the basename of the process, the first sed
		# evaluation takes care of swapped out processes, and the
		# second takes care of getting the basename of the process)
	        COMPREPLY=( $( ps ahx | sed -e 's#[]\[()]##g' | \
		   awk '{if (gensub("^.*/","",1,$5) ~ /^'$cur'/) print $5}' | \
		   sed  -e 's#^.*/##' ) )
		return 0
	fi

	# first parameter can be either a signal or a process
	if [ $COMP_CWORD -eq 1 ]; then
		# standard signal completion is rather braindead, so we need
		# to hack around to get what we want here, which is to
		# complete on a dash, followed by the signal name minus
		# the SIG prefix
		COMPREPLY=( $( compgen -A signal SIG${cur#-} ))
		for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
			COMPREPLY[i]=-${COMPREPLY[i]#SIG}
		done
	fi

	# get processes, adding to signals if applicable
	COMPREPLY=( ${COMPREPLY[*]} $( ps ahx | sed -e 's#[]\[()]##g' | \
		   awk '{if (gensub("^.*/","",1,$5) ~ /^'$cur'/) print $5}' | \
		   sed -e 's#^.*/##' ))
	return 0
}
complete -F _killall killall

# GNU find(1) completion. This makes heavy use of ksh style extended
# globs and contains Linux specific code for completing the parameter
# to the -fstype option.
#
_find()
{
	local cur prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]#-}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	case "$prev" in
	-@(max|min)depth)
		COMPREPLY=( $( compgen -W '0 1 2 3 4 5 6 7 8 9' ) )
		return 0
		;;
	-?(a)newer|-fls|-fprint?(0|f))
		COMPREPLY=( $( compgen -f $cur ) )
		return 0
		;;
	-fstype)
		# this is highly non-portable (the option to -d is a tab)
		COMPREPLY=( $( cut -d'	' -f 2 /proc/filesystems | grep ^$cur ) )
		return 0
		;;
	-gid)
		COMPREPLY=( $( awk 'BEGIN {FS=":"} \
				{if ($3 ~ /^'$cur'/) print $3}' /etc/group ) )
		return 0
		;;
	-group)
		COMPREPLY=( $( awk 'BEGIN {FS=":"} \
				{if ($1 ~ /^'$cur'/) print $1}' /etc/group ) )
		return 0
		;;
	-?(x)type)
		COMPREPLY=( $( compgen -W 'b c d p f l s' $cur ) )
		return 0
		;;
	-uid)
		COMPREPLY=( $( awk 'BEGIN {FS=":"} \
				{if ($3 ~ /^'$cur'/) print $3}' /etc/passwd ) )
		return 0
		;;
	-user)
		COMPREPLY=( $( compgen -u $cur ) )
		return 0
		;;
	-[acm]min|-[acm]time|-?(i)?(l)name|-inum|-?(i)path|-?(i)regex| \
	-links|-perm|-size|-used|-exec|-ok|-printf)
		# do nothing, just wait for a parameter to be given
		return 0
		;;
	esac

	# complete using basic options ($cur has had its dash removed here,
	# as otherwise compgen will bomb out with an error, since it thinks
	# the dash is an option to itself)
	COMPREPLY=( $( compgen -W 'daystart depth follow help maxdepth \
			mindepth mount noleaf version xdev amin anewer atime \
			cmin cnewer ctime empty false fstype gid group ilname \
			iname inum ipath iregex links lname mmin mtime name \
			newer nouser nogroup perm regex size true type uid \
			used user xtype exec fls fprint fprint0 fprintf ok \
			print print0 printf prune ls' $cur ) )

	# this removes any options from the list of completions that have
	# already been specified somewhere on the command line.
	COMPREPLY=( $( echo "${COMP_WORDS[@]}-" | \
		       (while read -d '-' i; do
			    [ "$i" == "" ] && continue
			    # flatten array with spaces on either side,
			    # otherwise we cannot grep on word boundaries of
			    # first and last word
			    COMPREPLY=" ${COMPREPLY[@]} "
			    # remove word from list of completions
			    COMPREPLY=( ${COMPREPLY/ ${i%% *} / } )
		        done
		        echo ${COMPREPLY[@]})
		  ) )
	
	# put dashes back
	for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
		COMPREPLY[i]=-${COMPREPLY[i]}
	done


	return 0
}
complete -F _find -o filenames find

# Linux ifconfig(8) completion
#
[ $OS = Linux ] &&
_ifconfig()
{
	local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	case "${COMP_WORDS[1]}" in
	-|*[0-9]*)
		COMPREPLY=( $( compgen -W '-a up down arp promisc allmulti \
					   metric mtu dstaddr netmask add del \
					   tunnel irq io_addr mem_start media \
					   broadcast pointopoint hw multicast \
					   address txqueuelen' $cur ))
		COMPREPLY=( $( echo " ${COMP_WORDS[@]}" | \
			       (while read -d ' ' i; do
				   [ "$i" == "" ] && continue
				   # flatten array with spaces on either side,
				   # otherwise we cannot grep on word
				   # boundaries of first and last word
				   COMPREPLY=" ${COMPREPLY[@]} "
				   # remove word from list of completions
				   COMPREPLY=( ${COMPREPLY/ $i / } )
				done
			        echo ${COMPREPLY[@]})
			  ) )
		return 0
		;;
	esac

	COMPREPLY=( $( ifconfig -a | sed -ne 's/^\('$cur'[^ ]*\).*$/\1/p' ))
}
[ $OS = Linux ] && complete -F _ifconfig ifconfig

# Linux ipsec(8) completion (for FreeS/WAN). Basic.
#
[ $OS = Linux ] && have ipsec &&
_ipsec()
{
	local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	
	if [ $COMP_CWORD = 1 ]; then
		COMPREPLY=( $( compgen -W 'auto barf eroute klipsdebug look manual \
				   pluto ranbits rsasigkey setup showdefaults \
				   showhostkey spi spigrp tncfg whack' $cur ))
		return 0
	fi

	case ${COMP_WORDS[1]} in
	auto)
		COMPREPLY=( $( compgen -W '--asynchronous --up --add --delete \
					   --replace --down --route --unroute \
					   --ready --status --rereadsecrets' $cur ) )
		return 0
		;;
	manual)
		COMPREPLY=( $( compgen -W '--up --down --route --unroute \
					   --union' $cur ) )
		return 0
		;;
	ranbits)
		COMPREPLY=( $( compgen -W '--quick --continuous --bytes' $cur ) )
		return 0
		;;
	setup)
		COMPREPLY=( $( compgen -W '--start --stop --restart' $cur ) )
		return 0
		;;

	*)
		return 0
		;;
	esac

	return 0
}
[ $OS = Linux ] && [ "$have" ] && complete -F _ipsec ipsec

# cvs(1) completion
#
_cvs()
{
	local cur prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	if [ $COMP_CWORD -eq 1 ] || [[ "$prev" == -* ]]; then
		COMPREPLY=( $( compgen -W 'add admin checkout commit diff \
		export history import log rdiff release remove rtag status \
		tag update' $cur ))
	fi

	return 0
}
complete -F _cvs -o default cvs

# rpm(8) completion. This is quite comprehensive now and covers rpm 4.x
# 
have rpm &&
_rpm()
{
	dashify()
	{
		local i

		for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
			if [ ${#COMPREPLY[i]} -le 2 ]; then
				COMPREPLY[i]=-${COMPREPLY[i]}
			else
				COMPREPLY[i]=--${COMPREPLY[i]}
			fi
		done
	}

	add_package_list()
	{
		if [ -f /var/log/rpmpkgs ]; then
		# using RHL 7.2 - this is quicker than querying the DB
			COMPREPLY=( ${COMPREPLY[@]}
			$( sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9a-z.]\+.*\.rpm$/\1/p' /var/log/rpmpkgs ) )
		else
			COMPREPLY=( ${COMPREPLY[@]} $( rpm -qa | \
		        sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9a-z.]\+$/\1/p' ) )
		fi
	}

	file_glob()
	{
		local suffix

		# get extension of current word, if relevant
		suffix=${cur##*.}
		# nullify it if it's not a substring of the extension we're
		# completing on
		[ "$suffix" != "${1:0:${#suffix}}" ] && suffix=""
		COMPREPLY=( ${COMPREPLY[@]} $( compgen -G $cur\*${1:${#suffix}} ) )
		# directory completion if all else fails and current word
		# contains a slash
		if [ ${#COMPREPLY[@]} = 0 ] && [[ $cur == */* ]]; then
	    		COMPREPLY=( $( compgen -d $cur ) )
		fi
	}

	local cur cur_nodash prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
	cur_nodash=${cur#-}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	if [ $COMP_CWORD = 1 ]; then
		# first parameter on line
		case "$cur" in
		-b*)
			COMPREPLY=( $( compgen -W 'ba bb bc bi bl bp bs' \
				       $cur_nodash ) )
			dashify
			return 0
			;;
		-t*)
			COMPREPLY=( $( compgen -W 'ta tb tc ti tl tp ts' \
				       $cur_nodash ) )
			dashify
			return 0
			;;
		--*)
			COMPREPLY=( $( compgen -W 'help version initdb \
			checksig recompile rebuild resign addsign rebuilddb \
			showrc setperms setugids tarbuild eval install \
			upgrade query freshen erase verify querytags rmsource' \
			${cur_nodash#-} ) )
			dashify
			return 0
			;;
		*)
			COMPREPLY=( $( compgen -W 'b e F i q t U V' \
				       $cur_nodash ) )
			dashify
			return 0
			;;
		esac
	fi

	case "$prev" in
	--@(db|exclude)path|prefix|relocate|root)
		COMPREPLY=( $( compgen -d $cur ) )
		return 0
		;;
	--eval)
		# get a list of macros (char class contains a space and tab)
		COMPREPLY=( $( sed -ne 's/^\(%'${cur#\%}'[^ 	]*\).*$/\1/p' \
			       /usr/lib/rpm/macros ) )
		return 0
		;;
	--pipe)
		COMPREPLY=( $( compgen -c $cur ) )
		return 0
		;;
	--rcfile)
		COMPREPLY=( $( compgen -f $cur ) )
		return 0
		;;
	--specfile)
		# complete on .spec files
		file_glob spec
		return 0
		;;
	--whatprovides)
		# complete on capabilities
		COMPREPLY=( $( rpm -qa --queryformat '%{providename}\n' | grep ^$cur ) )
		return 0
		;;
	--whatrequires)
		# complete on capabilities
		COMPREPLY=( $( rpm -qa --queryformat '%{requirename}\n' | grep ^$cur ) )
		return 0
		;;
	esac

	case "${COMP_WORDS[1]}" in
	-@([iFU]*|-install|-freshen|-upgrade))
		# complete on list of relevant options
		COMPREPLY=( $( compgen -W 'percent force test replacepkgs \
		replacefiles root excludedocs includedocs noscripts rcfile \
		ignorearch dbpath prefix ignoreos nodeps allfiles ftpproxy \
		ftpport justdb httpproxy httpport noorder relocate badreloc \
		notriggers excludepath ignoresize oldpackage define eval \
		pipe queryformat' ${cur_nodash#-} ))
		dashify
		# return if $cur is an option
		[[ "$cur" == -* ]] && return 0
		# add a list of RPMS to possible completions
		file_glob rpm
		return 0
		;;
	-qp*)
		# complete on list of relevant options
		COMPREPLY=( $( compgen -W 'scripts root rcfile whatprovides \
		whatrequires requires triggeredby ftpport ftpproxy httpproxy \
		httpport provides triggers dump changelog dbpath filesbypkg \
		define eval pipe showrc info list state docfiles \
		configfiles queryformat' ${cur_nodash#-} ) )
		dashify
		# return if $cur is an option
		[[ "$cur" == -* ]] && return 0
		# add a list of RPMS to possible completions
		file_glob rpm
		return 0
		;;
	-*f)
		# standard filename completion
		COMPREPLY=( $( compgen -f $cur ) )
		return 0
		;;
	-@(e|-erase))
		# complete on list of relevant options
		COMPREPLY=( $( compgen -W 'allmatches noscripts notriggers \
		nodeps test' ${cur_nodash#-} ) )
		dashify
		# return if $cur is an option
		[[ "$cur" == -* ]] && return 0
		add_package_list
		return 0
		;;
	-q*)
		# complete on list of relevant options
		COMPREPLY=( $( compgen -W 'scripts root rcfile whatprovides \
		whatrequires requires triggeredby ftpport ftpproxy httpproxy \
		httpport provides triggers dump changelog dbpath specfile \
		querybynumber last filesbypkg define eval pipe showrc info \
		list state docfiles configfiles queryformat' \
		${cur_nodash#-} ) )
		dashify
		# return if $cur is an option
		[[ "$cur" == -* ]] && return 0
		# don't complete on packages if we are querying all packages
		[[ ${COMP_WORDS[1]} == -qa* ]] && return 0
		add_package_list
		return 0
		;;
	-@(K|-checksig))
		# complete on list of relevant options
		COMPREPLY=( $( compgen -W 'nopgp nogpg nomd5' \
		${cur_nodash#-} ) )
		dashify
		# return if $cur is an option
		[[ "$cur" == -* ]] && return 0
		# add a list of RPMS to possible completions
		file_glob rpm
		return 0
		;;
	-@([Vy]*|-verify))
		# complete on list of relevant options
		COMPREPLY=( $( compgen -W 'root rcfile dbpath nodeps nofiles \
		noscripts nomd5' ${cur_nodash#-} ) )
		dashify
		# return if $cur is an option
		[[ "$cur" == -* ]] && return 0
		add_package_list
		return 0
		;;
	-[bt]*)
		# complete on list of relevant options
		COMPREPLY=( $( compgen -W 'short-circuit timecheck clean \
		rmsource test sign buildroot target buildarch buildos \
		nobuild' ${cur_nodash#-} ) )
		dashify
		# return if $cur is an option
		[[ "$cur" == -* ]] && return 0
		if [[ ${COMP_WORDS[1]} == -b* ]]; then
			# complete on .spec files
			file_glob spec
		else
			# complete on .tar files
			COMPREPLY=( $( compgen -G $cur\*.+(tgz|tar.+(gz|bz2)) ) )
		fi
		return 0
		;;
	--re@(build|compile))
		# complete on source RPMs
		COMPREPLY=( $( compgen -G $cur\*.src.rpm ) )
		return 0
		;;
	--tarbuild)
		# complete on tarred sources
		COMPREPLY=( $( compgen -G $cur\*.+(tgz|tar.+(gz|bz2)) ) )
		return 0
		;;
	--@(re|add)sign)
		# complete on RPMs
		file_glob rpm
		return 0
		;;
	--set@(perms|gids))
		add_package_list
		return 0
		;;
	--rmsource)
		file_glob spec
		return 0
		;;
	-*g)
		# package group completion
		local IFS=$(echo -e "\t")
		# remove trailing backslash, or grep will complain
		cur=${cur%'\'}
		COMPREPLY=( $( rpm -qa --queryformat '%{group}\n' | \
			       grep ^$cur ) )
		# backslash escape spaces and translate newlines to tabs
		COMPREPLY=( $( echo ${COMPREPLY[@]} | sed 's/ /\\ /g' | \
			       tr '\n' '\t' ) )
		return 0
		;;
	esac

	return 0
}
[ "$have" ] && complete -F _rpm -o filenames rpm

# Debian Linux apt-get(8) completion.
#
have apt-get &&
_apt-get()
{
	local cur prev special

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	for (( i=0; i < ${#COMP_WORDS}-1; i++ )); do
		if [[ ${COMP_WORDS[i]} == @(install|remove|source) ]]; then
			special=${COMP_WORDS[i]}
		fi
	done
	if [ -n "$special" ]; then
		case $special in
		@(install|remove|source))
			COMPREPLY=( $( apt-cache pkgnames $cur ) )
			return 0
			;;
		esac
	fi

	if [[ "$prev" == -*c ]] || [ "$prev" = --config-file ]; then
		COMPREPLY=( $( compgen -f $cur ) )
	else
		COMPREPLY=( $( compgen -W 'update upgrade dselect-upgrade \
				  dist-upgrade install remove source check \
				  clean autoclean -d -f -h -v -m -q -s -y -u \
				  -b -c -o --download-only --fix-broken --help \
				  --version --ignore-missing --fix-missing \
				  --no-download --quiet --simulate \
				  --just-print --dry-run --recon --no-act \
				  --yes --assume-yes --show-upgraded \
				  --compile --build --ignore-hold \
				  --no-upgrade --force-yes --print-uris \
				  --purge --reinstall --list-cleanup \
				  --trivial-only --no-remove --diff-only \
				  --tar-only --config-file --option ' | \
				  grep ^$cur ) )
	fi

	return 0
}
[ "$have" ] && complete -F _apt-get -o filenames apt-get

# Debian Linux apt-cache(8) completion.
#
have apt-cache &&
_apt-cache()
{
	local cur prev special

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	
	for (( i=0; i < ${#COMP_WORDS}-1; i++ )); do
		if [[ ${COMP_WORDS[i]} == @(add|showpkg) ]]; then
			special=${COMP_WORDS[i]}
		fi
	done
	if [ -n "$special" ]; then
		case $special in
		add)
			COMPREPLY=( $( compgen -f $cur ) )
			return 0
			;;
		showpkg)
			COMPREPLY=( $( apt-cache pkgnames $cur ) )
			return 0
			;;
		esac
	fi


	if [[ "$prev" == -*c ]] || [ "$prev" = --config-file ]; then
		COMPREPLY=( $( compgen -f $cur ) )
	else
		COMPREPLY=( $( compgen -W 'add gencaches showpkg stats dump \
				dumpavail unmet check search show showpkg \
				depends pkgnames -h -v -p -s -q -i -f -a -g -c \
				-o --help --version --pkg-cache --src-cache \
				--quiet --important --full --all-versions \
				--no-generate --names-only --all-names \
				--config-file --option' | grep ^$cur ) )
	fi

	return 0
}
[ "$have" ] && complete -F _apt-cache -o filenames apt-cache

# chsh(1) completion
#
_chsh()
{
	local cur prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	if [ "$prev" = "-s" ]; then
		COMPREPLY=( $( chsh -l | grep ^$cur ) )
	else
		COMPREPLY=( $( compgen -u $cur ) )
	fi

	return 0
}
complete -F _chsh chsh

# chkconfig(8) completion
#
have chkconfig &&
_chkconfig()
{
	local cur prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
	cur_nodash=${cur#--}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	if [ $COMP_CWORD -eq 1 ]; then
		COMPREPLY=( $( compgen -W 'list add del level' $cur_nodash ) )
		for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
			COMPREPLY[i]=--${COMPREPLY[i]}
		done
		return 0
	fi

	if [ $COMP_CWORD -eq 4 ]; then
		COMPREPLY=( $( compgen -W 'on off reset' $cur ) )
		return 0
	fi

	case "$prev" in
	@([1-6]|--@(list|add|del)))
		COMPREPLY=( $( compgen -W "`(cd /etc/rc.d/init.d; echo *)`" \
			       $cur) )
		return 0
		;;
	--level)
		COMPREPLY=( $( compgen -W '1 2 3 4 5 6' $cur ) )
		return 0
		;;
	esac

	return 0
}
[ "$have" ] && complete -F _chkconfig chkconfig

# This function performs host completion based on ssh's known_hosts files, defaulting
# to standard host completion if they don't exist.
#
_known_hosts()
{
	local cur kh

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
	kh=()

	[ -r /etc/known_hosts ]    && kh[0]=/etc/known_hosts
	[ -r /etc/known_hosts2 ]   && kh[1]=/etc/known_hosts2
	[ -r ~/.ssh/known_hosts ]  && kh[2]=~/.ssh/known_hosts
	[ -r ~/.ssh/known_hosts2 ] && kh[3]=~/.ssh/known_hosts2

	# If we have known_hosts files to use
	if [ ${#kh[@]} -gt 0 ]; then
	    if [[ $cur == [0-9]*.* ]]; then
		# Digits followed by a dot - just search for that
		cur="^$cur.*"
	    elif [[ $cur == [0-9]* ]]; then
		# Digits followed by no dot - search for digits followed
		# by a dot
		cur="^$cur.*\."
	    elif [ -z $cur ]; then
		# A blank - search for a dot or an alpha character
		cur="[a-z.]"
	    else
		cur="^$cur"
	    fi
	    # FS needs to look for a comma separated list
	    COMPREPLY=( $( awk 'BEGIN {FS="[ ,]"}
				{for (i=1; i<=NR; ++i) { \
				       if ($i ~ /'$cur'/) {print $i} \
				}}' ${kh[@]} ) )
	else
	    # Just do normal hostname completion
	    COMPREPLY=( $( compgen -A hostname $cur ) )
	fi

	return 0
}
complete -F _known_hosts traceroute ping fping telnet host nslookup

# ssh(1) completion. Should be able to improve this with user@host notation,
# but the '@' seems to trigger some kind of bug in bash's completion.
#
have ssh &&
_ssh()
{
	local cur prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	case "$prev" in
	-*c)
	    COMPREPLY=( $( compgen -W 'blowfish 3des 3des-cbc blowfish-cbc \
			   arcfour cast128-cbc' $cur ) )
	    return 0
	    ;;
	-*l)
	    COMPREPLY=( $( compgen -u $cur ) )
	    return 0
	    ;;
	esac

	# Host has been specified, so now do simple command completion
	if [ $COMP_CWORD -gt 1 ]; then
	    COMPREPLY=( $( compgen -c $cur ) )
	    return 0
	fi

	# Otherwise, check for known hosts
	_known_hosts

	return 0
}
[ "$have" ] && complete -F _ssh ssh slogin sftp

# Linux route(8) completion. This could be improved by adding address family
# completion for -A, etc.
#
_route()
{
	local cur prev

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	if [ "$prev" = dev ]; then
	    COMPREPLY=( $( ifconfig -a | sed -ne 's/^\('$cur'[^ ]*\).*$/\1/p' ))
	    return 0
	fi

	# Must use grep here, otherwise $cur will cause compgen to barf, if
	# it begins with a hyphen
	COMPREPLY=( $( compgen -W 'add del -host -net netmask metric mss \
				  window irtt reject mod dyn reinstate dev' | \
		       grep ^$cur ) )

	COMPREPLY=( $( echo " ${COMP_WORDS[@]}" | \
		       (while read -d ' ' i; do
			   [ "$i" == "" ] && continue
			   # flatten array with spaces on either side,
			   # otherwise we cannot grep on word
			   # boundaries of first and last word
			   COMPREPLY=" ${COMPREPLY[@]} "
			   # remove word from list of completions
			   COMPREPLY=( ${COMPREPLY/ $i / } )
			done
		       echo ${COMPREPLY[@]})
		  ) )
	return 0
}
complete -F _route route

# GNU make(1) completion (adapted from the example supplied with the bash 2.04
# source code)
#
_make()
{
        local mdef makef gcmd cur prev i

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

        # if prev argument is -f, return possible filename completions.
        # we could be a little smarter here and return matches against
        # `makefile Makefile *.mk', whatever exists
        if [[ "$prev" == -*f ]]; then
	    COMPREPLY=( $( compgen -f $cur ) )
	    return 0
	fi

        # if we want an option, return the possible posix options
        if [[ "$cur" == - ]]; then
            COMPREPLY=( $( compgen -W '-e -f -i -k -n -p -q -r -S -s -t' | grep ^$cur ) )
	    return 0
        fi

        # make reads `makefile' before `Makefile'
        if [ -f makefile ]; then
                mdef=makefile
        elif [ -f Makefile ]; then
                mdef=Makefile
        else
                mdef=*.mk               # local convention
        fi

        # before we scan for targets, see if a makefile name was specified
        # with -f
        for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
                if [[ ${COMP_WORDS[i]} == -*f ]]; then
                        eval makef=${COMP_WORDS[i+1]}   # eval for tilde expansion
                        break
                fi
        done

        [ -z "$makef" ] && makef=$mdef

        # if we have a partial word to complete, restrict completions to
        # matches of that word
        if [ -n "$2" ]; then
	    gcmd='grep "^$2"'
	else
	    gcmd=cat
	fi

        # if we don't want to use *.mk, we can take out the cat and use
        # test -f $makef and input redirection  
        COMPREPLY=( $( cat $makef 2>/dev/null | \
		       awk 'BEGIN {FS=":"} /^[^.#	][^=]*:/ {print $1}' | \
		       eval $gcmd ) )

	# default to filename completion if all else failed
	if [ ${#COMPREPLY[@]} = 0 ]; then
	    COMPREPLY=( $( compgen -f $cur ) )
	fi

	return 0
}
complete -F _make -X '+($*|*.[cho])' -o filenames make gmake pmake

# Red Hat Linux service completion. This completes on a list of all available
# service scripts in the SysV init.d directory, followed by that script's
# available commands
#
have service &&
_service()
{
	local cur sysvdir

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	[ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \
				|| sysvdir=/etc/init.d

	#[[ "$cur" == -* ]] && return 0
	if [ $COMP_CWORD = 1 ]; then
		COMPREPLY=( $( compgen -W '`echo $sysvdir/!(*.rpmsave|*.rpmorig)`' ) )
		COMPREPLY=( $( compgen -W '${COMPREPLY[@]#$sysvdir/}' $cur ) )
	else
		COMPREPLY=( $( compgen -W '`sed -ne "y/|/ /; \
					    s/^.*Usage.*{\(.*\)}.*$/\1/p" \
					    $sysvdir/${COMP_WORDS[1]}' $cur ) )
	fi

	return 0
}
[ "$have" ] && complete -F _service service

# The beginnings of a completion function for GNU tar(1)
#
_tar()
{
	local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	if [[ ${COMP_WORDS[1]} == *z*f ]]; then
		COMPREPLY=( $( compgen -G $cur\*.tar.gz ) )
	elif [[ ${COMP_WORDS[1]} == *j*f ]]; then
		COMPREPLY=( $( compgen -G $cur\*.tar.bz2 ) )
	fi

	return 0
}
complete -F _tar -o default tar

# Linux iptables(8) completion
#
have iptables &&
_iptables()
{
	local cur

	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}
	prev=${COMP_WORDS[COMP_CWORD-1]}
	
	[ "$prev" = -t ] && COMPREPLY=( $( compgen -W 'nat filter mangle' $cur ) )
}
 [ "$have" ] && complete -F _iptables iptables

# Linux iptables(8) completion
#
have tcpdump &&
_tcpdump()
{
	local cur

	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}
	prev=${COMP_WORDS[COMP_CWORD-1]}

	COMPREPLY=( $( compgen -W 'host net port src dst ether gateway 
				   less greater' $cur ) )

}
[ "$have" ] && complete -F _tcpdump tcpdump

# This meta-cd function observes the CDPATH variable, so that cd additionally
# completes on directories under those specified in CDPATH.
#
_cd()
{
        local cur=${COMP_WORDS[COMP_CWORD]} dirs=()

	# standard dir completion if parameter contains a /
	[[ "$cur" == /* ]] && COMPREPLY=( $( compgen -d $cur ) ) && return 0

	if [ -n "$CDPATH" ]; then
		# we have a CDPATH, so loop on its contents
		for i in ${CDPATH//:/ }; do
			# create an array of matched subdirs
			dirs=( $( compgen -d $i/$cur ) )
			# add subdirs to list of completions as necessary
			[ ${#dirs[@]} ] && COMPREPLY=( ${COMPREPLY[@]} ${dirs[@]#$i/})
		done
	else
		COMPREPLY=( $( compgen -d $cur ) )
	fi

	return 0
}
complete -F _cd -o filenames cd

# A meta-command completion function, for commands like sudo, which often
# need to complete on a command, followed by a file-name
#
_command()
{
	local cur

        COMPREPLY=()
        cur=${COMP_WORDS[COMP_CWORD]}

	if [ $COMP_CWORD -eq 1 ]; then
		COMPREPLY=( $( compgen -c $cur ) )
	else
		# XXX sudo chkconfig should complete just as chkconfig would
		COMPREPLY=( $( compgen -f $cur ) )
	fi
}
complete -F _command -o filenames type nohup exec nice eval strace sudo gdb

# Basic Perforce completion by Frank Cusack (frank@google.com)
#
have p4 &&
_p4()
{
	local cur prev prev2 p4commands p4filetypes

	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}
        prev=${COMP_WORDS[COMP_CWORD-1]}

	# rename isn't really a command
	p4commands="add admin branch branches change changes client \
		clients counter counters delete depot depots describe \
		diff diff2 dirs edit filelog files fix fixes flush \
		fstat group groups have help info integrate integrated \
		job jobs jobspec label labels labelsync lock obliterate \
		opened passwd print protect rename reopen resolve \
		resolved revert review reviews set submit sync triggers \
		typemap unlock user users verify where"
	p4filetypes="ctext cxtext ktext kxtext ltext tempobj ubinary \
		uresource uxbinary xbinary xltext xtempobj xtext \
		text binary resource"

	if [ $COMP_CWORD -eq 1 ]; then
		COMPREPLY=( $( compgen -W "$p4commands" $cur ) )
	elif [ $COMP_CWORD -eq 2 ]; then
		case "$prev" in
		help)
			COMPREPLY=( $( compgen -W "simple commands \
				environment filetypes jobview revisions \
				usage views $p4commands" $cur ) )
			;;
		admin)
			COMPREPLY=( $( compgen -W "checkpoint stop" $cur ) )
			;;
		*)
			;;
		esac
	elif [ $COMP_CWORD -gt 2 ]; then
        	prev2=${COMP_WORDS[COMP_CWORD-2]}
		case "$prev" in
		-t)
			case "$prev2" in
			add|edit|reopen)
				COMPREPLY=( $(compgen -W "$p4filetypes" $cur) )
				;;
			*)
				;;
			esac
			;;
		*)
			;;
		esac
	fi

	return 0
}
[ "$have" ] && complete -F _p4 -o default p4

# 
# Return 1 if $1 appears to contain a redirection operator.  Handles backslash
# quoting (barely).
#
_redir_op()
{
	case "$1" in
	*\\'[\<\>]'*)	return 1;;
	*[\<\>]*)	return 0;;
	*)		return 1;;
	esac
}


# _redir_test tests the current word ($1) and the previous word ($2) for
# redirection operators and does filename completion on the current word
# if either one contains a redirection operator
_redir_test()
{
	if _redir_op "$1" ; then
		COMPREPLY=( $( compgen -f "$1" ) )
		return 0
	elif _redir_op "$2" ; then
		COMPREPLY=( $( compgen -f "$1" ) )
		return 0
	fi
	return 1
}

_configure_func ()
{
	case "$2" in
	-*)	;;
	*)	return ;;
	esac

	case "$1" in
	\~*)	eval cmd=$1 ;;
	*)	cmd="$1" ;;
	esac

	COMPREPLY=( $("$cmd" --help | awk '{if ($1 ~ /--.*/) print $1}' | grep ^"$2" | sort -u) )
}
complete -F _configure_func configure

unset -f have
unset OS RELEASE have
