summaryrefslogtreecommitdiff
path: root/Misc
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:05:35 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:05:35 +0000
commitc175751b501a3a4cb40ad4787340a597ea769be4 (patch)
treef5cd9e9bf7dbfb5b91569181f260965c0a3cb8ad /Misc
downloadzsh-c175751b501a3a4cb40ad4787340a597ea769be4.tar.gz
zsh-c175751b501a3a4cb40ad4787340a597ea769be4.zip
Initial revision
Diffstat (limited to 'Misc')
-rw-r--r--Misc/.distfiles4
-rw-r--r--Misc/.lastloc2
-rwxr-xr-xMisc/c2z128
-rw-r--r--Misc/compctl-examples716
-rwxr-xr-xMisc/globtests107
-rwxr-xr-xMisc/globtests.ksh91
-rwxr-xr-xMisc/lete2ctl301
7 files changed, 1349 insertions, 0 deletions
diff --git a/Misc/.distfiles b/Misc/.distfiles
new file mode 100644
index 000000000..a02614511
--- /dev/null
+++ b/Misc/.distfiles
@@ -0,0 +1,4 @@
+DISTFILES_SRC='
+ .distfiles
+ c2z compctl-examples globtests globtests.ksh lete2ctl
+'
diff --git a/Misc/.lastloc b/Misc/.lastloc
new file mode 100644
index 000000000..8ba7dd946
--- /dev/null
+++ b/Misc/.lastloc
@@ -0,0 +1,2 @@
+(("/home/user2/pws/src/zsh-3.1.5/Misc/globtests.ksh" . 2763)
+ ("/home/user2/pws/src/zsh-3.1.5/Misc/globtests" . 3123))
diff --git a/Misc/c2z b/Misc/c2z
new file mode 100755
index 000000000..8a90d5fd8
--- /dev/null
+++ b/Misc/c2z
@@ -0,0 +1,128 @@
+#! /bin/sh
+#
+# c2z - environment conversion tool
+# Contributed by Bart Schaefer
+# (Tweaked a bit by Paul Falstad)
+#
+# This is a quick script to convert csh aliases to zsh aliases/functions.
+# It also converts the csh environment and local variables to zsh. c2z
+# uses the csh to parse its own dot-files, then processes csh output to
+# convert the csh settings to zsh.
+#
+# When run as a zsh fuction, c2z runs csh as if it were an interactive
+# shell whenever the parent zsh is interactive. When run as a shell
+# script, the -i switch can be used to force this behavior.
+#
+# The -l (login) switch causes csh to run as if it were a login shell.
+# This is done "properly" if c2z is used as a zsh function, otherwise
+# it's faked by explicitly sourcing .login. Use with caution if your
+# .login initializes an X server or does other one-time-only startup
+# procedures.
+#
+# usage:
+# c2z [-i | -l | filename]
+#
+# You can use this script in your .zshrc or .zlogin files to load your
+# regular csh environment into zsh; for example, in .zlogin:
+#
+# . =(c2z -l)
+#
+# This is not perfect, but it gets most common aliases and variables.
+# It's also rather time-consuming to do this every time you log in.
+# However, if you're moving from csh to zsh for the first time, this
+# can get you started with a familiar environment right away.
+#
+# In case your mailer eats tabs, $T is set to expand to a tab.
+#
+T="`echo x | tr x '\011'`"
+
+# If we're zsh, we can run "- csh" to get the complete environment.
+#
+MINUS=""
+LOADFILE=""
+INTERACT=""
+CSH=csh
+case "$ZSH_NAME$ZSH_VERSION$VERSION" in
+zsh*)
+ case $1 in
+ -l*) MINUS="-" ;;
+ -i*) INTERACT="-i" ;;
+ *) LOADFILE="source $1" CSH="csh -f";;
+ esac
+ if [[ -o INTERACTIVE ]]; then INTERACT="-i"; fi
+ setopt nobanghist
+ ;;
+*)
+ case $1 in
+ -l*) LOADFILE="source ~/.login" ;;
+ -i*) INTERACT="-i" ;;
+ *) LOADFILE="source $1" CSH="csh -f";;
+ esac
+ ;;
+esac
+
+( eval $MINUS $CSH $INTERACT ) <<EOF 2>&1 >/dev/null
+$LOADFILE
+alias >! /tmp/cz$$.a
+setenv >! /tmp/cz$$.e
+set >! /tmp/cz$$.v
+EOF
+
+# save stdin
+exec 9<&0
+
+# First convert aliases
+exec < /tmp/cz$$.a
+
+# Taken straight from ctoz except for $T and "alias --"
+sed -e 's/'"$T"'(\(.*\))/'"$T"'\1/' >/tmp/cz$$.1
+grep ! /tmp/cz$$.1 >/tmp/cz$$.2
+grep -v ! /tmp/cz$$.1 >/tmp/cz$$.3
+sed -e "s/'/'"\\\\"''"/g \
+ -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/alias -- \1='"'\2'/" \
+ /tmp/cz$$.3
+sed -e 's/![:#]*/$/g' \
+ -e 's/\$cwd/$PWD/' \
+ -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/\1 () { \2 }/' \
+ /tmp/cz$$.2
+
+# Next, convert environment variables
+exec < /tmp/cz$$.e
+
+# Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ...
+sed -e '/^SHLVL/d' \
+ -e '/^PWD/d' \
+ -e "s/'/'"\\\\"''"/g \
+ -e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \
+ -e "s/$/'/"
+
+# Finally, convert local variables
+exec < /tmp/cz$$.v
+
+sed -e 's/'"$T"'/=/' \
+ -e "s/'/'"\\\\"''"/g \
+ -e '/^[A-Za-z0-9_]*=[^(]/{
+ s/=/='"'/"'
+ s/$/'"'/"'
+ }' |
+sed -e '/^argv=/d' -e '/^cwd=/d' -e '/^filec=/d' -e '/^status=/d' \
+ -e '/^autolist=/s/.*/setopt autolist/' \
+ -e '/^correct=all/s//setopt correctall/' \
+ -e '/^correct=/s//setopt correct/' \
+ -e '/^histchars=/s//HISTCHARS=/' \
+ -e '/^history=/s//HISTSIZE=/' \
+ -e '/^home=/s//HOME=/' \
+ -e '/^ignoreeof=/s/.*/setopt ignoreeof/' \
+ -e '/^noclobber=/s/.*/setopt noclobber/' \
+ -e '/^notify=/d' \
+ -e '/^prompt=/s/!/%h/' \
+ -e 's/^prompt/PROMPT/' \
+ -e '/^showdots=/s/.*/setopt globdots/' \
+ -e '/^savehist=/s//HISTFILE=\~\/.zhistory SAVEHIST=/' \
+ -e '/^who=/s//WATCHFMT=/'
+
+
+exec 0<&9
+
+rm /tmp/cz$$.?
+exit
diff --git a/Misc/compctl-examples b/Misc/compctl-examples
new file mode 100644
index 000000000..e84a37fbb
--- /dev/null
+++ b/Misc/compctl-examples
@@ -0,0 +1,716 @@
+#
+# This file gives examples of possible programmable completions (compctl).
+# You can either put the compctl commands in your .zshrc file, or put them
+# in a separate file (say .zcompctl) and source it from your .zshrc file.
+#
+# These are just examples. Use and modify to personal taste. Copying
+# this file without thought will needlessly increase zsh's memory usage
+# and startup time.
+#
+# For a detailed description of how these work, check the zshcompctl man
+# page.
+#
+#------------------------------------------------------------------------------
+hosts=("${${(s: :)${(s: :)${${(f)$(</etc/hosts)}%%\#*}#*[ ]*}}:#}")
+ports=( "${${${(f)$(</etc/services)}:#\#*}%%[ ]*}" )
+
+# groups=( $(cut -d: -f1 /etc/group) )
+# groups=( $(ypcat group.byname | cut -d: -f1) ) # if you use NIS
+
+# It can be done without forking, but it used too much memory in old zsh's:
+groups=( "${${(f)$(</etc/group)}%%:*}" )
+#groups=( "${${(f)$(ypcat groups)}%%:*}" ) # if you use NIS
+
+# Completion for zsh builtins.
+compctl -z -P '%' bg
+compctl -j -P '%' fg jobs disown
+compctl -j -P '%' + -s '`ps -x | tail +2 | cut -c1-5`' wait
+compctl -A shift
+compctl -c type whence where which
+compctl -m -x 'W[1,-*d*]' -n - 'W[1,-*a*]' -a - 'W[1,-*f*]' -F -- unhash
+compctl -m -q -S '=' -x 'W[1,-*d*] n[1,=]' -/ - \
+ 'W[1,-*d*]' -n -q -S '=' - 'n[1,=]' -/g '*(*)' -- hash
+compctl -F functions unfunction
+compctl -k '(al dc dl do le up al bl cd ce cl cr
+ dc dl do ho is le ma nd nl se so up)' echotc
+compctl -a unalias
+compctl -v getln getopts read unset vared
+compctl -v -S '=' -q declare export integer local readonly typeset
+compctl -eB -x 'p[1] s[-]' -k '(a f m r)' - \
+ 'C[1,-*a*]' -ea - 'C[1,-*f*]' -eF - 'C[-1,-*r*]' -ew -- disable
+compctl -dB -x 'p[1] s[-]' -k '(a f m r)' - \
+ 'C[1,-*a*]' -da - 'C[1,-*f*]' -dF - 'C[-1,-*r*]' -dw -- enable
+compctl -k "(${(j: :)${(f)$(limit)}%% *})" limit unlimit
+compctl -l '' -x 'p[1]' -f -- . source
+# Redirection below makes zsh silent when completing unsetopt xtrace
+compctl -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)' + -o + -x 's[no]' -o -- unsetopt
+compctl -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)' + -o + -x 's[no]' -o -- setopt
+compctl -s '${^fpath}/*(N:t)' autoload
+compctl -b -x 'W[1,-*[DAN]*],C[-1,-*M]' -s '$(bindkey -l)' -- bindkey
+compctl -c -x 'C[-1,-*k]' -A - 'C[-1,-*K]' -F -- compctl
+compctl -x 'C[-1,-*e]' -c - 'C[-1,-[ARWI]##]' -f -- fc
+compctl -x 'p[1]' - 'p[2,-1]' -l '' -- sched
+compctl -x 'C[-1,[+-]o]' -o - 'c[-1,-A]' -A -- set
+compctl -b -x 'w[1,-N] p[3]' -F -- zle
+compctl -s '${^module_path}/*(N:t:r)' -x \
+ 'W[1,-*(a*u|u*a)*],W[1,-*a*]p[3,-1]' -B - \
+ 'W[1,-*u*]' -s '$(zmodload)' -- zmodload
+
+# Anything after nohup is a command by itself with its own completion
+compctl -l '' nohup noglob exec nice eval - time rusage
+compctl -l '' -x 'p[1]' -eB -- builtin
+compctl -l '' -x 'p[1]' -em -- command
+compctl -x 'p[1]' -c - 'p[2,-1]' -k signals -- trap
+#------------------------------------------------------------------------------
+# kill takes signal names as the first argument after -, but job names after %
+# or PIDs as a last resort
+compctl -j -P '%' + -s '`ps -x | tail +2 | cut -c1-5`' + \
+ -x 's[-] p[1]' -k "($signals[1,-3])" -- kill
+#------------------------------------------------------------------------------
+compctl -s '$(groups)' + -k groups newgrp
+compctl -f -x 'p[1], p[2] C[-1,-*]' -k groups -- chgrp
+compctl -f -x 'p[1] n[-1,.], p[2] C[-1,-*] n[-1,.]' -k groups - \
+ 'p[1], p[2] C[-1,-*]' -u -S '.' -q -- chown
+compctl -/g '*.x' rpcgen
+compctl -u -x 's[+] c[-1,-f],s[-f+]' -W ~/Mail -f - \
+ 's[-f],c[-1,-f]' -f -- mail elm
+compctl -x 'c[-1,-f]' -W ~/Mail -f -- pine
+#------------------------------------------------------------------------------
+compctl -s "\$(awk '/^[a-zA-Z0-9][^ ]+:/ {print \$1}' FS=: [mM]akefile)" -x \
+ 'c[-1,-f]' -f -- make gmake pmake
+#------------------------------------------------------------------------------
+# tar
+tarnames () {
+ # Completion function for use with tar:
+ # get the names of files in the tar archive to extract.
+ #
+ # The main claim to fame of this particular function is that it
+ # completes directories in the tar-file in a manner very roughly
+ # consistent with `compctl -f'. There are two bugs: first, the whole
+ # path prefix up to the present is listed with ^D, not just the new
+ # part to add; second, after a unique completion a space is always
+ # inserted, even if the completion ends with a slash. These are
+ # currently limitations of zsh.
+ #
+ # This only works for the (fairly common) tar argument style where
+ # the arguments are bunched into the first argument, and the second
+ # argument is the name of the tarfile. For example,
+ # tar xvzf zsh-3.1.2.tar.gz ...
+ # You can only use compressed/gzipped files if tar is GNU tar,
+ # although the correct name for the tar programme will be inferred.
+
+ local line list=tf
+ read -cA line
+ # $line[2] is the first argument: check for possible compression args.
+ # (This is harmless when used with non-GNU tar, but then the file must
+ # be uncompressed to be able to use it with tar anyway.)
+ [[ $line[2] = *[Zz]* ]] && list=tfz
+ # $line[1] is the command name: something like tar or gnutar.
+ # $line[3] is the name of the tar archive.
+
+ # cache contents for multiple completion: note tar_cache_name
+ # and tar_cache_list are not local. Assumes all files with the
+ # same name are the same file, even if in different directories:
+ # you can trick it with $PWD/file on the command line.
+ if [[ $line[3] != $tar_cache_name ]]; then
+ tar_cache_list=($($line[1] $list $line[3]))
+ tar_cache_name=$line[3]
+ fi
+
+ # Now prune the list to include only appropriate directories.
+ local file new
+ reply=()
+ if [[ $1 = */* ]]; then
+ local sofar=${1%/*}/
+ for file in $tar_cache_list; do
+ if [[ $file = $sofar* ]]; then
+ new=${file#$sofar}
+ if [[ $new = */* ]]; then
+ new=$sofar${new%%/*}/
+ else
+ new=$file
+ fi
+ if [[ $1 != */ || $new != $1 ]]; then
+ reply=($reply $new)
+ fi
+ fi
+ done
+ else
+ for file in $tar_cache_list; do
+ if [[ $file = */* ]]; then
+ new=${file%%/*}/
+ else
+ new=$file
+ fi
+ reply=($reply $new)
+ done
+ fi
+}
+
+compctl -f \
+ -x 'p[2] C[-1,*(z*f|f*z)*]' -/g '*.(taz|tar.(gz|z|Z)|tgz)' \
+ - 'p[2] C[-1,*(Z*f|f*Z)*]' -/g '*.(tar.Z|taz)' \
+ - 'p[2] C[-1,*f*]' -/g '*.tar' \
+ - 'p[1] N[-1,ctxvzZ]' -k "(v z f)" \
+ - 'p[1] s[]' -k "(c t x)" -S '' \
+ - 'p[3,-1] W[1,*x*]' -K tarnames \
+ -- tar gtar gnutar
+#------------------------------------------------------------------------------
+# rmdir only real directories
+compctl -/g '*(/)' rmdir dircmp
+#------------------------------------------------------------------------------
+# cd/pushd only directories or symbolic links to directories
+compctl -/ cd chdir dirs pushd
+
+# Another possibility for cd/pushd is to use it in conjunction with the
+# cdmatch function (in the Functions subdirectory of zsh distribution).
+compctl -K cdmatch -S '/' -q -x 'p[2]' -Q -K cdmatch2 - \
+ 'S[/][~][./][../]' -g '*(-/)' + -g '*(-/D)' - \
+ 'n[-1,/]' -K cdmatch -S '/' -q -- cd chdir pushd
+#------------------------------------------------------------------------------
+# If the command is rsh, make the first argument complete to hosts and treat the
+# rest of the line as a command on its own.
+compctl -k hosts -x 'p[2,-1]' -l '' -- rsh
+
+# rlogin takes hosts and users after `-l'
+compctl -k hosts -x 'c[-1,-l]' -u -- rlogin
+
+# rcp: match users, hosts and files initially. Match files after a :, or hosts
+# after an @. If one argument contains a : then the other matches files only.
+# Not quite perfect; compctl just isn't up to it yet.
+compctl -u -k hosts -f -x 'n[1,:]' -f - 'n[1,@]' -k hosts -S ':' - \
+ 'p[1] W[2,*:*]' -f - 'p[1] W[2,*?*]' -u -k hosts -S ':' - \
+ 'p[2] W[1,*:*]' -f - 'p[2] W[1,*?*]' -u -k hosts -S ':' -- rcp
+
+compctl -k hosts host rup rusers ping
+#------------------------------------------------------------------------------
+# strip, profile, and debug only executables. The compctls for the
+# debuggers could be better, of course.
+compctl -/g '*(*)' strip gprof adb dbx xdbx ups
+compctl -/g '*.[ao]' -/g '*(*)' nm
+#------------------------------------------------------------------------------
+# shells: compctl needs some more enhancement to do -c properly.
+compctl -f -x 'C[-1,-*c]' -c - 'C[-1,[-+]*o]' -o -- bash ksh sh zsh
+#------------------------------------------------------------------------------
+# su takes a username and args for the shell.
+compctl -u -x 'w[1,-]p[3,-1]' -l sh - 'w[1,-]' -u - 'p[2,-1]' -l sh -- su
+#------------------------------------------------------------------------------
+# Run ghostscript on postscript files, but if no postscript file matches what
+# we already typed, complete directories as the postscript file may not be in
+# the current directory.
+compctl -/g '*.(e|E|)(ps|PS)' \
+ gs ghostview nup psps pstops psmulti psnup psselect
+#------------------------------------------------------------------------------
+# Similar things for tex, texinfo and dvi files.
+compctl -/g '*.tex*' {,la,gla,ams{la,},{g,}sli}tex texi2dvi
+compctl -/g '*.dvi' xdvi dvips
+#------------------------------------------------------------------------------
+# For rcs users, co and rlog from the RCS directory. We don't want to see
+# the RCS and ,v though.
+compctl -g 'RCS/*(:s@RCS/@@:s/,v//)' co rlog rcs rcsdiff
+#------------------------------------------------------------------------------
+# gzip uncompressed files, but gzip -d only gzipped or compressed files
+compctl -x 'R[-*[dt],^*]' -/g '*.(gz|z|Z|t[agp]z|tarZ|tz)' + -f - \
+ 's[]' -/g '^*(.(tz|gz|t[agp]z|tarZ|zip|ZIP|jpg|JPG|gif|GIF|[zZ])|[~#])' \
+ + -f -- gzip
+compctl -/g '*.(gz|z|Z|t[agp]z|tarZ|tz)' gunzip gzcat zcat
+compctl -/g '*.Z' uncompress zmore
+compctl -/g '*.F' melt fcat
+#------------------------------------------------------------------------------
+# ftp takes hostnames
+ftphosts=(prep.ai.mit.edu wuarchive.wustl.edu ftp.uu.net ftp.math.gatech.edu)
+compctl -k ftphosts ftp
+
+# Some systems have directories containing indices of ftp servers.
+# For example: we have the directory /home/ftp/index/INDEX containing
+# files of the form `<name>-INDEX.Z', this leads to:
+#compctl -g '/home/ftp/index/INDEX/*-INDEX.Z(:t:r:s/-INDEX//)' ftp tftp
+#------------------------------------------------------------------------------
+# Change default completion (see the multicomp function in the Function
+# subdirectory of the zsh distribution).
+#compctl -D -f + -U -K multicomp
+# If completion of usernames is slow for you, you may want to add something
+# like
+# -x 'C[0,*/*]' -f - 's[~]' -S/ -k users + -u
+# where `users' contains the names of the users you want to complete often.
+# If you want to use this and to be able to complete named directories after
+# the `~' you should add `+ -n' at the end
+#------------------------------------------------------------------------------
+# This is to complete all directories under /home, even those that are not
+# yet mounted (if you use the automounter).
+
+# This is for NIS+ (e.g. Solaris 2.x)
+#compctl -Tx 's[/home/] C[0,^/home/*/*]' -S '/' -s '$(niscat auto_home.org_dir | \
+# awk '\''/export\/[a-zA-Z]*$/ {print $NF}'\'' FS=/)'
+
+# And this is for YP (e.g. SunOS4.x)
+#compctl -Tx 's[/home/] C[0,^/home/*/*]' -S '/' -s '$(ypcat auto.home | \
+# awk '\''/export\/[a-zA-Z]*$/ {print $NF}'\'' FS=/)'
+#------------------------------------------------------------------------------
+# Find is very system dependent, this one is for GNU find.
+# Note that 'r[-exec,;]' must come first
+if [[ -r /proc/filesystems ]]; then
+ # Linux
+ filesystems='"${${(f)$(</proc/filesystems)}#* }"'
+else
+ filesystems='ufs 4.2 4.3 nfs tmp mfs S51K S52K'
+fi
+compctl -x 'r[-exec,;][-ok,;]' -l '' - \
+'s[-]' -s 'daystart {max,min,}depth follow noleaf version xdev
+ {a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links
+ {i,}{l,}name {no,}{user,group} path perm regex size true uid used
+ exec {f,}print{f,0,} ok prune ls' - \
+ 'p[1]' -g '. .. *(-/)' - \
+ 'C[-1,-((a|c|)newer|fprint(|0|f))]' -f - \
+ 'c[-1,-fstype]' -s $filesystems - \
+ 'c[-1,-group]' -k groups - \
+ 'c[-1,-user]' -u -- find
+#------------------------------------------------------------------------------
+# Generic completion for C compiler.
+compctl -/g "*.[cCoa]" -x 's[-I]' -/ - \
+ 's[-l]' -s '${(s.:.)^LD_LIBRARY_PATH}/lib*.a(:t:r:s/lib//)' -- cc
+#------------------------------------------------------------------------------
+# GCC completion, by Andrew Main
+# completes to filenames (*.c, *.C, *.o, etc.); to miscellaneous options after
+# a -; to various -f options after -f (and similarly -W, -g and -m); and to a
+# couple of other things at different points.
+# The -l completion is nicked from the cc compctl above.
+# The -m completion should be tailored to each system; the one below is i386.
+compctl -/g '*.([cCmisSoak]|cc|cxx|ii|k[ih])' -x \
+ 's[-l]' -s '${(s.:.)^LD_LIBRARY_PATH}/lib*.a(:t:r:s/lib//)' - \
+ 'c[-1,-x]' -k '(none c objective-c c-header c++ cpp-output
+ assembler assembler-with-cpp)' - \
+ 'c[-1,-o]' -f - \
+ 'C[-1,-i(nclude|macros)]' -/g '*.h' - \
+ 'C[-1,-i(dirafter|prefix)]' -/ - \
+ 's[-B][-I][-L]' -/ - \
+ 's[-fno-],s[-f]' -k '(all-virtual cond-mismatch dollars-in-identifiers
+ enum-int-equiv external-templates asm builtin strict-prototype
+ signed-bitfields signd-char this-is-variable unsigned-bitfields
+ unsigned-char writable-strings syntax-only pretend-float caller-saves
+ cse-follow-jumps cse-skip-blocks delayed-branch elide-constructors
+ expensive-optimizations fast-math float-store force-addr force-mem
+ inline-functions keep-inline-functions memoize-lookups default-inline
+ defer-pop function-cse inline peephole omit-frame-pointer
+ rerun-cse-after-loop schedule-insns schedule-insns2 strength-reduce
+ thread-jumps unroll-all-loops unroll-loops)' - \
+ 's[-g]' -k '(coff xcoff xcoff+ dwarf dwarf+ stabs stabs+ gdb)' - \
+ 's[-mno-][-mno][-m]' -k '(486 soft-float fp-ret-in-387)' - \
+ 's[-Wno-][-W]' -k '(all aggregate-return cast-align cast-qual
+ char-subscript comment conversion enum-clash error format id-clash-6
+ implicit inline missing-prototypes missing-declarations nested-externs
+ import parentheses pointer-arith redundant-decls return-type shadow
+ strict-prototypes switch template-debugging traditional trigraphs
+ uninitialized unused write-strings)' - \
+ 's[-]' -k '(pipe ansi traditional traditional-cpp trigraphs pedantic
+ pedantic-errors nostartfiles nostdlib static shared symbolic include
+ imacros idirafter iprefix iwithprefix nostdinc nostdinc++ undef)' \
+ -X 'Use "-f", "-g", "-m" or "-W" for more options' -- gcc g++
+#------------------------------------------------------------------------------
+# There are (at least) two ways to complete manual pages. This one is
+# extremely memory expensive if you have lots of man pages
+man_var() {
+ man_pages=( ${^manpath}/man*/*(N:t:r) )
+ compctl -k man_pages -x 'C[-1,-P]' -m - \
+ 'R[-*l*,;]' -/g '*.(man|[0-9](|[a-z]))' -- man
+ reply=( $man_pages )
+}
+compctl -K man_var -x 'C[-1,-P]' -m - \
+ 'R[-*l*,;]' -/g '*.(man|[0-9](|[a-z]))' -- man
+
+# This one isn't that expensive but somewhat slower
+man_glob () {
+ local a
+ read -cA a
+ if [[ $a[2] = -s ]] then # Or [[ $a[2] = [0-9]* ]] for BSD
+ reply=( ${^manpath}/man$a[3]/$1*$2(N:t:r) )
+ else
+ reply=( ${^manpath}/man*/$1*$2(N:t:r) )
+ fi
+}
+#compctl -K man_glob -x 'C[-1,-P]' -m - \
+# 'R[-*l*,;]' -/g '*.(man|[0-9nlpo](|[a-z]))' -- man
+#------------------------------------------------------------------------------
+# xsetroot: gets possible colours, cursors and bitmaps from wherever.
+# Uses two auxiliary functions. You might need to change the path names.
+Xcolours() {
+ reply=( ${(L)$(awk '{ if (NF = 4) print $4 }' \
+ < /usr/openwin/lib/X11/rgb.txt)} )
+}
+Xcursor() {
+ reply=( $(sed -n 's/^#define[ ][ ]*XC_\([^ ]*\)[ ].*$/\1/p' \
+ < /usr/include/X11/cursorfont.h) )
+}
+compctl -k '(-help -def -display -cursor -cursor_name -bitmap -mod -fg -bg
+ -grey -rv -solid -name)' -x \
+ 'c[-1,-display]' -s '$DISPLAY' -k hosts -S ':0' - \
+ 'c[-1,-cursor]' -f - 'c[-2,-cursor]' -f - \
+ 'c[-1,-bitmap]' -g '/usr/include/X11/bitmaps/*' - \
+ 'c[-1,-cursor_name]' -K Xcursor - \
+ 'C[-1,-(solid|fg|bg)]' -K Xcolours -- xsetroot
+#------------------------------------------------------------------------------
+# dd
+compctl -k '(if of conv ibs obs bs cbs files skip file seek count)' \
+ -S '=' -x 's[if=], s[of=]' -f - 'C[0,conv=*,*] n[-1,,], s[conv=]' \
+ -k '(ascii ebcdic ibm block unblock lcase ucase swap noerror sync)' \
+ -q -S ',' - 'n[-1,=]' -X '<number>' -- dd
+#------------------------------------------------------------------------------
+# Various MH completions by Peter Stephenson
+# You may need to edit where it says *Edit Me*.
+
+# The following three functions are best autoloaded.
+# mhcomp completes folders (including subfolders),
+# mhfseq completes sequence names and message numbers,
+# mhfile completes files in standard MH locations.
+
+function mhcomp {
+ # Completion function for MH folders.
+ # Works with both + (rel. to top) and @ (rel. to current).
+ local nword args pref char mhpath
+ read -nc nword
+ read -cA args
+
+ pref=$args[$nword]
+ char=$pref[1]
+ pref=$pref[2,-1]
+
+ # The $(...) here accounts for most of the time spent in this function.
+ if [[ $char = + ]]; then
+ # mhpath=$(mhpath +)
+ # *Edit Me*: use a hard wired value here: it's faster.
+ mhpath=~/Mail
+ elif [[ $char = @ ]]; then
+ mhpath=$(mhpath)
+ fi
+
+ eval "reply=($mhpath/$pref*(N-/))"
+
+ # I'm frankly amazed that this next step works, but it does.
+ reply=(${reply#$mhpath/})
+}
+
+mhfseq() {
+ # Extract MH message names and numbers for completion. Use of the
+ # correct folder, if it is not the current one, requires that it
+ # should be the previous command line argument. If the previous
+ # argument is `-draftmessage', a hard wired draft folder name is used.
+
+ local folder foldpath words pos nums
+ read -cA words
+ read -cn pos
+
+ # Look for a folder name.
+ # First try the previous word.
+ if [[ $words[$pos-1] = [@+]* ]]; then
+ folder=$words[$pos-1]
+ # Next look and see if we're looking for a draftmessage
+ elif [[ $words[$pos-1] = -draftmessage ]]; then
+ # *Edit Me*: shortcut -- hard-wire draftfolder here
+ # Should really look for a +draftfolder argument.
+ folder=+drafts
+ fi
+ # Else use the current folder ($folder empty)
+
+ if [[ $folder = +* ]]; then
+ # *Edit Me*: use hard-wired path with + for speed.
+ foldpath=~/Mail/$folder[2,-1]
+ else
+ foldpath=$(mhpath $folder)
+ fi
+
+ # Extract all existing message numbers from the folder.
+ nums=($foldpath/<->(N:t))
+ # If that worked, look for marked sequences.
+ # *Edit Me*: if you never use non-standard sequences, comment out
+ # or delete the next three lines.
+ if (( $#nums )); then
+ nums=($nums $(mark $folder | awk -F: '{print $1}'))
+ fi
+
+ # *Edit Me*: `unseen' is the value of Unseen-Sequence, if it exists;
+ set -A reply next cur prev first last all unseen $nums
+
+}
+
+mhfile () {
+ # Find an MH file; for use with -form arguments and the like.
+ # Use with compctl -K mhfile.
+
+ local mhfpath file
+ # *Edit Me*: Array containing all the places MH will look for templates etc.
+ mhfpath=(~/Mail /usr/local/lib/MH)
+
+ # Emulate completeinword behaviour as appropriate
+ local wordstr
+ if [[ -o completeinword ]]; then
+ wordstr='$1*$2'
+ else
+ wordstr='$1$2*'
+ fi
+
+ if [[ $1$2 = */* ]]; then
+ # path given: don't search MH locations
+ eval "reply=($wordstr(.N))"
+ else
+ # no path: only search MH locations.
+ eval "reply=(\$mhfpath/$wordstr(.N:t))"
+ fi
+}
+
+# Note: you must type the initial + or @ of a folder name to get
+# completion, even in places where only folder names are allowed.
+# Abbreviations for options are not recognised. Hit tab to complete
+# the option name first.
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \
+ 's[-]' -k "(all fast nofast header noheader help list nolist \
+ pack nopack pop push recurse norecurse total nototal)" -- folder
+compctl -K mhfseq -x 's[+][@],c[-1,-draftfolder] s[+][@]' \
+ -K mhcomp -S / -q - 'c[-1,-draftmessage]' -K mhfseq - \
+ 'C[-1,-(editor|whatnowproc)]' -c - \
+ 's[-]' -k "(draftfolder draftmessage nodraftfolder editor noedit \
+ file form use nouse whatnowproc nowhatnowproc help)" - \
+ 'c[-1,-form]' -K mhfile -- comp
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \
+ 's[-]' -k "(audit noaudit changecur nochangecur form format \
+ file silent nosilent truncate notruncate width help)" - \
+ 'C[-1,-(audit|form)]' -K mhfile - 'c[-1,-file]' -f + -- inc
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \
+ 's[-]' -k "(sequence add delete list public nopublic zero nozero help)" -- \
+ mark
+compctl -K mhfseq -x 's[+][@]' \
+ -K mhcomp -S / -q - 'c[-1,-file]' -f - 'c[-1,-rmmprov]' -c - \
+ 's[-]' -k "(draft link nolink preserve nopreserve src file \
+ rmmproc normmproc help)" -- refile
+compctl -K mhfseq -x 's[+][@]' \
+ -K mhcomp -S / -q - 'c[-1,-draftmessage]' -K mhfseq -\
+ 's[-]' -k "(annotate noannotate cc nocc draftfolder nodraftfolder \
+ draftmessage editor noedit fcc filter form inplace noinplace query \
+ noquery width whatnowproc nowhatnowproc help)" - 'c[-1,(cc|nocc)]' \
+ -k "(all to cc me)" - 'C[-1,-(filter|form)]' -K mhfile - \
+ 'C[-1,-(editor|whatnowproc)]' -c -- repl
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \
+ 's[-]' -k "(clear noclear form format header noheader reverse noreverse \
+ file help width)" - 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile -- scan
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \
+ 's[-]' -k "(draft form moreproc nomoreproc header noheader \
+ showproc noshowproc length width help)" - 'C[-1,-(show|more)proc]' -c - \
+ 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile - \
+ 'c[-1,-length]' -s '$LINES' - 'c[-1,-width]' -s '$COLUMNS' -- show next prev
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \
+ -k "(help)" -- rmm
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \
+ 's[-]' -k "(after before cc date datefield from help list nolist \
+ public nopublic search sequence subject to zero nozero not or and \
+ lbrace rbrace)" -- pick
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \
+ -k "(alias check draft draftfolder draftmessage help nocheck \
+ nodraftfolder)" -- whom
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \
+ -k "(file part type list headers noheaders realsize norealsize nolist \
+ show serialonly noserialonly form pause nopause noshow store auto noauto \
+ nostore cache nocache rcache wcache check nocheck ebcdicsafe noebcdicsafe \
+ rfc934mode norfc934mode verbose noverbose help)" - \
+ 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile - \
+ 'C[-1,-[rw]cache]' -k '(public private never ask)' -- mhn
+compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' -k '(help)' -- mhpath
+#------------------------------------------------------------------------------
+# CVS
+#
+cvscmds=(add admin rcs checkout commit diff rdiff export history import log rlog
+ release remove status tag rtag update annotate)
+cvsignore="*~ *# .#* *.o *.a CVS . .."
+
+compctl -k cvscmds \
+ -x "c[-1,-D]" -k '(today yesterday 1\ week\ ago)' \
+ - "c[-1,-m]" -k '(bugfix cosmetic\ fix ... added\ functionality foo)' \
+ - "c[-1,-F]" -f \
+ - "c[-1,-r]" -K cvsrevisions \
+ - "c[-1,-I]" -f \
+ - "R[add,;]" -K cvsaddp \
+ - "R[(admin|rcs),;]" -/K cvstargets \
+ - "R[(checkout|co),;]" -K cvsrepositories \
+ - "R[(commit|ci),;]" -/K cvstargets \
+ - "R[(r|)diff,;]" -/K cvstargets \
+ - "R[export,;]" -f \
+ - "R[history,;]" -/K cvstargets \
+ - "R[history,;] c[-1,-u]" -u \
+ - "R[import,;]" -K cvsrepositories \
+ - "R[(r|)log,;]" -/K cvstargets \
+ - 'R[(r|)log,;] s[-w] n[-1,,],s[-w]' -u -S , -q \
+ - "R[rel(|ease),;]" -f \
+ - "R[(remove|rm),;] R[-f,;]" -/K cvstargets \
+ - "R[(remove|rm),;]" -K cvsremovep \
+ - "R[status,;]" -/K cvstargets \
+ - "R[(r|)tag,;]" -/K cvstargets \
+ - "R[up(|date),;]" -/K cvstargets \
+ - "R[annotate,;]" -/K cvstargets \
+ -- cvs
+
+compctl -/K cvstargets cvstest
+
+cvsprefix() {
+ local nword args f
+ read -nc nword; read -Ac args
+ pref=$args[$nword]
+ if [[ -d $pref:h && ! -d $pref ]]; then
+ pref=$pref:h
+ elif [[ $pref != */* ]]; then
+ pref=
+ fi
+ [[ -n "$pref" && "$pref" != */ ]] && pref=$pref/
+}
+
+cvsentries() {
+ setopt localoptions nullglob unset
+ if [[ -f ${pref}CVS/Entries ]]; then
+ reply=( "${pref}${^${${${(f@)$(<${pref}CVS/Entries)}:#D*}#/}%%/*}" )
+ fi
+}
+
+cvstargets() {
+ local pref
+ cvsprefix
+ cvsentries
+}
+
+cvsrevisions() {
+ reply=( "${${${(M)${(f)$(cvs -q status -vl .)}:# *}##[ ]##}%%[ ]*}" )
+}
+
+cvsrepositories() {
+ local root=$CVSROOT
+ [[ -f CVS/Root ]] && root=$(<CVS/Root)
+ reply=(
+ $root/^CVSROOT(:t)
+ "${${(M)${(f)$(<$root/CVSROOT/modules)}:#[^#]*}%%[ ]*}"
+ )
+}
+
+cvsremovep() {
+ local pref
+ cvsprefix
+ cvsentries
+ setopt localoptions unset
+ local omit
+ omit=( ${pref}*(D) )
+ eval 'reply=( ${reply:#('${(j:|:)omit}')} )'
+}
+
+cvsaddp() {
+ local pref
+ cvsprefix
+ cvsentries
+ setopt localoptions unset
+ local all omit
+ all=( ${pref}*(D) )
+ omit=( $reply ${pref}${^${=cvsignore}} )
+ [[ -r ~/.cvsignore ]] && omit=( $omit ${pref}${^$(<~/.cvsignore)} )
+ [[ -r ${pref}.cvsignore ]] && omit=( $omit ${pref}${^$(<${pref}.cvsignore)} )
+ eval 'reply=( ${all:#('${(j:|:)omit}')} )'
+}
+
+#------------------------------------------------------------------------------
+# RedHat Linux rpm utility
+#
+compctl -s '$(rpm -qa)' \
+ -x 's[--]' -s 'oldpackage percent replacefiles replacepkgs noscripts
+ root excludedocs includedocs test upgrade test clean
+ short-circuit sign recompile rebuild resign querytags
+ queryformat version help quiet rcfile force hash' - \
+ 's[ftp:]' -P '//' -s '$(</u/zsh/ftphosts)' -S '/' - \
+ 'c[-1,--root]' -/ - \
+ 'c[-1,--rcfile]' -f - \
+ 'p[1] s[-b]' -k '(p l c i b a)' - \
+ 'c[-1,--queryformat] N[-1,{]' \
+ -s '"${${(f)$(rpm --querytags)}#RPMTAG_}"' -S '}' - \
+ 'W[1,-q*] C[-1,-([^-]*|)f*]' -f - \
+ 'W[1,-i*], W[1,-q*] C[-1,-([^-]*|)p*]' \
+ -/g '*.rpm' + -f -- rpm
+#------------------------------------------------------------------------------
+compctl -u -x 'c[-1,-w]' -f -- ac
+compctl -/g '*.m(.)' mira
+#------------------------------------------------------------------------------
+# talk completion: complete local users, or users at hosts listed via rwho
+compctl -K talkmatch talk ytalk ytalk3
+function talkmatch {
+ local u
+ reply=($(users))
+ for u in "${${(f)$(rwho 2>/dev/null)}%%:*}"; do
+ reply=($reply ${u%% *}@${u##* })
+ done
+}
+#------------------------------------------------------------------------------
+# Linux mount
+comp_fsmount () {
+ local tmp; if [[ $UID = 0 ]]; then tmp=""; else tmp="user"; fi
+ sed -n -e "s|^[^# ][^ ]*[ ][ ]*\(/[^ ]*\)[ ].*$tmp.*|\1|p" /etc/fstab
+}
+comp_nfsmount () {
+ local cmd args host
+ read -Ac cmd; read -cn where
+ host=${${cmd[$where]}%%:*}
+ reply=("${(@f)$(showmount -e $host | sed -n -e "s|^/\([^ ]*\) .*|$host:/\1|p")}")
+}
+compctl -s '$(mount | \
+ sed -e "s/^[^ ]* on \\([^ ]*\\) type.*/\\1/"'"$(
+ if [[ ! $UID = 0 ]]; then
+ echo ' | egrep "^${(j:|:)$(comp_fsmount)}\$"'
+ fi)"')' umount
+compctl -s '$(comp_fsmount)' + \
+ -x 'S[/]' -f -- + \
+ -x 'C[0,*:*]' -K comp_nfsmount -- + \
+ -s '$(< /etc/hosts)' \
+ mount
+#------------------------------------------------------------------------------
+# Lynx (web browser)
+compctl -k '(http:// file: ftp:// gopher:// news://)' -S '' \
+ -x 's[ftp://]' -k ftphosts -S/ \
+ - 'n[1,://]' -k hosts -S/ \
+ - 's[file:/]' -/g '*.html' -W/ \
+ - 's[file:]' -s '~+' -S '/' \
+ - 's[-]' -k '(anonymous auth base book buried_news cache case
+ cfg child cookies crawl display dump editor emacskeys
+ enable_scrollback error_file fileversions force_html
+ from ftp get_data head help historical homepage
+ image_links index link localhost locexec mime_header
+ minimal newschunksize newsmaxchunk nobrowse noexec
+ nofilereferer nofilereferer nolist nolog nopause
+ noprint noredir noreferer nosocks nostatus number_links
+ popup post_data print pseudo_inlines raw realm reload
+ restrictions resubmit_posts rlogin selective show_cursor
+ source startfile_ok telnet term trace traversal underscore
+ validate version vikeys)' \
+ -- lynx
+#------------------------------------------------------------------------------
+# ssh (secure shell)
+compctl -k hosts \
+ -x "c[-1,-l]" -u \
+ - "c[-1,-i]" -f \
+ - "c[-1,-e]" -k "(~ none)" \
+ - "c[-1,-c]" -k "(idea des 3des tss arcfour none)" \
+ - "c[-1,-p]" -k ports \
+ - "c[-1,-L] c[-1,-R] c[-1,-o]" -k "()" \
+ -- ssh
+#------------------------------------------------------------------------------
+# network stuff
+compctl -k hosts \
+ -x "s[-class=]" -k "(any in chaos hesiod)" \
+ - "s[-query=]" -k "(a cname hinfo md mx mb mg minfo ns ptr soa txt uinfo wks any)" \
+ - "s[-]" -Q -S '' -k "(query= all\ class= d2\ nod2\ debug\ nodebug\ defname\ nodefname\ domain= ignoretc\ noignoretc\ )" \
+ -- nslookup
+
+compctl -k hosts \
+ -x "C[-1,[^-]*] p[2,-1]" -k ports \
+ -- telnet
+
+compctl -x 'N[-1,@]' -k hosts - 's[]' -u -qS '@' -- finger
+#------------------------------------------------------------------------------
+# gdb
+compctl -/g "*(*)" \
+ -x "s[-]" -k "(help nx q batch cd f b tty exec se core symbols c x d)" \
+ - "C[-1,(-cd|-directory)]" -/ \
+ - "C[-1,(-core|-c)]" -/g 'core*' \
+ - "C[-1,(-se|-exec)]" -f \
+ - "C[-1,(-symbols|-command|-x)]" -f \
+ - "p[2,-1] C[-1,[^-]*]" -/g "core*" \
+ -- gdb
diff --git a/Misc/globtests b/Misc/globtests
new file mode 100755
index 000000000..728aee5ae
--- /dev/null
+++ b/Misc/globtests
@@ -0,0 +1,107 @@
+#!/usr/local/bin/zsh -f
+
+setopt extendedglob badpattern
+unsetopt kshglob
+
+failed=0
+while read res str pat; do
+ [[ $res = '#' ]] && continue
+ [[ $str = ${~pat} ]]
+ ts=$?
+ [[ $1 = -q ]] || print "$ts: [[ $str = $pat ]]"
+ if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then
+ print "Test failed: [[ $str = $pat ]]"
+ (( failed++ ))
+ fi
+done <<EOT
+t fofo (fo#)#
+t ffo (fo#)#
+t foooofo (fo#)#
+t foooofof (fo#)#
+t fooofoofofooo (fo#)#
+f foooofof (fo##)#
+f xfoooofof (fo#)#
+f foooofofx (fo#)#
+t ofxoofxo ((ofo#x)#o)#
+f ofooofoofofooo (fo#)#
+t foooxfooxfoxfooox (fo#x)#
+f foooxfooxofoxfooox (fo#x)#
+t foooxfooxfxfooox (fo#x)#
+t ofxoofxo ((ofo#x)#o)#
+t ofoooxoofxo ((ofo#x)#o)#
+t ofoooxoofxoofoooxoofxo ((ofo#x)#o)#
+t ofoooxoofxoofoooxoofxoo ((ofo#x)#o)#
+f ofoooxoofxoofoooxoofxofo ((ofo#x)#o)#
+t ofoooxoofxoofoooxoofxooofxofxo ((ofo#x)#o)#
+t aac ((a))#a(c)
+t ac ((a))#a(c)
+f c ((a))#a(c)
+t aaac ((a))#a(c)
+f baaac ((a))#a(c)
+t abcd ?(a|b)c#d
+t abcd (ab|ab#)c#d
+t acd (ab|ab#)c#d
+t abbcd (ab|ab#)c#d
+t effgz (bc##d|ef#g?|(h|)i(j|k))
+t efgz (bc##d|ef#g?|(h|)i(j|k))
+t egz (bc##d|ef#g?|(h|)i(j|k))
+t egzefffgzbcdij (bc##d|ef#g?|(h|)i(j|k))#
+f egz (bc##d|ef##g?|(h|)i(j|k))
+t ofoofo (ofo##)#
+t oxfoxoxfox (oxf(ox)##)#
+f oxfoxfox (oxf(ox)##)#
+t ofoofo (ofo##|f)#
+# The following is supposed to match only as fo+ofo+ofo
+t foofoofo (foo|f|fo)(f|ofo##)#
+t oofooofo (of|oofo##)#
+t fffooofoooooffoofffooofff (f#o#)#
+# If the following is really slow, that's a bug.
+f fffooofoooooffoofffooofffx (f#o#)#
+# The following tests backtracking in alternation matches
+t fofoofoofofoo (fo|foo)#
+# Exclusion: test both types
+t foo ((^x))
+t foo ((^x)*)
+f foo ((^foo))
+t foo ((^foo)*)
+t foobar ((^foo))
+t foobar ((^foo)*)
+f foot z*~*x
+t zoot z*~*x
+f foox z*~*x
+f zoox z*~*x
+t moo.cow (*~*.*).(*~*.*)
+f mad.moo.cow (*~*.*).(*~*.*)
+t moo.cow (^*.*).(^*.*)
+f sane.moo.cow (^*.*).(^*.*)
+f mucca.pazza mu(^c#)?.pa(^z#)?
+t fff ((^f))
+t fff ((^f)#)
+t fff ((^f)##)
+t ooo ((^f))
+t ooo ((^f)#)
+t ooo ((^f)##)
+t foo ((^f))
+t foo ((^f)#)
+t foo ((^f)##)
+f f ((^f))
+f f ((^f)#)
+f f ((^f)##)
+t foot (^z*|*x)
+f zoot (^z*|*x)
+t foox (^z*|*x)
+t zoox (^z*|*x)
+t foo (^foo)#
+f foob (^foo)b*
+t foobb (^foo)b*
+f zsh ^z*
+t a%1X [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]]
+f a%1 [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]]
+t [: [[:]#
+t :] []:]#
+t :] [:]]#
+t [ [[]
+t ] []]
+t [] [^]]]
+EOT
+print "$failed tests failed."
diff --git a/Misc/globtests.ksh b/Misc/globtests.ksh
new file mode 100755
index 000000000..b03cc488e
--- /dev/null
+++ b/Misc/globtests.ksh
@@ -0,0 +1,91 @@
+#!/usr/local/bin/zsh -f
+
+setopt kshglob
+
+failed=0
+while read res str pat; do
+ [[ $res = '#' ]] && continue
+ [[ $str = ${~pat} ]]
+ ts=$?
+ [[ $1 = -q ]] || print "$ts: [[ $str = $pat ]]"
+ if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then
+ print "Test failed: [[ $str = $pat ]]"
+ (( failed++ ))
+ fi
+done <<EOT
+t fofo *(f*(o))
+t ffo *(f*(o))
+t foooofo *(f*(o))
+t foooofof *(f*(o))
+t fooofoofofooo *(f*(o))
+f foooofof *(f+(o))
+f xfoooofof *(f*(o))
+f foooofofx *(f*(o))
+t ofxoofxo *(*(of*(o)x)o)
+f ofooofoofofooo *(f*(o))
+t foooxfooxfoxfooox *(f*(o)x)
+f foooxfooxofoxfooox *(f*(o)x)
+t foooxfooxfxfooox *(f*(o)x)
+t ofxoofxo *(*(of*(o)x)o)
+t ofoooxoofxo *(*(of*(o)x)o)
+t ofoooxoofxoofoooxoofxo *(*(of*(o)x)o)
+t ofoooxoofxoofoooxoofxoo *(*(of*(o)x)o)
+f ofoooxoofxoofoooxoofxofo *(*(of*(o)x)o)
+t ofoooxoofxoofoooxoofxooofxofxo *(*(of*(o)x)o)
+t aac *(@(a))a@(c)
+t ac *(@(a))a@(c)
+f c *(@(a))a@(c)
+t aaac *(@(a))a@(c)
+f baaac *(@(a))a@(c)
+t abcd ?@(a|b)*@(c)d
+t abcd @(ab|a*@(b))*(c)d
+t acd @(ab|a*(b))*(c)d
+t abbcd @(ab|a*(b))*(c)d
+t effgz @(b+(c)d|e*(f)g?|?(h)i@(j|k))
+t efgz @(b+(c)d|e*(f)g?|?(h)i@(j|k))
+t egz @(b+(c)d|e*(f)g?|?(h)i@(j|k))
+t egzefffgzbcdij *(b+(c)d|e*(f)g?|?(h)i@(j|k))
+f egz @(b+(c)d|e+(f)g?|?(h)i@(j|k))
+t ofoofo *(of+(o))
+t oxfoxoxfox *(oxf+(ox))
+f oxfoxfox *(oxf+(ox))
+t ofoofo *(of+(o)|f)
+# The following is supposed to match only as fo+ofo+ofo
+t foofoofo @(foo|f|fo)*(f|of+(o))
+t oofooofo *(of|oof+(o))
+t fffooofoooooffoofffooofff *(*(f)*(o))
+# If the following is really slow, that's a bug.
+f fffooofoooooffoofffooofffx *(*(f)*(o))
+# The following tests backtracking in alternation matches
+t fofoofoofofoo *(fo|foo)
+# Exclusion
+t foo !(x)
+t foo !(x)*
+f foo !(foo)
+t foo !(foo)*
+t foobar !(foo)
+t foobar !(foo)*
+t moo.cow !(*.*).!(*.*)
+f mad.moo.cow !(*.*).!(*.*)
+f mucca.pazza mu!(*(c))?.pa!(*(z))?
+t fff !(f)
+t fff *(!(f))
+t fff +(!(f))
+t ooo !(f)
+t ooo *(!(f))
+t ooo +(!(f))
+t foo !(f)
+t foo *(!(f))
+t foo +(!(f))
+f f !(f)
+f f *(!(f))
+f f +(!(f))
+t foot @(!(z*)|*x)
+f zoot @(!(z*)|*x)
+t foox @(!(z*)|*x)
+t zoox @(!(z*)|*x)
+t foo *(!(foo))
+f foob !(foo)b*
+t foobb !(foo)b*
+EOT
+print "$failed tests failed."
diff --git a/Misc/lete2ctl b/Misc/lete2ctl
new file mode 100755
index 000000000..ca00b8aee
--- /dev/null
+++ b/Misc/lete2ctl
@@ -0,0 +1,301 @@
+#!/usr/local/bin/perl -w
+#
+# ``Wee have also Shelles, thee Lyke of whych you knowe not, wherein
+# thee User may with thee merest Presse of thee Tabbe-Keye expande
+# or compleat al Maner of Wordes and such-like Diversities.''
+# - Francis Bacon, `New Atlantis' (or not).
+#
+# Convert tcsh "complete" statements to zsh "compctl" statements.
+# Runs as a filter. Should ignore anything which isn't a "complete".
+# It expects each "complete" statement to be the first thing on a line.
+# All the examples in the tcsh manual give sensible results.
+#
+# Option:
+# -x (exact): only applies in the case of command disambiguation (is
+# that really a word?) If you have lines like
+# complete '-co*' 'p/0/(compress)'
+# (which makes co<TAB> always complete to `compress') then the
+# resulting "compctl" statements will produce one of two behaviours:
+# (1) By default (like tcsh), com<TAB> etc. will also complete to
+# "compress" and nothing else.
+# (2) With -x, com<TAB> does ordinary command completion: this is
+# more flexible.
+# I don't understand what the hyphen in complete does and I've ignored it.
+#
+# Notes:
+# (1) The -s option is the way to do backquote expansion. In zsh,
+# "compctl -s '`users`' talk" works (duplicates are removed).
+# (2) Complicated backquote completions should definitely be rewritten as
+# shell functions (compctl's "-K func" option). Although most of
+# these will be translated correctly, differences in shell syntax
+# are not handled.
+# (3) Replacement of $:n with the n'th word on the current line with
+# backquote expansion now works; it is not necessarily the most
+# efficient way of doing it in any given case, however.
+# (4) I have made use of zsh's more sophisticated globbing to change
+# things like ^foo.{a,b,c,d} to ^foo.(a|b|c|d), which works better.
+# It's just possible in some cases you may want to change it back.
+# (5) Make sure all command names with wildcards are processed together --
+# they need to be lumped into one "compctl -C" or "compctl -D"
+# statement for zsh.
+
+# Handle options
+if (@ARGV) {
+ ($ARGV[0] eq '-x') && shift && ($opt_x = 1);
+ ($ARGV[0] =~ /^-+$/) && shift;
+}
+
+# Function names used (via magic autoincrement) when cmdline words are needed
+$funcnam = 'compfn001';
+
+# Read next word on command line
+sub getword {
+ local($word, $word2, $ret);
+ ($_) = /^\s*(.*)$/;
+ while ($_ =~ /^\S/) {
+ if (/^[\']/) {
+ ($word, $_) = /^\'([^\']*).(.*)$/;
+ } elsif (/^[\"]/) {
+ ($word, $_) = /^\"([^\"]*).(.*)$/;
+ while ($word =~ /\\$/) {
+ chop($word);
+ ($word2, $_) = /^([^\"]*).(.*)$/;
+ $word .= '"' . $word2;
+ }
+ } elsif (/\S/) {
+ ($word, $_) = /^([^\s\\\'\"\#;]*)(.*)$/;
+ # Backslash: literal next character
+ /^\\(.)/ && (($word .= substr($_,1,1)),
+ ($_ = substr($_,2)));
+ # Rest of line quoted or end of command
+ /^[\#;]/ && ($_ = '');
+ } else {
+ return undef;
+ }
+ length($word) && ($ret = defined($ret) ? $ret . $word : $word);
+ }
+ $ret;
+}
+
+# Interpret the x and arg in 'x/arg/type/'
+sub getpat {
+ local($pat,$arg) = @_;
+ local($ret,$i);
+ if ($pat eq 'p') {
+ $ret = "p[$arg]";
+ } elsif ($pat eq 'n' || $pat eq 'N') {
+ $let = ($arg =~ /[*?|]/) ? 'C' : 'c';
+ $num = ($pat eq 'N') ? 2 : 1;
+ $ret = "${let}[-${num},$arg]";
+ } elsif ($pat eq 'c' || $pat eq 'C') {
+ # A few tricks to get zsh to ignore up to the end of
+ # any matched pattern.
+ if (($pat eq 'c' && $arg =~ /^\*([^*?]*)$/)) {
+ $ret = "n[-1,$1]";
+ } elsif ($arg =~ /[*?]([^*?]*)$/) {
+ length($1) && ($ret = " n[-1,$1]");
+ $ret = "C[0,$arg] $ret";
+ } else {
+ $let = ($pat eq 'c') ? 's' : 'S';
+ $ret = "${let}[$arg]";
+ }
+ }
+ $ret =~ s/'/'\\''/g;
+ $ret;
+}
+
+# Interpret the type in 'x/arg/type/'
+sub gettype {
+ local ($_) = @_;
+ local($qual,$c,$glob,$ret,$b,$m,$e,@m);
+ $c = substr($_,0,1);
+ ($c =~ /\w/) && (substr($_,1,1) eq ':') && ($glob = substr($_,2));
+# Nothing (n) can be handled by returning nothing. (C.f. King Lear, I.i.)
+ if ($c =~ /[abcjuv]/) {
+ $ret = "-$c";
+ } elsif ($c eq 'S') {
+ $ret = '-k signals';
+ } elsif ($c eq 'd') {
+ if (defined($glob)) {
+ $qual = '-/';
+ } else {
+ $ret = '-/';
+ }
+ } elsif ($c eq 'e') {
+ $ret = '-E';
+ } elsif ($c eq 'f' && !$glob) {
+ $ret = '-f';
+ } elsif ($c eq 'l') {
+ $ret = q!-k "(`limit | awk '{print $1}'`)"!;
+ } elsif ($c eq 'p') {
+ $ret = "-W $glob -f", undef($glob) if defined($glob);
+ } elsif ($c eq 's') {
+ $ret = '-p';
+ } elsif ($c eq 't') {
+ $qual = '.';
+ } elsif ($c eq 'x') {
+ $glob =~ s/'/'\\''/g;
+ $ret = "-X '$glob'";
+ undef($glob);
+ } elsif ($c eq '$') { # '){
+ $ret = "-k " . substr($_,1);
+ } elsif ($c eq '(') {
+ s/'/'\\''/g;
+ $ret = "-k '$_'";
+ } elsif ($c eq '`') {
+ # this took some working out...
+ if (s/\$:(\d+)/$foo=$1+1,"\${word[$foo]}"/ge) {
+ $ret = "-K $funcnam";
+ $genfunc .= <<"HERE";
+function $funcnam {
+ local word
+ read -cA word
+ reply=($_)
+}
+HERE
+ $funcnam++;
+ } else {
+ s/'/'\\''/g;
+ $ret = "-s '$_'";
+ }
+ }
+
+ # foo{bar,ba,blak,sheap} -> foo(bar|ba|blak|sheap).
+ # This saves a lot of mess, since in zsh brace expansion occurs
+ # before globbing. I'm sorry, but I don't trust $` and $'.
+ while (defined($glob) && (($b,$m,$e) = ($glob =~ /^(.*)\{(.*)\}(.*)$/))
+ && $m =~ /,/) {
+ @m = split(/,/, $m);
+ for ($i = 0; $i < @m; $i++) {
+ while ($m[$i] =~ /\\$/) {
+ substr($m[$i],-1,1) = "";
+ splice(@m,$i,2,"$m[$i]\\,$m[$i+1]");
+ }
+ }
+ $glob = $b . "(" . join('|',@m) . ")" . $e;
+ }
+
+ if ($qual) {
+ $glob || ($glob = '*');
+ $glob .= "($qual)";
+ }
+ $glob && (($glob =~ s/'/'\\''/g),($glob = "-g '$glob'"));
+
+ defined($ret) && defined($glob) && ($ret .= " $glob");
+ defined($ret) ? $ret : $glob;
+}
+
+# Quoted array separator for extended completions
+$" = " - ";
+
+while (<>) {
+ if (/^\s*complete\s/) {
+ undef(@stuff);
+ $default = '';
+ $_ = $';
+ while (/\\$/) {
+ # Remove backslashed newlines: in principle these should become
+ # real newlines inside quotes, but what the hell.
+ ($_) = /^(.*)\\$/;
+ $_ .= <>;
+ }
+ $command = &getword;
+ if ($command =~ /^-/ || $command =~ /[*?]/) {
+ # E.g. complete -co* ...
+ $defmatch = $command;
+ ($defmatch =~ /^-/) && ($defmatch = substr($defmatch,1));
+ } else {
+ undef($defmatch);
+ }
+ while (defined($word = &getword)) {
+ # Loop over remaining arguments to "complete".
+ $sep = substr($word,1,1);
+ $sep =~ s/(\W)/\\$1/g;
+ @split = split(/$sep/,$word);
+ for ($i = 0; $i < 3; $i++) {
+ while ($split[$i] =~ /\\$/) {
+ substr($split[$i],-1,1) = "";
+ splice(@split,$i,2,"$split[$i]\\$sep$split[$i+1]");
+ }
+ }
+ ($pat,$arg,$type,$suffix) = @split;
+ defined($suffix) && ($suffix =~ /^\s*$/) && undef($suffix);
+ if (($word =~ /^n$sep\*$sep/) &&
+ (!defined($defmatch))) {
+ # The "complete" catch-all: treat this as compctl\'s
+ # default (requiring no pattern matching).
+ $default .= &gettype($type) . ' ';
+ defined($suffix) && ($defsuf .= $suffix);
+ } else {
+ $pat = &getpat($pat,$arg);
+ $type = &gettype($type);
+ if (defined($defmatch)) {
+ # The command is a pattern: use either -C or -D option.
+ if ($pat eq 'p[0]') {
+ # Command word (-C): 'p[0]' is redundant.
+ if ($defmatch eq '*') {
+ $defcommand = $type;
+ } else {
+ ($defmatch =~ /\*$/) && chop($defmatch);
+ if ($opt_x) {
+ $c = ($defmatch =~ /[*?]/) ? 'C' : 'c';
+ $pat = $c . "[0,${defmatch}]";
+ } else {
+ $pat = ($defmatch =~ /[*?]/) ?
+ "C[0,${defmatch}]" : "S[${defmatch}]";
+ }
+ push(@commandword,defined($suffix) ?
+ "'$pat' $type -S '$suffix'" : "'$pat' $type");
+ }
+ } elsif ($pat eq "C[-1,*]") {
+ # Not command word completion, but match
+ # command word (only)
+ if ($defmatch eq "*") {
+ # any word of any command
+ $defaultdefault .= " $type";
+ } else {
+ $pat = "W[0,$defmatch]";
+ push(@defaultword,defined($suffix) ?
+ "'$pat' $type -S '$suffix'" : "'$pat' $type");
+ }
+ } else {
+ # Not command word completion, but still command
+ # word with pattern
+ ($defmatch eq '*') || ($pat = "W[0,$defmatch] $pat");
+ push(@defaultword,defined($suffix) ?
+ "'$pat' $type -S '$suffix'" : "'$pat' $type");
+ }
+ } else {
+ # Ordinary command
+ push(@stuff,defined($suffix) ?
+ "'$pat' $type -S '$suffix'" : "'$pat' $type");
+ }
+ }
+ }
+ if (!defined($defmatch)) {
+ # Ordinary commands with no pattern
+ print("compctl $default");
+ defined($defsuf) && print("-S '$defsuf' ") && undef($defsuf);
+ defined(@stuff) && print("-x @stuff -- ");
+ print("$command\n");
+ }
+ if (defined($genfunc)) {
+ print $genfunc;
+ undef($genfunc);
+ }
+ }
+}
+
+(defined(@commandword) || defined($defcommand)) &&
+ print("compctl -C ",
+ defined($defcommand) ? $defcommand : '-c',
+ defined(@commandword) ? " -x @commandword\n" : "\n");
+
+if (defined($defaultdefault) || defined(@defaultword)) {
+ defined($defaultdefault) || ($defaultdefault = "-f");
+ print "compctl -D $defaultdefault";
+ defined(@defaultword) && print(" -x @defaultword");
+ print "\n";
+}
+
+__END__