about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:17:36 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:17:36 +0000
commit904b939cbd81a542303da2c58288b95b153106f5 (patch)
tree84b3751ed1deacc51eb186023101360ae92ef221
parentb4a5b9db8b528f9c9b6a9cbb00db381c95659380 (diff)
downloadzsh-904b939cbd81a542303da2c58288b95b153106f5.tar.gz
zsh-904b939cbd81a542303da2c58288b95b153106f5.tar.xz
zsh-904b939cbd81a542303da2c58288b95b153106f5.zip
zsh-3.1.5-pws-10 zsh-3.1.5-pws-10
-rw-r--r--Completion/Base/_command_names3
-rw-r--r--Completion/Base/_condition10
-rw-r--r--Completion/Base/_default13
-rw-r--r--Completion/Base/_match_pattern31
-rw-r--r--Completion/Base/_match_test15
-rw-r--r--Completion/Base/_precommand5
-rw-r--r--Completion/Base/_redirect3
-rw-r--r--Completion/Base/_subscript4
-rw-r--r--Completion/Base/_vars3
-rw-r--r--Completion/Builtins/_aliases3
-rw-r--r--Completion/Builtins/_arrays3
-rw-r--r--Completion/Builtins/_autoload3
-rw-r--r--Completion/Builtins/_bg_jobs3
-rw-r--r--Completion/Builtins/_bindkey7
-rw-r--r--Completion/Builtins/_builtin7
-rw-r--r--Completion/Builtins/_cd3
-rw-r--r--Completion/Builtins/_command7
-rw-r--r--Completion/Builtins/_dirs3
-rw-r--r--Completion/Builtins/_disable6
-rw-r--r--Completion/Builtins/_echotc3
-rw-r--r--Completion/Builtins/_enable6
-rw-r--r--Completion/Builtins/_fc7
-rw-r--r--Completion/Builtins/_functions3
-rw-r--r--Completion/Builtins/_hash13
-rw-r--r--Completion/Builtins/_jobs3
-rw-r--r--Completion/Builtins/_kill11
-rw-r--r--Completion/Builtins/_limits3
-rw-r--r--Completion/Builtins/_sched3
-rw-r--r--Completion/Builtins/_set7
-rw-r--r--Completion/Builtins/_setopt7
-rw-r--r--Completion/Builtins/_source7
-rw-r--r--Completion/Builtins/_trap7
-rw-r--r--Completion/Builtins/_unhash6
-rw-r--r--Completion/Builtins/_unsetopt7
-rw-r--r--Completion/Builtins/_vars_eq3
-rw-r--r--Completion/Builtins/_wait7
-rw-r--r--Completion/Builtins/_which3
-rw-r--r--Completion/Builtins/_zftp50
-rw-r--r--Completion/Builtins/_zle7
-rw-r--r--Completion/Builtins/_zmodload9
-rw-r--r--Completion/Commands/_correct_filename37
-rw-r--r--Completion/Commands/_most_recent_file4
-rw-r--r--Completion/Core/_comp_parts147
-rw-r--r--Completion/Core/_compalso13
-rw-r--r--Completion/Core/_files26
-rw-r--r--Completion/Core/_main_complete48
-rw-r--r--Completion/Core/_normal54
-rw-r--r--Completion/Core/_path_files311
-rw-r--r--Completion/Core/compdump89
-rw-r--r--Completion/Core/compinit269
-rw-r--r--Completion/README107
-rw-r--r--Completion/User/_a2ps22
-rw-r--r--Completion/User/_compress3
-rw-r--r--Completion/User/_configure12
-rw-r--r--Completion/User/_dd13
-rw-r--r--Completion/User/_dvi3
-rw-r--r--Completion/User/_find21
-rw-r--r--Completion/User/_gunzip3
-rw-r--r--Completion/User/_gzip3
-rw-r--r--Completion/User/_hosts3
-rw-r--r--Completion/User/_make3
-rw-r--r--Completion/User/_man11
-rw-r--r--Completion/User/_mh70
-rw-r--r--Completion/User/_pdf3
-rw-r--r--Completion/User/_ps3
-rw-r--r--Completion/User/_rcs9
-rw-r--r--Completion/User/_rlogin9
-rw-r--r--Completion/User/_strip2
-rw-r--r--Completion/User/_stty16
-rw-r--r--Completion/User/_tar11
-rw-r--r--Completion/User/_tex3
-rw-r--r--Completion/User/_uncompress3
-rw-r--r--Completion/User/_x_options5
-rw-r--r--Completion/User/_xfig3
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Zsh/compwid.yo27
-rw-r--r--Doc/Zsh/expn.yo65
-rw-r--r--Doc/Zsh/guide.yo4
-rwxr-xr-xMisc/globtests32
-rw-r--r--Src/.cvsignore1
-rw-r--r--Src/Builtins/rlimits.c12
-rw-r--r--Src/Zle/comp.h7
-rw-r--r--Src/Zle/comp1.c5
-rw-r--r--Src/Zle/compctl.c12
-rw-r--r--Src/Zle/zle_thingy.c11
-rw-r--r--Src/Zle/zle_tricky.c953
-rw-r--r--Src/exec.c2
-rw-r--r--Src/glob.c441
-rw-r--r--Src/hashtable.c20
-rw-r--r--Src/module.c49
-rw-r--r--Src/params.c13
-rw-r--r--Src/subst.c5
-rw-r--r--Src/system.h11
-rw-r--r--Src/zsh.export1
-rw-r--r--acconfig.h7
-rw-r--r--configure.in54
-rw-r--r--patchlist.txt117
97 files changed, 2949 insertions, 547 deletions
diff --git a/Completion/Base/_command_names b/Completion/Base/_command_names
new file mode 100644
index 000000000..d3b8a109a
--- /dev/null
+++ b/Completion/Base/_command_names
@@ -0,0 +1,3 @@
+#defcomp -command-
+
+complist -c
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
new file mode 100644
index 000000000..3e45e1b8f
--- /dev/null
+++ b/Completion/Base/_condition
@@ -0,0 +1,10 @@
+#defcomp -condition-
+
+if [[ -current -1 -o ]]; then
+  complist -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}'
+elif [[ -current -1 -nt || -current -1 -ot || -current -1 -ef ]]; then
+  _files
+else
+  _files
+  complist -v
+fi
diff --git a/Completion/Base/_default b/Completion/Base/_default
new file mode 100644
index 000000000..8bcf14f6a
--- /dev/null
+++ b/Completion/Base/_default
@@ -0,0 +1,13 @@
+#defcomp -default-
+
+# We first try the `compctl's. This is without first (-T) and default (-D)
+# completion. If you want them add `-T' and/or `-D' to this command.
+# If there is a `compctl' for the command we are working on, we return
+# immediatly. If you want to use new style completion anyway, remove the
+# `|| return'. Also, you may want to use new style completion if the 
+# `compctl' didn't produce any matches. In that case remove the `|| return'
+# and at the line `[[ -nmatches 0 ]] || return' after `compcall'.
+
+compcall || return
+
+_files
diff --git a/Completion/Base/_match_pattern b/Completion/Base/_match_pattern
new file mode 100644
index 000000000..c5debc0b9
--- /dev/null
+++ b/Completion/Base/_match_pattern
@@ -0,0 +1,31 @@
+#autoload
+
+# This function is called from functions that do matching whenever they
+# need to build a pattern that is used to match possible completions.
+# It gets the name of the calling function and two names of parameters
+# as arguments. The first one is used in the calling function to build
+# the pattern used for matching possible completions. The content of this
+# parameter on entry to this function is the string taken from the line.
+# Here it parameter should be changed to a pattern that matches words as
+# the match specs currently in use do.
+# In the calling function this pattern may be changed again or used only 
+# in parts. The second parameter whose name is given as the third argument
+# allows to give pattern flags liek `(#l)' that are to be used whenever
+# matching is done.
+#
+# As an example, if you have global match specifications like:
+#
+#  compctl -M 'm:{a-z}={A-Z}' 'm:{a-z}={A-Z} r:|[.-]=* r:|=*'
+#
+# This function would look like:
+#
+#   eval "${3}='(#l)'"
+#   [[ MATCHER -eq 2 ]] && eval "$1='${(P)2:gs/./*./:gs/-/*-/}'"
+#
+# The first line makes sure that matching is done case-insensitive as
+# specified by `m:{a-z}={A-Z}'. The second line replaces dots and hyphens
+# in the given string by patterns matching any characters before them,
+# like the `r:|[.-]=* r:|=*'. To make this work, the function `_match_test'
+# would have to be changed to `(( MATCHERS <= 2 ))'
+#
+# The default implementation of this function is empty.
diff --git a/Completion/Base/_match_test b/Completion/Base/_match_test
new file mode 100644
index 000000000..e8b6e6424
--- /dev/null
+++ b/Completion/Base/_match_test
@@ -0,0 +1,15 @@
+#autoload
+
+# This function is called at the beginning of functions that do matching in
+# shell code. It should test the value of the `MATCHER' special parameter
+# and return non-zero if the calling function should try to generate matches
+# for the global match specification in use.
+#
+# This function gets one argument, the name of the function calling it.
+#
+# If you have a global match specification with more than one set of patterns
+# you may want to modify this function to return non-zero for all of your
+# match specifications and modify the function `_match_pattern' to build the
+# pattern to use in the calling function.
+
+(( MATCHER == 1 ))
diff --git a/Completion/Base/_precommand b/Completion/Base/_precommand
new file mode 100644
index 000000000..2cf661147
--- /dev/null
+++ b/Completion/Base/_precommand
@@ -0,0 +1,5 @@
+#defcomp - nohup nice eval time rusage noglob nocorrect exec
+
+[[ -position 1 -1 ]]
+
+_normal "$@"
diff --git a/Completion/Base/_redirect b/Completion/Base/_redirect
new file mode 100644
index 000000000..32113ad7c
--- /dev/null
+++ b/Completion/Base/_redirect
@@ -0,0 +1,3 @@
+#defcomp -redirect-
+
+_files
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
new file mode 100644
index 000000000..2b827a117
--- /dev/null
+++ b/Completion/Base/_subscript
@@ -0,0 +1,4 @@
+#defcomp -subscript-
+
+_compalso -math- "$@"
+[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )"
diff --git a/Completion/Base/_vars b/Completion/Base/_vars
new file mode 100644
index 000000000..7153b6f38
--- /dev/null
+++ b/Completion/Base/_vars
@@ -0,0 +1,3 @@
+#defcomp -math- getopts read unset vared
+
+complist -v
diff --git a/Completion/Builtins/_aliases b/Completion/Builtins/_aliases
new file mode 100644
index 000000000..1038a726e
--- /dev/null
+++ b/Completion/Builtins/_aliases
@@ -0,0 +1,3 @@
+#defcomp unalias
+
+complist -a
diff --git a/Completion/Builtins/_arrays b/Completion/Builtins/_arrays
new file mode 100644
index 000000000..cbeac7118
--- /dev/null
+++ b/Completion/Builtins/_arrays
@@ -0,0 +1,3 @@
+#defcomp shift
+
+complist -A
diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload
new file mode 100644
index 000000000..4f506baeb
--- /dev/null
+++ b/Completion/Builtins/_autoload
@@ -0,0 +1,3 @@
+#defcomp autoload
+
+complist -s '${^fpath}/*(N:t)'
diff --git a/Completion/Builtins/_bg_jobs b/Completion/Builtins/_bg_jobs
new file mode 100644
index 000000000..511bb8308
--- /dev/null
+++ b/Completion/Builtins/_bg_jobs
@@ -0,0 +1,3 @@
+#defcomp bg
+
+complist -z -P '%'
diff --git a/Completion/Builtins/_bindkey b/Completion/Builtins/_bindkey
new file mode 100644
index 000000000..8eddeb2a8
--- /dev/null
+++ b/Completion/Builtins/_bindkey
@@ -0,0 +1,7 @@
+#defcomp bindkey
+
+if [[ -mword 1 -*[DAN]* || -mcurrent -1 -*M ]]; then
+  complist -s '$(bindkey -l)'
+else
+  complist -b
+fi
diff --git a/Completion/Builtins/_builtin b/Completion/Builtins/_builtin
new file mode 100644
index 000000000..a967932ee
--- /dev/null
+++ b/Completion/Builtins/_builtin
@@ -0,0 +1,7 @@
+#defcomp builtin
+
+if [[ -position 2 -1 ]]; then
+  _normal "$@"
+else
+  complist -eB
+fi
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
new file mode 100644
index 000000000..f3ce67ec7
--- /dev/null
+++ b/Completion/Builtins/_cd
@@ -0,0 +1,3 @@
+#defcomp cd
+
+_files -W cdpath -g '*(-/)'
diff --git a/Completion/Builtins/_command b/Completion/Builtins/_command
new file mode 100644
index 000000000..b2812de25
--- /dev/null
+++ b/Completion/Builtins/_command
@@ -0,0 +1,7 @@
+#defcomp command
+
+if [[ -position 2 -1 ]]; then
+  _normal "$@"
+else
+  complist -em
+fi
diff --git a/Completion/Builtins/_dirs b/Completion/Builtins/_dirs
new file mode 100644
index 000000000..bc426e322
--- /dev/null
+++ b/Completion/Builtins/_dirs
@@ -0,0 +1,3 @@
+#defcomp rmdir df du dircmp
+
+_files -/
diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable
new file mode 100644
index 000000000..063b65a7d
--- /dev/null
+++ b/Completion/Builtins/_disable
@@ -0,0 +1,6 @@
+#defcomp disable
+
+[[ -mcurrent -1 -*a* ]] && complist -ea
+[[ -mcurrent -1 -*f* ]] && complist -eF
+[[ -mcurrent -1 -*r* ]] && complist -ew
+[[ ! -mcurrent -1 -* ]] && complist -eB
diff --git a/Completion/Builtins/_echotc b/Completion/Builtins/_echotc
new file mode 100644
index 000000000..85ebb97ce
--- /dev/null
+++ b/Completion/Builtins/_echotc
@@ -0,0 +1,3 @@
+#defcomp echotc
+
+complist -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)'
diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable
new file mode 100644
index 000000000..22ff53ee7
--- /dev/null
+++ b/Completion/Builtins/_enable
@@ -0,0 +1,6 @@
+#defcomp enable
+
+[[ -mcurrent -1 -*a* ]] && complist -da
+[[ -mcurrent -1 -*f* ]] && complist -dF
+[[ -mcurrent -1 -*r* ]] && complist -dw
+[[ ! -mcurrent -1 -* ]] && complist -dB
diff --git a/Completion/Builtins/_fc b/Completion/Builtins/_fc
new file mode 100644
index 000000000..f0d2c03fd
--- /dev/null
+++ b/Completion/Builtins/_fc
@@ -0,0 +1,7 @@
+#defcomp fc
+
+if [[ -mcurrent -1 -*e ]]; then
+  complist -c
+elif [[ -mcurrent -1 -[ARWI]## ]]; then
+  _files
+fi
diff --git a/Completion/Builtins/_functions b/Completion/Builtins/_functions
new file mode 100644
index 000000000..8a352ea08
--- /dev/null
+++ b/Completion/Builtins/_functions
@@ -0,0 +1,3 @@
+#defcomp unfunction
+
+complist -F
diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash
new file mode 100644
index 000000000..171c5e2e8
--- /dev/null
+++ b/Completion/Builtins/_hash
@@ -0,0 +1,13 @@
+#defcomp hash
+
+if [[ -mword 1 -*d* ]]; then
+  if [[ -string 1 '=' ]]; then
+    _path_files -g '*(-/)'
+  else
+    complist -n -q -S '='
+  fi
+elif [[ -string 1 '=' ]]; then
+  _files -/g '*(*)'
+else
+  complist -m -q -S '='
+fi
diff --git a/Completion/Builtins/_jobs b/Completion/Builtins/_jobs
new file mode 100644
index 000000000..018883c61
--- /dev/null
+++ b/Completion/Builtins/_jobs
@@ -0,0 +1,3 @@
+#defcomp fg jobs
+
+complist -j -P '%'
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
new file mode 100644
index 000000000..50796d36f
--- /dev/null
+++ b/Completion/Builtins/_kill
@@ -0,0 +1,11 @@
+#defcomp kill
+
+local list
+
+if [[ -iprefix '-' ]]; then
+  complist -k "($signals[1,-3])"
+else
+  complist -P '%' -j
+  list=("$(ps 2>/dev/null)")
+  complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
+fi
diff --git a/Completion/Builtins/_limits b/Completion/Builtins/_limits
new file mode 100644
index 000000000..35ccbe07e
--- /dev/null
+++ b/Completion/Builtins/_limits
@@ -0,0 +1,3 @@
+#defcomp limit unlimit
+
+complist -k "(${(j: :)${(f)$(limit)}%% *})"
diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched
new file mode 100644
index 000000000..1e8ae3445
--- /dev/null
+++ b/Completion/Builtins/_sched
@@ -0,0 +1,3 @@
+#defcomp sched
+
+[[ -position 2 -1 ]] && _normal "$@"
diff --git a/Completion/Builtins/_set b/Completion/Builtins/_set
new file mode 100644
index 000000000..5597025bc
--- /dev/null
+++ b/Completion/Builtins/_set
@@ -0,0 +1,7 @@
+#defcomp set
+
+if [[ -mcurrent -1 [-+]o ]]; then
+  complist -o
+elif [[ -current -1 -A ]]; then
+  complist -A
+fi
diff --git a/Completion/Builtins/_setopt b/Completion/Builtins/_setopt
new file mode 100644
index 000000000..4abb3ccee
--- /dev/null
+++ b/Completion/Builtins/_setopt
@@ -0,0 +1,7 @@
+#defcomp setopt
+
+local nm=$NMATCHES
+
+complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
+         -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)'
+[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
diff --git a/Completion/Builtins/_source b/Completion/Builtins/_source
new file mode 100644
index 000000000..aae2c7320
--- /dev/null
+++ b/Completion/Builtins/_source
@@ -0,0 +1,7 @@
+#defcomp source
+
+if [[ -position 2 -1 ]]; then
+  _normal "$@"
+else
+  _files
+fi
diff --git a/Completion/Builtins/_trap b/Completion/Builtins/_trap
new file mode 100644
index 000000000..59e81c589
--- /dev/null
+++ b/Completion/Builtins/_trap
@@ -0,0 +1,7 @@
+#defcomp trap
+
+if [[ -position 1 ]]; then
+  complist -c
+else
+  complist -k signals
+fi
diff --git a/Completion/Builtins/_unhash b/Completion/Builtins/_unhash
new file mode 100644
index 000000000..fe40c25a2
--- /dev/null
+++ b/Completion/Builtins/_unhash
@@ -0,0 +1,6 @@
+#defcomp unhash
+
+[[ -mword 1 -*d* ]] && complist -n
+[[ -mword 1 -*a* ]] && complist -a
+[[ -mword 1 -*f* ]] && complist -F
+[[ ! -mword 1 -* ]] && complist -m
diff --git a/Completion/Builtins/_unsetopt b/Completion/Builtins/_unsetopt
new file mode 100644
index 000000000..90d642b51
--- /dev/null
+++ b/Completion/Builtins/_unsetopt
@@ -0,0 +1,7 @@
+#defcomp unsetopt
+
+local nm=$NMATCHES
+
+complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
+         -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)'
+[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
diff --git a/Completion/Builtins/_vars_eq b/Completion/Builtins/_vars_eq
new file mode 100644
index 000000000..fcbb0148c
--- /dev/null
+++ b/Completion/Builtins/_vars_eq
@@ -0,0 +1,3 @@
+#defcomp declare export integer local readonly typeset
+
+complist -v -q -S '='
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
new file mode 100644
index 000000000..29a7f6002
--- /dev/null
+++ b/Completion/Builtins/_wait
@@ -0,0 +1,7 @@
+#defcomp wait
+
+local list
+
+complist -P '%' -j
+list=("$(ps 2>/dev/null)")
+complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
diff --git a/Completion/Builtins/_which b/Completion/Builtins/_which
new file mode 100644
index 000000000..324256e3d
--- /dev/null
+++ b/Completion/Builtins/_which
@@ -0,0 +1,3 @@
+#defcomp which whence where type
+
+complist -caF
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
new file mode 100644
index 000000000..9be9c94db
--- /dev/null
+++ b/Completion/Builtins/_zftp
@@ -0,0 +1,50 @@
+#defpatcomp zf*
+
+# Don't try any more completion after this.
+_compskip=1
+
+# Completion for zftp builtin and zf* functions.  The functions
+# zfcd_match and zfget_match (used for old-style completion)
+# need to be installed for remote file and directory completion to work.
+
+local subcom
+
+if [[ $COMMAND = zftp ]]; then
+  if [[ $CURRENT -eq 1 ]]; then
+    compadd -m open params user login type ascii binary mode put \
+      putat get getat append appendat ls dir local remote mkdir rmdir
+    return
+  fi
+  subcom=$1
+else
+  subcom=$COMMAND
+fi
+
+case $subcom in
+  *(cd|ls|dir))
+   # complete remote directories; we could be smarter about hiding prefixes
+   zfcd_match $PREFIX $SUFFIX
+   (( $#reply )) && compadd -m -S/ -q $reply
+   ;;
+
+  *(get(|at)|gcp|delete|remote))
+   # complete remote files
+   zfget_match $PREFIX $SUFFIX
+   (( $#reply )) && compadd -F fignore -m $reply
+   ;;
+
+  *(put(|at)|pcp))
+   # complete local files
+   _files
+   ;;
+
+  *(open|anon|params))
+  # complete hosts:  should do cleverer stuff with user names
+  complist -k hosts
+  ;;
+
+  *)
+  # dunno... try ordinary completion after all.
+  unset _compskip   
+  ;;
+esac
diff --git a/Completion/Builtins/_zle b/Completion/Builtins/_zle
new file mode 100644
index 000000000..bb1102e74
--- /dev/null
+++ b/Completion/Builtins/_zle
@@ -0,0 +1,7 @@
+#defcomp zle
+
+if [[ -word 1 -N && -position 3 ]]; then
+  complist -F
+else
+  complist -b
+fi
diff --git a/Completion/Builtins/_zmodload b/Completion/Builtins/_zmodload
new file mode 100644
index 000000000..112acb57c
--- /dev/null
+++ b/Completion/Builtins/_zmodload
@@ -0,0 +1,9 @@
+#defcomp zmodload
+
+if [[ -mword 1 -*(a*u|u*a)* || -mword 1 -*a* && -position 3 -1 ]]; then
+  complist -B
+elif [[ -mword 1 -*u* ]]; then
+  complist -s '$(zmodload)'
+else
+  complist -s '${^module_path}/*(N:t:r)'
+fi
diff --git a/Completion/Commands/_correct_filename b/Completion/Commands/_correct_filename
new file mode 100644
index 000000000..edf1c65c2
--- /dev/null
+++ b/Completion/Commands/_correct_filename
@@ -0,0 +1,37 @@
+#defkeycomp complete-word \C-xc
+
+# Function to correct a filename.  Can be used as a completion widget,
+# or as a function in its own right, in which case it will print the
+# corrected filename to standard output.
+#
+# You can adapt max_approx to the maximum number of mistakes
+# which are allowed in total.
+
+emulate -LR zsh
+setopt extendedglob
+
+local file="$PREFIX$SUFFIX" trylist
+integer approx max_approx=6
+
+[[ -z $WIDGET ]] && file=$1 
+
+if [[ -e "$file" ]]; then
+  if [[ -n $WIDGET ]]; then
+    compadd "$file"
+  else
+    print "$file"
+  fi
+  return
+fi
+
+for (( approx = 1; approx <= max_approx; approx++ )); do
+  trylist=( (#a$approx)"$file"(N) )
+  (( $#trylist )) && break
+done
+(( $#trylist )) || return 1
+
+if [[ -n $WIDGET ]]; then
+  compadd -U "${trylist[@]}"
+else
+  print "${trylist[@]}"
+fi
diff --git a/Completion/Commands/_most_recent_file b/Completion/Commands/_most_recent_file
new file mode 100644
index 000000000..ff5645de5
--- /dev/null
+++ b/Completion/Commands/_most_recent_file
@@ -0,0 +1,4 @@
+#defkeycomp complete-word \C-xm
+local file
+file=($~PREFIX*$~SUFFIX(om[1]N))
+(( $#file )) && compadd -f $file
diff --git a/Completion/Core/_comp_parts b/Completion/Core/_comp_parts
new file mode 100644
index 000000000..7c24fd19d
--- /dev/null
+++ b/Completion/Core/_comp_parts
@@ -0,0 +1,147 @@
+#autoload
+
+# This function can be used to separately complete parts of strings
+# where each part may be one of a set of matches and different parts
+# have different sets.
+# Arguments are alternatingly arrays and separator strings. Arrays may
+# be given by name or literally as words separated by white space in
+# parentheses, e.g.:
+#
+#  _comp_parts '(foo bar)' @ hosts
+#
+# This will make this function complete the strings in the array
+# `friends'. If the string on the line contains a `@', the substring
+# after it will be completed from the array `hosts'. Of course more
+# arrays may be given, each preceded by another separator string.
+#
+# This function understands the `-J group', `-V group', and
+# `-X explanation' options.
+#
+# This function does part of the matching itself and calls the functions
+# `_match_test' and `_match_pattern' for this.
+
+local str arr sep test testarr tmparr prefix suffixes matchers autosuffix
+local matchflags opt group expl
+
+# Test if we should use this function for the global matcher in use.
+
+_match_test _comp_parts || return
+
+# Get the options.
+
+group=()
+expl=()
+while getopts "J:V:X:" opt; do
+  case "$opt" in
+  [JV]) group=("-$opt" "$OPTARG");;
+  X)    expl=(-X "$OPTARG");;
+  esac
+done
+shift OPTIND-1
+
+# Get the string from the line.
+
+str="$PREFIX$SUFFIX"
+prefix=""
+
+# Walk through the arguments to find the longest unambiguous prefix.
+
+while [[ $# -gt 1 ]]; do
+  # Get the next array and separator.
+  arr="$1"
+  sep="$2"
+
+  if [[ "$arr[1]" == '(' ]]; then
+    tmparr=( ${=arr[2,-2]} )
+    arr=tmparr
+  fi
+  # Is the separator on the line?
+  [[ "$str" != *${sep}* ]] && break
+
+  # Build a pattern matching the possible matches and get all these
+  # matches in an array.
+  test="${str%%${sep}*}"
+  matchflags=""
+  _match_pattern _comp_parts test matchflags
+  test="${matchflags}${test}"
+  testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+
+  # If there are no matches we give up. If there is more than one
+  # match, this is the part we will complete.
+  (( $#testarr )) || return
+  [[ $#testarr -gt 1 ]] && break
+
+  # Only one match, add it to the prefix and skip over it in `str',
+  # continuing with the next array and separator.
+  prefix="${prefix}${testarr[1]}${sep}"
+  str="${str#*${sep}}"
+  shift 2
+done
+
+# Get the array to work upon.
+arr="$1"
+if [[ "$arr[1]" == '(' ]]; then
+  tmparr=( ${=arr[2,-2]} )
+  arr=tmparr
+fi
+if [[ $# -le 1 || "$str" != *${2}* ]]; then
+  # No more separators, build the matches.
+  matchflags=""
+  test="$str"
+  _match_pattern _comp_parts test matchflags
+  test="${matchflags}${test}"
+  testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+fi
+
+[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return
+
+# Now we build the suffixes to give to the completion code.
+shift
+matchers=()
+suffixes=("")
+autosuffix=()
+
+while [[ $# -gt 0 && "$str" == *${1}* ]]; do
+  # Remove anything up to the the suffix.
+  str="${str#*${1}}"
+
+  # Again, we get the string from the line up to the next separator
+  # and build a pattern from it.
+  if [[ $# -gt 2 ]]; then
+    test="${str%%${3}*}"
+  else
+    test="$str"
+  fi
+  matchflags=""
+  _match_pattern _comp_parts test matchflags
+  test="${matchflags}${test}"
+
+  # We incrementally add suffixes by appending to them the seperators
+  # and the strings from the next array that match the pattern we built.
+
+  arr="$2"
+  if [[ "$arr[1]" == '(' ]]; then
+    tmparr=( ${=arr[2,-2]} )
+    arr=tmparr
+  fi
+  suffixes=("${^suffixes[@]}${1}${(@M)^${(@P)arr}:#${~test}*}")
+
+  # We want the completion code to generate the most specific suffix
+  # for us, so we collect matching specifications that allow partial
+  # word matching before the separators on the fly.
+  matchers=("$matchers[@]" "r:|${1}=*")
+  shift 2
+done
+
+# If we were given at least one more separator we make the completion
+# code offer it by appending it as a autoremovable suffix.
+(( $# )) && autosuffix=(-qS "$1")
+
+# If we have collected matching specifications, we build an array
+# from it that can be used as arguments to `compadd'.
+[[ $#matchers -gt 0 ]] && matchers=(-M "$matchers")
+
+# Add the matches for each of the suffixes.
+for i in "$suffixes[@]"; do
+  compadd "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" -p "$prefix" -s "$i" - "$testarr[@]"
+done
diff --git a/Completion/Core/_compalso b/Completion/Core/_compalso
new file mode 100644
index 000000000..23a40e2d0
--- /dev/null
+++ b/Completion/Core/_compalso
@@ -0,0 +1,13 @@
+#autoload
+
+# This searches $1 in the array for normal completions and calls the result.
+# It is used to include completions for another command or special context
+# into the list generated by the calling function.
+# For example the function for `-subscript-' could call this as in
+# `_compalso -math- "$@"' to get the completions that would be generated
+# for a mathematical context.
+
+local tmp
+
+tmp="$_comps[$1]"
+[[ -z "$tmp" ]] || "$tmp" "$@"
diff --git a/Completion/Core/_files b/Completion/Core/_files
new file mode 100644
index 000000000..d2cce35e7
--- /dev/null
+++ b/Completion/Core/_files
@@ -0,0 +1,26 @@
+#autoload
+
+# Utility function for completing files of a given type or any file.
+# In many cases you will want to call this one instead of _path_files().
+
+local nm=$NMATCHES
+
+_path_files "$@"
+
+if [[ $# -ne 0 && -nmatches nm ]]; then
+  local opt opts
+
+  # We didn't get any matches for those types of files described by
+  # the `-g' or `-/' option. Now we try it again accepting all files.
+  # First we get those options that we have to use even if then. If
+  # we find out that the `-f' option was given, we already accepted
+  # all files and give up immediatly.
+
+  opts=()
+  while getopts "P:S:W:F:J:V:X:f/g:" opt; do
+    [[ "$opt" = f ]] && return
+    [[ "$opt" = [PSWFJVX] ]] && opts=("$opts[@]" "-$opt" "$OPTARG")
+  done
+
+  _path_files "$opts[@]"
+fi
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
new file mode 100644
index 000000000..c7f5a5a96
--- /dev/null
+++ b/Completion/Core/_main_complete
@@ -0,0 +1,48 @@
+#autoload
+
+# The main loop of the completion code. This is what is called when 
+# completion is attempted from the command line.
+# The completion code gives us the special variables and the arguments
+# from the command line are given as positional parameters.
+
+local comp name
+
+setopt localoptions nullglob rcexpandparam globdots
+unsetopt markdirs globsubst shwordsplit nounset
+
+# An entry for `-first-' is the replacement for `compctl -T'
+# Completion functions may set `_compskip' to any value to make the 
+# main loops stop calling other completion functions.
+
+comp="$_comps[-first-]"
+if [[ ! -z "$comp" ]]; then
+  "$comp" "$@"
+  if (( $+_compskip )); then
+    unset _compskip
+    return
+  fi
+fi
+
+# For arguments we use the `_normal function.
+
+if [[ $CONTEXT == argument || $CONTEXT == command ]]; then
+  _normal "$@"
+else
+  # Let's see if we have a special completion definition for the other
+  # possible contexts.
+
+  comp=''
+
+  case $CONTEXT in
+  redirect)  comp="$_comps[-redirect-]";;
+  math)      comp="$_comps[-math-]";;
+  subscript) comp="$_comps[-subscript-]";;
+  value)     comp="$_comps[-value-]";;
+  condition) comp="$_comps[-condition-]";;
+  esac
+
+  # If not, we use default completion, if any.
+
+  [[ -z "$comp" ]] && comp="$_comps[-default-]"
+  [[ -z "$comp" ]] || "$comp" "$@"
+fi
diff --git a/Completion/Core/_normal b/Completion/Core/_normal
new file mode 100644
index 000000000..19da6d79b
--- /dev/null
+++ b/Completion/Core/_normal
@@ -0,0 +1,54 @@
+#autoload
+
+local comp cmd1 cmd2 pat val name
+
+# Completing in command position? If not we set up `cmd1' and `cmd2' as
+# two strings we have search in the completion definition arrays (e.g.
+# a path and the last path name component).
+
+if [[ $CONTEXT == command ]]; then
+  comp="$_comps[-command-]"
+  [[ -z "$comp" ]] || "$comp" "$@"
+  return
+elif [[ "$COMMAND[1]" == '=' ]]; then
+  eval cmd1\=$COMMAND
+  cmd2="$COMMAND[2,-1]"
+elif [[ "$COMMAND" == */* ]]; then
+  cmd1="$COMMAND"
+  cmd2="${COMMAND:t}"
+else
+  cmd1="$COMMAND"
+  eval cmd2=$(whence -p $COMMAND)
+fi
+
+# See if there are any matching pattern completions.
+
+for i in "$_patcomps[@]"; do
+  pat="${i% *}"
+  val="${i#* }"
+  if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then
+    "$val" "$@"
+    if (( $+_compskip )); then
+      unset _compskip
+      return
+    fi
+  fi
+done
+
+# Now look up the two names in the normal completion array.
+
+name="$cmd1"
+comp="$_comps[$cmd1]"
+
+if [[ -z "$comp" ]]; then
+  name="$cmd2"
+  comp="$_comps[$cmd2]"
+fi
+
+# And generate the matches, probably using default completion.
+
+if [[ -z "$comp" ]]; then
+  name=-default-
+  comp="$_comps[-default-]"
+fi
+[[ -z "$comp" ]] || "$comp" "$@"
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
new file mode 100644
index 000000000..83b6e8a09
--- /dev/null
+++ b/Completion/Core/_path_files
@@ -0,0 +1,311 @@
+#autoload
+
+# Utility function for in-path completion.
+# Supported arguments are: `-f', `-/', `-g <patterns>', `-J <group>',
+# `-V <group>', `-W paths', `-X explanation', and `-F <ignore>'. All but 
+# the last have the same syntax and meaning as for `complist'. The
+# `-F <ignore>' option may be used to give a list of suffixes either by
+# giving the name of an array or literally by giving them in a string
+# surrounded by parentheses. Files with one of the suffixes thus given
+# are treated like files with one of the suffixes in the `fignore' array
+# in normal completion.
+#
+# This function uses the helper functions `_match_test' and `_match_pattern'.
+
+# First see if we should generate matches for the global matcher in use.
+
+_match_test _path_files || return
+
+# Yes, so...
+
+local nm prepaths str linepath realpath donepath patstr prepath testpath rest
+local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt
+local addpfx addsfx expl
+
+setopt localoptions nullglob rcexpandparam globdots extendedglob
+unsetopt markdirs globsubst shwordsplit nounset
+
+prepaths=('')
+ignore=()
+group=()
+sopt='-'
+gopt=''
+pats=()
+addpfx=()
+addsfx=()
+expl=()
+
+# Get the options.
+
+while getopts "P:S:W:F:J:V:X:f/g:" opt; do
+  case "$opt" in
+  P)     addpfx=(-P "$OPTARG")
+         ;;
+  S)     addsfx=(-S "$OPTARG")
+         ;;
+  W)     tmp1="$OPTARG"
+         if [[ "$tmp1[1]" = '(' ]]; then
+           prepaths=( ${^=tmp1[2,-2]}/ )
+         else
+           prepaths=( ${(P)=${tmp1}} )
+           (( ! $#prepaths )) && prepaths=( ${tmp1}/ )
+         fi
+         (( ! $#prepaths )) && prepaths=( '' )
+         ;;
+  F)     tmp1="$OPTARG"
+         if [[ "$tmp1[1]" = '(' ]]; then
+           ignore=( ${^=tmp1[2,-2]}/ )
+         else
+           ignore=( ${(P)${tmp1}} )
+         fi
+	 (( $#ignore )) && ignore=(-F "( $ignore )")
+         ;;
+  [JV])  group=("-$opt" "$OPTARG")
+         ;;
+  X)     expl=(-X "$OPTARG")
+         ;;
+  f)     sopt="${sopt}f"
+         pats=("$pats[@]" '*')
+	 ;;
+  /)     sopt="${sopt}/"
+         pats=("$pats[@]" '*(-/)')
+	 ;;
+  g)     gopt='-g'
+         pats=("$pats[@]" ${=OPTARG})
+	 ;;
+  esac
+done
+
+# If we were given no file selection option, we behave as if we were given
+# a `-f'.
+
+if [[ "$sopt" = - ]]; then
+  if [[ -z "$gopt" ]]; then
+    sopt='-f'
+    pats=('*')
+  else
+    unset sopt
+  fi
+fi
+
+# str holds the whole string from the command line with a `*' between
+# the prefix and the suffix.
+
+str="${PREFIX:q}*${SUFFIX:q}"
+
+# If the string began with a `~', the quoting turned this into `\~',
+# remove the slash.
+
+[[ "$str" = \\\~* ]] && str="$str[2,-1]"
+
+# We will first try normal completion called with `complist', but only if we
+# weren't given a `-F' option.
+
+if (( ! $#ignore )); then
+  # First build an array containing the `-W' option, if there is any and we
+  # want to use it. We don't want to use it if the string from the command line
+  # is a absolute path or relative to the current directory.
+
+  if [[ -z "$tmp1[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]]; then
+    tmp1=()
+  else
+    tmp1=(-W "( $prepaths )")
+  fi
+
+  # Now call complist.
+
+  nm=$NMATCHES
+  if [[ -z "$gopt" ]]; then
+    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
+  else
+    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
+  fi
+
+  # If this generated any matches, we don't want to do in-path completion.
+
+  [[ -nmatches nm ]] || return
+
+  # No `-F' option, so we want to use `fignore'.
+
+  ignore=(-F fignore)
+fi
+
+# Now let's have a closer look at the string to complete.
+
+if [[ "$str[1]" = \~ ]]; then
+  # It begins with `~', so remember anything before the first slash to be able
+  # to report it to the completion code. Also get an expanded version of it
+  # (in `realpath'), so that we can generate the matches. Then remove that
+  # prefix from the string to complete, set `donepath' to build the correct
+  # paths and make sure that the loop below is run only once with an empty
+  # prefix path by setting `prepaths'.
+  
+  linepath="${str%%/*}/"
+  eval realpath\=$linepath
+  str="${str#*/}"
+  donepath=''
+  prepaths=( '' )
+else
+  # If the string does not start with a `~' we don't remove a prefix from the
+  # string.
+
+  liniepath=''
+  realpath=''
+
+  if [[ "$str[1]" = / ]]; then
+    # If it is a absolut path name, we remove the first slash and put it in
+    # `donepath' meaning that we treat it as the path that was already handled.
+    # Also, we don't use the paths from `-W'.
+
+    str="$str[2,-1]"
+    donepath='/'
+    prepaths=( '' )
+  else
+    # The common case, we just use the string as it is, unless it begins with
+    # `./' or `../' in which case we don't use the paths from `-W'.
+    
+    [[ "$str" = (.|..)/* ]] && prepaths=( '' )
+    donepath=''
+  fi
+fi
+
+# First we skip over all pathname components in `str' which really exist in
+# the file-system, so that `/usr/lib/l<TAB>' doesn't offer you `lib' and
+# `lib5'. Pathname components skipped this way are taken from `str' and added
+# to `donepath'.
+
+while [[ "$str" = */* ]] do
+  [[ -e "$realpath$donepath${str%%/*}" ]] || break
+  donepath="$donepath${str%%/*}/"
+  str="${str#*/}"
+done
+
+# Now build the glob pattern by calling `_match_pattern'.
+patstr="$str"
+matchflags=""
+_match_pattern _path_files patstr matchflags
+
+# We almost expect the pattern to have changed `..' into `*.*.', `/.' into
+# `/*.', and probably to contain two or more consecutive `*'s. Since these
+# have special meaning for globbing, we remove them. But before that, we
+# add the pattern for matching any characters before a slash.
+
+patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/"
+
+# Finally, generate the matches. First we loop over all the paths from `-W'.
+# Note that in this loop `str' is used as a modifyable version of `patstr'
+# and `testpath' is a modifyable version of `donepath'.
+
+for prepath in "$prepaths[@]"; do
+  str="$patstr"
+  testpath="$donepath"
+
+  # The second loop tests the components of the path in `str' to get the
+  # possible matches.
+
+  while [[ "$str" = */* ]] do
+    # `rest' is the pathname after the first slash that is left. In `tmp1'
+    # we get the globbing matches for the pathname component currently
+    # handled.
+
+    rest="${str#*/}"
+    tmp1="${prepath}${realpath}${testpath}${~matchflags}${str%%/*}(-/)"
+    tmp1=( $~tmp1 )
+
+    if [[ $#tmp1 -eq 0 ]]; then
+      # If this didn't produce any matches, we don't need to test this path
+      # any further, so continue with the next `-W' path, if any.
+
+      continue 2
+    elif [[ $#tmp1 -gt 1 ]]; then
+      # If it produced more than one match, we want to remove those which
+      # don't have possible following pathname components matching the 
+      # rest of the string we are completing. (The case with only one
+      # match is handled below.)
+      # In `collect' we will collect those of the produced pathnames that
+      # have a matching possible path-suffix. In `suffixes' we build an
+      # array containing strings build from the rest of the string to 
+      # complete and the glob patterns we were given as arguments.
+
+      collect=()
+      suffixes=( $rest$^pats )
+      suffixes=( "${(@)suffixes:gs.**.*.}" )
+
+      # In the loop the prefixes from the `tmp1' array produced above and
+      # the suffixes we just built are used to produce possible matches
+      # via globbing.
+
+      for i in $tmp1; do
+        tmp2=( ${~i}/${~matchflags}${~suffixes} )
+        [[ $#tmp2 -ne 0 ]] && collect=( $collect $i )
+      done
+
+      # If this test showed that none of the matches from the glob in `tmp1'
+      # has a possible sub-path matching what's on the line, we give up and
+      # continue with the next `-W' path.
+
+      if [[ $#collect -eq 0 ]]; then
+        continue 2
+      elif [[ $#collect -ne 1 ]]; then
+        # If we have more than one possible match, this means that the
+	# pathname component currently handled is ambiguous, so we give
+	# it to the completion code.
+	# First we build the full path prefix in `tmp1'.
+
+        tmp1="$prepath$realpath$testpath"
+
+	# Now produce all matching pathnames in `collect'.
+
+        collect=( ${~collect}/${~matchflags}${~suffixes} )
+
+	# And then remove the common path prefix from all these matches.
+
+        collect=( ${collect#$tmp1} )
+
+	# Finally, we add all these matches with the common (unexpanded)
+	# pathprefix (the `-p' option), the path-prefix (the `-W' option)
+	# to allow the completion code to test file type, and the path-
+	# suffix (the `-s' option). We also tell the completion code that
+	# these are file names and that `fignore' should be used as usual
+	# (the `-f' and `-F' options).
+
+        for i in $collect; do
+          compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}"
+        done
+
+	# We have just finished handling all the matches from above, so we
+	# can continue with the next `-W' path.
+
+	continue 2
+      fi
+      # We reach this point if only one of the path prefixes in `tmp1'
+      # has a existing path-suffix matching the string from the line.
+      # In this case we accept this match and continue with the next
+      # path-name component.
+
+      tmp1=( "$collect[1]" )
+    fi
+    # This is also reached if the first globbing produced only one match
+    # in this case we just continue with the next pathname component, too.
+
+    tmp1="$tmp1[1]"
+    testpath="$testpath${tmp1##*/}/"
+    str="$rest"
+  done
+
+  # We are here if all pathname components except the last one (which is still
+  # not tested) are unambiguous. So we add matches with the full path prefix, 
+  # no path suffix, the `-W' we are currently handling, all the matches we
+  # can produce in this directory, if any.
+
+  tmp1="$prepath$realpath$testpath"
+  suffixes=( $str$^pats )
+  suffixes=( "${(@)suffixes:gs.**.*.}" )
+  tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
+  if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then
+    [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]"
+    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath"
+  else
+    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1}
+  fi
+done
diff --git a/Completion/Core/compdump b/Completion/Core/compdump
new file mode 100644
index 000000000..8be096f50
--- /dev/null
+++ b/Completion/Core/compdump
@@ -0,0 +1,89 @@
+# This is a file to be sourced to dump the definitions for new-style
+# completion defined by 'compinit' in the same directory.  The output
+# should be directed into the "compinit.dump" in the same directory as
+# compinit. If you rename init, just stick .dump onto the end of whatever
+# you have called it and put it in the same directory.  This is handled
+# automatically if you invoke compinit with the option -d.
+#
+# You will need to update the dump every time you add a new completion.
+# To do this, simply remove the .dump file, start a new shell, and
+# create the .dump file as before.  Again, compinit -d handles this
+# automatically.
+#
+# It relies on KSH_ARRAYS not being set.
+
+# Print the number of files used for completion. This is used in compinit
+# to see if auto-dump should re-dump the dump-file.
+
+_d_file=${COMPDUMP-${0:h}/compinit.dump}
+
+typeset -U _d_files
+_d_files=( ${^~fpath}/_*~*~(N:t) )
+
+print "#files: $#_d_files" > $_d_file
+
+unset _d_files
+
+# First dump the arrays _comps and _patcomps.  The quoting hieroglyphyics
+# ensure that a single quote inside a variable is itself correctly quoted.
+
+print "_comps=(" >> $_d_file
+for _d_f in ${(ok)_comps}; do
+    print -r - "'${_d_f//\'/'\\''}'" "'${_comps[$_d_f]//\'/'\\''}'"
+done  >> $_d_file
+print ")" >> $_d_file
+
+print "\n_patcomps=(" >> $_d_file
+for _d_f in "$_patcomps[@]"; do
+  print -r - "'${_d_f//\'/'\\''}'"
+done >> $_d_file
+print ")" >> $_d_file
+
+print >> $_d_file
+
+# Now dump the key bindings. We dump all bindings for zle widgets
+# whose names start with a underscore.
+# We need both the zle -C's and the bindkey's to recreate.
+
+_d_bks=()
+zle -lL |
+  while read -rA _d_line; do
+    if [[ ${_d_line[5]} = _* ]]; then
+      print -r - ${_d_line}
+      _d_bks=($_d_bks ${_d_line[3]})
+    fi
+  done >> $_d_file
+bindkey |
+  while read -rA _d_line; do
+    if [[ ${_d_line[2]} = (${(j.|.)~_d_bks}) ]]; then
+      print -r "bindkey '${_d_line[1][2,-2]}' ${_d_line[2]}"
+    fi
+  done >> $_d_file
+
+print >> $_d_file
+
+
+# Autoloads: whence -w produces "_d_foo: function", so look for
+# all functions beginning with `_'.
+
+_d_als=($(whence -wm '_*' | sort |
+while read -rA _d_line; do
+  [[ ${_d_line[2]} = function ]] && print -r - ${_d_line[1]%:}
+done))
+
+# print them out:  about five to a line looks neat
+
+while (( $#_d_als )); do
+  print -n autoload
+  for (( _i = 0; _i < 5; _i++ )); do
+    if (( $#_d_als )); then
+      print -n " $_d_als[1]"
+      shift _d_als
+    fi
+  done
+  print
+done >> $_d_file
+
+print >> $_d_file
+
+unset _d_line _d_zle _d_bks _d_als _d_f _f_file
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
new file mode 100644
index 000000000..ec5867838
--- /dev/null
+++ b/Completion/Core/compinit
@@ -0,0 +1,269 @@
+# Initialisation for new style completion. This mainly contains some helper
+# function and aliases. Everything else is split into different files in this
+# directory that will automatically be made autoloaded (see the end of this
+# file).
+# The names of the files that will be considered for autoloading have to
+# start with a underscores (like `_setopt).
+# The first line of these files will be read and has to say what should be
+# done with its contents:
+#
+#   `#defcomp <names ...>'
+#     if the first line looks like this, the file is
+#     autoloaded as a function and that function will
+#     be called to generate the matches when completing
+#     for one of the commands whose <name> is given
+#
+#   `#defpatcomp <pattern>'
+#     this defines a function that should be called to generate
+#     matches for commands whose name matches <pattern>; note
+#     that only one pattern may be given
+#
+#   `#defkeycomp <style> [ <key-sequence> ... ]
+#     this is used to bind special completions to all the given
+#     <key-sequence>(s). The <style> is the name of one of the built-in
+#     completion widgets (complete-word, delete-char-or-list,
+#     expand-or-complete, expand-or-complete-prefix, list-choices,
+#     menu-complete, menu-expand-or-complete, or reverse-menu-complete).
+#     This creates a widget behaving like <style> so that the
+#     completions are chosen as given in the the rest of the file,
+#     rather than by the context.  The widget has the same name as
+#     the autoload file and can be bound using bindkey in the normal way.
+#
+#   `#autoload'
+#     this is for helper functions that are not used to
+#     generate matches, but should automatically be loaded
+#     when they are called
+#
+# Note that no white space is allowed between the `#' and the rest of
+# the string.
+#
+# See the file `compdump' for how to speed up initialiation.
+#
+# If you are using global matching specifications with `compctl -M ...'
+# have a look at the files `_match_test' and `_match_pattern'. To make
+# all the example functions use matching as specified with `-M' these
+# need some editing.
+#
+# If we got the `-d'-flag, we will automatically dump the new state (at
+# the end).
+
+if [[ "$1" = -d ]]; then
+  _i_autodump=1
+else
+  _i_autodump=0
+fi
+
+# The associative array containing the definitions for the commands.
+# Definitions for patterns will be stored in the normal array `_patcomps'.
+
+typeset -A _comps
+_patcomps=()
+
+# This function is used to register or delete completion functions. For
+# registering completion functions, it is invoked with the name of the
+# function as it's first argument (after the options). The other
+# arguments depend on what type of completion function is defined. If
+# none of the `-p' and `-k' options is given a function for a command is
+# defined. The arguments after the function name are then interpreted as
+# the names of the command for which the function generates matches.
+# With the `-p' option a function for a name pattern is defined. This 
+# function will be invoked when completing for a command whose name 
+# matches the pattern given as argument after the function name (in this
+# case only one argument is accepted).
+# With the `-k' option a function for a special completion keys is 
+# defined and immediatly bound to those keys. Here, the extra arguments
+# are the name of one of the builtin completion widgets and any number
+# of key specifications as accepted by the `bindkey' builtin.
+# In any case the `-a' option may be given which makes the function
+# whose name is given as the first argument be autoloaded. When defining
+# a function for command names the `-n' option may be given and keeps
+# the definitions from overriding any previous definitions for the
+# commands.
+# For deleting definitions, the `-d' option must be given. Without the
+# `-p' option, this deletes definitions for functions for the commands
+# whose names are given as arguments. If combined with the `-p' option
+# it deletes the definitions for the patterns given as argument.
+# The `-d' option may not be combined with the `-k' option, i.e.
+# definitions for key function can not be removed.
+#
+# Examples:
+#
+#  compdef -a foo bar baz
+#    make the completion for the commands `bar' and `baz' use the
+#    function `foo' and make this function be autoloaded
+#
+#  compdef -p foo 'c*'
+#    make completion for all command whose name begins with a `c'
+#    generate matches by calling the function `foo' before generating
+#    matches defined for the command itself
+#
+#  compdef -k foo list-choices '^X^M' '\C-xm'
+#    make the function `foo' be invoked when typing `Control-X Control-M'
+#    or `Control-X m'; the function should generate matches and will
+#    behave like the `list-choices' builtin widget
+#
+#  compdef -d bar baz
+#   delete the definitions for the command names `bar' and `baz'
+
+compdef() {
+  local opt autol type func delete new i
+
+  # Get the options.
+
+  while getopts "anpkd" opt; do
+    case "$opt" in
+    a)    autol=yes;;
+    n)    new=yes;;
+    [pk]) if [[ -n "$type" ]]; then
+            # Error if both `-p' and `-k' are given (or one of them
+	    # twice).
+            echo "$0: type already set to $type"
+	    return 1
+	  fi
+	  if [[ "$opt" = p ]]; then
+	    type=pattern
+	  else
+	    type=key
+	  fi
+	  ;;
+    d) delete=yes;;
+    esac
+  done
+  shift OPTIND-1
+
+  if [[ -z "$delete" ]]; then
+    # Adding definitions, first get the name of the function name
+    # and probably do autoloading.
+
+    func="$1"
+    [[ -n "$autol" ]] && autoload "$func"
+    shift
+
+    case "$type" in
+    pattern)
+      if [[ $# -gt 1 ]]; then
+        echo "$0: only one pattern allowed"
+	return 1
+      fi
+      # Patterns are stored in strings like `c* foo', with a space
+      # between the pattern and the function name.
+
+      _patcomps=("$_patcomps[@]" "$1 $func")
+      ;;
+    key)
+      if [[ $# -lt 2 ]]; then
+        echo "$0: missing keys"
+	return 1
+      fi
+
+      # Define the widget.
+      zle -C "$func" "$1" "$func"
+      shift
+
+      # And bind the keys...
+      for i; do
+        bindkey "$i" "$func"
+      done
+      ;;
+    *)
+      # For commands store the function name in the `_comps'
+      # associative array, command names as keys.
+      for i; do
+        [[ -z "$new" || "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
+      done
+      ;;
+    esac
+  else
+    # Handle the `-d' option, deleting.
+    case "$type" in
+    pattern)
+      # Note the space.
+      for i; do
+        _patcomps=("${(@)patcomps:#$i *}")
+      done
+      ;;
+    key)
+      # Oops, cannot do that yet.
+
+      echo "$0: cannot restore key bindings"
+      return 1
+      ;;
+    *)
+      # Deleting definitons for command is even simpler.
+      for i; do
+        unset "_comps[$i]"
+      done
+    esac
+  fi
+}
+
+# Now we automatically make the definition files autoloaded.
+
+# First we get the name of a dump file if this will be used.
+
+: ${COMPDUMP:=$0.dump}
+
+if [[ ! -o extendedglob ]]; then
+  _i_noextglob=yes
+  setopt extendedglob
+fi
+
+typeset -U _i_files
+_i_files=( ${^~fpath}/_*~*~(N:t) )
+_i_initname=$0
+_i_done=''
+
+# If we have a dump file, load it.
+
+if [[ -f "$COMPDUMP" ]]; then
+  read -rA _i_line < "$COMPDUMP"
+  if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then
+    builtin . "$COMPDUMP"
+    _i_done=yes
+  fi
+  unset _i_line
+fi
+if [[ -z "$_i_done" ]]; then
+  for _i_dir in $fpath; do
+    [[ $_i_dir = . ]] && continue
+    for _i_file in $_i_dir/_*~*~(N); do
+      read -rA _i_line < $_i_file
+      _i_tag=$_i_line[1]
+      shift _i_line
+      if [[ $_i_tag = '#defcomp' ]]; then
+        compdef -na "${_i_file:t}" "${_i_line[@]}"
+      elif [[ $_i_tag = '#defpatcomp' ]]; then
+        compdef -pa "${_i_file:t}" "${_i_line[@]}"
+      elif [[ $_i_tag = '#defkeycomp' ]]; then
+        compdef -ka "${_i_file:t}" "${_i_line[@]}"
+      elif [[ $_i_tag = '#autoload' ]]; then
+	autoload ${_i_file:t}
+      fi
+    done
+  done
+
+  bindkey |
+    while read -rA _i_line; do
+      if [[ "$_i_line[2]" = complete-word ||
+	"$_i_line[2]" = delete-char-or-list ||
+	"$_i_line[2]" = expand-or-complete ||
+	"$_i_line[2]" = expand-or-complete-prefix ||
+	"$_i_line[2]" = list-choices ||
+	"$_i_line[2]" = menu-complete ||
+	"$_i_line[2]" = menu-expand-or-complete ||
+	"$_i_line[2]" = reverse-menu-complete ]]; then
+	zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
+	bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
+      fi
+    done
+
+  unset _i_dir _i_line _i_file _i_tag
+
+  # If autodumping was requested, do it now.
+
+  (( _i_autodump )) && builtin . ${_i_initname:h}/compdump
+fi
+
+[[ -z "$_i_noextglob" ]] || unsetopt extendedglob
+
+unset _i_files _i_initname _i_done _i_autodump _i_noextglob
diff --git a/Completion/README b/Completion/README
new file mode 100644
index 000000000..ac2accfca
--- /dev/null
+++ b/Completion/README
@@ -0,0 +1,107 @@
+The subdirectories contain code for the new function-based completion
+system.  Broadly speaking, this uses shell functions defined for each
+command to determine how the arguments of a command should be completed.
+
+You should copy all the files you need or want to a directory of your own,
+which should be included in your autoload path as defined by $fpath.  Then
+in your .zshrc you should source the file which appears here in
+Core/compinit.  It is recommnded that you use the -d option, which outputs
+a file containing the necessary variables, bindkeys etc., making later
+loading much faster.  For example,
+  [[ -f ~/completion/compinit ]] && . ~/completion/compinit -d
+This will rebind any keys which do completion to use the new system.
+For more detailed instructions, including how to add new completions, see
+the top of Core/compinit .
+
+The subdirectories contain:
+
+Core:
+  The basic functions and files to be sourced.  You will certainly need
+  these, and will most likely not feel like altering them (or, in some
+  cases, even reading them, unless you are a shell wizard).  The files are:
+  compinit
+    As already described, this is not a function, but is sourced once
+    (with the `source' or `.' commands) to set up the completion system.
+  compdump
+    This dumps the completions status for faster initialisation.  The
+    easiest way of doing this is to use the -d option to compinit rather
+    than calling compdump directly.
+  _comp_parts
+    Utility used for completing words with multiple separate parts, such as
+    `<user>@<host>'
+  _compalso
+    Utility for calling a function to add additional completions to an
+    already existing set.
+  _files
+    A frontend to _path_files which will default to any old file if the
+    specified file was not found.
+  _main_complete
+    The main entry point called by the key bindings which compinit sets
+    up (the main `completion widget' in zsh jargon).
+  _normal
+    The function called by _main_complete to handle the most common
+    cases, such as completing a command name or its arguments.  This
+    function dispatches to the various other functions for individual
+    commands.  (Actually, the system is fairly context-sensitive, so
+    it is wider than just command+argument.)
+  _path_files
+    The function usually called to complete filenames and directories.  It
+    replaces the standard -f and -/ options for the basic completion
+    commands:  it can do various extra tricks, such as expanding a whole
+    path at once, e.g. F/C/C/_p<TAB> -> Functions/Completion/Core/_path_files
+Base:
+  You will almost certainly want these files, too, which handle standard
+  tasks like completing files.  However, you may want to edit them for
+  your own particular setup.  Files are:
+  _command_names
+    This handles completion of the command word, i.e. the first thing
+    on the command line.  You may want to alter this, for example,
+    to complete parameters to assign to.
+  _condition
+    This handles completing inside [[ ... ]] .
+  _default
+    This handles completion of command arguments when no special function
+    exists.  Usually this means completing files, but you can modify this
+    as you wish.
+  _match_pattern
+  _match_test
+    These are used by Base/_path_files (and hence also Base/_files) for
+    file completion with control over matching (whether to complete
+    case-insensitively, or to allow insertion before `.', etc.)  See
+    _match_test for instructions.  Note _path_files expects these files
+    to be present.
+  _precommand
+    Allows completion when the first word on the line has to be ignored,
+    for example `noglob ...' should ignore the noglob and just complete
+    as if it wasn't there.  Add other such commands to the top line.
+  _redirect
+    Completes after `<' or `<': this version calls _files.
+  _subscript
+    For completion in subscripts of parameters, e.g $foo[...].
+  _vars
+    Completion for commands which need variables (so this could also be in
+    the Builtins directory), but also in math environments such as ((...)).
+Builtins:
+  Define completions for various shell builtins.  The top line of each file
+  says which builtins they apply to; in many cases you can guess from the
+  name.  Note in particular that _zftp defines completions for all commands
+  beginning `zf', not just for the module command zftp.  This is only
+  really useful if you use zftp with the zf* function suite (zfopen, zfget,
+  ...).
+User:
+  This contains a pot pourri of completions for various external commands.
+  Not all will work unmodified on your system.
+Commands:
+  These functions define separate completion commands which do not use
+  the usual context information, and hence have to be bound separately
+  to keys.  As they appear, they have bindings which you can change or
+  delete by altering the top line of the file.  To bind a function
+  (strictly speaking, the corresponding completion widget) yourself
+  after completion is loaded, use `bindkey '<key-string>' <_function_name>'.
+  The files are:
+  _correct_filename, bound to \C-xc
+    Correct the word under the cursor as a filename.  This is significantly
+    more powerful than the standard \e$ (spell-word) binding.
+  _most_recent_file, bound to \C-xm
+    Insert the name of the most recent file matching the pattern
+    so far on the command line.
diff --git a/Completion/User/_a2ps b/Completion/User/_a2ps
new file mode 100644
index 000000000..9aa9d3d99
--- /dev/null
+++ b/Completion/User/_a2ps
@@ -0,0 +1,22 @@
+#defcomp a2ps
+
+if [[ -prefix -- ]]; then
+  _comp_parts '(--borders --compact --truncate-lines --interpret
+                --print-anyway --delegate)' '=' '(yes no)'
+  _comp_parts '(--major)' '=' '(rows columns)'
+  _comp_parts '(--end-of-line)' '=' '(r n nr rn any)'
+
+  complist -S= -k '(--medium --columns --rows --line-numbers
+                    --font-size --lines-per-page --chars-per-line
+ 		    --tabsize --non-printable-format --encoding
+		    --title --stdin --prologue --highlight-level
+		    --strip-level --output --version-control --suffix
+		    --printer --copies --sides --page-prefeed
+		    --no-page-prefeed)'
+  complist -qS= -k '(--margin --header --underlay --left-title
+                     --right-title --left-footer --footer --right-footer
+		     --pages --pretty-print)'
+  complist -k '(--landscape --portrait --catman --no-header)'
+else
+  _files -F fignore -g "*~*.ps"
+fi
diff --git a/Completion/User/_compress b/Completion/User/_compress
new file mode 100644
index 000000000..860aeb5b0
--- /dev/null
+++ b/Completion/User/_compress
@@ -0,0 +1,3 @@
+#defcomp compress
+
+_files -g '*~*.Z'
diff --git a/Completion/User/_configure b/Completion/User/_configure
new file mode 100644
index 000000000..de8d5fba5
--- /dev/null
+++ b/Completion/User/_configure
@@ -0,0 +1,12 @@
+#defcomp configure
+
+if [[ $PREFIX = *=* ]]; then
+  # Complete filenames after e.g. --prefix=
+  IPREFIX=${PREFIX%%=*}=
+  PREFIX=${PREFIX#*=}
+  complist -f
+else
+  # Generate a list of options from configure --help
+  complist -s '$($COMMAND --help |
+  sed -n -e '\''s/^ *\(--[-a-z0-9]*\)[    =,].*$/\1/p'\'')'
+fi
diff --git a/Completion/User/_dd b/Completion/User/_dd
new file mode 100644
index 000000000..2458541ea
--- /dev/null
+++ b/Completion/User/_dd
@@ -0,0 +1,13 @@
+#defcomp dd
+
+if [[ -iprefix conv= ]]; then
+  # If there's a comma present, ignore up to the last one.  The
+  # test alone will have that effect.
+  [[ -string , ]]
+  complist -S, -q \
+  -k '(ascii ebcdic ibm block unblock lcase ucase swab noerror sync)'
+elif [[ -iprefix 'if=' || -iprefix 'of=' ]]; then
+  _files
+else
+  complist -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)'
+fi
diff --git a/Completion/User/_dvi b/Completion/User/_dvi
new file mode 100644
index 000000000..bb2fc293e
--- /dev/null
+++ b/Completion/User/_dvi
@@ -0,0 +1,3 @@
+#defcomp xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype
+
+_files -g '*.(dvi|DVI)'
diff --git a/Completion/User/_find b/Completion/User/_find
new file mode 100644
index 000000000..ca4f79908
--- /dev/null
+++ b/Completion/User/_find
@@ -0,0 +1,21 @@
+#defcomp find
+
+if [[ -mbetween -(ok|exec) \\\; ]]; then
+  _normal "$@"
+elif [[ -iprefix - ]]; then
+  complist -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'
+elif [[ -position 1 ]]; then
+  complist -g '. ..'
+  _files -g '(-/)'
+elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]]; then
+  _files
+elif [[ -current -1 -fstype ]]; then
+  complist -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)'
+elif [[ -current -1 -group ]]; then
+  complist -k groups
+elif [[ -current -1 -user ]]; then
+  complist -u
+fi
diff --git a/Completion/User/_gunzip b/Completion/User/_gunzip
new file mode 100644
index 000000000..35a27e774
--- /dev/null
+++ b/Completion/User/_gunzip
@@ -0,0 +1,3 @@
+#defcomp gunzip zcat
+
+_files -g '*.[gG][z]'
diff --git a/Completion/User/_gzip b/Completion/User/_gzip
new file mode 100644
index 000000000..3cda1e4ed
--- /dev/null
+++ b/Completion/User/_gzip
@@ -0,0 +1,3 @@
+#defcomp gzip
+
+_files -g '*~*.[gG][zZ]'
diff --git a/Completion/User/_hosts b/Completion/User/_hosts
new file mode 100644
index 000000000..3acc327ac
--- /dev/null
+++ b/Completion/User/_hosts
@@ -0,0 +1,3 @@
+#defcomp ftp ncftp ping rwho rup xping traceroute nslookup
+
+complist -k hosts
diff --git a/Completion/User/_make b/Completion/User/_make
new file mode 100644
index 000000000..d576b0308
--- /dev/null
+++ b/Completion/User/_make
@@ -0,0 +1,3 @@
+#defcomp make gmake pmake
+
+complist -s "\$(awk '/^[a-zA-Z0-9][^/ 	]+:/ {print \$1}' FS=: [mM]akefile)"
diff --git a/Completion/User/_man b/Completion/User/_man
new file mode 100644
index 000000000..8204fba0b
--- /dev/null
+++ b/Completion/User/_man
@@ -0,0 +1,11 @@
+#defcomp man
+setopt localoptions rcexpandparam
+
+local rep
+if [[ $2 = (<->*|ln) ]]; then
+  rep=( $manpath/(man|cat)$2/$PREFIX*$SUFFIX.<->*(N:t:r) )
+else
+  rep=( $manpath/(man|cat)*/$PREFIX*$SUFFIX.<->*(N:t:r) )
+fi
+
+(( $#rep )) && compadd -m $rep
diff --git a/Completion/User/_mh b/Completion/User/_mh
new file mode 100644
index 000000000..67ce49fd2
--- /dev/null
+++ b/Completion/User/_mh
@@ -0,0 +1,70 @@
+#defcomp folder comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath mhpatch
+
+# Completion for all possible MH commands.
+# Alter the following two to your own mh directory and the directory
+# where standard mh library files live.  (It works anyway, but this
+# will save a little time.)
+local mymhdir=~/Mail
+local mhlib=/usr/lib/mh
+
+# To be on the safe side, check this exists and if not, get it anyway.
+[[ -d $mymhdir ]] || mymhdir=$(mhpath +)
+
+if [[ -iprefix - ]]; then
+  # get list of options, which MH commands can generate themselves
+  # awk is just too icky to use for this, sorry.  send me one if
+  # you come up with it.
+  compadd -m $($COMMAND -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
+    $n = $1;
+    $n =~ s/\)//g;
+    print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n";
+  }')
+  return
+elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then
+  # Complete folder names.
+  local mhpath
+  if [[ $IPREFIX != '@' ]]; then
+    [[ $IPREFIX = '+' ]] || IPREFIX=+
+    mhpath=$mymhdir
+  else
+    mhpath=$(mhpath)
+  fi
+
+  # painless, or what?
+  complist -W mhpath -/
+elif [[ -mcurrent -1 -(editor|(whatnow|rmm|show|more)proc) ]]; then
+  complist -c
+elif [[ -current -1 -file ]]; then
+  complist -f
+elif [[ -mcurrent -1 -(form|audit|filter) ]]; then
+  # Need some MH template file, which may be in our own MH directory
+  # or with the standard library.
+  local mhfpath
+  # This is the only place we need mhlib, so leave the test till here.
+  [[ -d $mhlib ]] || { mhlib=$(mhparam mhlproc); mhlib=$mhlib:h; }
+  mhfpath=($mymhdir $mhlib)
+
+  complist -W mhfpath -g '*(.)'
+elif [[ -mcurrent -1 -(no|)cc ]]; then
+  compadd -m all to cc me
+elif [[ -mcurrent -1 -[rw]cache ]]; then
+  compadd -m public private never ask
+else
+  # Generate sequences.
+  local foldnam folddir f
+  for f in $argv; do
+    [[ $f = [@+]* ]] && foldnam=$f
+  done
+  if [[ $foldnam = '+'* ]]; then
+    folddir=$mymhdir/${foldnam#+}
+  elif [[ $foldnam = '@'* ]]; then
+    folddir=$(mhpath)/${foldnam#@}
+  else
+    folddir=$(mhpath)
+    # leaving foldnam empty works here
+  fi
+
+  complist -s '$(mark $foldnam | awk -F: '\''{ print $1 }'\'')'
+  compadd -m reply next cur prev first last all unseen
+  complist -W folddir -g '<->'
+fi
diff --git a/Completion/User/_pdf b/Completion/User/_pdf
new file mode 100644
index 000000000..7d7756c3e
--- /dev/null
+++ b/Completion/User/_pdf
@@ -0,0 +1,3 @@
+function acroread
+
+_files -g '*.(pdf|PDF)'
diff --git a/Completion/User/_ps b/Completion/User/_ps
new file mode 100644
index 000000000..6bc0643b2
--- /dev/null
+++ b/Completion/User/_ps
@@ -0,0 +1,3 @@
+#defcomp  gs ghostview gview psnup psselect pswrap pstops pstruct lpr
+
+_files -g '*([pP][sS]|eps)'
diff --git a/Completion/User/_rcs b/Completion/User/_rcs
new file mode 100644
index 000000000..537db6278
--- /dev/null
+++ b/Completion/User/_rcs
@@ -0,0 +1,9 @@
+#defcomp co ci rcs
+
+[[ $COMMAND = ci || $COMMAND = rcs ]] && _files
+
+if [[ $NMATCHES -eq 0 && -d RCS && $COMMAND != ci ]]; then
+  local rep
+  rep=(RCS/$PREFIX*$SUFFIX,v(:t:s/\,v//))
+  (( $#rep )) && compadd -m $rep
+fi
diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin
new file mode 100644
index 000000000..e36554f23
--- /dev/null
+++ b/Completion/User/_rlogin
@@ -0,0 +1,9 @@
+#defcomp rlogin rsh ssh
+
+if [[ -position 1 ]]; then
+  complist -k hosts
+elif [[ -position 2 ]]; then
+  complist -k '(-l)'
+else
+  complist -u
+fi
diff --git a/Completion/User/_strip b/Completion/User/_strip
new file mode 100644
index 000000000..6962ac455
--- /dev/null
+++ b/Completion/User/_strip
@@ -0,0 +1,2 @@
+#defcomp strip
+_files -g '*(*)'
diff --git a/Completion/User/_stty b/Completion/User/_stty
new file mode 100644
index 000000000..6b54b5007
--- /dev/null
+++ b/Completion/User/_stty
@@ -0,0 +1,16 @@
+#defcomp stty
+
+if [[ -mcurrent -1 \
+  (*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]]
+then
+     compadd -m -Q '^-' '^h' '^?' '^c' '^u'
+else
+  [[ -string '-' || -string '+' ]]
+  compadd -m rows columns intr quit erase kill eof eol \
+    eol2 start stop susp dsusp reprint discard werase lnext \
+    parenb parodd cs8 cstopb hupcl cread clocal parext \
+    ignbrk brkint ignpar parmrk inpck istrip inlcr igncr icrnl iuclc \
+    ixon ixany ixoff imaxbel isig icanon xcase echo echoe echok \
+    echonl noflsh tostop echoctl echoprt echoke flusho pending iexten \
+    opost olcuc onlcr ocrnl onocr onlret ofill ofdel 
+fi
diff --git a/Completion/User/_tar b/Completion/User/_tar
new file mode 100644
index 000000000..91767e44d
--- /dev/null
+++ b/Completion/User/_tar
@@ -0,0 +1,11 @@
+#defcomp tar
+
+local nm=$NMATCHES tf="$2"
+
+if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]]; then
+  complist -k "( $(tar tf $tf) )"
+elif [[ -mword 1 *c*f* && -position 3 100000 ]]; then
+  _files
+elif [[ -mcurrent -1 *f* && -position 2 ]]; then
+  _files -g '*.(tar|TAR)'
+fi
diff --git a/Completion/User/_tex b/Completion/User/_tex
new file mode 100644
index 000000000..1f645e2a2
--- /dev/null
+++ b/Completion/User/_tex
@@ -0,0 +1,3 @@
+#defcomp tex latex slitex
+
+_files -g '*.(tex|TEX|texinfo|texi)'
diff --git a/Completion/User/_uncompress b/Completion/User/_uncompress
new file mode 100644
index 000000000..e25805d50
--- /dev/null
+++ b/Completion/User/_uncompress
@@ -0,0 +1,3 @@
+#defcomp uncompress zmore
+
+_files -g '*.Z'
diff --git a/Completion/User/_x_options b/Completion/User/_x_options
new file mode 100644
index 000000000..cc469286d
--- /dev/null
+++ b/Completion/User/_x_options
@@ -0,0 +1,5 @@
+#defpatcomp */X11/*
+
+# A simple pattern completion, just as an example.
+
+complist -J options -k '(-display -name -xrm)'
diff --git a/Completion/User/_xfig b/Completion/User/_xfig
new file mode 100644
index 000000000..fcd2bba9f
--- /dev/null
+++ b/Completion/User/_xfig
@@ -0,0 +1,3 @@
+#defcomp xfig
+
+_files -g '*.fig'
diff --git a/Config/version.mk b/Config/version.mk
index 3e36faf5c..496dea13a 100644
--- a/Config/version.mk
+++ b/Config/version.mk
@@ -27,5 +27,5 @@
 # This must also serve as a shell script, so do not add spaces around the
 # `=' signs.
 
-VERSION=3.1.5-pws-9
-VERSION_DATE='February 18, 1999'
+VERSION=3.1.5-pws-10
+VERSION_DATE='February 26, 1999'
diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo
index 2cb12e2c2..4208317fb 100644
--- a/Doc/Zsh/compwid.yo
+++ b/Doc/Zsh/compwid.yo
@@ -162,7 +162,7 @@ xitem(tt(compadd) [ tt(-qQfnUam) ] [ tt(-F) var(array) ])
 xitem([ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ])
 xitem([ tt(-p) var(hidden-prefix) ] [ tt(-s) var(hidden-suffix) ])
 xitem([ tt(-i) var(ignored-prefix) ] [ tt(-W) var(file-prefix) ])
-xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ])
+xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ])
 xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
 item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])(
 
@@ -182,14 +182,17 @@ item(tt(-S) var(suffix))(
 Like tt(-P) but gives a string that has to be inserted after the match.
 )
 item(tt(-p) var(hidden-prefix))(
-This gives a string that should be 
-...
+This gives a string that should be inserted in the line before the
+match but that should not appear in the list of matches.
 )
 item(tt(-s) var(hidden-suffix))(
-...
+Like `tt(-p)', but gives a string to insert after the match.
 )
 item(tt(-i) var(ignored-prefix))(
-...
+This gives a string to insert into the command line just before any
+string given with the `tt(-P)' option. Without `tt(-P)' the string is
+inserted before the string given with `tt(-p)' or directly before the
+match.
 )
 item(tt(-J) var(name))(
 As for tt(compctl) and tt(complist) this gives the name of the group
@@ -198,6 +201,10 @@ of matches the words should be stored in.
 item(tt(-V) var(name))(
 Like tt(-J) but naming a unsorted group.
 )
+item(tt(-X) var(explanation))(
+The var(explanation) string will be printed with the list of matches,
+as for tt(compctl -X).
+)
 item(tt(-q))(
 This flag has the same meaning as for tt(compctl) and tt(complist),
 too. It makes the suffix given with tt(-S) be automatically removed if 
@@ -382,15 +389,19 @@ given, it is true if the number of words is equal to or greater than
 var(min) and equal to or less than var(max)
 )
 item(tt(-after) var(string))(
-true if the cursor is after a word that is equal to var(string)
+true if the cursor is after a word that is equal to var(string); this
+removes all words up to and including the matched word from the
+positional parameters
 )
 item(tt(-mafter) var(pattern))(
 like tt(-after) but using pattern matching
 )
 item(tt(-between) var(string1) var(string2))(
 true if the cursor is after a word that is equal to var(string1), if
-there is also a word that is equal to va(string2), this is true only
-if the cursor is before it
+there is also a word that is equal to var(string2), this is true only
+if the cursor is before it; as a side effect, all words before
+var(string1) and after var(string2) (both inclusive) are removed from
+the positional parameters
 )
 item(tt(-mbetween) var(pattern1) var(pattern2))(
 like tt(-between) but using pattern matching
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index ccf245367..fa56bc0af 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -869,7 +869,7 @@ can be specified by separating two characters by a `tt(-)'.
 A `tt(-)' or `tt(])' may be matched by including it as the
 first character in the list.
 There are also several named classes of characters, in the form
-`tt([:)var(name)(tt:])' with the following meanings:  `tt([:alnum:])'
+`tt([:)var(name)tt(:])' with the following meanings:  `tt([:alnum:])'
 alphanumeric, `tt([:alpha:])' alphabetic,
 `tt([:blank:])' space or tab,
 `tt([:cntrl:])' control character, `tt([:digit:])' decimal
@@ -988,12 +988,18 @@ item(I)(
 Case sensitive:  locally negates the effect of tt(i) or tt(l) from
 that point on.
 )
+item(tt(a)var(num))(
+Approximate matching: var(num) errors are allowed in the string matched by
+the pattern.  The rules for this are described in the next subsection.
+)
 enditem()
 
 For example, the test string tt(fooxx) can be matched by the pattern
 tt(LPAR()#i)tt(RPAR()FOOXX), but not by tt(LPAR()#l)tt(RPAR()FOOXX),
 tt(LPAR()#i)tt(RPAR()FOO)tt(LPAR()#I)tt(RPAR()XX) or
-tt(LPAR()LPAR()#i)tt(RPAR()FOOX)tt(RPAR()X).
+tt(LPAR()LPAR()#i)tt(RPAR()FOOX)tt(RPAR()X).  The string
+tt(LPAR()#ia2)tt(RPAR()readme) specifies case-insensitive matching of
+tt(readme) with up to two errors.
 
 When using the ksh syntax for grouping both tt(KSH_GLOB) and
 tt(EXTENDED_GLOB) must be set and the left parenthesis should be
@@ -1004,6 +1010,61 @@ examining whole paths case-insensitively every directory must be
 searched for all files which match, so that a pattern of the form
 tt(LPAR()#i)tt(RPAR()/foo/bar/...) is potentially slow.
 
+subsect(Approximate Matching)
+When matching approximately, the shell keeps a count of the errors found,
+which cannot exceed the number specified in the
+tt(LPAR()#a)var(num)tt(RPAR()) flags.  Four types of error are recognised:
+
+startitem()
+item(1.)(
+Different characters, as in tt(fooxbar) and tt(fooybar).
+)
+item(2.)(
+Transposition of characters, as in tt(banana) and tt(abnana).
+)
+item(3.)(
+A character missing in the target string, as with the pattern tt(road) and
+target string tt(rod).
+)
+item(4.)(
+An extra character appearing in the target string, as with tt(stove)
+and tt(strove).
+)
+enditem()
+
+Thus, the pattern tt(LPAR()#a3)tt(RPAR()abcd) matches tt(dcba), with the
+errors occurring by using the first rule twice and the second once,
+grouping the string as tt([d][cb][a]) and tt([a][bc][d]).
+
+Non-literal parts of the pattern must match exactly, including characters
+in character ranges: hence tt(LPAR()#a1)tt(RPAR()???)  matches strings of
+length four, by applying rule 4 to an empty part of the pattern, but not
+strings of length three, since all the tt(?) must match.  Other characters
+which must match exactly are initial dots in filenames (unless the
+tt(GLOB_DOTS) option is set), and all slashes in file names, so that
+tt(a/bc) is two errors from tt(ab/c) (the slash cannot be transposed with
+another character).  Similarly, errors are counted separately for
+non-contiguous strings in the pattern, so that tt(LPAR()ab|cd)tt(RPAR()ef)
+is two errors from tt(aebf).
+
+When using exclusion via the tt(~) operator, approximate matching is
+treated entirely separately for the excluded part and must be activated
+separately.  Thus, tt(LPAR()#a1)tt(RPAR()README~READ_ME) matches
+tt(READ.ME) but not tt(READ_ME), as the trailing tt(READ_ME) is matched
+without approximation.  However,
+tt(LPAR()#a1)tt(RPAR()README~LPAR()#a1)tt(RPAR()READ_ME)
+does not match any pattern of the form tt(READ)var(?)tt(ME) as all
+such forms are now excluded.
+
+Apart from exclusions, there is only one overall error count; however, the
+maximum errors allowed may be altered locally, and this can be delimited by
+grouping.  For example,
+tt(LPAR()#a1)tt(RPAR()cat)tt(LPAR()LPAR()#a0)tt(RPAR()dog)tt(RPAR()fox)
+allows one error in total, which may not occur in the tt(dog) section, and
+the pattern
+tt(LPAR()#a1)tt(RPAR()cat)tt(LPAR()#a0)tt(RPAR()dog)tt(LPAR()#a1)tt(RPAR()fox)
+is equivalent.
+
 subsect(Recursive Globbing)
 A pathname component of the form `tt(LPAR())var(foo)tt(/RPAR()#)'
 matches a path consisting of zero or more directories
diff --git a/Doc/Zsh/guide.yo b/Doc/Zsh/guide.yo
index e0005e339..96e12fc58 100644
--- a/Doc/Zsh/guide.yo
+++ b/Doc/Zsh/guide.yo
@@ -144,8 +144,8 @@ then be processed with bf(dvips) and optionally bf(gs) (Ghostscript) to
 produce a nicely formatted printed guide.
 )
 item(The HTML guide)(
-Mark Borges, tt(<mdb@cdc.noaa.gov), maintains an HTML version of this
-guide at tt(http://www.peak.org/zsh/Doc/zsh_toc.html).
+An HTML version of this guide is available at the Zsh web site via
+tt(http://sunsite.auc.dk/zsh/Doc/index.html).
 (The HTML version is produced with bf(texi2html), which may be obtained
 from tt(http://wwwcn.cern.ch/dci/texi2html/). The command is
 `tt(texi2html -split_chapter -expandinfo zsh.texi)'.)
diff --git a/Misc/globtests b/Misc/globtests
index 9a12a11e1..3bd634ca9 100755
--- a/Misc/globtests
+++ b/Misc/globtests
@@ -103,6 +103,7 @@ t :]            [:]]#
 t [             [[]
 t ]             []]
 t []            [^]]]
+# Case insensitive matching
 t fooxx         (#i)FOOXX
 f fooxx         (#l)FOOXX
 t FOOXX         (#l)fooxx
@@ -113,5 +114,36 @@ f fooxx         ((#i)FOOX)X
 f BAR           (bar|(#i)foo)
 t FOO           (bar|(#i)foo)
 t Modules       (#i)*m*
+# Approximate matching
+t READ.ME       (#ia1)readme
+f READ..ME      (#ia1)readme
+t README        (#ia1)readm
+t READM         (#ia1)readme
+t README        (#ia1)eadme
+t EADME         (#ia1)readme
+t READEM        (#ia1)readme
+f ADME          (#ia1)readme
+f README        (#ia1)read
+t bob           (#a1)[b][b]
+f bob           (#a1)[b][b]a
+t bob           (#a1)[b]o[b]a
+f bob           (#a1)[c]o[b]
+t abcd          (#a2)XbcX
+t abcd          (#a2)ad
+t ad            (#a2)abcd
+t abcd          (#a2)bd
+t bd            (#a2)abcd
+t badc          (#a2)abcd
+# This next one is a little tricky: a[d]bc[] = a[]bc[d]
+t adbc          (#a2)abcd
+f dcba          (#a2)abcd
+# the next one is [d][cb][a] = [a][bc][d] with a transposition
+t dcba          (#a3)abcd
+t aabaXaaabY    (#a1)(a#b)#Y
+t aabaXaaabY    (#a1)(a#b)(a#b)Y
+t aaXaaaaabY    (#a1)(a#b)(a#b)Y
+f read.me       (#ia1)README~READ.ME
+t read.me       (#ia1)README~READ_ME
+f read.me       (#ia1)README~(#a1)READ_ME
 EOT
 print "$failed tests failed."
diff --git a/Src/.cvsignore b/Src/.cvsignore
index edec5401b..fcef4da67 100644
--- a/Src/.cvsignore
+++ b/Src/.cvsignore
@@ -19,6 +19,7 @@ zsh
 libzsh.so*
 sigcount.h
 signames.c
+version.h
 zshpaths.h
 zshxmods.h
 bltinmods.list
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 2af8dc6ac..7825a900d 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -37,7 +37,7 @@
 
 # include "rlimits.h"
 
-# if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_UNSIGNED)
+# if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_LONG_LONG) || defined(RLIM_T_IS_UNSIGNED)
 static rlim_t
 zstrtorlimt(const char *s, char **t, int base)
 {
@@ -62,9 +62,9 @@ zstrtorlimt(const char *s, char **t, int base)
 	*t = (char *)s;
     return ret;
 }
-# else /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_UNSIGNED */
+# else /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */
 #  define zstrtorlimt(a, b, c)	zstrtol((a), (b), (c))
-# endif /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_UNSIGNED */
+# endif /* !RLIM_T_IS_QUAD_T && !RLIM_T_IS_LONG_LONG && !RLIM_T_IS_UNSIGNED */
 
 /* Display resource limits.  hard indicates whether `hard' or `soft'  *
  * limits should be displayed.  lim specifies the limit, or may be -1 *
@@ -107,9 +107,15 @@ showlimits(int hard, int lim)
 	    else
 		printf("%qdkB\n", val / 1024L);
 # else
+#  ifdef RLIM_T_IS_LONG_LONG
+		printf("%lldMB\n", val / (1024L * 1024L));
+            else
+		printf("%lldkB\n", val / 1024L);
+#  else
 		printf("%ldMB\n", val / (1024L * 1024L));
             else
 		printf("%ldkB\n", val / 1024L);
+#  endif /* RLIM_T_IS_LONG_LONG */
 # endif /* RLIM_T_IS_QUAD_T */
 	}
 }
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 0d5419817..76ac67114 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -271,9 +271,10 @@ struct cline {
 #define CLF_MISS   4
 #define CLF_DIFF   8
 #define CLF_SUF   16
-#define CLF_NEW   32
-#define CLF_VAR   64
-#define CLF_JOIN 128
+#define CLF_PNEW  32
+#define CLF_SNEW  64
+#define CLF_VAR  128
+#define CLF_JOIN 256
 
 /* Flags for makecomplist*(). Things not to do. */
 
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index 77fe0a1fe..72f3cea53 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -49,10 +49,10 @@ void (*makecompparamsptr) _((void));
 /* pointers to functions required by compctl and defined by zle */
 
 /**/
-void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char **));
+void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **));
 
 /**/
-char *(*comp_strptr) _((int*,int*));
+char *(*comp_strptr) _((int*, int*, int));
 
 /**/
 int (*getcpatptr) _((char *, int, char *, int));
@@ -410,6 +410,7 @@ setup_comp1(Module m)
     cc_first.mask2 = CC_CCCONT;
     compcontext = compcommand = compprefix = compsuffix =
 	compiprefix = NULL;
+    makecompparamsptr = NULL;
     return 0;
 }
 
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index e3b778508..f71d67510 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1676,7 +1676,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
     char *p, **sp, *e;
     char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
     char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
-    char *ign = NULL, *rf = NULL;
+    char *ign = NULL, *rf = NULL, *expl = NULL;
     int f = 0, a = 0, dm;
     Cmatcher match = NULL;
 
@@ -1757,6 +1757,10 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 		e = "matching specification expected after -%c";
 		dm = 1;
 		break;
+	    case 'X':
+		sp = &expl;
+		e = "string expected after -%c";
+		break;
 	    case 'r':
 		f |= CMF_REMOVE;
 		sp = &rs;
@@ -1802,7 +1806,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 
     match = cpcmatcher(match);
     addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group,
-		  rs, rf, ign, f, a, match, argv);
+		  rs, rf, ign, f, a, match, expl, argv);
     freecmatcher(match);
 
     return 0;
@@ -2049,8 +2053,8 @@ cond_strcl(char **a, int id)
 	    zerr("zle not loaded, zle condition not available", NULL, 0);
 	    return 1;
 	}
-	i = getcpatptr(comp_strptr(&ipl, NULL), i, s, id);
-	if (i != -1) {
+	i = getcpatptr(comp_strptr(&ipl, NULL, 1), i, s, id);
+	if (i != -1 && i >= ipl) {
 	    ignore_prefix(i - ipl);
 	    return 1;
 	}
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index d055c45c1..28781e7f0 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -478,6 +478,17 @@ bin_zle_complete(char *name, char **args, char *ops, char func)
     Thingy t;
     Widget w, cw;
 
+#ifdef DYNAMIC
+    if (!require_module(name, "compctl", 0, 0)) {
+	zerrnam(name, "can't load compctl module", NULL, 0);
+	return 1;
+    }
+#else
+    if (!makecompparamsptr) {
+	zerrnam(name, "compctl module not available", NULL, 0);
+	return 1;
+    }
+#endif
     t = rthingy(args[1]);
     cw = t->widget;
     unrefthingy(t);
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index af78e1c06..4b42640e1 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -214,11 +214,9 @@ static Cmlist mstack;
 
 /* The completion matchers used when building new stuff for the line. */
 
-static struct cmlist bmstack0, bmstack1;
-static Cmlist bmstack;
-static int had_lm;
+static Cmlist bmatchers;
 
-/* A list with references to all matcher we used. */
+/* A list with references to all matchers we used. */
 
 static LinkList matchers;
 
@@ -293,12 +291,24 @@ enum { COMP_COMPLETE,
 
 static int lastambig;
 
-/* Non-zero if the string on the line came from a previous completion. *
- * This is used to detect if the string should be taken as an exact    *
- * match (see do_ambiguous()).                                         */
+/* This says what of the state the line is in when completion is started *
+ * came from a previous completion. If the FC_LINE bit is set, the       *
+ * string was inserted. If FC_INWORD is set, the last completion moved   *
+ * the cursor into the word although it was at the end of it when the    *
+ * last completion was invoked.                                          *
+ * This is used to detect if the string should be taken as an exact      *
+ * match (see do_ambiguous()) and if the cursor has to be moved to the   *
+ * end of the word before generating the completions.                    */
 
 static int fromcomp;
 
+/* This holds the end-position of the last string inserted into the line. */
+
+static int lastend;
+
+#define FC_LINE   1
+#define FC_INWORD 2
+
 /**/
 void
 completecall(void)
@@ -607,6 +617,12 @@ docomplete(int lst)
 	return;
     }
 
+    /* We may have to reset the cursor to its position after the   *
+     * string inserted by the last completion. */
+
+    if (fromcomp & FC_INWORD)
+	cs = lastend;
+
     /* Check if we have to start a menu-completion (via automenu). */
 
     if ((amenu = (isset(AUTOMENU) && lastambig &&
@@ -1567,6 +1583,83 @@ addtocline(Cline *retp, Cline *lrp,
     *lrp = ln;
 }
 
+/* This compares two cpattern lists and returns non-zero if they are
+ * equal. */
+
+static int
+cmp_cpatterns(Cpattern a, Cpattern b)
+{
+    while (a) {
+	if (a->equiv != b->equiv || memcmp(a->tab, b->tab, 256))
+	    return 0;
+	a = a->next;
+	b = b->next;
+    }
+    return 1;
+}
+
+/* This compares two cmatchers and returns non-zero if they are equal. */
+
+static int
+cmp_cmatchers(Cmatcher a, Cmatcher b)
+{
+    return (a == b ||
+	    (a->flags == b->flags &&
+	     a->llen == b->llen && a->wlen == b->wlen &&
+	     (!a->llen || cmp_cpatterns(a->line, b->line)) &&
+	     (a->wlen <= 0 || cmp_cpatterns(a->word, b->word)) &&
+	     (!(a->flags & CMF_LEFT) ||
+	      (a->lalen == b->lalen &&
+	       (!a->lalen || cmp_cpatterns(a->left, b->left)))) &&
+	     (!(a->flags & CMF_RIGHT) ||
+	      (a->ralen == b->ralen &&
+	       (!a->ralen || cmp_cpatterns(a->right, b->right))))));
+}
+
+/* Add the given matchers to the bmatcher list. */
+
+static void
+add_bmatchers(Cmatcher m)
+{
+    Cmlist old = bmatchers, *q = &bmatchers, n;
+
+    for (; m; m = m->next) {
+	if ((!m->flags && m->wlen > 0 && m->llen > 0) ||
+	    (m->flags == CMF_RIGHT && m->wlen == -1 && !m->llen)) {
+	    *q = n = (Cmlist) halloc(sizeof(struct cmlist));
+	    n->matcher = m;
+	    q = &(n->next);
+	}
+    }
+    *q = old;
+}
+
+/* This is called when the matchers in the mstack have changed to
+ * ensure that the bmatchers list contains no matchers not in mstack. */
+
+static void
+update_bmatchers(void)
+{
+    Cmlist p = bmatchers, q = NULL, ms;
+    Cmatcher mp;
+    int t;
+
+    while (p) {
+	t = 0;
+	for (ms = mstack; ms && !t; ms = ms->next)
+	    for (mp = ms->matcher; mp && !t; mp = mp->next)
+		t = cmp_cmatchers(mp, p->matcher);
+
+	p = p->next;
+	if (!t) {
+	    if (q)
+		q->next = p;
+	    else
+		bmatchers = p;
+	}
+    }
+}
+
 /* When building up cline lists that are to be inserted at the end of the
  * string or on the left hand side in the middle, we do this separately for
  * multiple runs of characters separated by the anchors of `*' match patterns.
@@ -1582,21 +1675,20 @@ end_list(int len, char *str)
     char *p = str;
 
     while (len) {
-	for (t = 0, ms = bmstack; ms && !t; ms = ms->next) {
-	    for (mp = ms->matcher; mp && !t; mp = mp->next) {
-		if (mp->flags == CMF_RIGHT && mp->wlen == -1 &&
-		    !mp->llen && len >= mp->ralen && mp->ralen &&
-		    pattern_match(mp->right, str, NULL, NULL)) {
-		    /* This is one of those patterns, so add a cline struct.
-		     * We store the anchor string in the line and the contents
-		     * (i.e. the strings between the anchors) in the word field. */
-		    *q = getcline(str, mp->ralen, p, str - p, 0);
-		    q = &((*q)->next);
-		    str += mp->ralen;
-		    len -= mp->ralen;
-		    p = str;
-		    t = 1;
-		}
+	for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
+	    mp = ms->matcher;
+	    if (mp->flags == CMF_RIGHT && mp->wlen == -1 &&
+		!mp->llen && len >= mp->ralen && mp->ralen &&
+		pattern_match(mp->right, str, NULL, NULL)) {
+		/* This is one of those patterns, so add a cline struct.
+		 * We store the anchor string in the line and the contents
+		 * (i.e. the strings between the anchors) in the word field. */
+		*q = getcline(str, mp->ralen, p, str - p, 0);
+		q = &((*q)->next);
+		str += mp->ralen;
+		len -= mp->ralen;
+		p = str;
+		t = 1;
 	    }
 	}
 	if (!t) {
@@ -1616,7 +1708,7 @@ end_list(int len, char *str)
 
 /* This builds a string that may be put on the line that fully matches the
  * given strings. The return value is NULL if no such string could be built
- * or that string, allocated on the heap.
+ * or that string in local static memory, dup it.
  * All this is a lot like the procedure in bld_new_pfx(), only slightly
  * simpler, see that function for more comments. */
 
@@ -1644,60 +1736,59 @@ join_strs(int la, char *sa, int lb, char *sb)
     }
     while (la && lb) {
 	if (*sa != *sb) {
-	    for (t = 0, ms = bmstack; ms && !t; ms = ms->next) {
-		for (mp = ms->matcher; mp && !t; mp = mp->next) {
-		    if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
-			mp->wlen <= la && mp->wlen <= lb) {
-			if (pattern_match(mp->word, sa, NULL, ea)) {
-			    if (mp->llen + 1 > llen) {
-				if (llen)
-				    zfree(line, llen);
-				line = (char *) zalloc(llen = mp->llen + 20);
-			    }
-			    if ((bl = bld_line_pfx(mp->line, line, line,
-						   lb, sb, ea))) {
-				line[mp->llen] = '\0';
-				if (rr <= mp->llen) {
-				    char *or = rs;
-
-				    rs = realloc(rs, (rl += 20));
-				    rr += 20;
-				    rp += rs - or;
-				}
-				memcpy(rp, line, mp->llen);
-				rp += mp->llen;
-				rr -= mp->llen;
-				sa += mp->wlen;
-				sb += bl;
-				la -= mp->wlen;
-				lb -= bl;
-				t = 1;
-			    }
-			} else if (pattern_match(mp->word, sb, NULL, ea)) {
-			    if (mp->llen + 1 > llen) {
-				if (llen)
-				    zfree(line, llen);
-				line = (char *) zalloc(llen = mp->llen + 20);
+	    for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
+		mp = ms->matcher;
+		if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
+		    mp->wlen <= la && mp->wlen <= lb) {
+		    if (pattern_match(mp->word, sa, NULL, ea)) {
+			if (mp->llen + 1 > llen) {
+			    if (llen)
+				zfree(line, llen);
+			    line = (char *) zalloc(llen = mp->llen + 20);
+			}
+			if ((bl = bld_line_pfx(mp->line, line, line,
+					       lb, sb, ea))) {
+			    line[mp->llen] = '\0';
+			    if (rr <= mp->llen) {
+				char *or = rs;
+
+				rs = realloc(rs, (rl += 20));
+				rr += 20;
+				rp += rs - or;
 			    }
-			    if ((bl = bld_line_pfx(mp->line, line, line,
-						   la, sa, ea))) {
-				line[mp->llen] = '\0';
-				if (rr <= mp->llen) {
-				    char *or = rs;
-
-				    rs = realloc(rs, (rl += 20));
-				    rr += 20;
-				    rp += rs - or;
-				}
-				memcpy(rp, line, mp->llen);
-				rp += mp->llen;
-				rr -= mp->llen;
-				sa += bl;
-				sb += mp->wlen;
-				la -= bl;
-				lb -= mp->wlen;
-				t = 1;
+			    memcpy(rp, line, mp->llen);
+			    rp += mp->llen;
+			    rr -= mp->llen;
+			    sa += mp->wlen;
+			    sb += bl;
+			    la -= mp->wlen;
+			    lb -= bl;
+			    t = 1;
+			}
+		    } else if (pattern_match(mp->word, sb, NULL, ea)) {
+			if (mp->llen + 1 > llen) {
+			    if (llen)
+				zfree(line, llen);
+			    line = (char *) zalloc(llen = mp->llen + 20);
+			}
+			if ((bl = bld_line_pfx(mp->line, line, line,
+					       la, sa, ea))) {
+			    line[mp->llen] = '\0';
+			    if (rr <= mp->llen) {
+				char *or = rs;
+
+				rs = realloc(rs, (rl += 20));
+				rr += 20;
+				rp += rs - or;
 			    }
+			    memcpy(rp, line, mp->llen);
+			    rp += mp->llen;
+			    rr -= mp->llen;
+			    sa += bl;
+			    sb += mp->wlen;
+			    la -= bl;
+			    lb -= mp->wlen;
+			    t = 1;
 			}
 		    }
 		}
@@ -1725,7 +1816,7 @@ join_strs(int la, char *sa, int lb, char *sb)
 
     *rp = '\0';
 
-    return dupstring(rs);
+    return rs;
 }
 
 /* This gets two cline lists with separated runs and joins the corresponding
@@ -1752,26 +1843,55 @@ join_ends(Cline o, Cline n, int *olp, int *nlp)
 	     * and mark the cline so that we don't try to join it again. */
 	    o->flags |= CLF_JOIN;
 	    o->llen = strlen(j);
-	    o->line = j;
+	    o->line = dupstring(j);
 	    bld_pfx(o, n, &mol, &mnl);
 	    smol += mol + o->llen;
 	    smnl += mnl + n->llen;
 	} else {
-	    /* Different anchor strings, so shorten the list. */
+	    /* Different anchors, see if we can find matching anchors
+	     * further down the lists. */
+	    Cline to, tn;
+	    int t = 0;
+
+	    /* But first build the common prefix. */
 	    bld_pfx(o, n, &mol, &mnl);
 	    smol += mol;
 	    smnl += mnl;
-	    o->flags |= CLF_MISS;
-	    o->next = NULL;
-	    o->llen = 0;
-	    if (olp)
-		*olp = smol;
-	    if (nlp)
-		*nlp = smnl;
-	    return ret;
+
+	    for (to = o; to && !t; to = to->next) {
+		for (tn = n; tn && !t; tn = tn->next) {
+		    if ((t = ((to->llen == tn->llen &&
+			       !strncmp(to->line, tn->line, to->llen)) ||
+			      (!(to->flags & CLF_JOIN) &&
+			       join_strs(to->llen, to->line,
+					 tn->llen, tn->line)))))
+			break;
+		}
+		if (t)
+		    break;
+	    }
+	    if (t) {
+		/* Found matching anchors, continue with them. */
+		o->line = to->line;
+		o->llen = to->llen;
+		o->next = to->next;
+		o->flags |= CLF_MISS;
+		n = tn;
+	    } else {
+		/* No matching anchors found, shorten the list. */
+		o->flags |= CLF_MISS;
+		o->next = NULL;
+		o->llen = 0;
+		if (olp)
+		    *olp = smol;
+		if (nlp)
+		    *nlp = smnl;
+		return ret;
+	    }
 	}
 	/* If we reached the end of the new list but not the end of the old
-	 * list, we mark the old list (saying that characters are missing here). */
+	 * list, we mark the old list (saying that characters are missing 
+	 * here). */
 	if (!(n = n->next) && o->next)
 	    o->flags |= CLF_MISS;
 	o = o->next;
@@ -1859,20 +1979,19 @@ bld_line_pfx(Cpattern pat, char *line, char *lp,
 		rl++;
 	    } else {
 		t = 0;
-		for (ms = bmstack; ms && !t; ms = ms->next) {
-		    for (mp = ms->matcher; mp && !t; mp = mp->next) {
-			if (!mp->flags && mp->wlen <= wlen && mp->llen <= l &&
-			    pattern_match(mp->line, line, NULL, ea) &&
-			    pattern_match(mp->word, word, ea, NULL)) {
-			    /* Both the line and the word pattern matched,
-			     * now skip over the matched portions. */
-			    line += mp->llen;
-			    word += mp->wlen;
-			    l -= mp->llen;
-			    wlen -= mp->wlen;
-			    rl += mp->wlen;
-			    t = 1;
-			}
+		for (ms = bmatchers; ms && !t; ms = ms->next) {
+		    mp = ms->matcher;
+		    if (!mp->flags && mp->wlen <= wlen && mp->llen <= l &&
+			pattern_match(mp->line, line, NULL, ea) &&
+			pattern_match(mp->word, word, ea, NULL)) {
+			/* Both the line and the word pattern matched,
+			 * now skip over the matched portions. */
+			line += mp->llen;
+			word += mp->wlen;
+			l -= mp->llen;
+			wlen -= mp->wlen;
+			rl += mp->wlen;
+			t = 1;
 		    }
 		}
 		if (!t)
@@ -1923,100 +2042,99 @@ bld_new_pfx(int ol, char *ow, int nl, char *nw, int *olp, int *nlp, Cline *lp)
     while (ol && nl) {
 	if (*ow != *nw) {
 	    /* Not the same character, use the patterns. */
-	    for (t = 0, ms = bmstack; ms && !t; ms = ms->next) {
-		for (mp = ms->matcher; mp && !t; mp = mp->next) {
-		    /* We use only those patterns that match a non-empty
-		     * string in both the line and the word, that match
-		     * strings no longer than the string we still have
-		     * to compare, that don't have anchors, and that don't
-		     * use the line strings for insertion. */
-		    if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
-			mp->wlen <= ol && mp->wlen <= nl) {
-			/* Try the pattern only if the word-pattern matches
-			 * one of the strings. */
-			if (pattern_match(mp->word, ow, NULL, ea)) {
-			    /* Make the buffer where we build the possible
-			     * line patterns big enough. */
-			    if (mp->llen + 1 > llen) {
-				if (llen)
-				    zfree(line, llen);
-				line = (char *) zalloc(llen = mp->llen + 20);
-			    }
-			    /* Then build all the possible lines and see
-			     * if one of them matches the othe string. */
-			    if ((bl = bld_line_pfx(mp->line, line, line,
-						   nl, nw, ea))) {
-				/* Yep, one of the lines matched the other
-				 * string. */
-				if (p != ow) {
-				    /* There is still a substring that is
-				     * the same in both strings, so add
-				     * a cline for it. */
-				    char sav = *ow;
-
-				    *ow = '\0';
-				    n = getcline(NULL, 0, dupstring(p),
-						 ow - p, 0);
-				    *ow = sav;
-				    if (l)
-					l->next = n;
-				    else
-					ret = n;
-				    l = n;
-				}
-				/* Then we add the line string built. */
-				line[mp->llen] = '\0';
-				n = getcline(dupstring(line), mp->llen,
-					     NULL, 0, CLF_DIFF);
+	    for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
+		mp = ms->matcher;
+		/* We use only those patterns that match a non-empty
+		 * string in both the line and the word, that match
+		 * strings no longer than the string we still have
+		 * to compare, that don't have anchors, and that don't
+		 * use the line strings for insertion. */
+		if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
+		    mp->wlen <= ol && mp->wlen <= nl) {
+		    /* Try the pattern only if the word-pattern matches
+		     * one of the strings. */
+		    if (pattern_match(mp->word, ow, NULL, ea)) {
+			/* Make the buffer where we build the possible
+			 * line patterns big enough. */
+			if (mp->llen + 1 > llen) {
+			    if (llen)
+				zfree(line, llen);
+			    line = (char *) zalloc(llen = mp->llen + 20);
+			}
+			/* Then build all the possible lines and see
+			 * if one of them matches the othe string. */
+			if ((bl = bld_line_pfx(mp->line, line, line,
+					       nl, nw, ea))) {
+			    /* Yep, one of the lines matched the other
+			     * string. */
+			    if (p != ow) {
+				/* There is still a substring that is
+				 * the same in both strings, so add
+				 * a cline for it. */
+				char sav = *ow;
+
+				*ow = '\0';
+				n = getcline(NULL, 0, dupstring(p),
+					     ow - p, 0);
+				*ow = sav;
 				if (l)
 				    l->next = n;
 				else
 				    ret = n;
 				l = n;
-				ow += mp->wlen;
-				nw += bl;
-				ol -= mp->wlen;
-				nl -= bl;
-				p = ow;
-				t = 1;
-			    }
-			} else if (pattern_match(mp->word, nw, NULL, ea)) {
-			    /* Now do the same for the other string. */
-			    if (mp->llen + 1 > llen) {
-				if (llen)
-				    zfree(line, llen);
-				line = (char *) zalloc(llen = mp->llen + 20);
 			    }
-			    if ((bl = bld_line_pfx(mp->line, line, line,
-						   ol, ow, ea))) {
-				if (p != ow) {
-				    char sav = *ow;
-
-				    *ow = '\0';
-				    n = getcline(NULL, 0, dupstring(p),
-						 ow - p, 0);
-				    *ow = sav;
-				    if (l)
-					l->next = n;
-				    else
-					ret = n;
-				    l = n;
-				}
-				line[mp->llen] = '\0';
-				n = getcline(dupstring(line), mp->llen,
-					     NULL, 0, CLF_DIFF);
+			    /* Then we add the line string built. */
+			    line[mp->llen] = '\0';
+			    n = getcline(dupstring(line), mp->llen,
+					 NULL, 0, CLF_DIFF);
+			    if (l)
+				l->next = n;
+			    else
+				ret = n;
+			    l = n;
+			    ow += mp->wlen;
+			    nw += bl;
+			    ol -= mp->wlen;
+			    nl -= bl;
+			    p = ow;
+			    t = 1;
+			}
+		    } else if (pattern_match(mp->word, nw, NULL, ea)) {
+			/* Now do the same for the other string. */
+			if (mp->llen + 1 > llen) {
+			    if (llen)
+				zfree(line, llen);
+			    line = (char *) zalloc(llen = mp->llen + 20);
+			}
+			if ((bl = bld_line_pfx(mp->line, line, line,
+					       ol, ow, ea))) {
+			    if (p != ow) {
+				char sav = *ow;
+
+				*ow = '\0';
+				n = getcline(NULL, 0, dupstring(p),
+					     ow - p, 0);
+				*ow = sav;
 				if (l)
 				    l->next = n;
 				else
 				    ret = n;
 				l = n;
-				ow += bl;
-				nw += mp->wlen;
-				ol -= bl;
-				nl -= mp->wlen;
-				p = ow;
-				t = 1;
 			    }
+			    line[mp->llen] = '\0';
+			    n = getcline(dupstring(line), mp->llen,
+					 NULL, 0, CLF_DIFF);
+			    if (l)
+				l->next = n;
+			    else
+				ret = n;
+			    l = n;
+			    ow += bl;
+			    nw += mp->wlen;
+			    ol -= bl;
+			    nl -= mp->wlen;
+			    p = ow;
+			    t = 1;
 			}
 		    }
 		}
@@ -2107,19 +2225,18 @@ join_new_pfx(Cline line, int len, char *word, int *missp)
 		    ll--;
 		    len--;
 		} else {
-		    for (t = 0, ms = bmstack; ms && !t; ms = ms->next) {
-			for (mp = ms->matcher; mp && !t; mp = mp->next) {
-			    if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
-				mp->wlen <= len && mp->llen <= len &&
-				pattern_match(mp->word, word, NULL, ea) &&
-				pattern_match(mp->line, p, ea, NULL)) {
-				/* We have a matched substring, skip over. */
-				p += mp->llen;
-				word += mp->wlen;
-				ll -= mp->llen;
-				len -= mp->wlen;
-				t = 1;
-			    }
+		    for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
+			mp = ms->matcher;
+			if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
+			    mp->wlen <= len && mp->llen <= len &&
+			    pattern_match(mp->word, word, NULL, ea) &&
+			    pattern_match(mp->line, p, ea, NULL)) {
+			    /* We have a matched substring, skip over. */
+			    p += mp->llen;
+			    word += mp->wlen;
+			    ll -= mp->llen;
+			    len -= mp->wlen;
+			    t = 1;
 			}
 		    }
 		    if (!t)
@@ -2148,6 +2265,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp)
 		    l->next = line;
 		else
 		    ret = line;
+		l = line;
 	    }
 	} else {
 	    /* The cline doesn't have a string built by reverse matching,
@@ -2163,6 +2281,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp)
 		    l->next = line;
 		else
 		    ret = line;
+		l = line;
 		len = 0;
 	    } else {
 		char sav = word[len];
@@ -2180,6 +2299,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp)
 			l->next = line;
 		    else
 			ret = line;
+		    l = line;
 		    len = 0;
 		} else if (strpfx(line->word, word)) {
 		    word[len] = sav;
@@ -2190,6 +2310,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp)
 			l->next = line;
 		    else
 			ret = line;
+		    l = line;
 		    len = 0;
 		} else {
 		    /* Not the same and no prefix, so we try to build a
@@ -2208,6 +2329,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp)
 			    l->next = sl;
 			else
 			    ret = sl;
+			l = sl;
 			if (!mol) {
 			    send->next = next;
 			    word += len - mnl;
@@ -2238,7 +2360,11 @@ join_new_pfx(Cline line, int len, char *word, int *missp)
 static void
 bld_pfx(Cline o, Cline n, int *olp, int *nlp)
 {
-    if (o->flags & CLF_NEW) {
+    if (olp)
+	*olp = 0;
+    if (nlp)
+	*nlp = 0;
+    if (o->flags & CLF_PNEW) {
 	if (o->flags & (CLF_END | CLF_MID))
 	    /* We split the suffix in the middle and at the end into
 	     * separate runs. */
@@ -2255,7 +2381,7 @@ bld_pfx(Cline o, Cline n, int *olp, int *nlp)
 		o->flags |= CLF_MISS;
 	}
     } else if (o->flags & (CLF_END | CLF_MID)) {
-	o->flags |= CLF_NEW;
+	o->flags |= CLF_PNEW;
 	o->prefix = join_ends(end_list(o->wlen, o->word),
 			      end_list(n->wlen, n->word), olp, nlp);
     } else if (o->wlen && n->wlen) {
@@ -2280,7 +2406,7 @@ bld_pfx(Cline o, Cline n, int *olp, int *nlp)
 	     * matches both strings from the original cline structs
 	     * and thus can be put in the command line to represent
 	     * them. This cline list is stored in o. */
-	    o->flags |= CLF_NEW;
+	    o->flags |= CLF_PNEW;
 	    o->prefix = bld_new_pfx(o->wlen, o->word, n->wlen, n->word,
 				    &mol, &mnl, NULL);
 	    newl = 0;
@@ -2300,7 +2426,8 @@ bld_pfx(Cline o, Cline n, int *olp, int *nlp)
 
 	if (!o->prefix && n->wlen != o->wlen)
 	    o->flags |= CLF_MISS;
-    }
+    } else
+	o->wlen = 0;
 }
 
 /* The following function are like their counterparts above, only for
@@ -2353,20 +2480,19 @@ bld_line_sfx(Cpattern pat, char *line, char *lp,
 		rl++;
 	    } else {
 		t = 0;
-		for (ms = bmstack; ms && !t; ms = ms->next) {
-		    for (mp = ms->matcher; mp && !t; mp = mp->next) {
-			if (!mp->flags && mp->wlen <= wlen && mp->llen <= l &&
-			    pattern_match(mp->line, line - mp->llen,
-					  NULL, ea) &&
-			    pattern_match(mp->word, word - mp->wlen,
-					  ea, NULL)) {
-			    line -= mp->llen;
-			    word -= mp->wlen;
-			    l -= mp->llen;
-			    wlen -= mp->wlen;
-			    rl += mp->wlen;
-			    t = 1;
-			}
+		for (ms = bmatchers; ms && !t; ms = ms->next) {
+		    mp = ms->matcher;
+		    if (!mp->flags && mp->wlen <= wlen && mp->llen <= l &&
+			pattern_match(mp->line, line - mp->llen,
+				      NULL, ea) &&
+			pattern_match(mp->word, word - mp->wlen,
+				      ea, NULL)) {
+			line -= mp->llen;
+			word -= mp->wlen;
+			l -= mp->llen;
+			wlen -= mp->wlen;
+			rl += mp->wlen;
+			t = 1;
 		    }
 		}
 		if (!t)
@@ -2404,84 +2530,83 @@ bld_new_sfx(int ol, char *ow, int nl, char *nw, int *olp, int *nlp, Cline *lp)
     }
     while (ol && nl) {
 	if (ow[-1] != nw[-1]) {
-	    for (t = 0, ms = bmstack; ms && !t; ms = ms->next) {
-		for (mp = ms->matcher; mp && !t; mp = mp->next) {
-		    if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
-			mp->wlen <= ol && mp->wlen <= nl) {
-			if (pattern_match(mp->word, ow - mp->wlen,
-					  NULL, ea)) {
-			    if (mp->llen + 1 > llen) {
-				if (llen)
-				    zfree(line, llen);
-				line = (char *) zalloc(llen = mp->llen + 20);
-			    }
-			    if ((bl = bld_line_sfx(mp->line, line, line,
-						   nl, nw, ea))) {
-				if (p != ow) {
-				    char sav = *p;
-
-				    *p = '\0';
-				    n = getcline(NULL, 0, dupstring(ow),
-						 p - ow, 0);
-				    *p = sav;
-				    if (l)
-					l->next = n;
-				    else
-					ret = n;
-				    l = n;
-				}
-				line[mp->llen] = '\0';
-				n = getcline(dupstring(line), mp->llen,
-					     NULL, 0, CLF_DIFF);
+	    for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
+		mp = ms->matcher;
+		if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
+		    mp->wlen <= ol && mp->wlen <= nl) {
+		    if (pattern_match(mp->word, ow - mp->wlen,
+				      NULL, ea)) {
+			if (mp->llen + 1 > llen) {
+			    if (llen)
+				zfree(line, llen);
+			    line = (char *) zalloc(llen = mp->llen + 20);
+			}
+			if ((bl = bld_line_sfx(mp->line, line, line,
+					       nl, nw, ea))) {
+			    if (p != ow) {
+				char sav = *p;
+
+				*p = '\0';
+				n = getcline(NULL, 0, dupstring(ow),
+					     p - ow, 0);
+				*p = sav;
 				if (l)
 				    l->next = n;
 				else
 				    ret = n;
 				l = n;
-				ow -= mp->wlen;
-				nw -= bl;
-				ol -= mp->wlen;
-				nl -= bl;
-				p = ow;
-				t = 1;
 			    }
-			} else if (pattern_match(mp->word, nw - mp->wlen,
-						 NULL, ea)) {
-			    if (mp->llen + 1 > llen) {
-				if (llen)
-				    zfree(line, llen);
-				line = (char *) zalloc(llen = mp->llen + 20);
-			    }
-			    if ((bl = bld_line_sfx(mp->line, line, line,
-						   ol, ow, ea))) {
-				if (p != ow) {
-				    char sav = *p;
-
-				    *p = '\0';
-				    n = getcline(NULL, 0, dupstring(ow),
-						 p - ow, 0);
-				    *p = sav;
-				    if (l)
-					l->next = n;
-				    else
-					ret = n;
-				    l = n;
-				}
-				line[mp->llen] = '\0';
-				n = getcline(dupstring(line), mp->llen,
-					     NULL, 0, CLF_DIFF);
+			    line[mp->llen] = '\0';
+			    n = getcline(dupstring(line), mp->llen,
+					 NULL, 0, CLF_DIFF);
+			    if (l)
+				l->next = n;
+			    else
+				ret = n;
+			    l = n;
+			    ow -= mp->wlen;
+			    nw -= bl;
+			    ol -= mp->wlen;
+			    nl -= bl;
+			    p = ow;
+			    t = 1;
+			}
+		    } else if (pattern_match(mp->word, nw - mp->wlen,
+					     NULL, ea)) {
+			if (mp->llen + 1 > llen) {
+			    if (llen)
+				zfree(line, llen);
+			    line = (char *) zalloc(llen = mp->llen + 20);
+			}
+			if ((bl = bld_line_sfx(mp->line, line, line,
+					       ol, ow, ea))) {
+			    if (p != ow) {
+				char sav = *p;
+
+				*p = '\0';
+				n = getcline(NULL, 0, dupstring(ow),
+					     p - ow, 0);
+				*p = sav;
 				if (l)
 				    l->next = n;
 				else
 				    ret = n;
 				l = n;
-				ow -= bl;
-				nw -= mp->wlen;
-				ol -= bl;
-				nl -= mp->wlen;
-				p = ow;
-				t = 1;
 			    }
+			    line[mp->llen] = '\0';
+			    n = getcline(dupstring(line), mp->llen,
+					 NULL, 0, CLF_DIFF);
+			    if (l)
+				l->next = n;
+			    else
+				ret = n;
+			    l = n;
+			    ow -= bl;
+			    nw -= mp->wlen;
+			    ol -= bl;
+			    nl -= mp->wlen;
+			    p = ow;
+			    t = 1;
 			}
 		    }
 		}
@@ -2554,21 +2679,20 @@ join_new_sfx(Cline line, int len, char *word, int *missp)
 		    len--;
 		    ind++;
 		} else {
-		    for (t = 0, ms = bmstack; ms && !t; ms = ms->next) {
-			for (mp = ms->matcher; mp && !t; mp = mp->next) {
-			    if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
-				mp->wlen <= len && mp->llen <= len &&
-				pattern_match(mp->word, word - mp->wlen,
-					      NULL, ea) &&
-				pattern_match(mp->line, p - mp->llen,
-					      ea, NULL)) {
-				p -= mp->llen;
-				word -= mp->wlen;
-				ll -= mp->llen;
-				len -= mp->wlen;
-				ind += mp->wlen;
-				t = 1;
-			    }
+		    for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
+			mp = ms->matcher;
+			if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
+			    mp->wlen <= len && mp->llen <= len &&
+			    pattern_match(mp->word, word - mp->wlen,
+					  NULL, ea) &&
+			    pattern_match(mp->line, p - mp->llen,
+					  ea, NULL)) {
+			    p -= mp->llen;
+			    word -= mp->wlen;
+			    ll -= mp->llen;
+			    len -= mp->wlen;
+			    ind += mp->wlen;
+			    t = 1;
 			}
 		    }
 		    if (!t)
@@ -2663,7 +2787,7 @@ join_new_sfx(Cline line, int len, char *word, int *missp)
 static void
 bld_sfx(Cline o, Cline n)
 {
-    if (o->flags & CLF_NEW) {
+    if (o->flags & CLF_SNEW) {
 	int miss;
 
 	o->suffix = join_new_sfx(o->suffix, n->wlen, n->word, &miss);
@@ -2679,7 +2803,7 @@ bld_sfx(Cline o, Cline n)
 	    new = dupstring(n->word);
 	    newl = n->wlen;
 	} else if (!strpfx(o->word, n->word)) {
-	    o->flags |= CLF_NEW;
+	    o->flags |= CLF_SNEW;
 	    o->suffix = bld_new_sfx(o->wlen, o->word, n->wlen, n->word,
 				    &mol, &mnl, NULL);
 	    newl = 0;
@@ -2732,7 +2856,7 @@ join_clines(Cline o, Cline n)
 		    n = q;
 		}
 	    }
-	    if (n->flags & CLF_MID) {
+	    if (n && n->flags & CLF_MID) {
 		while (o && !(o->flags & CLF_MID)) {
 		    o->word = NULL;
 		    o->flags |= CLF_DIFF;
@@ -3128,6 +3252,7 @@ inst_cline(Cline l, int pl, int sl)
 	}
 	l = l->next;
     }
+    lastend = cs;
     /* Now place the cursor. Preferably in a position where something
      * is missing, otherwise in a place where the string differs from
      * any of the matches, or just leave it at the end. */
@@ -3281,6 +3406,7 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp)
 				     * to continue after the matched portion. */
 				    w = q;
 				    iw = j;
+				    lw = k;
 				    l = p;
 				    il = jj;
 				    ll = kk;
@@ -3501,6 +3627,7 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp)
 				    }
 				    w = q + 1;
 				    iw = j;
+				    lw = k;
 				    l = p + 1;
 				    il = jj;
 				    ll = kk;
@@ -3765,6 +3892,7 @@ instmatch(Cmatch m)
 	inststrlen(m->suf, 1, (l = strlen(m->suf)));
 	r += l;
     }
+    lastend = cs;
     cs = ocs;
     return r;
 }
@@ -3777,10 +3905,10 @@ instmatch(Cmatch m)
 void
 addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 	   char *suf, char *group, char *rems, char *remf, char *ign,
-	   int flags, int aflags, Cmatcher match, char **argv)
+	   int flags, int aflags, Cmatcher match, char *exp, char **argv)
 {
-    char *s, *t, *e, *me, *te, *ms, *lipre = NULL, *lpre, *lsuf, **aign = NULL;
-    int lpl, lsl, i, pl, sl, test, bpl, bsl, lsm, llpl;
+    char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre, *lsuf, **aign = NULL;
+    int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl, llsl;
     Aminfo ai;
     Cline lc = NULL;
     LinkList l;
@@ -3788,43 +3916,39 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
     struct cmlist mst;
     Cmlist oms = mstack;
 
-    /* Select the set of matches. */
-    if (aflags & CAF_ALT) {
-	l = fmatches;
-	ai = fainfo;
-    } else {
-	l = matches;
-	ai = ainfo;
-    }
-    /* Store the matcher in our stack of matchers. */
-    if (match) {
-	mst.next = mstack;
-	mst.matcher = match;
-	mstack = &mst;
-	if (had_lm && mnum)
-	    bmstack1.matcher = NULL;
-	else {
-	    bmstack1.matcher = match;
-	    had_lm = 1;
-	}
-	addlinknode(matchers, match);
-	match->refc++;
-    } else {
-	bmstack1.matcher = NULL;
-	if (mnum)
-	    had_lm = 1;
-    }
     /* Use menu-completion (-U)? */
     if ((aflags & CAF_MENU) && isset(AUTOMENU))
 	usemenu = 1;
-    /* Get the suffixes to ignore. */
-    if (ign)
-	aign = get_user_var(ign);
 
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
+	    if (exp) {
+		expl = (Cexpl) halloc(sizeof(struct cexpl));
+		expl->count = expl->fcount = 0;
+		expl->str = dupstring(exp);
+	    } else
+		expl = NULL;
+
+	    /* Store the matcher in our stack of matchers. */
+	    if (match) {
+		mst.next = mstack;
+		mst.matcher = match;
+		mstack = &mst;
+
+		if (!mnum)
+		    add_bmatchers(match);
+
+		addlinknode(matchers, match);
+		match->refc++;
+	    }
+	    if (mnum && (mstack || bmatchers))
+		update_bmatchers();
+
+	    /* Get the suffixes to ignore. */
+	    if (ign)
+		aign = get_user_var(ign);
 	    /* Get the contents of the completion variables if we have
 	     * to perform matching. */
 	    if (aflags & CAF_MATCH) {
@@ -3832,6 +3956,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		lpre = dupstring(compprefix);
 		llpl = strlen(lpre);
 		lsuf = dupstring(compsuffix);
+		llsl = strlen(lsuf);
 	    }
 	    /* Now duplicate the strings we have from the command line. */
 	    if (ipre)
@@ -3848,8 +3973,6 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		lsl = strlen(psuf);
 	    } else
 		lsl = 0;
-	    if (aflags & CAF_MATCH)
-		lsm = (psuf ? !strcmp(psuf, lsuf) : (!lsuf || !*lsuf));
 	    if (pre)
 		pre = dupstring(pre);
 	    if (suf)
@@ -3865,6 +3988,17 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		begcmgroup(group, (aflags & CAF_NOSORT));
 		if (aflags & CAF_NOSORT)
 		    mgroup->flags |= CGF_NOSORT;
+	    } else {
+		endcmgroup(NULL);
+		begcmgroup("default", 0);
+	    }
+	    /* Select the set of matches. */
+	    if (aflags & CAF_ALT) {
+		l = fmatches;
+		ai = fainfo;
+	    } else {
+		l = matches;
+		ai = ainfo;
 	    }
 	    if (remf) {
 		remf = dupstring(remf);
@@ -3908,19 +4042,19 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		}
 		if (aflags & CAF_MATCH) {
 		    /* Do the matching. */
-		    t = (ppre ? dyncat(ppre, s) : s);
-		    pl = sl + lpl;
-		    if ((test = (llpl <= pl && !strncmp(t, lpre, pl))))
-			test = lsm;
+		    test = (sl >= llpl + llsl &&
+			    strpfx(lpre, s) && strsfx(lsuf, s));
 		    if (!test && mstack &&
-			(ms = comp_match(lpre, lsuf,
-					 (psuf ? dyncat(t, psuf) : t),
+			(ms = comp_match(lpre, lsuf, s,
 					 &lc, (aflags & CAF_QUOTE),
 					 &bpl, &bsl)))
 			test = 1;
+
 		    if (!test)
 			continue;
-		    me = e = s + sl;
+		    pl = sl - llsl;
+		    me = s + sl - llsl;
+		    e = s + llpl;
 		} else {
 		    e = s;
 		    me = s + sl;
@@ -3928,8 +4062,10 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		}
 		/* Quoting? */
 		if (!(aflags & CAF_QUOTE)) {
-		    te = s + pl;
-		    s = quotename(s, &e, te, &pl);
+		    int tmp = me - s;
+
+		    s = quotename(s, &e, me, &tmp);
+		    me = s + tmp;
 		    sl = strlen(s);
 		}
 		/* The rest is almost the same as in addmatch(). */
@@ -3944,31 +4080,48 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		if (ppre)
 		    t = dyncat(ppre, t);
 		if (!ms && mstack) {
+		    int bl = ((aflags & CAF_MATCH) ? llpl : 0);
 		    Cline *clp = &lc, tlc;
 		    char *ss = dupstring(s), *ee = me + (ss - s);
 
 		    if (ppre && *ppre) {
-			*clp = str_cline(ppre, strlen(ppre), &tlc);
+			*clp = tlc = getcline(NULL, 0, ppre, lpl, CLF_VAR);
 			clp = &(tlc->next);
 		    }
-		    if (ee != ss + sl || (lpsuf && *lpsuf)) {
-			*clp = tlc = getcline(ss, ee - ss,
+		    if (bl) {
+			*clp = str_cline(ss, bl, &tlc);
+			clp = &(tlc->next);
+		    }
+		    if (ee != ss + sl) {
+			*clp = tlc = getcline(ss + bl, ee - ss - bl,
 					      NULL, 0, CLF_MID);
 			clp = &(tlc->next);
-			if (ee != ss + sl) {
-			    *clp = str_cline(ee, (ss + sl) - ee, &tlc);
-			    clp = &(tlc->next);
-			}
-			if (lpsuf && *lpsuf) {
-			    *clp = str_cline(lpsuf, strlen(lpsuf), &tlc);
-			    clp = &(tlc->next);
-			}
+			*clp = str_cline(ee, (ss + sl) - ee, &tlc);
+			clp = &(tlc->next);
 		    } else {
-			*clp = tlc = getcline(NULL, 0, ss, sl,
+			*clp = tlc = getcline(NULL, 0, ss + bl, sl - bl,
+					      CLF_END | CLF_VAR);
+			clp = &(tlc->next);
+		    }
+		    if (psuf && *psuf) {
+			*clp = tlc = getcline(NULL, 0, psuf, lsl,
 					      CLF_END | CLF_VAR);
 			clp = &(tlc->next);
 		    }
 		    *clp = NULL;
+		} else if (mstack) {
+		    Cline tlc;
+
+		    if (ppre && *ppre) {
+			tlc = getcline(NULL, 0, ppre, lpl, CLF_VAR);
+			tlc->next = lc;
+			lc = tlc;
+		    }
+		    if (psuf && *psuf) {
+			for (tlc = lc; tlc->next; tlc = tlc->next);
+			tlc->next = getcline(NULL, 0, psuf, lsl,
+					     CLF_END | CLF_VAR);
+		    }
 		}
 		if (ipre && *ipre) {
 		    Cline tlc = prepend_cline(ipre, lc);
@@ -4047,6 +4200,8 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		}
 	    }
 	    compnmatches = mnum;
+	    if (exp)
+		addexpl();
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
 
@@ -4129,8 +4284,10 @@ addmatch(char *s, char *t)
 	    mpl = fpl; msl = fsl;
 	} else {
 	    if ((cp = filecomp)) {
-		if ((test = domatch(s, filecomp, 0)))
+		if ((test = domatch(s, filecomp, 0))) {
+		    e = s + sl;
 		    cc = 1;
+		}
 	    } else {
 		e = s + sl - fsl;
 		if ((test = !strncmp(s, fpre, fpl)))
@@ -4168,6 +4325,7 @@ addmatch(char *s, char *t)
 		strcat(tt, s);
 		if (lpsuf)
 		    strcat(tt, lpsuf);
+		e += (tt - s);
 		untokenize(s = tt);
 		sl = strlen(s);
 	    }
@@ -4196,9 +4354,10 @@ addmatch(char *s, char *t)
 		  ((addwhat & CC_EXCMDS)  && !(hn->flags & DISABLED)))) ||
 		((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) {
 	if (sl >= rpl + rsl || mstack) {
-	    if (cp)
+	    if (cp) {
 		test = domatch(s, patcomp, 0);
-	    else {
+		e = s + sl;
+	    } else {
 		e = s + sl - rsl;
 		if ((test = !strncmp(s, rpre, rpl)))
 		    if ((test = !strcmp(e, rsuf))) {
@@ -4888,9 +5047,11 @@ makecomplist(char *s, int incmd, int lst)
 {
     struct cmlist ms;
     Cmlist m;
+    char *os = s;
 
-    /* If we already have a list from a previous execution of this *
-     * function, skip the list building code.                      */
+    /* We build a copy of the list of matchers to use to make sure that this
+     * works even if a shell function called from the completion code changes
+     * the global matchers. */
 
     if ((m = cmatcher)) {
 	Cmlist mm, *mp = &mm;
@@ -4906,16 +5067,19 @@ makecomplist(char *s, int incmd, int lst)
 	m = mm;
     }
     compmatcher = 1;
-    bmstack = &bmstack1;
-    bmstack1.next = &bmstack0;
-    bmstack0.next = NULL;
-    bmstack0.matcher = bmstack1.matcher = NULL;
+
+    /* Walk through the global matchers. */
     for (;;) {
+	bmatchers = NULL;
 	if (m) {
 	    ms.next = NULL;
 	    ms.matcher = m->matcher;
 	    mstack = &ms;
-	    bmstack0.matcher = m->matcher;
+
+	    /* Store the matchers used in the bmatchers list which is used
+	     * when building new parts for the string to insert into the 
+	     * line. */
+	    add_bmatchers(m->matcher);
 	} else
 	    mstack = NULL;
 
@@ -4932,12 +5096,12 @@ makecomplist(char *s, int incmd, int lst)
 	    lastambig = 0;
 	amatches = 0;
 	mnum = 0;
-	had_lm = 0;
 	begcmgroup("default", 0);
 
 	ccused = newlinklist();
 	ccstack = newlinklist();
 
+	s = dupstring(os);
 	if (compfunc)
 	    callcompfunc(s, compfunc);
 	else
@@ -5004,7 +5168,7 @@ ctokenize(char *p)
 
 /**/
 char *
-comp_str(int *ipl, int *pl)
+comp_str(int *ipl, int *pl, int untok)
 {
     char *p = dupstring(compprefix);
     char *s = dupstring(compsuffix);
@@ -5012,12 +5176,14 @@ comp_str(int *ipl, int *pl)
     char *str;
     int lp, ls, lip;
 
-    ctokenize(p);
-    remnulargs(p);
-    ctokenize(s);
-    remnulargs(s);
-    ctokenize(ip);
-    remnulargs(ip);
+    if (!untok) {
+	ctokenize(p);
+	remnulargs(p);
+	ctokenize(s);
+	remnulargs(s);
+	ctokenize(ip);
+	remnulargs(ip);
+    }
     ls = strlen(s);
     lip = strlen(ip);
     lp = strlen(p);
@@ -5041,7 +5207,7 @@ makecomplistcall(Compctl cc)
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
 	    int ooffs = offs, lip, lp;
-	    char *str = comp_str(&lip, &lp);
+	    char *str = comp_str(&lip, &lp, 0);
 
 	    offs = lip + lp;
 	    cc->refc++;
@@ -5073,7 +5239,7 @@ makecomplistctl(int flags)
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
 	    int ooffs = offs, lip, lp;
-	    char *str = comp_str(&lip, &lp), *t;
+	    char *str = comp_str(&lip, &lp, 0), *t;
 	    char *os = cmdstr, **ow = clwords, **p, **q;
 	    int on = clwnum, op = clwpos;
 
@@ -5571,19 +5737,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	ms.next = mstack;
 	ms.matcher = cc->matcher;
 	mstack = &ms;
-	if (had_lm && mnum)
-	    bmstack1.matcher = NULL;
-	else {
-	    bmstack1.matcher = cc->matcher;
-	    had_lm = 1;
-	}
+
+	if (!mnum)
+	    add_bmatchers(cc->matcher);
+
 	addlinknode(matchers, cc->matcher);
 	cc->matcher->refc++;
-    } else {
-	bmstack1.matcher = NULL;
-	if (mnum)
-	    had_lm = 1;
     }
+    if (mnum && (mstack || bmatchers))
+	update_bmatchers();
+
     /* Insert the prefix (compctl -P), if any. */
     if (cc->prefix) {
 	int pl = 0;
@@ -6344,7 +6507,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	}
 	
 	if ((tt = cc->explain)) {
-	    if (cc->mask & CC_EXPANDEXPL && !parsestr(tt = dupstring(tt))) {
+	    tt = dupstring(tt);
+	    if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) {
 		singsub(&tt);
 		untokenize(tt);
 	    }
@@ -6358,7 +6522,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	begcmgroup("default", 0);
     }
     else if ((tt = cc->explain)) {
-	if (cc->mask & CC_EXPANDEXPL && !parsestr(tt = dupstring(tt))) {
+	tt = dupstring(tt);
+	if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) {
 	    singsub(&tt);
 	    untokenize(tt);
 	}
@@ -6631,7 +6796,7 @@ begcmgroup(char *n, int nu)
 	}
     }
     mgroup = (Cmgroup) halloc(sizeof(struct cmgroup));
-    mgroup->name = n;
+    mgroup->name = dupstring(n);
     mgroup->flags = mgroup->lcount = mgroup->mcount = 0;
     mgroup->matches = NULL;
     mgroup->ylist = NULL;
@@ -6872,7 +7037,7 @@ do_ambiguous(void)
     /* If we have to insert the first match, call do_single().  This is *
      * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
      * completion into an unambiguous one.                              */
-    if (ainfo && ainfo->exact == 1 && isset(RECEXACT) && !fromcomp &&
+    if (ainfo && ainfo->exact == 1 && isset(RECEXACT) && !(fromcomp & FC_LINE) &&
 	(usemenu == 0 || unset(AUTOMENU))) {
 	do_single(ainfo->exactm);
 	invalidatelist();
@@ -6945,7 +7110,6 @@ do_ambiguous(void)
 		    merge_cline(lc, ps, lp, NULL, 0, 0);
 	    }
 	    inst_cline(lc, pl, sl);
-
 	} else {
 	    inststrlen(ps, 1, -1);
 	    ocs = cs;
@@ -6966,6 +7130,7 @@ do_ambiguous(void)
 		cs -= brsl;
 		inststrlen(brend, 1, -1);
 	    }
+	    lastend = cs;
 	    cs = ocs;
 	}
 	/* la is non-zero if listambiguous may be used. Copying and
@@ -6973,11 +7138,13 @@ do_ambiguous(void)
 	 * solution. Really. */
 	la = (ll != oll || strncmp(oline, (char *) line, ll));
 
-	/* If REC_EXACT and AUTO_MENU are set and what we inserted is an *
-	 * exact match, we want menu completion the next time round      *
-	 * so we set fromcomp,to ensure that the word on the line is not *
-	 * taken as an exact match.                                      */
-	fromcomp = isset(AUTOMENU);
+	/* If REC_EXACT and AUTO_MENU are set and what we inserted is an  *
+	 * exact match, we want menu completion the next time round       *
+	 * so we set fromcomp,to ensure that the word on the line is not  *
+	 * taken as an exact match. Also we remember if we just moved the *
+	 * cursor into the word.                                          */
+	fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) |
+		    ((atend && cs != lastend) ? FC_INWORD : 0));
 
 	/*
 	 * If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
diff --git a/Src/exec.c b/Src/exec.c
index 59061af3f..764b7140c 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2558,7 +2558,7 @@ execarith(Cmd cmd)
 	val = matheval(e);
     }
     if (isset(XTRACE)) {
-	fprintf(stderr, " ))\n", stderr);
+	fprintf(stderr, " ))\n");
 	fflush(stderr);
     }
     errflag = 0;
diff --git a/Src/glob.c b/Src/glob.c
index 516f75618..47fa63567 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -71,6 +71,7 @@ struct gmatch {
 int badcshglob;
  
 static int mode;		/* != 0 if we are parsing glob patterns */
+static int scanning;		/* != 0 if we are scanning file paths   */
 static int pathpos;		/* position in pathbuf                  */
 static int matchsz;		/* size of matchbuf                     */
 static int matchct;		/* number of matches found              */
@@ -134,7 +135,7 @@ struct complist {
 struct comp {
     Comp left, right, next, exclude;
     char *str;
-    int stat;
+    int stat, errsmax;
 };
 
 /* Type of Comp:  a closure with one or two #'s, the end of a *
@@ -162,6 +163,18 @@ struct comp {
 #define GF_PATHADD	1	/* file glob, adding path components */
 #define GF_TOPLEV	2	/* outside (), so ~ ends main match */
 
+/* Next character after one which may be a Meta (x is any char *) */
+#define METANEXT(x)	(*(x) == Meta ? (x)+2 : (x)+1)
+/*
+ * Increment pointer which may be on a Meta (x is a pointer variable),
+ * returning the incremented value (i.e. like pre-increment).
+ */
+#define METAINC(x)	((x) += (*(x) == Meta) ? 2 : 1)
+/*
+ * Return unmetafied char from string (x is any char *)
+ */
+#define UNMETA(x)	(*(x) == Meta ? (x)[1] ^ 32 : *(x))
+
 static char *pptr;		/* current place in string being matched */
 static Comp tail;
 static int first;		/* are leading dots special? */
@@ -352,6 +365,25 @@ haswilds(char *str)
     return 0;
 }
 
+/* Flags to apply to current level of grouping */
+
+static int addflags;
+
+/*
+ * Approximate matching.
+ *
+ * errsmax is used while parsing to store the current number
+ * of errors allowed.  While executing it is usually set to -1,
+ * but can be set to something else to fix a different maximum
+ * no. of errors which acts as a limit on the local value:  see
+ * scanner() for why this is necessary.
+ *
+ * errsfound is used while executing a pattern to record the
+ * number of errors found so far.
+ */
+
+static int errsmax, errsfound;
+
 /* Do the globbing:  scanner is called recursively *
  * with successive bits of the path until we've    *
  * tried all of it.                                */
@@ -363,6 +395,7 @@ scanner(Complist q)
     Comp c;
     int closure;
     int pbcwdsav = pathbufcwd;
+    int errssofar = errsfound;
     struct dirsav ds;
 
     ds.ino = ds.dev = 0;
@@ -381,7 +414,7 @@ scanner(Complist q)
     c = q->comp;
     /* Now the actual matching for the current path section. */
     if (!(c->next || c->left) && !haswilds(c->str)
-	&& (!(c->stat & (C_LCMATCHUC|C_IGNCASE))
+	&& (!((c->stat & (C_LCMATCHUC|C_IGNCASE)) || c->errsmax)
 	    || !strcmp(".", c->str) || !strcmp("..", c->str))) {
 	/*
 	 * We always need to match . and .. explicitly, even if we're
@@ -433,6 +466,7 @@ scanner(Complist q)
 		((glob_pre && !strpfx(glob_pre, fn))
 		 || (glob_suf && !strsfx(glob_suf, fn))))
 		continue;
+	    errsfound = errssofar;
 	    if (domatch(fn, c, gf_noglobdots)) {
 		/* if this name matchs the pattern... */
 		if (pbcwdsav == pathbufcwd &&
@@ -453,7 +487,34 @@ scanner(Complist q)
 		if (dirs) {
 		    int l;
 
-		    /* if not the last component in the path */
+		    /*
+		     * If not the last component in the path:
+		     *
+		     * If we made an approximation in the new path segment,
+		     * and the pattern includes closures other than a
+		     * trailing * (we only test if it is not a string),
+		     * then it is possible we made too many errors.  For
+		     * example, (ab)#(cb)# will match the directory abcb
+		     * with one error if allowed to, even though it can
+		     * match with none.  This will stop later parts of the
+		     * path matching, so we need to check by reducing the
+		     * maximum number of errors and seeing if the directory
+		     * still matches.  Luckily, this is not a terribly
+		     * common case, since complex patterns typically occur
+		     * in the last part of the path which is not affected
+		     * by this problem.
+		     */
+		    if (errsfound > errssofar && (c->next || c->left)) {
+			errsmax = errsfound - 1;
+			while (errsmax >= errssofar) {
+			    errsfound = errssofar;
+			    if (!domatch(fn, c, gf_noglobdots))
+				break;
+			    errsmax = errsfound - 1;
+			}
+			errsfound = errsmax + 1;
+			errsmax = -1;
+		    }
 		    if (closure) {
 			/* if matching multiple directories */
 			struct stat buf;
@@ -470,9 +531,14 @@ scanner(Complist q)
 			    continue;
 		    }
 		    l = strlen(fn) + 1;
-		    subdirs = hrealloc(subdirs, subdirlen, subdirlen + l);
+		    subdirs = hrealloc(subdirs, subdirlen, subdirlen + l
+				       + sizeof(int));
 		    strcpy(subdirs + subdirlen, fn);
 		    subdirlen += l;
+		    /* store the count of errors made so far, too */
+		    memcpy(subdirs + subdirlen, (char *)&errsfound,
+			   sizeof(int));
+		    subdirlen += sizeof(int);
 		} else
 		    /* if the last filename component, just add it */
 		    insert(fn, 1);
@@ -482,8 +548,11 @@ scanner(Complist q)
 	if (subdirs) {
 	    int oppos = pathpos;
 
-	    for (fn = subdirs; fn < subdirs+subdirlen; fn += strlen(fn) + 1) {
+	    for (fn = subdirs; fn < subdirs+subdirlen; ) {
 		addpath(fn);
+		fn += strlen(fn) + 1;
+		memcpy((char *)&errsfound, fn, sizeof(int));
+		fn += sizeof(int);
 		scanner((q->closure) ? q : q->next);  /* scan next level */
 		pathbuf[pathpos = oppos] = '\0';
 	    }
@@ -502,16 +571,13 @@ scanner(Complist q)
 
 /* Parse a series of path components pointed to by pptr */
 
-/* Flags to apply to current level of grourping */
-
-static int addflags;
-
 /**/
 static Comp
 compalloc(void)
 {
     Comp c = (Comp) alloc(sizeof *c);
     c->stat |= addflags;
+    c->errsmax = errsmax;
     return c;
 }
 
@@ -519,10 +585,19 @@ compalloc(void)
 static int
 getglobflags()
 {
+    char *nptr;
     /* (#X): assumes we are still positioned on the initial '(' */
     pptr++;
     while (*++pptr && *pptr != Outpar) {
 	switch (*pptr) {
+	case 'a':
+	    /* Approximate matching, max no. of errors follows */
+	    errsmax = zstrtol(++pptr, &nptr, 10);
+	    if (pptr == nptr)
+		return 1;
+	    pptr = nptr-1;
+	    break;
+
 	case 'l':
 	    /* Lowercase in pattern matches lower or upper in target */
 	    addflags |= C_LCMATCHUC;
@@ -635,6 +710,7 @@ parsecomp(int gflag)
 	    if (eptr == cstr) {
 		/* if no string yet, carry on and get one. */
 		c->stat = addflags;
+		c->errsmax = errsmax;
 		cstr = pptr;
 		continue;
 	    }
@@ -817,6 +893,7 @@ parsecompsw(int gflag)
 {
     Comp c1, c2, c3, excl = NULL, stail = tail;
     int oaddflags = addflags;
+    int oerrsmax = errsmax;
     char *sptr;
 
     /*
@@ -845,12 +922,14 @@ parsecompsw(int gflag)
 	return NULL;
     if (isset(EXTENDEDGLOB) && *pptr == Tilde) {
 	/* Matching remainder of pattern excludes the pattern from matching */
-	int oldmode = mode;
+	int oldmode = mode, olderrsmax = errsmax;
 
 	mode = 1;
+	errsmax = 0;
 	pptr++;
 	excl = parsecomp(gflag);
 	mode = oldmode;
+	errsmax = olderrsmax;
 	if (!excl)
 	    return NULL;
     }
@@ -878,8 +957,10 @@ parsecompsw(int gflag)
 	    c2->stat |= C_PATHADD;
 	c1 = c2;
     }
-    if (!(gflag & GF_TOPLEV))
+    if (!(gflag & GF_TOPLEV)) {
 	addflags = oaddflags;
+	errsmax = oerrsmax;
+    }
     return c1;
 }
 
@@ -965,6 +1046,7 @@ parsepat(char *str)
 {
     mode = 0;			/* path components present */
     addflags = 0;
+    errsmax = 0;
     pptr = str;
     tail = NULL;
     /*
@@ -1102,7 +1184,7 @@ static int
 gmatchcmp(Gmatch a, Gmatch b)
 {
     int i, *s;
-    long r;
+    long r = 0L;
 
     for (i = gf_nsorts, s = gf_sortlist; i; i--, s++) {
 	switch (*s & ~GS_DESC) {
@@ -1594,10 +1676,14 @@ glob(LinkList list, LinkNode np)
     matchptr = matchbuf = (Gmatch)zalloc((matchsz = 16) *
 					 sizeof(struct gmatch));
     matchct = 0;
+    errsfound = 0;
+    errsmax = -1;
 
     /* The actual processing takes place here: matches go into  *
      * matchbuf.  This is the only top-level call to scanner(). */
+    scanning = 1;
     scanner(q);
+    scanning = 0;
 
     /* Deal with failures to match depending on options */
     if (matchct)
@@ -2427,6 +2513,14 @@ domatch(char *str, Comp c, int fist)
     int ret;
     pptr = str;
     first = fist;
+    /*
+     * If scanning paths, keep the error count over the whole
+     * filename
+     */
+    if (!scanning) {
+	errsfound = 0;
+	errsmax = -1;
+    }
     if (*pptr == Nularg)
 	pptr++;
     PERMALLOC {
@@ -2444,15 +2538,17 @@ static int
 excluded(Comp c, char *eptr)
 {
     char *saves = pptr;
-    int savei = first, savel = longest, ret;
+    int savei = first, savel = longest, savee = errsfound, ret;
 
     first = 0;
     /*
      * Even if we've been told always to match the longest string,
      * i.e. not anchored to the end, we want to match the full string
      * we've already matched when we're trying to exclude it.
+     * Likewise, approximate matching here is treated separately.
      */
     longest = 0;
+    errsfound = 0;
     if (PATHADDP(c) && pathpos) {
 	VARARR(char, buf, pathpos + strlen(eptr) + 1);
 
@@ -2470,13 +2566,18 @@ excluded(Comp c, char *eptr)
     pptr = saves;
     first = savei;
     longest = savel;
+    errsfound = savee;
 
     return ret;
 }
 
+/*
+ * Structure for storing instances of a pattern in a closured.
+ */
 struct gclose {
-    char *start;
-    char *end;
+    char *start;		/* Start of this instance */
+    char *end;			/* End of this instance */
+    int errsfound;		/* Errors found up to start of instance */
 };
 typedef struct gclose *Gclose;
 
@@ -2488,34 +2589,48 @@ typedef struct gclose *Gclose;
  * also not bother going any further, since the first time we got to
  * that position (when it was marked), we must already have failed on
  * and backtracked over any further closure matches beyond that point.
+ * If we are using approximation, the number in the string is incremented
+ * by the current error count; if we come back to that point with a
+ * lower error count, it is worth trying from that point again, but
+ * we must now mark that point in trystring with the new error.
  */
 
 /**/
 static void
-addclosures(Comp c, LinkList closlist, int *pdone, char *trystring)
+addclosures(Comp c, LinkList closlist, int *pdone, unsigned char *trystring)
 {
     Gclose gcnode;
     char *opptr = pptr;
+    unsigned char *tpos;
 
     while (*pptr) {
 	if (STARP(c)) {
-	    if (trystring[(pptr+1)-opptr])
-		break;
+	    if (*(tpos = trystring + ((pptr+1) - opptr))) {
+		if ((unsigned)(errsfound+1) >= *tpos)
+		    break;
+		*tpos = (unsigned)(errsfound+1);
+	    }
 	    gcnode = (Gclose)zalloc(sizeof(struct gclose));
 	    gcnode->start = pptr;
-	    gcnode->end = ++pptr;
+	    gcnode->end = METAINC(pptr);
+	    gcnode->errsfound = errsfound;
 	} else {
 	    char *saves = pptr;
+	    int savee = errsfound;
 	    if (OPTIONALP(c) && *pdone >= 1)
 		return;
 	    if (!matchonce(c) || saves == pptr ||
-		trystring[pptr-opptr]) {
+		(*(tpos = trystring + (pptr-opptr)) &&
+		 (unsigned)(errsfound+1) >= *tpos)) {
 		pptr = saves;
 		break;
 	    }
+	    if (*tpos)
+		*tpos = (unsigned)(errsfound+1);
 	    gcnode = (Gclose)zalloc(sizeof(struct gclose));
 	    gcnode->start = saves;
 	    gcnode->end = pptr;
+	    gcnode->errsfound = savee;
 	}
 	pushnode(closlist, gcnode);
 	(*pdone)++;
@@ -2523,13 +2638,29 @@ addclosures(Comp c, LinkList closlist, int *pdone, char *trystring)
 }
 
 /*
- * Match characters with case-insensitivity.
- * Note CHARMATCH(x,y) != CHARMATCH(y,x)
+ * Match characters with case-insensitivity.  Note charmatch(x,y) !=
+ * charmatch(y,x): the first argument comes from the target string, the
+ * second from the pattern.  This used to be a macro, and in principle
+ * could be turned back into one.
  */
-#define CHARMATCH(x, y) \
-(x == y || (((c->stat & C_IGNCASE) ? (tulower(x) == tulower(y)) : \
-	     (c->stat & C_LCMATCHUC) ? (islower(y) && tuupper(y) == x) : 0)))
 
+/**/
+static int
+charmatch(Comp c, char *x, char *y)
+{
+    /*
+     * This takes care of matching two characters which may be a
+     * two byte sequence, Meta followed by something else.
+     * Here we bypass tulower() and tuupper() for speed.
+     */
+    int xi = (STOUC(UNMETA(x)) & 0xff), yi = (STOUC(UNMETA(y)) & 0xff);
+    return xi == yi ||
+	(((c->stat & C_IGNCASE) ?
+	  ((isupper(xi) ? tolower(xi) : xi) ==
+	   (isupper(yi) ? tolower(yi) : yi)) :
+	  (c->stat & C_LCMATCHUC) ?
+	  (islower(yi) && toupper(yi) == xi) : 0));
+}
 
 /* see if current string in pptr matches c */
 
@@ -2539,14 +2670,16 @@ doesmatch(Comp c)
 {
     if (CLOSUREP(c)) {
 	int done, retflag = 0;
-	char *saves, *trystring, *opptr;
+	char *saves, *opptr;
+	unsigned char *trystring, *tpos;
+	int savee;
 	LinkList closlist;
 	Gclose gcnode;
 
 	if (first && *pptr == '.')
 	    return 0;
 
-	if (!inclosure && !c->left) {
+	if (!inclosure && !c->left && !c->errsmax) {
 	    /* We are not inside another closure, and the current
 	     * pattern is a simple string.  We handle this very common
 	     * case specially: otherwise, matches like *foo* are
@@ -2561,26 +2694,30 @@ doesmatch(Comp c)
 		!itok(looka)) {
 		/* Another simple optimisation for a very common case:
 		 * we are processing a * and there is
-		 * an ordinary character match next.  We look ahead for
-		 * that character, taking care of Meta bytes.
+		 * an ordinary character match (which may not be a Metafied
+		 * character, just to make it easier) next.  We look ahead
+		 * for that character, taking care of Meta bytes.
 		 */
 		while (*pptr) {
 		    for (; *pptr; pptr++) {
 			if (*pptr == Meta)
 			    pptr++;
-			else if (CHARMATCH(STOUC(*pptr), STOUC(looka)))
+			else if (charmatch(c, pptr, &looka))
 			    break;
 		    }
 		    if (!*(saves = pptr))
 			break;
+		    savee = errsfound;
 		    if (doesmatch(c->next))
 			return 1;
 		    pptr = saves+1;
+		    errsfound = savee;
 		}
 	    } else {
 		/* Standard track-forward code */
 		for (done = 0; ; done++) {
 		    saves = pptr;
+		    savee = errsfound;
 		    if ((done || ONEHASHP(c) || OPTIONALP(c)) &&
 			((!c->next && (!LASTP(c) || !*pptr || longest)) ||
 			 (c->next && doesmatch(c->next))))
@@ -2588,6 +2725,7 @@ doesmatch(Comp c)
 		    if (done && OPTIONALP(c))
 			return 0;
 		    pptr = saves;
+		    errsfound = savee;
 		    first = 0;
 		    if (STARP(c)) {
 			if (!*pptr)
@@ -2602,7 +2740,7 @@ doesmatch(Comp c)
 	/* The full, gory backtracking code is now necessary. */
 	inclosure++;
 	closlist = newlinklist();
-	trystring = zcalloc(strlen(pptr)+1);
+	trystring = (unsigned char *)zcalloc(strlen(pptr)+1);
 	opptr = pptr;
 
 	/* Start by making a list where each match is as long
@@ -2621,7 +2759,7 @@ doesmatch(Comp c)
 		retflag = 1;
 		break;
 	    }
-	    trystring[saves-opptr] = 1;
+	    trystring[saves-opptr] = (unsigned)(errsfound + 1);
 	    /*
 	     * If we failed, the first thing to try is whether we can
 	     * shorten the match using the last pattern in the closure.
@@ -2633,14 +2771,18 @@ doesmatch(Comp c)
 		char savec = *gcnode->end;
 		*gcnode->end = '\0';
 		pptr = gcnode->start;
+		errsfound = gcnode->errsfound;
 		if (matchonce(c) && pptr != gcnode->start
-		    && !trystring[pptr-opptr]) {
+		    && (!*(tpos = trystring + (pptr-opptr)) ||
+			*tpos > (unsigned)(errsfound+1))) {
+		    if (*tpos)
+			*tpos = (unsigned)(errsfound+1);
 		    *gcnode->end = savec;
 		    gcnode->end = pptr;
 		    /* Try again to construct a list based on
 		     * this new position
 		     */
-		    addclosures(c, closlist, &done, trystring+(pptr-opptr));
+		    addclosures(c, closlist, &done, tpos);
 		    continue;
 		}
 		*gcnode->end = savec;
@@ -2650,6 +2792,7 @@ doesmatch(Comp c)
 	     */
 	    if ((gcnode = (Gclose)getlinknode(closlist))) {
 		pptr = gcnode->start;
+		errsfound = gcnode->errsfound;
 		zfree(gcnode, sizeof(struct gclose));
 		done--;
 	    } else
@@ -2723,8 +2866,7 @@ rangematch(char **patptr, int ch, int rchar)
 #define PAT(X) (pat[X] == Meta ? pat[(X)+1] ^ 32 : untok(pat[X]))
 #define PPAT(X) (pat[(X)-1] == Meta ? pat[X] ^ 32 : untok(pat[X]))
 
-    for (pat++; *pat != Outbrack && *pat;
-	 *pat == Meta ? pat += 2 : pat++) {
+    for (pat++; *pat != Outbrack && *pat; METAINC(pat)) {
 	if (*pat == Inbrack) {
 	    /* Inbrack can only occur inside a range if we found [:...:]. */
 	    pat += 2;
@@ -2748,6 +2890,22 @@ rangematch(char **patptr, int ch, int rchar)
     *patptr = pat;
 }
 
+/*
+ * matchonce() is the core of the pattern matching, handling individual
+ * strings and instances of a pattern in a closure.
+ *
+ * Note on approximate matching:  The rule is supposed to be
+ *   (1) Take the longest possible match without approximation.
+ *   (2) At any failure, make the single approximation that results
+ *       in the longest match for the remaining part (which may
+ *       include further approximations).
+ *   (3) If we match the same distance, take the one with fewer
+ *       approximations.
+ * If this is wrong, I haven't yet discovered a counterexample.  Email
+ * lines are now open.
+ *                   pws 1999/02/23
+ */
+
 /**/
 static int
 matchonce(Comp c)
@@ -2758,7 +2916,7 @@ matchonce(Comp c)
 	if (!pat || !*pat) {
 	    /* No current pattern (c->str). */
 	    char *saves;
-	    int savei;
+	    int savee, savei;
 
 	    if (errflag)
 		return 0;
@@ -2766,6 +2924,7 @@ matchonce(Comp c)
 	     * check for exclusion of pattern or alternatives. */
 	    saves = pptr;
 	    savei = first;
+	    savee = errsfound;
 	    /* Loop over alternatives with exclusions: (foo~bar|...). *
 	     * Exclusions apply to the pattern in c->left.            */
 	    if (c->left || c->right) {
@@ -2812,6 +2971,7 @@ matchonce(Comp c)
 			 */
 			exclend--;
 			pptr = saves;
+			errsfound = savee;
 		    }
 		    inclosure--;
 		    if (ret)
@@ -2822,19 +2982,43 @@ matchonce(Comp c)
 		if (c->right && (!ret || inclosure)) {
 		    /* If in a closure, we always want the longest match. */
 		    char *newpptr = pptr;
+		    int newerrsfound = errsfound;
 		    pptr = saves;
 		    first = savei;
+		    errsfound = savee;
 		    ret2 = doesmatch(c->right);
-		    if (ret && (!ret2 || pptr < newpptr))
+		    if (ret && (!ret2 || pptr < newpptr)) {
 			pptr = newpptr;
+			errsfound = newerrsfound;
+		    }
+		}
+		if (!ret && !ret2) {
+		    pptr = saves;
+		    first = savei;
+		    errsfound = savee;
+		    break;
 		}
-		if (!ret && !ret2)
-		    return 0;
 	    }
 	    if (CLOSUREP(c))
 		return 1;
-	    if (!c->next)	/* no more patterns left */
-		return (!LASTP(c) || !*pptr || longest);
+	    if (!c->next) {
+		/*
+		 * No more patterns left, but we may still be in the middle
+		 * of a match, in which case alles in Ordnung...
+		 */ 
+		if (!LASTP(c))
+		    return 1;
+		/*
+		 * ...else we're at the last pattern, so this is our last
+		 * ditch attempt at an approximate match: try to omit the
+		 * last few characters.
+		 */
+		for (; *pptr && errsfound < c->errsmax &&
+			 (errsmax == -1 || errsfound < errsmax);
+		     METAINC(pptr))
+		    errsfound++;
+		return !*pptr || longest;
+	    }
 	    /* optimisation when next pattern is not a closure */
 	    if (!CLOSUREP(c->next)) {
 		c = c->next;
@@ -2843,7 +3027,10 @@ matchonce(Comp c)
 	    }
 	    return doesmatch(c->next);
 	}
-	/* Don't match leading dot if first is set */
+	/*
+	 * Don't match leading dot if first is set
+	 * (don't even try for an approximate match)
+	 */
 	if (first && *pptr == '.' && *pat != '.')
 	    return 0;
 	if (*pat == Star) {	/* final * is not expanded to ?#; returns success */
@@ -2852,39 +3039,47 @@ matchonce(Comp c)
 	    return 1;
 	}
 	first = 0;		/* finished checking start of pattern */
-	if (*pat == Quest && *pptr) {
+	if (*pat == Quest) {
 	    /* match exactly one character */
-	    if (*pptr == Meta)
-		pptr++;
-	    pptr++;
+	    if (!*pptr)
+		break;
+	    METAINC(pptr);
 	    pat++;
 	    continue;
 	}
 	if (*pat == Inbrack) {
 	    /* Match groups of characters */
 	    char ch;
+	    char *saves, *savep;
 
 	    if (!*pptr)
 		break;
-	    ch = *pptr == Meta ? pptr[1] ^ 32 : *pptr;
+	    saves = pptr;
+	    savep = pat;
+	    ch = UNMETA(pptr);
 	    if (pat[1] == Hat || pat[1] == '^' || pat[1] == '!') {
 		/* group is negated */
 		*++pat = Hat;
 		rangematch(&pat, ch, Hat);
 		DPUTS(!*pat, "BUG: something is very wrong in doesmatch()");
-		if (*pat != Outbrack)
+		if (*pat != Outbrack) {
+		    pptr = saves;
+		    pat = savep;
 		    break;
+		}
 		pat++;
-		*pptr == Meta ? pptr += 2 : pptr++;
+		METAINC(pptr);
 		continue;
 	    } else {
 		/* pattern is not negated (affirmed? asserted?) */
 		rangematch(&pat, ch, Inbrack);
 		DPUTS(!pat || !*pat, "BUG: something is very wrong in doesmatch()");
-		if (*pat == Outbrack)
+		if (*pat == Outbrack) {
+		    pptr = saves;
+		    pat = savep;
 		    break;
-		for (*pptr == Meta ? pptr += 2 : pptr++;
-		     *pat != Outbrack; pat++);
+		}
+		for (METAINC(pptr); *pat != Outbrack; pat++);
 		pat++;
 		continue;
 	    }
@@ -2892,7 +3087,7 @@ matchonce(Comp c)
 	if (*pat == Inang) {
 	    /* Numeric globbing. */
 	    unsigned long t1, t2, t3;
-	    char *ptr;
+	    char *ptr, *saves = pptr, *savep = pat;
 
 	    if (!idigit(*pptr))
 		break;
@@ -2933,19 +3128,146 @@ matchonce(Comp c)
 		  pptr--;
 		  t1 /= 10;
 		}
-		if (t1 < t2 || (!not3 && t1 > t3))
+		if (t1 < t2 || (!not3 && t1 > t3)) {
+		    pptr = saves;
+		    pat = savep;
 		    break;
+		}
 	    }
 	    continue;
 	}
-	if (CHARMATCH(STOUC(*pptr), STOUC(*pat))) {
-	    /* just plain old characters */
-	    pptr++;
-	    pat++;
+	/* itok(Meta) is zero */
+	DPUTS(itok(*pat), "BUG: matching tokenized character");
+	if (charmatch(c, pptr, pat)) {
+	    /* just plain old characters (or maybe unplain new characters) */
+	    METAINC(pptr);
+	    METAINC(pat);
 	    continue;
 	}
+	if (errsfound < c->errsmax &&
+	    (errsmax == -1 || errsfound < errsmax)) {
+	    /*
+	     * We tried to match literal characters and failed.  Now it's
+	     * time to match approximately.  Note this doesn't handle the
+	     * case where we *didn't* try to match literal characters,
+	     * including the case where we were already at the end of the
+	     * pattern, because then we never get here.  In that case the
+	     * pattern has to be matched exactly, but we could maybe
+	     * advance up the target string before trying it, so we have to
+	     * handle that case elsewhere.
+	     */
+	    char *saves = pptr, *savep = c->str;
+	    char *maxpptr = pptr, *patnext = METANEXT(pat);
+	    int savee, maxerrs = -1;
+
+	    /* First try to advance up the pattern. */
+	    c->str = patnext;
+	    savee = ++errsfound;
+	    if (matchonce(c)) {
+		maxpptr = pptr;
+		maxerrs = errsfound;
+	    }
+	    errsfound = savee;
+
+	    if (*saves) {
+		/*
+		 * If we have characters on both strings, we have more
+		 * choice.
+		 *
+		 * Try to edge up the target string.
+		 */
+		char *strnext = METANEXT(saves);
+		pptr = strnext;
+		c->str = pat;
+		if (matchonce(c) &&
+		    (maxerrs == -1 || pptr > maxpptr ||
+		     (pptr == maxpptr && errsfound <= maxerrs))) {
+		    maxpptr = pptr;
+		    maxerrs = errsfound;
+		}
+		errsfound = savee;
+
+		/*
+		 * Try edging up both of them at once.
+		 * Note this takes precedence in the case of equal
+		 * length as we get further up the pattern.
+		 */
+		c->str = patnext;
+		pptr = strnext;
+		if (matchonce(c) &&
+		    (maxerrs == -1 || pptr > maxpptr ||
+		     (pptr == maxpptr && errsfound <= maxerrs))) {
+		    maxpptr = pptr;
+		    maxerrs = errsfound;
+		}
+		errsfound = savee;
+
+		/*
+		 * See if we can transpose: that counts as just one error.
+		 *
+		 * Note, however, `abanana' and `banana': transposing
+		 * is wrong here, as it gets us two errors,
+		 * [ab][a]nana vs [ba][]nana, instead of the correct
+		 * [a]banana vs []banana, so we still need to try
+		 * the other possibilities.
+		 */
+		if (strnext && patnext && !itok(*patnext) &&
+		    charmatch(c, strnext, pat) &&
+		    charmatch(c, saves, patnext)) {
+		    c->str = patnext;
+		    METAINC(c->str);
+
+		    pptr = strnext;
+		    METAINC(pptr);
+
+		    if (matchonce(c) &&
+			(maxerrs == -1 || pptr > maxpptr ||
+			 (pptr == maxpptr && errsfound <= maxerrs))) {
+			maxpptr = pptr;
+			maxerrs = errsfound;
+		    }
+		}
+	    }
+	    /*
+	     * We don't usually restore state on failure, but we need
+	     * to fix up the Comp structure which we altered to
+	     * look at the tail of the pattern.
+	     */
+	    c->str = savep;
+	    /*
+	     * If that failed, game over:  we don't want to break
+	     * and try the other approximate test, because we just did
+	     * that.
+	     */
+	    if (maxerrs == -1)
+		return 0;
+	    pptr = maxpptr;
+	    errsfound = maxerrs;
+	    return 1;
+	}
 	break;
     }
+    if (*pptr && errsfound < c->errsmax &&
+	(errsmax == -1 || errsfound < errsmax)) {
+	/*
+	 * The pattern failed, but we can try edging up the target string
+	 * and rematching with an error.  Note we do this from wherever we
+	 * got to in the pattern string c->str, not the start. hence the
+	 * need to modify c->str.
+	 *
+	 * At this point, we don't have a literal character in the pattern
+	 * (handled above), so we don't try any funny business on the
+	 * pattern itself.
+	 */
+	int ret;
+	char *savep = c->str;
+	errsfound++;
+	METAINC(pptr);
+	c->str = pat;
+	ret = matchonce(c);
+	c->str = savep;
+	return ret;
+    }
     return 0;
 }
 
@@ -2958,6 +3280,7 @@ parsereg(char *str)
     remnulargs(str);
     mode = 1;			/* no path components */
     addflags = 0;
+    errsmax = 0;
     pptr = str;
     tail = NULL;
     return parsecompsw(GF_TOPLEV);
diff --git a/Src/hashtable.c b/Src/hashtable.c
index b816f1892..72e4db21b 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -607,6 +607,9 @@ hashdir(char **dirp)
     Cmdnam cn;
     DIR *dir;
     char *fn;
+#ifdef _WIN32
+    char *exe;
+#endif
 
     if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp))))
 	return;
@@ -618,6 +621,23 @@ hashdir(char **dirp)
 	    cn->u.name = dirp;
 	    cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
 	}
+#ifdef _WIN32
+	/* Hash foo.exe as foo, since when no real foo exists, foo.exe
+	   will get executed by DOS automatically.  This quiets
+	   spurious corrections when CORRECT or CORRECT_ALL is set. */
+	if ((exe = strrchr(fn, '.')) &&
+	    (exe[1] == 'E' || exe[1] == 'e') &&
+	    (exe[2] == 'X' || exe[2] == 'x') &&
+	    (exe[3] == 'E' || exe[3] == 'e') && exe[4] == 0) {
+	    *exe = 0;
+	    if (!cmdnamtab->getnode(cmdnamtab, fn)) {
+		cn = (Cmdnam) zcalloc(sizeof *cn);
+		cn->flags = 0;
+		cn->u.name = dirp;
+		cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
+	    }
+	}
+#endif /* _WIN32 */
     }
     closedir(dir);
 }
diff --git a/Src/module.c b/Src/module.c
index f91650a7f..1117571a4 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -567,6 +567,37 @@ load_module(char const *name)
     return m;
 }
 
+/* This ensures that the module with the name given as the second argument
+ * is loaded.
+ * The third argument should be non-zero if the function should complain
+ * about trying to load a module with a full path name in restricted mode.
+ * The last argument should be non-zero if this function should signal an
+ * error if the module is already loaded.
+ * The return value is the module of NULL if the module couldn't be loaded. */
+
+/**/
+Module
+require_module(char *nam, char *module, int res, int test)
+{
+    Module m = NULL;
+    LinkNode node;
+
+    node = find_module(module);
+    if (node && (m = ((Module) getdata(node)))->handle &&
+	!(m->flags & MOD_UNLOAD)) {
+	if (test) {
+	    zwarnnam(nam, "module %s already loaded.", module, 0);
+	    return NULL;
+	}
+    } else if (res && isset(RESTRICTED) && strchr(module, '/')) {
+	zwarnnam(nam, "%s: restricted", module, 0);
+	return NULL;
+    } else
+	return load_module(module);
+
+    return m;
+}
+
 /**/
 void
 add_dep(char *name, char *from)
@@ -963,22 +994,10 @@ bin_zmodload_load(char *nam, char **args, char *ops)
 	return 0;
     } else {
 	/* load modules */
-	for (; *args; args++) {
-	    Module m;
-
-	    node = find_module(*args);
-	    if (node && (m = ((Module) getdata(node)))->handle &&
-		!(m->flags & MOD_UNLOAD)) {
-		if (!ops['i']) {
-		    zwarnnam(nam, "module %s already loaded.", *args, 0);
-		    ret = 1;
-		}
-	    } else if (isset(RESTRICTED) && strchr(*args, '/')) {
-		zwarnnam(nam, "%s: restricted", *args, 0);
+	for (; *args; args++)
+	    if (!require_module(nam, *args, 1, (!ops['i'])))
 		ret = 1;
-	    } else if (!load_module(*args))
-		ret = 1;
-	}
+
 	return ret;
     }
 }
diff --git a/Src/params.c b/Src/params.c
index 77166209f..e8182815e 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -679,11 +679,13 @@ static char **garr;
 static long
 getarg(char **str, int *inv, Value v, int a2, long *w)
 {
-    int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i;
+    int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash;
     char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt;
     long r = 0;
     Comp c;
 
+    ishash = (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED);
+
     /* first parse any subscription flags */
     if (v->pm && (*s == '(' || *s == Inpar)) {
 	int escapes = 0;
@@ -771,12 +773,13 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 	} else if (rev) {
 	    v->isarr |= SCANPM_WANTVALS;
 	}
-	if (!down && v->pm && PM_TYPE(v->pm->flags) == PM_HASHED)
+	if (!down && ishash)
 	    v->isarr &= ~SCANPM_MATCHMANY;
 	*inv = ind;
     }
 
-    for (t=s, i=0; *t && ((*t != ']' && *t != Outbrack && *t != ',') || i); t++)
+    for (t=s, i=0;
+	 *t && ((*t != ']' && *t != Outbrack && (ishash || *t != ',')) || i); t++)
 	if (*t == '[' || *t == Inbrack)
 	    i++;
 	else if (*t == ']' || *t == Outbrack)
@@ -791,7 +794,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
     singsub(&s);
 
     if (!rev) {
-	if (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED) {
+	if (ishash) {
 	    HashTable ht = v->pm->gets.hfn(v->pm);
 	    if (!ht) {
 		ht = newparamtable(17, v->pm->nam);
@@ -867,7 +870,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 
 	if ((c = parsereg(s))) {
 	    if (v->isarr) {
-		if (PM_TYPE(v->pm->flags) == PM_HASHED) {
+		if (ishash) {
 		    scancomp = c;
 		    if (ind)
 			v->isarr |= SCANPM_MATCHKEY;
diff --git a/Src/subst.c b/Src/subst.c
index 66c363145..2e9b84718 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -999,11 +999,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 
 	if (!(v = fetchvalue((subexp ? &ov : &s), (wantt ? -1 :
 				  ((unset(KSHARRAYS) || inbrace) ? 1 : -1)),
-			     hkeys|hvals)))
+			     hkeys|hvals)) ||
+	    (v->pm && (v->pm->flags & PM_UNSET)))
 	    vunset = 1;
 
 	if (wantt) {
-	    if (v) {
+	    if (v && v->pm && !(v->pm->flags & PM_UNSET)) {
 		int f = v->pm->flags;
 
 		switch (PM_TYPE(f)) {
diff --git a/Src/system.h b/Src/system.h
index 292943dd9..650690b51 100644
--- a/Src/system.h
+++ b/Src/system.h
@@ -70,8 +70,15 @@ char *alloca _((size_t));
 # endif
 #endif
 
-#ifdef HAVE_LIBC_H     /* NeXT */
-# include <libc.h>
+/*
+ * libc.h in an optional package for Debian Linux is broken (it
+ * defines dup() as a synonym for dup2(), which has a different
+ * number of arguments), so just include it for next.
+ */
+#ifdef __NeXT__
+# ifdef HAVE_LIBC_H
+#  include <libc.h>
+# endif
 #endif
 
 #ifdef HAVE_SYS_TYPES_H
diff --git a/Src/zsh.export b/Src/zsh.export
index bfad7aea2..d31e7902e 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -173,6 +173,7 @@ refreshptr
 remlpaths
 remnulargs
 removehashnode
+require_module
 resetneeded
 restoredir
 reswdtab
diff --git a/acconfig.h b/acconfig.h
index 77110b457..506441635 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -196,10 +196,13 @@
 /* Define to 1 if system has working FIFO's */
 #undef HAVE_FIFOS
 
-/* Define to 1 if struct rlimit use quad_t */
+/* Define to 1 if struct rlimit uses quad_t */
 #undef RLIM_T_IS_QUAD_T
 
-/* Define to 1 if rlimit use unsigned */
+/* Define to 1 if struct rlimit uses long long */
+#undef RLIM_T_IS_LONG_LONG
+
+/* Define to 1 if rlimit uses unsigned */
 #undef RLIM_T_IS_UNSIGNED
 
 /* Define to the type used in struct rlimit */
diff --git a/configure.in b/configure.in
index e41bf47d6..dd6bfee4b 100644
--- a/configure.in
+++ b/configure.in
@@ -673,7 +673,8 @@ dnl The backslash substitution is to persuade cygwin to cough up
 dnl slashes rather than doubled backslashes in the path.
 echo "#include <signal.h>" > nametmp.c
 sigfile_list="`$CPP nametmp.c |
-sed -n -e 's/^#[ 	].*\"\(.*\)\"/\1/p' -e 's/\\\\\\\\/\//g' |
+sed -n 's/^#[ 	].*\"\(.*\)\"/\1/p' |
+sed 's/\\\\\\\\/\//g' |
 $AWK '{ if (\$1 ~ \"sig\") files[[\$1]] = \$1 }
   END { for (var in files) print var }'`"
 rm -f nametmp.c
@@ -681,6 +682,7 @@ if test -z "$sigfile_list"; then
   dnl In case we don't get the stuff from the preprocesor, use the old
   dnl list of standard places.
   sigfile_list="/usr/include/bsd/sys/signal.h
+/usr/include/signum.h
 /usr/include/asm/signum.h
 /usr/include/asm/signal.h
 /usr/include/linux/signal.h
@@ -689,9 +691,13 @@ if test -z "$sigfile_list"; then
 fi
 for SIGNAL_H in $sigfile_list
 do
-  test -f $SIGNAL_H && \
-  grep '#[ 	]*define[ 	][ 	]*SIG[0-9A-Z]*[ 	]*[0-9][0-9]*' $SIGNAL_H > /dev/null && \
-  break
+  dnl Try to make sure it doesn't get confused by files that don't
+  dnl have real signal definitions in, but do #define SIG* by counting
+  dnl the number of signals.  Maybe we could even check for e.g. SIGHUP?
+  nsigs=`test -f $SIGNAL_H && \
+  grep '#[ 	]*define[ 	][ 	]*SIG[0-9A-Z]*[ 	]*[0-9][0-9]*' $SIGNAL_H | \
+  wc -l | sed 's/[ 	]//g'`
+  test "x$nsigs" != x && test "$nsigs" -ge 7 && break
 done
 zsh_cv_path_signal_h=$SIGNAL_H
 ])
@@ -729,20 +735,43 @@ dnl ------------------
 dnl rlimit type checks
 dnl ------------------
 DEFAULT_RLIM_T=long
-AC_CACHE_CHECK(if rlim_t is quad_t,
-zsh_cv_rlim_t_is_quad_t,
+AC_CACHE_CHECK(if rlim_t is longer than a long,
+zsh_cv_rlim_t_is_longer,
 [AC_TRY_RUN([
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 #include <sys/resource.h>
 main(){struct rlimit r;exit(sizeof(r.rlim_cur) <= sizeof(long));}],
-zsh_cv_rlim_t_is_quad_t=yes,
-zsh_cv_rlim_t_is_quad_t=no,
-zsh_cv_rlim_t_is_quad_t=yes)])
-if test $zsh_cv_rlim_t_is_quad_t = yes; then
-  AC_DEFINE(RLIM_T_IS_QUAD_T)
-  DEFAULT_RLIM_T=quad_t
+zsh_cv_rlim_t_is_longer=yes,
+zsh_cv_rlim_t_is_longer=no,
+zsh_cv_rlim_t_is_longer=yes)])
+if test $zsh_cv_rlim_t_is_longer = yes; then
+  AC_CACHE_CHECK(if rlim_t is a quad,
+  zsh_cv_rlim_t_is_quad_t,
+  [AC_TRY_RUN([
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <stdio.h>
+#include <sys/resource.h>
+main() { 
+  struct rlimit r;
+  char buf[[20]];
+  r.rlim_cur = 0;
+  sprintf(buf, "%qd", r.rlim_cur);
+  exit(strcmp(buf, "0"));
+}],
+  zsh_cv_rlim_t_is_quad_t=yes,
+  zsh_cv_rlim_t_is_quad_t=no,
+  zsh_cv_rlim_t_is_quad_t=no)])
+  if test $zsh_cv_tlim_t_is_quad_t = yes; then
+    AC_DEFINE(RLIM_T_IS_QUAD_T)
+    DEFAULT_RLIM_T=quad_t
+  else
+    AC_DEFINE(RLIM_T_IS_LONG_LONG)
+    DEFAULT_RLIM_T='long long'
+  fi
 else
   AC_CACHE_CHECK(if the rlim_t is unsigned,
   zsh_cv_type_rlim_t_is_unsigned,
@@ -1113,7 +1142,6 @@ main()
   elif test "x$zsh_cv_func_dlsym_needs_underscore" != xno; then
     dnl Do not cache failed value
     unset zsh_cv_func_dlsym_needs_underscore
-    dynamic=no
   fi
 fi
 
diff --git a/patchlist.txt b/patchlist.txt
index 9ec40d8dd..0497dee80 100644
--- a/patchlist.txt
+++ b/patchlist.txt
@@ -299,7 +299,7 @@ Phil: zless, 5032, simplified by Bart, 5037, also added a `setopt
 localoptions' after spending an hour wondering why nothing worked any
 more.
 
-Me: `make install' does not do `make install.info', 5047
+pws: `make install' does not do `make install.info', 5047
 
 Sven:  compcall tries old-style completion from new-style function,
 compctl -K ' func' handles newstyle completion, 5059; avoid recursion,
@@ -309,7 +309,7 @@ Sven: inserting completion inside brace expansion, 5060
 
 Sven: extra completion context, 5092
 
-Me: typeset -T MYPATH mypath, 5094, plus fix for MYPATH=(foo),
+pws: typeset -T MYPATH mypath, 5094, plus fix for MYPATH=(foo),
 mypath=foo (and also existing PATH=(foo) bug), 5120
 
 Sven: doc fix for glob qualifiers, 5102
@@ -320,18 +320,18 @@ Drazen Kacar, modified by me: workaround for terminal bug on Solaris,
 Sven:  zle and widget information via variables in new completion
 functions, 5104
 
-Me: remove old zle -C, zle -C now does new completion, 5105
+pws: remove old zle -C, zle -C now does new completion, 5105
 
 Sven:  glob qualifier o for modes, 5107
 
-Me: fix for unsetting special zle variables, 5111
+pws: fix for unsetting special zle variables, 5111
 
 Drazen Kacar, modified by me: unlock terminal device on Solaris, 5118
 (5117 was wrong)
 
   pws-7
 
-Me: patch for zls, 5054 (appeared in pws-6 but not in corresponding
+pws: patch for zls, 5054 (appeared in pws-6 but not in corresponding
 patchlist).
 
 Bart: finally added missing hunk from 4965 which allowed unsetting an
@@ -355,7 +355,7 @@ Sven: fix for command completion and pattern completions, 5178
 
 Sven: ${(P)...} 5183, 5199, 5200
 
-Me: compctl documentation tidy-up, 5185, 5198
+pws: compctl documentation tidy-up, 5185, 5198
 
 Sven: zle commands which use the minibuffer erase completion listings,
 5201
@@ -370,13 +370,13 @@ Sven: ${foo:q}, 5208, preliminary
 
 Sven: use ${foo:q} for quoting prefix and suffix in new completion, 5120
 
-Me: bashautolist option, 5229; Sven's addition, 5234, and doc 5235; 5269
+pws: bashautolist option, 5229; Sven's addition, 5234, and doc 5235; 5269
 
-Me: .zlogout doc, 5233
+pws: .zlogout doc, 5233
 
-Me: added note on Linux Alpha with egcs to Etc/MACHINES, not posted
+pws: added note on Linux Alpha with egcs to Etc/MACHINES, not posted
 
-Me: typeset -T fix, 5247
+pws: typeset -T fix, 5247
 
 Bart: parameter scoping docs, 5258
  
@@ -390,7 +390,7 @@ Sven: rewrite of $foo:q, 5265, +doc, 5284
 
 Sven: get matcher number in new completion function, 5266
 
-Me: interrupts in getquery() weren't gracefully handled, 5281
+pws: interrupts in getquery() weren't gracefully handled, 5281
 
   pws-8
 
@@ -409,14 +409,14 @@ Sven: compctl matcher to use reference counts, 5316
 
 Sven: keys available in zle widget functions, 5320
 
-Me: compctl -LM, 5321
+pws: compctl -LM, 5321
 
-Me: revamped signames.c generation, 5326, 5329, plus Matt fix, 5330
+pws: revamped signames.c generation, 5326, 5329, plus Matt fix, 5330
 
 Sweth, Bart, Me: Functions/allopt, basically as in 2121 with the odd
 emulate and local.
 
-Me: emulate -L, 5332
+pws: emulate -L, 5332
 
 Sven: printing of zle condition codes, 5335
 
@@ -425,9 +425,9 @@ Sven: Modularisation of new completion shell code, 5341
 Sven: ignoring ignored prefix in new conditions, 5342; related fixes,
 5343
 
-Me: patch for completion init and __normal, 5344; Sven fix, 5351
+pws: patch for completion init and __normal, 5344; Sven fix, 5351
 
-Me: "$foo[@]" didn't remove the argument if $foo wasn't set, 5349;
+pws: "$foo[@]" didn't remove the argument if $foo wasn't set, 5349;
 Bart's fix so this works on OSes other than AIX, 5361
 
 Sven: change fignore handling, 5352
@@ -437,14 +437,14 @@ failed, 5354
 
 Sven: compadd -R function for suffix removal, 5355
 
-Me: #key-* completions now allow 0 or more key bindings, 5362
+pws: #key-* completions now allow 0 or more key bindings, 5362
 
-Me: Moved Misc/Completion to Functions/Completion; added some of my own
+pws: Moved Misc/Completion to Functions/Completion; added some of my own
 new-style completions: not posted
 
-Me: 5281 now works, 5364
+pws: 5281 now works, 5364
 
-Me: make dependencies for main.o, Makemod, zshpaths.h, 5365
+pws: make dependencies for main.o, Makemod, zshpaths.h, 5365
 
   pws-9
 
@@ -458,9 +458,9 @@ Andrej: Reliant UNIX configuration, 5377
 
 Sven: Manual for new completion (so far), 5384, 5397
 
-Me: dump new completion status for fast initialisation, 5393
+pws: dump new completion status for fast initialisation, 5393
 
-Me: bug fixlet for __path_files, 5398
+pws: bug fixlet for __path_files, 5398
 
 Sven: overhaul of do_ambiguous with some bug-fixage, 5399, 5407
 
@@ -469,11 +469,11 @@ $COMPDUMP file, 5402
 
 Sven: files -> __files, 5401
 
-Me: magicequalsubst now affects all arguments ...=~...:~..., 5403
+pws: magicequalsubst now affects all arguments ...=~...:~..., 5403
 
-Me: set -x output for [[ ... ]], 5408
+pws: set -x output for [[ ... ]], 5408
 
-Me: IRIX 6.5 problems in Etc/MACHINES (see 5410 from Helmut Jarausch).
+pws: IRIX 6.5 problems in Etc/MACHINES (see 5410 from Helmut Jarausch).
 
 Sven: 5412: better matcher control.
 
@@ -483,7 +483,7 @@ Sven: 5417: multiple subscripts with undefined array
 
 Sven: 5418: small addmatches fixes
 
-Me: 5421: setting same element of assoc array in full array assignment crashed
+pws: 5421: setting same element of assoc array in full array assignment crashed
 
 Sven: 5422: braces in completions were not tokenized; array parameters were
 used uncopied
@@ -492,14 +492,73 @@ Sven: 5423: compadd accepts either - or -- to end options
 
 Sven: 5424: addmatches fix when not doing matching
 
-Me: 5425: fix pattern matching for new completion
+pws: 5425: fix pattern matching for new completion
 
 Sven: 5429: $CONTEXT strings
 
 Sven: 5430: rewrite Functions/Completions with simplified syntax (no #array
 type completions).
 
-Me: 5436: set -x for function calls and ((...)).
+pws: 5436: set -x for function calls and ((...)).
 
-Me: unposted (but see 5440): zftp changes: more return 6's, functions now
+pws: unposted (but see 5440): zftp changes: more return 6's, functions now
 do auto-open and avoid subshells.
+
+  pws-10
+
+Martin Buchholz: 5448: libc.h can't be included on Debian Linux, so only
+include it on NeXT where it's necessary.
+
+Matt: 5330: I've put this back the way it original was.  I hate sed almost
+as much as awk.
+
+Sven: 5455: keep track of which matcher specification to use
+
+Sven: 5466: compwid manual for -after and -between
+
+Sven: 5467: expn manual typo
+
+Sven: 5469: init fix and Functions/Completion/_comp_parts
+
+Sven: 5470: new completion conditions didn't handle untokenization
+consistently.
+
+Sven: 5471: range code knows not to handle associative arrays
+
+Sven: 5476: quoting of tildes in Functions/Completion/_path_files
+
+Sven: 5483: completeinword fixes
+
+Sven: 5489: control for matching in _path_files and _comp_parts
+
+Sven: 5490: unset test for AA elements when substituting
+
+pws: unposted, see 5503: remove dynamic=no from configure.in when
+underscore is needed.
+
+pws: 5508: init and dump, globbing and printing.
+
+Sven: 5511: make sure compctl is available for new completion
+
+Sven: 5512, 5525: globcomplete fix for new completion
+
+Sven: 5521: improved option handling for _path_files
+
+Sven: 5529: cleanup for Functions/Completion
+
+pws: 5531: small init fix
+
+pws: 5538: approximate pattern matching, (#a1)readme etc.
+
+Sven: 5543: compadd -X, zshcompwid manual
+
+Sven: 5544: another completion cleanup
+
+pws: 5545: silly set -x mistake
+
+Sven: 5548: _path_files, _comp_parts
+
+Matt: 5553: under _WIN32, .exe suffix is optional for commands
+
+pws: unposted: Functions/Completion moved to Completion; subdirectories
+Core, Base, Builtins, User, Commands created; Completion/README created.