# (C) 2010 magicant

# Completion script for the "find" command.
# Supports POSIX 2008, GNU findutils 4.5.9, FreeBSD 8.1, OpenBSD 4.8,
# NetBSD 5.0, Darwin 10.6.4, SunOS 5.10, HP-UX 11i v3.

function completion/find {

	typeset SAVEWORDS
	SAVEWORDS=("$WORDS")

	case $("${WORDS[1]}" --version 2>/dev/null) in
		(*'findutils'*) typeset type=GNU ;;
		(*)             typeset type="$(uname 2>/dev/null)" ;;
	esac

	typeset OPTIONS ARGOPT PREFIX
	OPTIONS=( #>#
	"H; follow symbolic links in operands"
	"L; follow all symbolic links"
	) #<#

	case $type in
	(GNU)
		OPTIONS=("$OPTIONS" #>#
		"D:; specify debug options"
		"O::; specify optimization level"
		"P; don't follow symbolic links"
		"--help"
		"--version"
		) #<#
		;;
	(*BSD|Darwin)
		OPTIONS=("$OPTIONS" #>#
		"d; do post-order traversal rather than pre-order"
		"f:; specify a directory to search"
		"X; warn about filenames incompatible with xargs"
		"x; don't search in different file systems"
		) #<#
		case $type in (FreeBSD|NetBSD|Darwin)
			OPTIONS=("$OPTIONS" #>#
			"E; use extended regular expression"
			"P; don't follow symbolic links"
			"s; sort filenames within each directory"
			) #<#
		esac
		;;
	esac

	command -f completion//parseoptions
	case $ARGOPT in
	(-)
		case $TARGETWORD in (-|--*)
			command -f completion//completeoptions
		esac
		if [ "$type" = GNU ]; then
			typeset i=2
			command -f completion/find::expr
		fi
		;;
	(D)
		if [ "$PREFIX" ]; then
			complete -P "$PREFIX" ""
		else
			typeset targetword="${TARGETWORD##*,}"
			PREFIX=${TARGETWORD%"$targetword"}
			#>>#
			complete -P "$PREFIX" -D "print help about the -D option" help
			complete -P "$PREFIX" -D "print the syntax tree of the expression" tree
			complete -P "$PREFIX" -D "print info during directory tree search" search
			complete -P "$PREFIX" -D "trace calls to the stat function" stat
			complete -P "$PREFIX" -D "print success rate for each predicate" rates
			complete -P "$PREFIX" -D "print debug info about optimization" opt
			complete -P "$PREFIX" -D "print debug info about execution of external commands" exec
			#<<#
		fi
		;;
	(f)
		complete -P "$PREFIX" -S / -T -d
		;;
	(O)
		;;
	(*)
		typeset path=false expr=false i=2
		WORDS=("$SAVEWORDS")
		if [ "$type" = GNU ]; then
			path=true
		fi
		while [ $i -le ${WORDS[#]} ]; do
			if [ "${WORDS[i]}" = -- ]; then
				i=$((i+1))
				break
			fi
			case $type in
			(GNU)
				case ${WORDS[i]} in (-[!DHLOP-]*)
					break
				esac
				;;
			(*BSD|Darwin)
				case ${WORDS[i]} in (-f*)
					path=true
				esac
				;;
			esac
			case ${WORDS[i]} in
			(-?*)
				;;
			(*)
				break
				;;
			esac
			i=$((i+1))
		done
		while [ $i -le ${WORDS[#]} ]; do
			case ${WORDS[i]} in
			(\(|!|-*)
				expr=true
				break
				;;
			(*)
				path=true
				;;
			esac
			i=$((i+1))
		done
		if ! $expr; then
			complete -S / -T -d
		fi
		if $path; then
			command -f completion/find::expr
		fi
		;;
	esac

}

# This function depends on variables $i, $type.
function completion/find::expr {

	while [ $i -le ${WORDS[#]} ]; do
		case ${WORDS[i]} in
		(-acl|-aclv)
			case $type in
			(HP-UX)
				if [ $i -eq ${WORDS[#]} ]; then #>>#
					complete -D "optional access control list entries" opt
				fi #<<#
				i=$((i+2))
				;;
			(*)
				i=$((i+1))
				;;
			esac
			;;
		(-[acmB]newer|-fls|-fprint|-fprint0|-ilname|-iname|-ipath|-iwholename|-linkedto|-lname|-name|-newer*|-path|-samefile|-wholename)
			if [ $i -eq ${WORDS[#]} ]; then
				complete -f
			fi
			i=$((i+2))
			;;
		(-[acmB]time)
			if [ $i -eq ${WORDS[#]} ]; then
				case $type in (FreeBSD|Darwin)
					case $TARGETWORD in (*[[:digit:]]*)
						PREFIX=${TARGETWORD%"${TARGETWORD##*[[:digit:]]}"}
						#>>#
						complete -P "$PREFIX" -D "second" s
						complete -P "$PREFIX" -D "minute" m
						complete -P "$PREFIX" -D "hour" h
						complete -P "$PREFIX" -D "day" d
						complete -P "$PREFIX" -D "week" w
						#<<#
					esac
				esac
			fi
			i=$((i+2))
			;;
		(-exec|-execdir|-ok|-okdir)
			i=$((i+1))
			typeset j=$i
			while [ $j -le ${WORDS[#]} ]; do
				if [ "${WORDS[j]}" = ";" ]; then
					i=$((j+1)); break
				elif [ "${WORDS[j]} ${WORDS[j+1]}" = "{} +" ]; then
					i=$((j+2)); break
				fi
				j=$((j+1))
			done
			if [ $i -le $j ]; then
				WORDS=("${WORDS[i,-1]}")
				command -f completion//reexecute -e
				return
			fi
			;;
		(-flags)
			if [ $i -eq ${WORDS[#]} ]; then
				# TODO
			fi
			i=$((i+2))
			;;
		(-fprintf)
			if [ $i -eq ${WORDS[#]} ]; then
				complete -f
			elif [ $((i+1)) -eq ${WORDS[#]} ]; then
				command -f completion/find::printf
			fi
			i=$((i+3))
			;;
		(-group)
			if [ $i -eq ${WORDS[#]} ]; then
				complete -g
			fi
			i=$((i+2))
			;;
		(-perm)
			if [ $i -eq ${WORDS[#]} ]; then
				if command -vf completion/chmod::mode >/dev/null 2>&1 ||
						. -AL completion/chmod; then
					command -f completion/chmod::mode find
				fi
			fi
			i=$((i+2))
			;;
		(-printf)
			if [ $i -eq ${WORDS[#]} ]; then
				command -f completion/find::printf
			fi
			i=$((i+2))
			;;
		(-regextype)
			if [ $i -eq ${WORDS[#]} ]; then
				complete emacs posix-awk posix-basic posix-egrep posix-extended
			fi
			i=$((i+2))
			;;
		(-size)
			if [ $i -eq ${WORDS[#]} ]; then
				case $TARGETWORD in (*[[:digit:]]*)
					PREFIX=${TARGETWORD%"${TARGETWORD##*[[:digit:]]}"}
					#>>#
					complete -P "$PREFIX" -D "byte" c
					#<<#
					case $type in (GNU|FreeBSD|Darwin)
						#>>#
						complete -P "$PREFIX" -D "kilobyte (2^10 bytes)" k
						complete -P "$PREFIX" -D "megabyte (2^20 bytes)" M
						complete -P "$PREFIX" -D "gigabyte (2^30 bytes)" G
						#<<#
						case $type in
						(GNU) #>>#
							complete -P "$PREFIX" -D "block (2^9 bytes)" b
							complete -P "$PREFIX" -D "word (2 bytes)" w
							;; #<<#
						(FreeBSD|Darwin) #>>#
							complete -P "$PREFIX" -D "terabyte (2^40 bytes)" T
							complete -P "$PREFIX" -D "petabyte (2^50 bytes)" P
							;; #<<#
						esac
					esac
				esac
			fi
			i=$((i+2))
			;;
		(-type|-xtype)
			if [ $i -eq ${WORDS[#]} ]; then #>>#
				complete -D "block special file" b
				complete -D "character special file" c
				complete -D "directory" d
				complete -D "regular file" f
				complete -D "symbolic link" l
				complete -D "FIFO" p
				complete -D "socket" s
			fi #<<#
			case $(uname) in (SunOS) #>>#
				complete -D "door" D
			esac #<<#
			case $type in
			(NetBSD) #>>#
				complete -D "whiteout" w
				;; #<<#
			(HP-UX) #>>#
				complete -D "mount point" M
				complete -D "network special file" n
				;; #<<#
			esac
			i=$((i+2))
			;;
		(-user)
			if [ $i -eq ${WORDS[#]} ]; then
				complete -u
			fi
			i=$((i+2))
			;;
		(-[acmB]min|-context|-cpio|-fsonly|-fstype|-[gu]id|-inum|-iregex|-links|-maxdepth|-mindepth|-ncpio|-regex|-used)
			i=$((i+2))
			;;
		(*)
			i=$((i+1))
			;;
		esac
	done

	if [ $i -eq $((${WORDS[#]}+1)) ]; then case $TARGETWORD in
	(-newer*)
		case $type in
		(GNU|FreeBSD|Darwin|HP-UX)
			typeset word="${TARGETWORD#-newer}"
			word=${word#?}
			PREFIX=${TARGETWORD%"$word"}
			#>>#
			complete -P "$PREFIX" -D "last access time" a
			complete -P "$PREFIX" -D "last status change time" c
			complete -P "$PREFIX" -D "last modified time" m
			#<<#
			case $type in (GNU|FreeBSD|Darwin)
				#>>#
				complete -P "$PREFIX" -D "creation time" B
				#<<#
				case $TARGETWORD in (-newer?*) #>>#
					complete -P "$PREFIX" -D "specify time" t
				esac #<<#
			esac
			;;
		(*)
			complete -- -newer
			;;
		esac
		;;
	(-*)
		#>>#
		complete -D "logical conjunction (and)" -- -a
		complete -D "true if the last access time is n days ago" -- -atime
		complete -D "true if the last status change time is n days ago" -- -ctime
		complete -D "search directories in post-order rather than pre-order" -- -depth
		complete -D "execute the specified command line" -- -exec
		complete -D "true if the group is the specified one" -- -group
		complete -D "true if the file has the specified hard link count" -- -links
		complete -D "true if the last modified time is n days ago" -- -mtime
		complete -D "true if the filename matches the specified pattern" -- -name
		complete -D "logical disjunction (or)" -- -o
		complete -D "prompt for execution of the specified command line" -- -ok
		complete -D "true if the pathname matches the specified pattern" -- -path
		complete -D "true if the file has the specified permission" -- -perm
		complete -D "print the pathname" -- -print
		complete -D "don't search the directory if evaluated" -- -prune
		complete -D "true if the file has the specified size" -- -size
		complete -D "true if the file has the specified type" -- -type
		complete -D "true if the owner is the specified one" -- -user
		complete -D "don't search different file systems" -- -xdev
		#<<#
		case $type in (GNU|*BSD|Darwin|SunOS|HP-UX)
			#>>#
			complete -D "true if the file is on the specified file system" -- -fstype
			complete -D "true if the file has the specified inode number" -- -inum
			#<<#
			case $type in (GNU|*BSD|Darwin|SunOS)
				#>>#
				complete -D "print the file in ls -dils format" -- -ls
				#<<#
				case $type in (GNU|FreeBSD|Darwin|SunOS) #>>#
					complete -D "don't search different file systems" -- -mount
				esac #<<#
			esac
			case $type in (GNU|*BSD|Darwin|SunOS) #>>#
				complete -D "print the pathname with a trailing null byte" -- -print0
			esac #<<#
		esac
		case $type in (GNU|*BSD|Darwin)
			#>>#
			complete -D "logical conjunction (and)" -- -and
			complete -D "true if the last access time is n minutes ago" -- -amin
			complete -D "true if the last access time is later than last modified time of the specified file" -- -anewer
			complete -D "true if the last status change time is n minutes ago" -- -cmin
			complete -D "true if the last status change time is later than last modified time of the specified file" -- -cnewer
			complete -D "true if the file is empty" -- -empty
			complete -D "execute the specified command line in the directory containing the file" -- -execdir
			complete -D "true if the filename matches the specified pattern (case-insensitive)" -- -iname
			complete -D "search directories of at most the specified depth only" -- -maxdepth
			complete -D "search directories of at least the specified depth only" -- -mindepth
			complete -D "true if the last modified time is n minutes ago" -- -mmin
			complete -D "true if the last modified time is later than that of the specified file" -T -- -newer
			complete -D "true if the file's group ID has no name" -T -- -nogroup
			complete -D "true if the file owner's user ID has no name" -T -- -nouser
			complete -D "prompt for execution of the specified command line in the directory containing the file" -- -okdir
			complete -D "logical disjunction (or)" -- -or
			#<<#
			case $type in (GNU|FreeBSD|NetBSD|Darwin)
				#>>#
				complete -D "remove the file" -- -delete
				complete -D "false" -- -false
				complete -D "true if the pathname matches the specified regular expression (case-insensitive)" -- -iregex
				complete -D "true if the pathname matches the specified regular expression" -- -regex
				complete -D "true if the file is a hard link to the specified" -- -samefile
				#<<#
				case $type in (GNU|FreeBSD|Darwin) #>>#
					complete -D "true if the file's group ID is the specified" -- -gid
					complete -D "true if the symbolic link's target matches the specified pattern (case-insensitive)" -- -ilname
					complete -D "true if the pathname matches the specified pattern (case-insensitive)" -- -ipath -iwholename
					complete -D "true if the symbolic link's target matches the specified pattern" -- -lname
					complete -D "true" -- -true
					complete -D "true if the file owner's user ID is the specified" -- -uid
					complete -D "true if the pathname matches the specified pattern" -- -wholename
				esac #<<#
			esac
			case $type in (GNU|NetBSD) #>>#
				complete -D "print the pathname to the specified file" -- -fprint
			esac #<<#
			case $type in (*BSD|Darwin)
				#>>#
				complete -D "true if the file has the specified flags" -- -flags
				#<<#
				case $type in (FreeBSD|Darwin) #>>#
					complete -D "true if the creation time is n minutes ago" -- -Bmin
					complete -D "true if the creation time is later than last modified time of the specified file" -- -Bnewer
					complete -D "true if the creation time is n days ago" -- -Btime
					complete -D "true if the last modified time is later than that of the specified file" -- -mnewer
				esac #<<#
			esac
		esac
		case $type in (FreeBSD|SunOS|HP-UX)
			#>>#
			complete -D "true if the file have additional ACLs defined" -- -acl
			#<<#
			case $type in (SunOS|HP-UX) #>>#
				complete -D "write the file in cpio format to the specified device" -- -cpio
				complete -D "write the file in cpio -c format to the specified device" -- -ncpio
				complete -D "true if the file is on the same file system" -- -local
			esac #<<#
		esac
		case $type in (GNU) #>>#
			complete -D "true if the SELinux context matches the specified pattern" -- -context
			complete -D "measure time from the beginning of today" -- -daystart
			complete -D "true if the file is executable" -- -executable
			complete -D "write file info to the specified file" -- -fls
			complete -D "print the null-terminated pathname to the specified file" -- -fprint0
			complete -D "print the specified formatted string to the specified file" -- -fprintf
			complete -D "ignore files removed during traversal" -- -ignore_readdir_race
			complete -D "disable warning messages" -- -nowarn
			complete -D "print the specified formatted string" -- -printf
			complete -D "stop directory traversal" -- -quit
			complete -D "true if the file is readable" -- -readable
			complete -D "specify the type of regular expression" -- -regextype
			complete -D "true if the last access time is n days after the last status change" -- -used
			complete -D "enable warning messages" -- -warn
			complete -D "true if the file is writable" -- -writable
			complete -D "don't search autofs file systems" -- -xautofs
			complete -D "true if the file has the specified type (do/don't follow symbolic links)" -- -xtype
		esac #<<#
		case $type in (NetBSD) #>>#
			complete -D "stop directory traversal" -- -exit
			complete -D "print the pathname with escapes for xargs" -- -printx
			complete -D "remove the file" -- -rm
		esac #<<#
		case $type in (SunOS) #>>#
			complete -D "true if the file has extended attributes" -- -xattr
		esac #<<#
		case $type in (HP-UX) #>>#
			complete -D "true if the file have additional JFS ACLs defined" -- -aclv
			complete -D "traverse the specified file system only" -- -fsonly
			complete -D "true if the file is a hard link to the specified" -- -linkedto
			complete -D "don't search different file systems" -- -mountstop
			complete -D "don't search the directory unless evaluated" -- -only
		esac #<<#
		;;
	esac fi

	return 0

}

function completion/find::printf {

	if command -vf completion/printf::backslash >/dev/null 2>&1 ||
		. -AL completion/printf; then
		command -f completion/printf::backslash echo
	fi

	typeset word="$TARGETWORD"
	word=${word//%%}
	case $word in
	(*%)
		PREFIX=${TARGETWORD%\%} #>>#
		complete -T -P "$PREFIX" -D "last access time, formatted" '%A'
		complete -T -P "$PREFIX" -D "last access time" '%a'
		complete -T -P "$PREFIX" -D "disk usage in 512-byte blocks" '%b'
		complete -T -P "$PREFIX" -D "last status change time, formatted" '%C'
		complete -T -P "$PREFIX" -D "last status change time" '%c'
		complete -T -P "$PREFIX" -D "device number" '%D'
		complete -T -P "$PREFIX" -D "depth in directory traversal" '%d'
		complete -T -P "$PREFIX" -D "file system type" '%F'
		complete -T -P "$PREFIX" -D "basename" '%f'
		complete -T -P "$PREFIX" -D "group ID (numeric)" '%G'
		complete -T -P "$PREFIX" -D "group" '%g'
		complete -T -P "$PREFIX" -D "the searched directory under which the file was found" '%H'
		complete -T -P "$PREFIX" -D "dirname" '%h'
		complete -T -P "$PREFIX" -D "inode number" '%i'
		complete -T -P "$PREFIX" -D "disk usage in kilobyte blocks" '%k'
		complete -T -P "$PREFIX" -D "target of symbolic link" '%l'
		complete -T -P "$PREFIX" -D "permission mode bits (symbolic)" '%M'
		complete -T -P "$PREFIX" -D "permission mode bits (octal)" '%m'
		complete -T -P "$PREFIX" -D "number of hard links" '%n'
		complete -T -P "$PREFIX" -D "pathname relative to the searched directory" '%P'
		complete -T -P "$PREFIX" -D "pathname" '%p'
		complete -T -P "$PREFIX" -D "sparseness" '%S'
		complete -T -P "$PREFIX" -D "file size in bytes" '%s'
		complete -T -P "$PREFIX" -D "last modified time, formatted" '%T'
		complete -T -P "$PREFIX" -D "last modified time" '%t'
		complete -T -P "$PREFIX" -D "owner's user ID (numeric)" '%U'
		complete -T -P "$PREFIX" -D "owner's user name" '%u'
		complete -T -P "$PREFIX" -D "file type (dereference symbolic link)" '%Y'
		complete -T -P "$PREFIX" -D "file type" '%y'
		complete -T -P "$PREFIX" -D "SELinux context" '%Z'
		complete -T -P "$PREFIX" -D "%" '%%'
		;; #<<#
	(*%[ACT])
		PREFIX=${TARGETWORD%\%?}
		word=${TARGETWORD#"$PREFIX"} #>>#
		complete -T -P "$PREFIX" -D "day of week, full, localized" "${word}A"
		complete -T -P "$PREFIX" -D "day of week, short, localized" "${word}a"
		complete -T -P "$PREFIX" -D "month, full, localized" "${word}B"
		complete -T -P "$PREFIX" -D "month, short, localized" "${word}b"
		complete -T -P "$PREFIX" -D "date and time, localized" "${word}c"
		complete -T -P "$PREFIX" -D "like %m/%d/%y (e.g. 12/31/99)" "${word}D"
		complete -T -P "$PREFIX" -D "day of month [01-31]" "${word}d"
		complete -T -P "$PREFIX" -D "hour [00-23]" "${word}H"
		complete -T -P "$PREFIX" -D "hour [01-12]" "${word}I"
		complete -T -P "$PREFIX" -D "day of year [001-366]" "${word}j"
		complete -T -P "$PREFIX" -D "hour [ 0-23] (space-padded)" "${word}k"
		complete -T -P "$PREFIX" -D "hour [ 1-12] (space-padded)" "${word}l"
		complete -T -P "$PREFIX" -D "month [01-12]" "${word}m"
		complete -T -P "$PREFIX" -D "AM or PM, localized" "${word}p"
		complete -T -P "$PREFIX" -D "12-hour clock time with AM/PM, localized" "${word}r"
		complete -T -P "$PREFIX" -D "second" "${word}S"
		complete -T -P "$PREFIX" -D "like %H:%M:%S (e.g. 13:45:56)" "${word}T"
		complete -T -P "$PREFIX" -D "week of year [00-53] (first Sunday in week 1)" "${word}U"
		complete -T -P "$PREFIX" -D "week of year [00-53] (first Monday in week 1)" "${word}W"
		complete -T -P "$PREFIX" -D "day of week in numeral [0-6]" "${word}w"
		complete -T -P "$PREFIX" -D "time, localized" "${word}X"
		complete -T -P "$PREFIX" -D "date, localized" "${word}x"
		complete -T -P "$PREFIX" -D "year, full (e.g. 1999)" "${word}Y"
		complete -T -P "$PREFIX" -D "year within century [00-99]" "${word}y"
		complete -T -P "$PREFIX" -D "timezone name" "${word}Z"
		complete -T -P "$PREFIX" -D "seconds since epoch" "${word}@"
		complete -T -P "$PREFIX" -D "the default localized format" "${word}+"
		;; #<<#
	esac

	return 0

}


# vim: set ft=sh ts=8 sts=8 sw=8 noet:
