about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:18:42 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:18:42 +0000
commit7a0415cfd70a02b2280d27556c6c54cef1c86e1a (patch)
tree37a88a1c4611ee37f2a3209873fc9a34a2624587
parent904b939cbd81a542303da2c58288b95b153106f5 (diff)
downloadzsh-7a0415cfd70a02b2280d27556c6c54cef1c86e1a.tar.gz
zsh-7a0415cfd70a02b2280d27556c6c54cef1c86e1a.tar.xz
zsh-7a0415cfd70a02b2280d27556c6c54cef1c86e1a.zip
zsh-3.1.5-pws-11 zsh-3.1.5-pws-11
-rw-r--r--Completion/Base/_brace_parameter5
-rw-r--r--Completion/Base/_command_names6
-rw-r--r--Completion/Base/_condition10
-rw-r--r--Completion/Base/_default3
-rw-r--r--Completion/Base/_equal3
-rw-r--r--Completion/Base/_match_pattern6
-rw-r--r--Completion/Base/_match_test8
-rw-r--r--Completion/Base/_parameter3
-rw-r--r--Completion/Base/_precommand5
-rw-r--r--Completion/Base/_subscript5
-rw-r--r--Completion/Base/_tilde10
-rw-r--r--Completion/Base/_vars2
-rw-r--r--Completion/Builtins/_aliases2
-rw-r--r--Completion/Builtins/_arrays2
-rw-r--r--Completion/Builtins/_autoload2
-rw-r--r--Completion/Builtins/_bg_jobs2
-rw-r--r--Completion/Builtins/_bindkey6
-rw-r--r--Completion/Builtins/_builtin8
-rw-r--r--Completion/Builtins/_cd63
-rw-r--r--Completion/Builtins/_command6
-rw-r--r--Completion/Builtins/_disable10
-rw-r--r--Completion/Builtins/_echotc2
-rw-r--r--Completion/Builtins/_enable10
-rw-r--r--Completion/Builtins/_fc8
-rw-r--r--Completion/Builtins/_functions2
-rw-r--r--Completion/Builtins/_hash6
-rw-r--r--Completion/Builtins/_jobs2
-rw-r--r--Completion/Builtins/_kill6
-rw-r--r--Completion/Builtins/_limits2
-rw-r--r--Completion/Builtins/_sched2
-rw-r--r--Completion/Builtins/_set10
-rw-r--r--Completion/Builtins/_setopt7
-rw-r--r--Completion/Builtins/_source4
-rw-r--r--Completion/Builtins/_trap6
-rw-r--r--Completion/Builtins/_unhash10
-rw-r--r--Completion/Builtins/_unsetopt7
-rw-r--r--Completion/Builtins/_vars_eq2
-rw-r--r--Completion/Builtins/_wait4
-rw-r--r--Completion/Builtins/_which2
-rw-r--r--Completion/Builtins/_zftp14
-rw-r--r--Completion/Builtins/_zle6
-rw-r--r--Completion/Builtins/_zmodload12
-rw-r--r--Completion/Commands/_correct_filename6
-rw-r--r--Completion/Commands/_most_recent_file24
-rw-r--r--Completion/Core/_comp_parts25
-rw-r--r--Completion/Core/_compalso6
-rw-r--r--Completion/Core/_files7
-rw-r--r--Completion/Core/_main_complete219
-rw-r--r--Completion/Core/_multi_parts201
-rw-r--r--Completion/Core/_normal30
-rw-r--r--Completion/Core/_path_files110
-rw-r--r--Completion/README31
-rw-r--r--Completion/User/_a2ps8
-rw-r--r--Completion/User/_configure29
-rw-r--r--Completion/User/_dd4
-rw-r--r--Completion/User/_find24
-rw-r--r--Completion/User/_hosts2
-rw-r--r--Completion/User/_make2
-rw-r--r--Completion/User/_man6
-rw-r--r--Completion/User/_mh36
-rw-r--r--Completion/User/_rcs8
-rw-r--r--Completion/User/_rlogin10
-rw-r--r--Completion/User/_stty6
-rw-r--r--Completion/User/_tar68
-rw-r--r--Completion/User/_x_options2
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Zsh/builtins.yo2
-rw-r--r--Doc/Zsh/compctl.yo28
-rw-r--r--Doc/Zsh/compwid.yo256
-rw-r--r--Doc/Zsh/expn.yo2
-rw-r--r--Doc/Zsh/params.yo5
-rw-r--r--Doc/Zsh/zle.yo4
-rw-r--r--INSTALL9
-rw-r--r--Src/Makefile.in15
-rw-r--r--Src/Zle/comp.h39
-rw-r--r--Src/Zle/comp1.c57
-rw-r--r--Src/Zle/comp1.export15
-rw-r--r--Src/Zle/compctl.c260
-rw-r--r--Src/Zle/zle_hist.c6
-rw-r--r--Src/Zle/zle_main.c4
-rw-r--r--Src/Zle/zle_misc.c6
-rw-r--r--Src/Zle/zle_params.c21
-rw-r--r--Src/Zle/zle_refresh.c8
-rw-r--r--Src/Zle/zle_tricky.c912
-rw-r--r--Src/Zle/zle_word.c2
-rw-r--r--Src/builtin.c12
-rw-r--r--Src/compat.c10
-rw-r--r--Src/glob.c4
-rw-r--r--Src/mem.c18
-rw-r--r--Src/params.c149
-rw-r--r--Src/subst.c4
-rw-r--r--Src/system.h2
-rw-r--r--Src/utils.c6
-rw-r--r--Src/zsh.export6
-rw-r--r--acconfig.h3
-rwxr-xr-xconfig.sub117
-rw-r--r--configure.in34
-rw-r--r--patchlist.txt101
98 files changed, 2354 insertions, 922 deletions
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
new file mode 100644
index 000000000..092376e78
--- /dev/null
+++ b/Completion/Base/_brace_parameter
@@ -0,0 +1,5 @@
+#defcomp -brace-parameter-
+
+# Simple but without spiffy suffix handling: compgen -v -S '} '
+
+compadd -S '} ' -r '-:?#%+=[/'  - "${(@)${${${(f)$(typeset)}%%\=*}##* }:gs/'//}"
diff --git a/Completion/Base/_command_names b/Completion/Base/_command_names
index d3b8a109a..eab314dfa 100644
--- a/Completion/Base/_command_names
+++ b/Completion/Base/_command_names
@@ -1,3 +1,7 @@
 #defcomp -command-
 
-complist -c
+local nm=$compstate[nmatches]
+
+compgen -c
+
+[[ nm -eq compstate[nmatches] ]] && _path_files -/g "*(*)"
diff --git a/Completion/Base/_condition b/Completion/Base/_condition
index 3e45e1b8f..fb6b98b1b 100644
--- a/Completion/Base/_condition
+++ b/Completion/Base/_condition
@@ -1,10 +1,12 @@
 #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
+local prev="$words[CURRENT-1]"
+
+if [[ "$prev" = -o ]]; then
+  compgen -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}'
+elif [[ "$prev" = -([no]t|ef) ]]; then
   _files
 else
   _files
-  complist -v
+  compgen -v
 fi
diff --git a/Completion/Base/_default b/Completion/Base/_default
index 8bcf14f6a..569bd6382 100644
--- a/Completion/Base/_default
+++ b/Completion/Base/_default
@@ -6,7 +6,8 @@
 # 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'.
+# and insert the line `[[ compstate[nmatches] -eq 0 ]] || return' after
+# `compcall'.
 
 compcall || return
 
diff --git a/Completion/Base/_equal b/Completion/Base/_equal
new file mode 100644
index 000000000..f407014fe
--- /dev/null
+++ b/Completion/Base/_equal
@@ -0,0 +1,3 @@
+#defcomp -equal-
+
+compgen -am
diff --git a/Completion/Base/_match_pattern b/Completion/Base/_match_pattern
index c5debc0b9..3df115d5b 100644
--- a/Completion/Base/_match_pattern
+++ b/Completion/Base/_match_pattern
@@ -10,7 +10,7 @@
 # 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
+# allows to give pattern flags like `(#l)' that are to be used whenever
 # matching is done.
 #
 # As an example, if you have global match specifications like:
@@ -20,12 +20,12 @@
 # This function would look like:
 #
 #   eval "${3}='(#l)'"
-#   [[ MATCHER -eq 2 ]] && eval "$1='${(P)2:gs/./*./:gs/-/*-/}'"
+#   [[ compstate[matcher] -eq 2 ]] && eval "$2='${(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 ))'
+# would have to be changed to `(( compstate[matcher] <= 2 ))'
 #
 # The default implementation of this function is empty.
diff --git a/Completion/Base/_match_test b/Completion/Base/_match_test
index e8b6e6424..7db521e81 100644
--- a/Completion/Base/_match_test
+++ b/Completion/Base/_match_test
@@ -1,9 +1,9 @@
 #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.
+# shell code. It should test the value of `compstate[matcher]' 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.
 #
@@ -12,4 +12,4 @@
 # match specifications and modify the function `_match_pattern' to build the
 # pattern to use in the calling function.
 
-(( MATCHER == 1 ))
+(( compstate[matcher] <= 1 ))
diff --git a/Completion/Base/_parameter b/Completion/Base/_parameter
new file mode 100644
index 000000000..2bd66ec93
--- /dev/null
+++ b/Completion/Base/_parameter
@@ -0,0 +1,3 @@
+#defcomp -parameter-
+
+compgen -v
diff --git a/Completion/Base/_precommand b/Completion/Base/_precommand
index 2cf661147..c13cd7465 100644
--- a/Completion/Base/_precommand
+++ b/Completion/Base/_precommand
@@ -1,5 +1,6 @@
 #defcomp - nohup nice eval time rusage noglob nocorrect exec
 
-[[ -position 1 -1 ]]
+shift words
+(( CURRENT-- ))
 
-_normal "$@"
+_normal
diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript
index 2b827a117..d50fd8335 100644
--- a/Completion/Base/_subscript
+++ b/Completion/Base/_subscript
@@ -1,4 +1,5 @@
 #defcomp -subscript-
 
-_compalso -math- "$@"
-[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )"
+_compalso -math-
+[[ ${(Pt)${compstate[parameter]}} = assoc* ]] &&
+    compgen -k "( ${(kP)${compstate[parameter]}} )"
diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde
new file mode 100644
index 000000000..aef575e19
--- /dev/null
+++ b/Completion/Base/_tilde
@@ -0,0 +1,10 @@
+#defcomp -tilde-
+
+# We use all named directories and user names here. If this is too slow
+# for you or if there are too many of them, you may want to use
+# `compgen -k friends -qS/' or something like that. To get all user names
+# if there are no matches in the `friends' array, add
+#   `(( compstate[nmatches] )) || compgen -nu -qS/'
+# below that.
+
+compgen -nu -qS/
diff --git a/Completion/Base/_vars b/Completion/Base/_vars
index 7153b6f38..92de51e1f 100644
--- a/Completion/Base/_vars
+++ b/Completion/Base/_vars
@@ -1,3 +1,3 @@
 #defcomp -math- getopts read unset vared
 
-complist -v
+compgen -v
diff --git a/Completion/Builtins/_aliases b/Completion/Builtins/_aliases
index 1038a726e..2ccf18439 100644
--- a/Completion/Builtins/_aliases
+++ b/Completion/Builtins/_aliases
@@ -1,3 +1,3 @@
 #defcomp unalias
 
-complist -a
+compgen -a
diff --git a/Completion/Builtins/_arrays b/Completion/Builtins/_arrays
index cbeac7118..94401f28a 100644
--- a/Completion/Builtins/_arrays
+++ b/Completion/Builtins/_arrays
@@ -1,3 +1,3 @@
 #defcomp shift
 
-complist -A
+compgen -A
diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload
index 4f506baeb..d1462e09a 100644
--- a/Completion/Builtins/_autoload
+++ b/Completion/Builtins/_autoload
@@ -1,3 +1,3 @@
 #defcomp autoload
 
-complist -s '${^fpath}/*(N:t)'
+compgen -s '${^fpath}/*(N:t)'
diff --git a/Completion/Builtins/_bg_jobs b/Completion/Builtins/_bg_jobs
index 511bb8308..4abee070c 100644
--- a/Completion/Builtins/_bg_jobs
+++ b/Completion/Builtins/_bg_jobs
@@ -1,3 +1,3 @@
 #defcomp bg
 
-complist -z -P '%'
+compgen -z -P '%'
diff --git a/Completion/Builtins/_bindkey b/Completion/Builtins/_bindkey
index 8eddeb2a8..d3d019492 100644
--- a/Completion/Builtins/_bindkey
+++ b/Completion/Builtins/_bindkey
@@ -1,7 +1,7 @@
 #defcomp bindkey
 
-if [[ -mword 1 -*[DAN]* || -mcurrent -1 -*M ]]; then
-  complist -s '$(bindkey -l)'
+if [[ "$words[2]" = -*[DAN]* || "$words[CURRENT-1] = -*M ]]; then
+  compgen -s '$(bindkey -l)'
 else
-  complist -b
+  compgen -b
 fi
diff --git a/Completion/Builtins/_builtin b/Completion/Builtins/_builtin
index a967932ee..bee67fe8f 100644
--- a/Completion/Builtins/_builtin
+++ b/Completion/Builtins/_builtin
@@ -1,7 +1,9 @@
 #defcomp builtin
 
-if [[ -position 2 -1 ]]; then
-  _normal "$@"
+if (( $CURRENT > 2 )); then
+  shift words
+  (( CURRENT -- ))
+  _normal
 else
-  complist -eB
+  compgen -eB
 fi
diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd
index f3ce67ec7..65ce7f293 100644
--- a/Completion/Builtins/_cd
+++ b/Completion/Builtins/_cd
@@ -1,3 +1,62 @@
-#defcomp cd
+#defcomp cd pushd
 
-_files -W cdpath -g '*(-/)'
+# Handling of cd.
+#  - Normally just completes directories.  Uses cdpath if that's set
+#    and the string doesn't begin with ~, /, ./ or ../.
+#  - In the second argument to cd for the form `cd old new', completes
+#    possible `new' strings by examining `old' and $PWD.
+#  - After pushd - or pushd +, completes numbers, but the listing
+#    gives you the list of directories to complete.  This turns on
+#    menu-completion and lists the possibilities automatically, otherwise
+#    it's not a lot of use.  If you don't type the + or - it will
+#    complete directories as normal.
+
+local pushdminus
+[[ -o pushdminus ]] && pushdminus=1
+
+emulate -LR zsh
+setopt extendedglob
+
+if [[ -position 3 ]]; then
+  # cd old new: look for old in $PWD and see what can replace it
+  local rep
+  # Get possible completions using word in position 2
+  rep=(${~PWD/$words[2]/*}~$PWD(-/N))
+  # Now remove all the common parts of $PWD and the completions from this
+  rep=(${${rep#${PWD%%$words[2]*}}%${PWD#*$words[2]}})
+  (( $#rep )) && compadd $rep
+elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then
+  # pushd: just complete the numbers, but show the full directory list with
+  # numbers.
+  # For - we do the same thing, but reverse the numbering (other
+  # way round if pushdminus is set).
+  # The test is for pu* because I have an alias pu since I'm too
+  # lazy to type pushd.
+  IPREFIX=$PREFIX[1]
+  PREFIX=$PREFIX[2,-1]
+  local list lines
+  # get the list of directories with their canonical number
+  lines="$(dirs -v)"
+  # turn the lines into an array, removing the current directory
+  list=(${${(f)lines}##0*})
+  if [[ ( $IPREFIX = - && -z $pushdminus ) ||
+        ( $IPREFIX = + && -n $pushdminus ) ]]; then
+    # reverse the numbering: it counts the last one as -0, which
+    # is a little strange.
+    integer tot i
+    for (( i = 1, tot = $#list-1; tot >= 0; i++, tot-- )); do
+      list[$i]="$tot${list[$i]##[0-9]#}"
+    done
+  fi
+  # make sure -y treats this as a single string
+  lines="${(F)list}"
+  # get the array of numbers only
+  list=(${list%%[ 	]*})
+  compgen -y '$lines' -Q -k list
+  [[ -z $compstate[list] ]] && compstate[list]=list
+  [[ -n $compstate[insert] ]] && compstat[insert]=menu
+elif [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then
+  _path_files -W cdpath -/
+else
+  _path_files -/
+fi
diff --git a/Completion/Builtins/_command b/Completion/Builtins/_command
index b2812de25..47eb0d667 100644
--- a/Completion/Builtins/_command
+++ b/Completion/Builtins/_command
@@ -1,7 +1,7 @@
 #defcomp command
 
-if [[ -position 2 -1 ]]; then
-  _normal "$@"
+if [[ -position 3 -1 ]]; then
+  _normal
 else
-  complist -em
+  compgen -em
 fi
diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable
index 063b65a7d..e3edafe2b 100644
--- a/Completion/Builtins/_disable
+++ b/Completion/Builtins/_disable
@@ -1,6 +1,8 @@
 #defcomp disable
 
-[[ -mcurrent -1 -*a* ]] && complist -ea
-[[ -mcurrent -1 -*f* ]] && complist -eF
-[[ -mcurrent -1 -*r* ]] && complist -ew
-[[ ! -mcurrent -1 -* ]] && complist -eB
+local prev="$words[CURRENT-1]"
+
+[[ "$prev" = -*a* ]] && compgen -ea
+[[ "$prev" = -*f* ]] && compgen -eF
+[[ "$prev" = -*r* ]] && compgen -ew
+[[ "$prev" != -* ]] && compgen -eB
diff --git a/Completion/Builtins/_echotc b/Completion/Builtins/_echotc
index 85ebb97ce..135cabada 100644
--- a/Completion/Builtins/_echotc
+++ b/Completion/Builtins/_echotc
@@ -1,3 +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)'
+compgen -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
index 22ff53ee7..111d1ae26 100644
--- a/Completion/Builtins/_enable
+++ b/Completion/Builtins/_enable
@@ -1,6 +1,8 @@
 #defcomp enable
 
-[[ -mcurrent -1 -*a* ]] && complist -da
-[[ -mcurrent -1 -*f* ]] && complist -dF
-[[ -mcurrent -1 -*r* ]] && complist -dw
-[[ ! -mcurrent -1 -* ]] && complist -dB
+local prev="$words[CURRENT-1]"
+
+[[ "$prev" = -*a* ]] && compgen -da
+[[ "$prev" = -*f* ]] && compgen -dF
+[[ "$prev" = -*r* ]] && compgen -dw
+[[ "$prev" != -* ]] && compgen -dB
diff --git a/Completion/Builtins/_fc b/Completion/Builtins/_fc
index f0d2c03fd..f8cf4dde8 100644
--- a/Completion/Builtins/_fc
+++ b/Completion/Builtins/_fc
@@ -1,7 +1,9 @@
 #defcomp fc
 
-if [[ -mcurrent -1 -*e ]]; then
-  complist -c
-elif [[ -mcurrent -1 -[ARWI]## ]]; then
+local prev="$words[CURRENT-1]"
+
+if [[ "$prev" = -*e ]]; then
+  compgen -c
+elif [[ "$prev" = -[ARWI]## ]]; then
   _files
 fi
diff --git a/Completion/Builtins/_functions b/Completion/Builtins/_functions
index 8a352ea08..7e3174af5 100644
--- a/Completion/Builtins/_functions
+++ b/Completion/Builtins/_functions
@@ -1,3 +1,3 @@
 #defcomp unfunction
 
-complist -F
+compgen -F
diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash
index 171c5e2e8..8c100b801 100644
--- a/Completion/Builtins/_hash
+++ b/Completion/Builtins/_hash
@@ -1,13 +1,13 @@
 #defcomp hash
 
-if [[ -mword 1 -*d* ]]; then
+if [[ "$words[2]" = -*d* ]]; then
   if [[ -string 1 '=' ]]; then
     _path_files -g '*(-/)'
   else
-    complist -n -q -S '='
+    compgen -n -q -S '='
   fi
 elif [[ -string 1 '=' ]]; then
   _files -/g '*(*)'
 else
-  complist -m -q -S '='
+  compgen -m -q -S '='
 fi
diff --git a/Completion/Builtins/_jobs b/Completion/Builtins/_jobs
index 018883c61..8f6991de0 100644
--- a/Completion/Builtins/_jobs
+++ b/Completion/Builtins/_jobs
@@ -1,3 +1,3 @@
 #defcomp fg jobs
 
-complist -j -P '%'
+compgen -j -P '%'
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
index 50796d36f..c1afa78cb 100644
--- a/Completion/Builtins/_kill
+++ b/Completion/Builtins/_kill
@@ -3,9 +3,9 @@
 local list
 
 if [[ -iprefix '-' ]]; then
-  complist -k "($signals[1,-3])"
+  compgen -k "($signals[1,-3])"
 else
-  complist -P '%' -j
+  compgen -P '%' -j
   list=("$(ps 2>/dev/null)")
-  complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
+  compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
 fi
diff --git a/Completion/Builtins/_limits b/Completion/Builtins/_limits
index 35ccbe07e..8b0b41c71 100644
--- a/Completion/Builtins/_limits
+++ b/Completion/Builtins/_limits
@@ -1,3 +1,3 @@
 #defcomp limit unlimit
 
-complist -k "(${(j: :)${(f)$(limit)}%% *})"
+compgen -k "(${(j: :)${(f)$(limit)}%% *})"
diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched
index 1e8ae3445..62cdbb070 100644
--- a/Completion/Builtins/_sched
+++ b/Completion/Builtins/_sched
@@ -1,3 +1,3 @@
 #defcomp sched
 
-[[ -position 2 -1 ]] && _normal "$@"
+[[ -position 3 -1 ]] && _normal
diff --git a/Completion/Builtins/_set b/Completion/Builtins/_set
index 5597025bc..959dac75d 100644
--- a/Completion/Builtins/_set
+++ b/Completion/Builtins/_set
@@ -1,7 +1,9 @@
 #defcomp set
 
-if [[ -mcurrent -1 [-+]o ]]; then
-  complist -o
-elif [[ -current -1 -A ]]; then
-  complist -A
+local prev="$words[CURRENT-1]"
+
+if [[ "$prev" = [-+]o ]]; then
+  compgen -o
+elif [[ "$prev" = -A ]]; then
+  compgen -A
 fi
diff --git a/Completion/Builtins/_setopt b/Completion/Builtins/_setopt
index 4abb3ccee..98800152f 100644
--- a/Completion/Builtins/_setopt
+++ b/Completion/Builtins/_setopt
@@ -1,7 +1,8 @@
 #defcomp setopt
 
-local nm=$NMATCHES
+local nm=$compstate[nmatches]
 
-complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
+compgen -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
+[[ compstate[nmatches] -eq nm ]] &&
+    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
diff --git a/Completion/Builtins/_source b/Completion/Builtins/_source
index aae2c7320..1bbbf15a4 100644
--- a/Completion/Builtins/_source
+++ b/Completion/Builtins/_source
@@ -1,7 +1,7 @@
 #defcomp source
 
-if [[ -position 2 -1 ]]; then
-  _normal "$@"
+if [[ -position 3 -1 ]]; then
+  _normal
 else
   _files
 fi
diff --git a/Completion/Builtins/_trap b/Completion/Builtins/_trap
index 59e81c589..36ab1f1a8 100644
--- a/Completion/Builtins/_trap
+++ b/Completion/Builtins/_trap
@@ -1,7 +1,7 @@
 #defcomp trap
 
-if [[ -position 1 ]]; then
-  complist -c
+if [[ CURRENT -eq 2 ]]; then
+  compgen -c
 else
-  complist -k signals
+  compgen -k signals
 fi
diff --git a/Completion/Builtins/_unhash b/Completion/Builtins/_unhash
index fe40c25a2..63d61c991 100644
--- a/Completion/Builtins/_unhash
+++ b/Completion/Builtins/_unhash
@@ -1,6 +1,8 @@
 #defcomp unhash
 
-[[ -mword 1 -*d* ]] && complist -n
-[[ -mword 1 -*a* ]] && complist -a
-[[ -mword 1 -*f* ]] && complist -F
-[[ ! -mword 1 -* ]] && complist -m
+local fl="$words[2]"
+
+[[ "$fl" = -*d* ]] && compgen -n
+[[ "$fl" = -*a* ]] && compgen -a
+[[ "$fl" = -*f* ]] && compgen -F
+[[ "$fl" != -* ]] && compgen -m
diff --git a/Completion/Builtins/_unsetopt b/Completion/Builtins/_unsetopt
index 90d642b51..a5c85b1ef 100644
--- a/Completion/Builtins/_unsetopt
+++ b/Completion/Builtins/_unsetopt
@@ -1,7 +1,8 @@
 #defcomp unsetopt
 
-local nm=$NMATCHES
+local nm=$compstate[nmatches]
 
-complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
+compgen -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
+[[ compstate[nmatches] -eq nm ]] &&
+    compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o
diff --git a/Completion/Builtins/_vars_eq b/Completion/Builtins/_vars_eq
index fcbb0148c..9488cb7f9 100644
--- a/Completion/Builtins/_vars_eq
+++ b/Completion/Builtins/_vars_eq
@@ -1,3 +1,3 @@
 #defcomp declare export integer local readonly typeset
 
-complist -v -q -S '='
+compgen -v -q -S '='
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
index 29a7f6002..6e3a4c3c9 100644
--- a/Completion/Builtins/_wait
+++ b/Completion/Builtins/_wait
@@ -2,6 +2,6 @@
 
 local list
 
-complist -P '%' -j
+compgen -P '%' -j
 list=("$(ps 2>/dev/null)")
-complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
+compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
diff --git a/Completion/Builtins/_which b/Completion/Builtins/_which
index 324256e3d..9248f9c9f 100644
--- a/Completion/Builtins/_which
+++ b/Completion/Builtins/_which
@@ -1,3 +1,3 @@
 #defcomp which whence where type
 
-complist -caF
+compgen -caF
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index 9be9c94db..e93021acf 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -9,28 +9,28 @@ _compskip=1
 
 local subcom
 
-if [[ $COMMAND = zftp ]]; then
+if [[ $words[1] = zftp ]]; then
   if [[ $CURRENT -eq 1 ]]; then
-    compadd -m open params user login type ascii binary mode put \
+    compadd open params user login type ascii binary mode put \
       putat get getat append appendat ls dir local remote mkdir rmdir
     return
   fi
-  subcom=$1
+  subcom=$words[2]
 else
-  subcom=$COMMAND
+  subcom=$words[1]
 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
+   (( $#reply )) && compadd -S/ -q - $reply
    ;;
 
   *(get(|at)|gcp|delete|remote))
    # complete remote files
    zfget_match $PREFIX $SUFFIX
-   (( $#reply )) && compadd -F fignore -m $reply
+   (( $#reply )) && compadd -F fignore - $reply
    ;;
 
   *(put(|at)|pcp))
@@ -40,7 +40,7 @@ case $subcom in
 
   *(open|anon|params))
   # complete hosts:  should do cleverer stuff with user names
-  complist -k hosts
+  compgen -k hosts
   ;;
 
   *)
diff --git a/Completion/Builtins/_zle b/Completion/Builtins/_zle
index bb1102e74..0a9ad0a9e 100644
--- a/Completion/Builtins/_zle
+++ b/Completion/Builtins/_zle
@@ -1,7 +1,7 @@
 #defcomp zle
 
-if [[ -word 1 -N && -position 3 ]]; then
-  complist -F
+if [[ "$words[2]" = -N && CURRENT -eq 3 ]]; then
+  compgen -F
 else
-  complist -b
+  compgen -b
 fi
diff --git a/Completion/Builtins/_zmodload b/Completion/Builtins/_zmodload
index 112acb57c..4259adf06 100644
--- a/Completion/Builtins/_zmodload
+++ b/Completion/Builtins/_zmodload
@@ -1,9 +1,11 @@
 #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)'
+local fl="$words[2]"
+
+if [[ "$fl" = -*(a*u|u*a)* || "$fl" = -*a* && -position 4 -1 ]]; then
+  compgen -B
+elif [[ "$fl" = -*u* ]]; then
+  compgen -s '$(zmodload)'
 else
-  complist -s '${^module_path}/*(N:t:r)'
+  compgen -s '${^module_path}/*(N:t:r)'
 fi
diff --git a/Completion/Commands/_correct_filename b/Completion/Commands/_correct_filename
index edf1c65c2..582555587 100644
--- a/Completion/Commands/_correct_filename
+++ b/Completion/Commands/_correct_filename
@@ -17,7 +17,8 @@ integer approx max_approx=6
 
 if [[ -e "$file" ]]; then
   if [[ -n $WIDGET ]]; then
-    compadd "$file"
+    compadd -U -i "$IPREFIX" "$file"
+    [[ -n "$compstate[insert]" ]] && compstate[insert]=menu
   else
     print "$file"
   fi
@@ -31,7 +32,8 @@ done
 (( $#trylist )) || return 1
 
 if [[ -n $WIDGET ]]; then
-  compadd -U "${trylist[@]}"
+  compadd -U -i "$IPREFIX" -U "${trylist[@]}"
+  [[ -n "$compstate[insert]" ]] && compstate[insert]=menu
 else
   print "${trylist[@]}"
 fi
diff --git a/Completion/Commands/_most_recent_file b/Completion/Commands/_most_recent_file
index ff5645de5..df35ecba7 100644
--- a/Completion/Commands/_most_recent_file
+++ b/Completion/Commands/_most_recent_file
@@ -1,4 +1,22 @@
 #defkeycomp complete-word \C-xm
-local file
-file=($~PREFIX*$~SUFFIX(om[1]N))
-(( $#file )) && compadd -f $file
+
+# Complete the most recent file matching the pattern on the line so
+# far: globbing is active, i.e. *.txt will be expanded to the most recent
+# file ending in .txt
+#
+# With a prefix argument, select the Nth most recent matching file;
+# negative arguments work in the opposite direction, so for example
+# `Esc - \C-x m' gets you the oldest file.
+#
+# (`Most recent' means most recently modified.)
+
+local file tilde etilde
+if [[ $PREFIX = \~*/* ]]; then
+  tilde=${PREFIX%%/*}
+  etilde=${~tilde}
+  file=($~PREFIX*$~SUFFIX(om[$NUMERIC]N))
+  file=(${file/#$etilde/$tilde})
+else
+  file=($~PREFIX*$~SUFFIX(om[$NUMERIC]N))
+fi
+(( $#file )) && compadd -U -f -Q $file
diff --git a/Completion/Core/_comp_parts b/Completion/Core/_comp_parts
index 7c24fd19d..d58669f29 100644
--- a/Completion/Core/_comp_parts
+++ b/Completion/Core/_comp_parts
@@ -21,11 +21,11 @@
 # `_match_test' and `_match_pattern' for this.
 
 local str arr sep test testarr tmparr prefix suffixes matchers autosuffix
-local matchflags opt group expl
+local matchflags opt group expl nm=$compstate[nmatches]
 
 # Test if we should use this function for the global matcher in use.
 
-_match_test _comp_parts || return
+_match_test _comp_parts || return 1
 
 # Get the options.
 
@@ -42,6 +42,7 @@ shift OPTIND-1
 # Get the string from the line.
 
 str="$PREFIX$SUFFIX"
+[[ -o globcomplete ]] && str="$str:q"
 prefix=""
 
 # Walk through the arguments to find the longest unambiguous prefix.
@@ -63,12 +64,14 @@ while [[ $# -gt 1 ]]; do
   test="${str%%${sep}*}"
   matchflags=""
   _match_pattern _comp_parts test matchflags
+  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
   test="${matchflags}${test}"
   testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+  testarr=( "${(@)testarr:#}" )
 
   # 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 )) || return 1
   [[ $#testarr -gt 1 ]] && break
 
   # Only one match, add it to the prefix and skip over it in `str',
@@ -89,11 +92,13 @@ if [[ $# -le 1 || "$str" != *${2}* ]]; then
   matchflags=""
   test="$str"
   _match_pattern _comp_parts test matchflags
+  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
   test="${matchflags}${test}"
   testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
+  testarr=( "${(@)testarr:#}" )
 fi
 
-[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return
+[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return 1
 
 # Now we build the suffixes to give to the completion code.
 shift
@@ -114,6 +119,7 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do
   fi
   matchflags=""
   _match_pattern _comp_parts test matchflags
+  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
   test="${matchflags}${test}"
 
   # We incrementally add suffixes by appending to them the seperators
@@ -124,7 +130,9 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do
     tmparr=( ${=arr[2,-2]} )
     arr=tmparr
   fi
-  suffixes=("${^suffixes[@]}${1}${(@M)^${(@P)arr}:#${~test}*}")
+  tmparr=( "${(@M)${(@P)arr}:#${~test}*}" )
+  tmparr=( "${(@)testarr:#}" )
+  suffixes=("${^suffixes[@]}${1}$^tmparr")
 
   # We want the completion code to generate the most specific suffix
   # for us, so we collect matching specifications that allow partial
@@ -143,5 +151,10 @@ done
 
 # Add the matches for each of the suffixes.
 for i in "$suffixes[@]"; do
-  compadd "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" -p "$prefix" -s "$i" - "$testarr[@]"
+  compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \
+          -i "$IPREFIX" -p "$prefix" -s "$i" - "$testarr[@]"
 done
+
+# This sets the return value to indicate that we added matches (or not).
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/Core/_compalso b/Completion/Core/_compalso
index 23a40e2d0..6ff6cf0bf 100644
--- a/Completion/Core/_compalso
+++ b/Completion/Core/_compalso
@@ -4,10 +4,10 @@
 # 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.
+# `_compalso -math-' to get the completions that would be generated for a
+# mathematical context.
 
 local tmp
 
 tmp="$_comps[$1]"
-[[ -z "$tmp" ]] || "$tmp" "$@"
+[[ -z "$tmp" ]] || "$tmp"
diff --git a/Completion/Core/_files b/Completion/Core/_files
index d2cce35e7..471824bfe 100644
--- a/Completion/Core/_files
+++ b/Completion/Core/_files
@@ -3,11 +3,12 @@
 # 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
+local nm=$compstate[nmatches] ret
 
 _path_files "$@"
+ret=$?
 
-if [[ $# -ne 0 && -nmatches nm ]]; then
+if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then
   local opt opts
 
   # We didn't get any matches for those types of files described by
@@ -23,4 +24,6 @@ if [[ $# -ne 0 && -nmatches nm ]]; then
   done
 
   _path_files "$opts[@]"
+else
+  return $ret
 fi
diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete
index c7f5a5a96..34c5a3d3c 100644
--- a/Completion/Core/_main_complete
+++ b/Completion/Core/_main_complete
@@ -2,47 +2,198 @@
 
 # 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.
+#
+# This code will automatically try to correct the string on the
+# line based on the strings generated for the context if the
+# parameter `COMPCORRECT' is set and normal completion didn't yield
+# any matches. These corrected strings will be shown in a list and
+# one can cycle through them as in a menucompletion. To use this 
+# feature, `COMPCORRECT' should be set to a number, specifying the
+# maximum number of errors that should be accepted. If the string also
+# contains a `n' or `N', the code will use the numeric argument as the
+# maximum number of errors if a numeric argument was given. If no
+# numeric argument was given, the number from the value of
+# `COMPCORRECT' will be used. E.g. with `COMPCORRECT=2n' two errors
+# will be accepted, but if the user gives another number with the
+# numeric argument, this will be prefered. Also, with `COMPCORRECT=0n',
+# normally no automatic correction will be tried, but if a numeric
+# argument is given, automatic correction will be used. Once the
+# number of errors to accept is determined, the code will repeatedly
+# try to generate matches by allowing one error, two errors, and so
+# on.
+# If the parameter `CCORIG' is set (independent of the value), the
+# line will first be left unchanged and consecutive TABs cycle through 
+# the list.
+# When using automatic correction, one can also set the parameter
+# `CCPROMPT' to a string that will be shown when multiple
+# correction results are displayed and the code starts cycling
+# through them (this string is used with the `-X' option and thus may
+# contain the control sequences `%n', `%B',...).
 
-local comp name
+local comp name _comp_correct comax
 
 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
+unsetopt markdirs globsubst shwordsplit nounset ksharrays
+
+# Special completion contexts after `~' and `='.
+
+if [[ -iprefix '=' ]]; then
+  compstate[context]=equal
+elif [[ "$PREFIX$SUFFIX" != */* && -iprefix '~' ]]; then
+  compstate[context]=tilde
 fi
 
-# For arguments we use the `_normal function.
+# This is not an endless loop.
 
-if [[ $CONTEXT == argument || $CONTEXT == command ]]; then
-  _normal "$@"
-else
-  # Let's see if we have a special completion definition for the other
-  # possible contexts.
+while true; do
 
-  comp=''
+  # 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.
 
-  case $CONTEXT in
-  redirect)  comp="$_comps[-redirect-]";;
-  math)      comp="$_comps[-math-]";;
-  subscript) comp="$_comps[-subscript-]";;
-  value)     comp="$_comps[-value-]";;
-  condition) comp="$_comps[-condition-]";;
-  esac
+  comp="$_comps[-first-]"
+  if [[ ! -z "$comp" ]]; then
+    "$comp"
+    if (( $+_compskip )); then
+      unset _compskip
+      return
+    fi
+  fi
 
-  # If not, we use default completion, if any.
+  # For arguments and command names we use the `_normal' function.
 
-  [[ -z "$comp" ]] && comp="$_comps[-default-]"
-  [[ -z "$comp" ]] || "$comp" "$@"
-fi
+  if [[ "$compstate[context]" = command ]]; then
+    _normal
+  else
+    # Let's see if we have a special completion definition for the other
+    # possible contexts.
+
+    comp=''
+
+    case $compstate[context] in
+    equal)           comp="$_comps[-equal-]";;
+    tilde)           comp="$_comps[-tilde-]";;
+    redirect)        comp="$_comps[-redirect-]";;
+    math)            comp="$_comps[-math-]";;
+    subscript)       comp="$_comps[-subscript-]";;
+    value)           comp="$_comps[-value-]";;
+    array_value)     comp="$_comps[-array-value-]";;
+    condition)       comp="$_comps[-condition-]";;
+    parameter)       comp="$_comps[-parameter-]";;
+    brace_parameter) comp="$_comps[-brace-parameter-]";;
+    esac
+
+    # If not, we use default completion, if any.
+
+    [[ -z "$comp" ]] && comp="$_comps[-default-]"
+    [[ -z "$comp" ]] || "$comp"
+  fi
+
+  # Use automatic correction?
+
+  if (( $+COMPCORRECT )); then
+
+    # Do we have matches?
+    if (( compstate[nmatches] )); then
+
+      # Yes, were they added using correction? (More than one match?)
+
+      if [[ -n "$_comp_correct" && compstate[nmatches] -gt 1 ]]; then
+
+        # If we got more than one string from correction, we add the 
+	# original string as a possible match, let it not be shown in
+	# the list, and probably display the `CCPROMPT'.
+
+        (( $+CCORIG )) && builtin compadd -nQ - "$PREFIX$SUFFIX"
+
+	# If you always want to see the list of possible corrections,
+	# set `compstate[list]=list' here.
+      fi
+      # Since we have matches, we don't want to try again.
+      break
+    fi
+
+    # No matches, so let's see if we already tried correction.
+
+    if [[ -n "$_comp_correct" ]]; then
+
+      # Yes, give up if we reached the maximum number of tries,
+      # otherwise increment our counter.
+
+      [[ _comp_correct -eq comax ]] && break
+      (( _comp_correct++ ))
+
+    elif [[ compstate[matcher] -eq compstate[total_matchers] ]]; then
+
+      # No matches and no correction tried yet, but we just tried the
+      # last global match specification, so let's see if we should use
+      # correction now. First, get the maximum number of errors.
+
+      if [[ "$COMPCORRECT" = *[nN]* && NUMERIC -ne 1 ]]; then
+        # Prefer the numeric argument if that has a sensible value.
+        comax="$NUMERIC"
+      else
+        comax="${COMPCORRECT//[^0-9]}"
+      fi
+      # If the number of errors to accept is to small, give up.
+
+      [[ "$comax" -lt 1 ]] && break
+
+      # Otherwise temporarily define functions to use instead of
+      # the builtins that add matches. This is used to be able
+      # to stick the `(#a...)' into the right place (after an
+      # ignored prefix).
+
+      compadd() {
+        if [[ "$PREFIX" = \~*/* ]]; then
+	  PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}"
+	else
+          PREFIX="(#a${_comp_correct})$PREFIX"
+	fi
+	if (( $+CCPROMPT )); then
+	  builtin compadd -X "$CCPROMPT" -J _correct "$@"
+	else
+	  builtin compadd -J _correct "$@"
+	fi
+      }
+      compgen() {
+        if [[ "$PREFIX" = \~*/* ]]; then
+	  PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}"
+	else
+          PREFIX="(#a${_comp_correct})$PREFIX"
+	fi
+	if (( $+CCPROMPT )); then
+	  builtin compgen "$@" -X "$CCPROMPT" -J _correct
+	else
+	  builtin compgen "$@" -J _correct
+	fi
+      }
+      # Now initialise our counter. We also set `compstate[matcher]'
+      # to `-1'. This allows completion functions to use the simple
+      # `[[ compstate[matcher] -gt 1 ]] && return' to avoid being
+      # called for multiple global match specs and still be called 
+      # again when correction is done. Also, this makes it easy to
+      # test if correction is attempted since `compstate[matcher]'
+      # will never be set to a negative value by the completion code.
+
+      _comp_correct=1
+      compstate[matcher]=-1
+
+      # We also need to set `extendedglob' and to make the completion
+      # code behave as if globcomplete were set.
+
+      setopt extendedglob
+      compstate[pattern_match]=yes
+    else
+      # We are still trying global match specifications...
+      break
+    fi
+  else
+    # No automatic correction to try, just give up.
+    break
+  fi
+done
+
+# If we added wrapper functions, remove them.
+
+[[ -n "$_comp_correct" ]] && unfunction compadd compgen
diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts
new file mode 100644
index 000000000..1f51d2f6d
--- /dev/null
+++ b/Completion/Core/_multi_parts
@@ -0,0 +1,201 @@
+#autoload
+
+# This gets two arguments, a separator (which should be only one
+# character) and an array. As usual, the array may be given by it's
+# name or literal as in `(foo bar baz)' (words separated by spaces in
+# parentheses).
+# The parts of words from the array that are separated by the
+# separator character are then completed independently.
+
+local sep matches patstr orig matchflags pref i tmp1 tmp2 nm
+local group expl
+
+_match_test _multi_parts || return 1
+
+# Save the current number of matches to be able to return if we added
+# matches or not.
+
+nm=$compstate[nmatches]
+
+# 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 arguments, first the separator, then the array. The array is 
+# stored in `matches'. Further on this array will always contain those 
+# words from the original array that still match everything we have
+# tried to match while we walk through the string from the line.
+
+sep="$1"
+if [[ "${2[1]}" = '(' ]]; then
+  matches=( ${2[2,-2]} )
+else
+  matches=( "${(@P)2}" )
+fi
+
+# Now build the pattern from what we have on the line. We also save
+# the original string in `orig'. The `eval' is used to replace our
+# separator character by `*<sep>'.
+
+if [[ -o globcomplete ]]; then
+  patstr="${PREFIX}*${SUFFIX}*"
+else
+  patstr="${PREFIX:q}*${SUFFIX:q}*"
+fi
+orig="${PREFIX}${SUFFIX}"
+
+matchflags=""
+_match_pattern _path_files patstr matchflags
+[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
+
+patstr="${${patstr//$sep/*$sep}//\*##/*}"
+#eval patstr\="\$patstr:gs-${sep}-\*${sep}-:gs/\*\*/\*/"
+
+# First we will skip over those parts of the matches for which we have 
+# exact substrings on the line. In `pref' we will build the
+# unambiguous prefix string.
+
+pref=''
+while [[ "$orig" = *${sep}* ]] do
+
+  # First build the pattern to use, then collect all strings from
+  # `matches' that match the prefix we have and the exact substring in 
+  # the array `tmp1'.
+
+  pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}${patstr##*${sep}}"
+  tmp1=( "${(@M)matches:#${~matchflags}${orig%%${sep}*}${sep}${~pat}}" )
+
+  # If there are no words matching the exact substring, stop.
+
+  (( $#tmp1 )) || break
+
+  # Otherwise add the part to the prefix, remove it from the matches
+  # (which will also remove all words not matching the string at all), 
+  # and set `patstr' and `orig' to the next component.
+
+  pref="$pref${orig%%${sep}*}${sep}"
+  matches=( "${(@)${(@)matches#${orig%%${sep}*}${sep}}:#}" )
+  orig="${orig#*${sep}}"
+  patstr="${patstr#*${sep}}"
+done
+
+# Now we get all the words that still match in `tmp1'.
+
+if [[ "$patstr" = *${sep}* ]]; then
+  tmp1="${patstr%${sep}*}${sep}"
+  pat="${tmp1//\*/[^${sep}]#}${patstr##*${sep}}"
+else
+  pat="$patstr"
+fi
+tmp1=( "${(@M)matches:#${~matchflags}${~pat}}" )
+
+if (( $#tmp1 )); then
+
+  # There are words that are matched, put them int `matches' and then
+  # move all unambiguous components from the beginning into `pref'.
+
+  matches=( "$tmp1[@]" )
+  while [[ "$matches[1]" = *${sep}* ]]; do
+
+    # We just take the first component of the first match and see if
+    # there are other matches with a different prefix (these are
+    # collected in `tmp2'). If there are any, we give up.
+
+    tmp1="${matches[1]%%${sep}*}${sep}"
+    tmp2=( "${(@)matches:#${tmp1}*}" )
+    (( $#tmp2 )) && break
+
+    # All matches have the same prefix, but it into `pref' and remove
+    # it from the matches.
+
+    pref="$pref$tmp1"
+    matches=( "${(@)${(@)matches#$tmp1}:#}" )
+
+    if [[ "$orig" = *${sep}* ]]; then
+      orig="${orig#*${sep}}"
+    else
+      orig=''
+    fi
+  done
+
+  # Now we can tell the completion code about the things we
+  # found. Strings that have a separator will be added with a suffix.
+
+  if [[ -z "$orig" && "$PREFIX$SUFFIX" != "$pref$orig" ]]; then
+    compadd -QU  "$group[@]" "$expl[@]" -i "$IPREFIX" -S '' - "${pref}${orig}"
+  elif [[ $compstate[insert] = *menu ]]; then
+    for i in "$matches[@]" ; do
+      if [[ "$i" = *${sep}* ]]; then
+        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \
+	        -p "$pref" -qS "$sep" - "${i%%${sep}*}"
+      else
+        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \
+	        -p "$pref" - "${i%%${sep}*}"
+      fi
+    done
+  else
+    for i in "$matches[@]" ; do
+      if [[ "$i" = *${sep}* ]]; then
+        compadd -U -i "$IPREFIX" -p "$pref" -s "${sep}${i#*${sep}}" \
+	        "$group[@]" "$expl[@]" -M "r:|${sep}=*" - "${i%%${sep}*}"
+      else
+        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -p "$pref" - "$i"
+      fi
+    done
+  fi
+elif [[ "$patstr" = *${sep}* ]]; then
+
+  # We had no words matching the string from the line. But we want to
+  # be friendly and at least expand the prefix as far as we can. So we 
+  # will loop through the rest of the string from the line and test
+  # the components one by one.
+
+  while [[ "$patstr" = *${sep}* ]]; do
+
+    # First we get all words matching at least this component in
+    # `tmp1'. If there are none, we give up.
+
+    tmp1=( "${(@M)matches:#${~matchflags}${~patstr%%${sep}*}${sep}*}" )
+    (( $#tmp1 )) || break
+
+    # Then we check if there are words that have a different prefix.
+
+    tmp2=( "${(@)tmp1:#${tmp1[1]%%${sep}*}${sep}*}" )
+    if (( $#tmp2 )); then
+
+      # There are words with another prefix, so we have found an
+      # ambiguous component. So we just give all possible prefixes to
+      # the completion code together with our prefix and the rest of
+      # the string from the line as the suffix.
+
+      compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" \
+              -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}"
+      return 0
+    fi
+
+    # All words have the same prefix, so add it to `pref' again and
+    # try the next component.
+
+    pref="$pref${tmp1[1]%%${sep}*}${sep}"
+    matches=( "${(@)matches#${tmp1[1]%%${sep}*}${sep}}" )
+    orig="${orig#*${sep}}"
+    patstr="${patstr#*${sep}}"
+  done
+
+  # Finally, add the unambiguous prefix and the rest of the string
+  # from the line.
+
+  compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" - "$orig"
+fi
+
+# This sets the return value to indicate that we added matches (or not).
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/Core/_normal b/Completion/Core/_normal
index 19da6d79b..f56849194 100644
--- a/Completion/Core/_normal
+++ b/Completion/Core/_normal
@@ -1,24 +1,25 @@
 #autoload
 
-local comp cmd1 cmd2 pat val name
+local comp command cmd1 cmd2 pat val name i ret
 
 # 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
+command="$words[1]"
+if [[ CURRENT -eq 1 ]]; then
   comp="$_comps[-command-]"
-  [[ -z "$comp" ]] || "$comp" "$@"
+  [[ -z "$comp" ]] || "$comp"
   return
-elif [[ "$COMMAND[1]" == '=' ]]; then
-  eval cmd1\=$COMMAND
-  cmd2="$COMMAND[2,-1]"
-elif [[ "$COMMAND" == */* ]]; then
-  cmd1="$COMMAND"
-  cmd2="${COMMAND:t}"
+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)
+  cmd1="$command"
+  eval cmd2=$(whence -p $command)
 fi
 
 # See if there are any matching pattern completions.
@@ -27,10 +28,11 @@ for i in "$_patcomps[@]"; do
   pat="${i% *}"
   val="${i#* }"
   if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then
-    "$val" "$@"
+    "$val"
+    ret=$?
     if (( $+_compskip )); then
       unset _compskip
-      return
+      return $ret
     fi
   fi
 done
@@ -51,4 +53,4 @@ if [[ -z "$comp" ]]; then
   name=-default-
   comp="$_comps[-default-]"
 fi
-[[ -z "$comp" ]] || "$comp" "$@"
+[[ -z "$comp" ]] || "$comp"
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 83b6e8a09..3c03c0c61 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -3,7 +3,7 @@
 # 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
+# the last have the same syntax and meaning as for `compgen'. 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
@@ -14,13 +14,13 @@
 
 # First see if we should generate matches for the global matcher in use.
 
-_match_test _path_files || return
+_match_test _path_files || return 1
 
 # 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
+local addpfx addsfx expl orig ostr nm=$compstate[nmatches]
 
 setopt localoptions nullglob rcexpandparam globdots extendedglob
 unsetopt markdirs globsubst shwordsplit nounset
@@ -91,14 +91,14 @@ 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]"
+if [[ -o globcomplete ]]; then
+  str="${PREFIX}*${SUFFIX}"
+else
+  str="${PREFIX:q}*${SUFFIX:q}"
+fi
+orig="${PREFIX}${SUFFIX}"
 
-# We will first try normal completion called with `complist', but only if we
+# We will first try normal completion called with `compgen', but only if we
 # weren't given a `-F' option.
 
 if (( ! $#ignore )); then
@@ -112,18 +112,18 @@ if (( ! $#ignore )); then
     tmp1=(-W "( $prepaths )")
   fi
 
-  # Now call complist.
+  # Now call compgen.
 
-  nm=$NMATCHES
+  nm=$compstate[nmatches]
   if [[ -z "$gopt" ]]; then
-    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
+    compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
   else
-    complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
+    compgen "$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
+  [[ compstate[nmatches] -eq nm ]] || return 0
 
   # No `-F' option, so we want to use `fignore'.
 
@@ -142,14 +142,16 @@ if [[ "$str[1]" = \~ ]]; then
   
   linepath="${str%%/*}/"
   eval realpath\=$linepath
+  [[ "$realpath" = "$linepath" ]] && return 1
   str="${str#*/}"
+  orig="${orig#*/}"
   donepath=''
   prepaths=( '' )
 else
   # If the string does not start with a `~' we don't remove a prefix from the
   # string.
 
-  liniepath=''
+  linepath=''
   realpath=''
 
   if [[ "$str[1]" = / ]]; then
@@ -158,6 +160,7 @@ else
     # Also, we don't use the paths from `-W'.
 
     str="$str[2,-1]"
+    orig="$orig[2,-1]"
     donepath='/'
     prepaths=( '' )
   else
@@ -169,28 +172,31 @@ else
   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
+[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
 
 # 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/**/*/"
+patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-"
+
+# 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 `orig' and added
+# to `donepath'.
+
+while [[ "$orig" = */* ]] do
+  tmp1=( ${~matchflags}$realpath$donepath${orig%%/*}/${~patstr#*/}$^pats )
+  [[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break
+  donepath="$donepath${orig%%/*}/"
+  orig="${orig#*/}"
+  patstr="${patstr#*/}"
+done
 
 # 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'
@@ -199,6 +205,9 @@ patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/"
 for prepath in "$prepaths[@]"; do
   str="$patstr"
   testpath="$donepath"
+  ostr="$orig"
+
+  [[ -z "$prepath" || "$prepath[-1]" = / ]] || prepath="${prepath}/"
 
   # The second loop tests the components of the path in `str' to get the
   # possible matches.
@@ -235,16 +244,20 @@ for prepath in "$prepaths[@]"; do
       # the suffixes we just built are used to produce possible matches
       # via globbing.
 
-      for i in $tmp1; do
+      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.
+      # has a possible sub-path matching what's on the line, we add the
+      # matches found in `tmp1' and otherwise give up and continue with the
+      # next `-W' path.
 
       if [[ $#collect -eq 0 ]]; then
+        compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+                -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \
+		-W "$tmp1" -f "$ignore[@]" - "${(@)tmp1:q}"
         continue 2
       elif [[ $#collect -ne 1 ]]; then
         # If we have more than one possible match, this means that the
@@ -269,9 +282,17 @@ for prepath in "$prepaths[@]"; do
 	# 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
+	if [[ $compstate[insert] = *menu ]]; then
+          compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+                  -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \
+		  -W "$tmp1" -f "$ignore[@]" - "${(@)${(@)collect%%/*}:q}"
+	else
+          for i in $collect; do
+            compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+	            -i "$IPREFIX" -p "$linepath$testpath" -s "/${i#*/}" \
+		    -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${i%%/*}"
+          done
+	fi
 
 	# We have just finished handling all the matches from above, so we
 	# can continue with the next `-W' path.
@@ -291,6 +312,7 @@ for prepath in "$prepaths[@]"; do
     tmp1="$tmp1[1]"
     testpath="$testpath${tmp1##*/}/"
     str="$rest"
+    ostr="${ostr#*/}"
   done
 
   # We are here if all pathname components except the last one (which is still
@@ -302,10 +324,24 @@ for prepath in "$prepaths[@]"; do
   suffixes=( $str$^pats )
   suffixes=( "${(@)suffixes:gs.**.*.}" )
   tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
-  if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then
+  if [[ $#tmp2 -eq 0 ]]; then
+    # No match, insert the expanded path and add the original tail.
+
     [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]"
-    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath"
+    [[ -n "$ostr" && -n "$linepath$testpath" ]] && ostr="/$ostr"
+
+    # But only if something changed.
+    [[ "$linepath$testpath$ostr" = "$PREFIX$SUFFIX" ]] && return 1
+
+    compadd -QU -S '' "$group[@]" "$expl[@]" \
+            -i "$IPREFIX" -f - "${linepath:q}${testpath:q}$ostr"
   else
-    compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1}
+    compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
+            -i "$IPREFIX" -p "$linepath$testpath" -f "$ignore[@]" \
+	    -W "$prepath$realpath$testpath" - "${(@)tmp2#$tmp1}"
   fi
 done
+
+# This sets the return value to indicate that we added matches (or not).
+
+[[ nm -ne compstate[nmatches] ]]
diff --git a/Completion/README b/Completion/README
index ac2accfca..43ffcbcc2 100644
--- a/Completion/README
+++ b/Completion/README
@@ -11,14 +11,15 @@ 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 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:
+  these, and will most likely not want to alter them --- if you do, it
+  would probably help to give your version a different name.  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.
@@ -29,6 +30,9 @@ Core:
   _comp_parts
     Utility used for completing words with multiple separate parts, such as
     `<user>@<host>'
+  _multi_parts
+    Utility for completion parts of words given a separator character and 
+    a list of words.
   _compalso
     Utility for calling a function to add additional completions to an
     already existing set.
@@ -46,7 +50,7 @@ Core:
     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
+    replaces the standard -f, -g 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:
@@ -65,22 +69,29 @@ Base:
     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.
+    These are used by Base/_path_files (and hence also Base/_files)
+    and Base/_comp_parts 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.
+    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 ((...)).
+  _tilde
+    Completion after `~', defaults to user names and named directories.
+  _equal
+    Completion after `=', normally command and alias names are used.
+  _parameter
+  _brace_parameter
+    For completion inside parameter expansions ($... and ${...).
 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
diff --git a/Completion/User/_a2ps b/Completion/User/_a2ps
index 9aa9d3d99..600b58872 100644
--- a/Completion/User/_a2ps
+++ b/Completion/User/_a2ps
@@ -1,22 +1,22 @@
 #defcomp a2ps
 
-if [[ -prefix -- ]]; then
+if [[ "$PREFIX[1,2]" = -- ]]; 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
+  compgen -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
+  compgen -qS= -k '(--margin --header --underlay --left-title
                      --right-title --left-footer --footer --right-footer
 		     --pages --pretty-print)'
-  complist -k '(--landscape --portrait --catman --no-header)'
+  compgen -k '(--landscape --portrait --catman --no-header)'
 else
   _files -F fignore -g "*~*.ps"
 fi
diff --git a/Completion/User/_configure b/Completion/User/_configure
index de8d5fba5..050701fac 100644
--- a/Completion/User/_configure
+++ b/Completion/User/_configure
@@ -1,12 +1,35 @@
 #defcomp configure
 
+setopt localoptions extendedglob
+
 if [[ $PREFIX = *=* ]]; then
   # Complete filenames after e.g. --prefix=
   IPREFIX=${PREFIX%%=*}=
   PREFIX=${PREFIX#*=}
-  complist -f
+  compgen -f
 else
   # Generate a list of options from configure --help
-  complist -s '$($COMMAND --help |
-  sed -n -e '\''s/^ *\(--[-a-z0-9]*\)[    =,].*$/\1/p'\'')'
+  local -a pars
+  local i
+  pars=($($words[1] --help | awk '$1 ~ /--[a-z]*.*/ {print $1}'))
+  for i in $pars
+  do
+    case $i in
+      (--(((en|dis)able-FEATURE)|(with(out|)-PACKAGE))*)
+        : Skip standard help output
+      ;;
+      --enable)
+        : Skip standard help output
+      ;;
+      --*\[=* )
+        compadd -M 'r:|-=* r:|=*' -q -S = -- ${i%%\[=*}
+      ;;
+      --*=* )
+        compadd -M 'r:|-=* r:|=*' -S = -- ${i%%=*}
+      ;;
+      * )
+        compadd -M 'r:|-=* r:|=*' -- $i
+      ;;
+    esac
+  done
 fi
diff --git a/Completion/User/_dd b/Completion/User/_dd
index 2458541ea..86a47b1ab 100644
--- a/Completion/User/_dd
+++ b/Completion/User/_dd
@@ -4,10 +4,10 @@ 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 \
+  compgen -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)'
+  compgen -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)'
 fi
diff --git a/Completion/User/_find b/Completion/User/_find
index ca4f79908..8fcdafb83 100644
--- a/Completion/User/_find
+++ b/Completion/User/_find
@@ -1,21 +1,23 @@
 #defcomp find
 
+local prev="$words[CURRENT-1]"
+
 if [[ -mbetween -(ok|exec) \\\; ]]; then
-  _normal "$@"
+  _normal
 elif [[ -iprefix - ]]; then
-  complist -s 'daystart {max,min,}depth follow noleaf version xdev \
+  compgen -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 '. ..'
+elif [[ -position 2 ]]; then
+  compgen -g '. ..'
   _files -g '(-/)'
-elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]]; then
+elif [[ "$prev" = -((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
+elif [[ "$prev" = -fstype ]]; then
+  compgen -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)'
+elif [[ "$prev" = -group ]]; then
+  compgen -k groups
+elif [[ "$prev" = -user ]]; then
+  compgen -u
 fi
diff --git a/Completion/User/_hosts b/Completion/User/_hosts
index 3acc327ac..eb418c5b3 100644
--- a/Completion/User/_hosts
+++ b/Completion/User/_hosts
@@ -1,3 +1,3 @@
 #defcomp ftp ncftp ping rwho rup xping traceroute nslookup
 
-complist -k hosts
+compgen -k hosts
diff --git a/Completion/User/_make b/Completion/User/_make
index d576b0308..24d2cf3f5 100644
--- a/Completion/User/_make
+++ b/Completion/User/_make
@@ -1,3 +1,3 @@
 #defcomp make gmake pmake
 
-complist -s "\$(awk '/^[a-zA-Z0-9][^/ 	]+:/ {print \$1}' FS=: [mM]akefile)"
+compgen -s "\$(awk '/^[a-zA-Z0-9][^/ 	]+:/ {print \$1}' FS=: [mM]akefile)"
diff --git a/Completion/User/_man b/Completion/User/_man
index 8204fba0b..67d59f24a 100644
--- a/Completion/User/_man
+++ b/Completion/User/_man
@@ -2,10 +2,10 @@
 setopt localoptions rcexpandparam
 
 local rep
-if [[ $2 = (<->*|ln) ]]; then
-  rep=( $manpath/(man|cat)$2/$PREFIX*$SUFFIX.<->*(N:t:r) )
+if [[ $words[2] = (<->*|ln) ]]; then
+  rep=( $manpath/(man|cat)${words[2]}/$PREFIX*$SUFFIX.<->*(N:t:r) )
 else
   rep=( $manpath/(man|cat)*/$PREFIX*$SUFFIX.<->*(N:t:r) )
 fi
 
-(( $#rep )) && compadd -m $rep
+(( $#rep )) && compadd - $rep
diff --git a/Completion/User/_mh b/Completion/User/_mh
index 67ce49fd2..7e8575123 100644
--- a/Completion/User/_mh
+++ b/Completion/User/_mh
@@ -1,4 +1,4 @@
-#defcomp folder comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath mhpatch
+#defcomp folder folders comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath
 
 # Completion for all possible MH commands.
 # Alter the following two to your own mh directory and the directory
@@ -7,6 +7,8 @@
 local mymhdir=~/Mail
 local mhlib=/usr/lib/mh
 
+local prev="$words[CURRENT-1]"
+
 # To be on the safe side, check this exists and if not, get it anyway.
 [[ -d $mymhdir ]] || mymhdir=$(mhpath +)
 
@@ -14,13 +16,13 @@ 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+)/) {
+  compadd - $($words[1] -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
+elif [[ -iprefix '+' || -iprefix '@' || "$prev" = -draftfolder ]]; then
   # Complete folder names.
   local mhpath
   if [[ $IPREFIX != '@' ]]; then
@@ -31,12 +33,12 @@ elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then
   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
+  _path_files -W mhpath -/
+elif [[ "$prev" = -(editor|(whatnow|rmm|show|more)proc) ]]; then
+  compgen -c
+elif [[ "$prev" = -file ]]; then
+  compgen -f
+elif [[ "$prev" = -(form|audit|filter) ]]; then
   # Need some MH template file, which may be in our own MH directory
   # or with the standard library.
   local mhfpath
@@ -44,11 +46,11 @@ elif [[ -mcurrent -1 -(form|audit|filter) ]]; then
   [[ -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
+  compgen -W mhfpath -g '*(.)'
+elif [[ "$prev" = -(no|)cc ]]; then
+  compadd all to cc me
+elif [[ "$prev" = -[rw]cache ]]; then
+  compadd public private never ask
 else
   # Generate sequences.
   local foldnam folddir f
@@ -64,7 +66,7 @@ else
     # 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 '<->'
+  compgen -s '$(mark $foldnam 2>/dev/null | awk -F: '\''{ print $1 }'\'')'
+  compadd reply next cur prev first last all unseen
+  compgen -W folddir -g '<->'
 fi
diff --git a/Completion/User/_rcs b/Completion/User/_rcs
index 537db6278..5a751605c 100644
--- a/Completion/User/_rcs
+++ b/Completion/User/_rcs
@@ -1,9 +1,11 @@
 #defcomp co ci rcs
 
-[[ $COMMAND = ci || $COMMAND = rcs ]] && _files
+local nm=$compstate[nmatches]
 
-if [[ $NMATCHES -eq 0 && -d RCS && $COMMAND != ci ]]; then
+[[ $words[1] = ci || $words[1] = rcs ]] && _files
+
+if [[ $compstate[nmatches] -eq nm && -d RCS && $words[1] != ci ]]; then
   local rep
   rep=(RCS/$PREFIX*$SUFFIX,v(:t:s/\,v//))
-  (( $#rep )) && compadd -m $rep
+  (( $#rep )) && compadd - $rep
 fi
diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin
index e36554f23..5d6daef9b 100644
--- a/Completion/User/_rlogin
+++ b/Completion/User/_rlogin
@@ -1,9 +1,9 @@
 #defcomp rlogin rsh ssh
 
-if [[ -position 1 ]]; then
-  complist -k hosts
-elif [[ -position 2 ]]; then
-  complist -k '(-l)'
+if [[ CURRENT -eq 2 ]]; then
+  compgen -k hosts
+elif [[ CURRENT -eq 3 ]]; then
+  compgen -k '(-l)'
 else
-  complist -u
+  compgen -u
 fi
diff --git a/Completion/User/_stty b/Completion/User/_stty
index 6b54b5007..d32d6bdff 100644
--- a/Completion/User/_stty
+++ b/Completion/User/_stty
@@ -1,12 +1,12 @@
 #defcomp stty
 
-if [[ -mcurrent -1 \
+if [[ "$words[CURRENT-1]" = \
   (*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]]
 then
-     compadd -m -Q '^-' '^h' '^?' '^c' '^u'
+     compadd -Q '^-' '^h' '^?' '^c' '^u'
 else
   [[ -string '-' || -string '+' ]]
-  compadd -m rows columns intr quit erase kill eof eol \
+  compadd 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 \
diff --git a/Completion/User/_tar b/Completion/User/_tar
index 91767e44d..84c490f1e 100644
--- a/Completion/User/_tar
+++ b/Completion/User/_tar
@@ -1,11 +1,69 @@
 #defcomp tar
 
-local nm=$NMATCHES tf="$2"
+# Tar completion.  Features:
+#  - Assumes tar commands are in second position, tar archive is in third
+#    e.g. tar xvzf zsh-3.0.5.tar.gz ...
+#    Could search better.  Send me the patch.
+#  - `tar' can be called anything, will use the correct name
+#  - Preferentially completes *.tar and *.TAR files in third position
+#  - unless z or Z appears in the commands, in which case prefer *.tar.gz
+#    and similar (GNU tar).
+#  - From fourth position on, if command is x or t, completes files inside
+#    archive.  This is supposed to look pretty much as if the files are
+#    in an ordinary directory hierarchy.  Handles extraction from compressed
+#    archives (GNU tar).
+#  - Anywhere -- appears, gets a list of long options to complete from
+#    tar itself (GNU tar); this needs perl.  If you have GNU tar but not
+#    perl:  your system manager is weird.
+#  - Things like --directory=... are also completed correctly.
 
-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
+emulate -LR zsh
+setopt extendedglob
+
+local nm=$NMATCHES tcmd="$words[2]" tf="$words[3]"
+
+if [[ $PREFIX = *=* ]]; then
+  # For GNU tar arguments like --directory=
+  IPREFIX=${PREFIX%%\=*}=
+  PREFIX=${PREFIX#*=}
+  if [[ $IPREFIX = --directory* ]]; then
+    _path_files -/
+  else
+    _files
+  fi
+elif [[ $PREFIX = --* ]]; then
+  # gnu tar, generate completions from --help
+  # ones followed by = get that as a suffix
+  local -a ownlist eqlist
+  local comp
+  $words[1] --help |
+  perl -ne 'while (/--[^[\s,='\'']+=?/g) { print "$&\n"; }' |
+  while read comp; do
+    if [[ $comp = *= ]]; then
+      eqlist[$#eqlist+1]=${comp%=}
+    else
+      ownlist[$#ownlist+1]=$comp
+    fi
+  done
+  compgen -S '=' -k eqlist
+  compgen -k ownlist
+elif [[ "$tcmd" = *[tx]*f* && $CURRENT -ge 4 ]] then
+  # Listing or extracting a particular file.  We run `tar t...'
+  # on the file, keeping the list of filenames cached, plus the
+  # name of the tarfile so we know if it changes.
+  local largs=-tf
+
+  [[ $words[2] = *z* ]] && largs=-tzf
+  [[ $words[2] = *Z* ]] && largs=-tZf
+  if [[ $tf != $tar_cache_name ]]; then
+    tar_cache_list=("${(@f)$($words[1] $largs $tf)}")
+    tar_cache_name=$tf
+  fi
+  _multi_parts / tar_cache_list
+elif [[ "$tcmd" = *c*f* && $CURRENT -ge 4 ]] then
   _files
-elif [[ -mcurrent -1 *f* && -position 2 ]]; then
+elif [[ "$tcmd" = *[zZ]*f* && $CURRENT -eq 3 ]] then
+  _files -g '*.((tar|TAR).(gz|Z)|.tgz)'
+elif [[ "$tcmd" = *f* && $CURRENT -eq 3 ]] then
   _files -g '*.(tar|TAR)'
 fi
diff --git a/Completion/User/_x_options b/Completion/User/_x_options
index cc469286d..3190ee377 100644
--- a/Completion/User/_x_options
+++ b/Completion/User/_x_options
@@ -2,4 +2,4 @@
 
 # A simple pattern completion, just as an example.
 
-complist -J options -k '(-display -name -xrm)'
+compgen -J options -k '(-display -name -xrm)'
diff --git a/Config/version.mk b/Config/version.mk
index 496dea13a..be39570f4 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-10
-VERSION_DATE='February 26, 1999'
+VERSION=3.1.5-pws-11
+VERSION_DATE='March 3, 1999'
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 0b2b9a4f8..ffc9f3cfe 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -924,7 +924,7 @@ both tt(typeset -xT ...) and tt(export -T ...) work, but only the
 scalar will be marked for export.
 
 If no var(name) is present, the names and values of all parameters are
-printed.  In this case the attribute flags restrict the the display to
+printed.  In this case the attribute flags restrict the display to
 only those parameters that have the specified attributes.  Using
 `tt(PLUS())' rather than `tt(-)' to introduce the flag causes the
 attribute to be turned off, and suppresses printing of the names and
diff --git a/Doc/Zsh/compctl.yo b/Doc/Zsh/compctl.yo
index 124f9e604..4e1a98dab 100644
--- a/Doc/Zsh/compctl.yo
+++ b/Doc/Zsh/compctl.yo
@@ -124,9 +124,9 @@ startlist()
 list([ tt(-fcFBdeaRGovNAIOPZEnbjrzu/) ])
 list([ tt(-k) var(array) ] [ tt(-g) var(globstring) ] \
   [ tt(-s) var(subststring) ])
-list([ tt(-K) var(function) ] [ tt(-H) var(num pattern) ])
+list([ tt(-K) var(function) ] [ tt(-i) var(function) ])
 list([ tt(-Q) ] [ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ])
-list([ tt(-W) var(file-prefix) ])
+list([ tt(-W) var(file-prefix) ] [ tt(-H) var(num pattern) ])
 list([ tt(-q) ] [ tt(-X) var(explanation) ] [ tt(-Y) var(explanation) ])
 list([ tt(-y) var(func-or-var) ] [ tt(-l) var(cmd) ] [ tt(-U) ])
 list([ tt(-t) var(continue) ] [ tt(-J) var(name) ] [ tt(-V) var(name) ])
@@ -280,7 +280,8 @@ completions.  The tt(fignore) special parameter is not applied to the
 resulting files.  Note that tt(-g) is faster for filenames.
 )
 item(tt(-K) var(function))(
-Call the given function to get the completions.  The function is
+Call the given function to get the completions.  Unless the name
+starts with an underscode, the function is
 passed two arguments: the prefix and the suffix of the word on which
 completion is to be attempted, in other words those characters before
 the cursor position, and those from the cursor position onwards.  The
@@ -300,6 +301,13 @@ compctl -K whoson talk))
 completes only logged-on users after `tt(talk)'.  Note that `tt(whoson)' must
 return an array, so `tt(reply=`users`)' would be incorrect.
 )
+item(tt(-i) var(function))(
+Like tt(-K), but the function is invoked in a context like that for
+completion widgets, see 
+ifzman(zmanref(zshzle))\
+ifnzman(noderef(The zle Module))\
+for more information.
+)
 item(tt(-H) var(num pattern))(
 The possible completions are taken from the last var(num) history
 lines.  Only words matching var(pattern) are taken.  If var(num) is
@@ -427,9 +435,19 @@ printed literally and if they appear output in columns is suppressed.
 )
 item(tt(-X) var(explanation))(
 Print var(explanation) when trying completion on the current set of
-options. A `tt(%n)' in this string is replaced by the number of matches.
+options. A `tt(%n)' in this string is replaced by the number of
+matches that were added for this explanation string.
 The explanation only appears if completion was tried and there was
-no unique match, or when listing completions.
+no unique match, or when listing completions. Explanation strings 
+will be listed together with the matches of the group specified
+together with the tt(-X) option (using the tt(-J) or tt(-V)
+option). If the same explanation string is given to multiple tt(-X)
+options, the string appears only once (for each group) and the number
+of matches shown for the `tt(%n)' is the total number of all matches
+for each of these uses. In any case, the explanation string will only
+be shown if there was at least one match added for the explanation
+string.
+
 The sequences tt(%B), tt(%b), tt(%S), tt(%s), tt(%U), and tt(%u) specify
 output attributes (bold, standout, and underline) as in prompts.
 )
diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo
index 4208317fb..44ae72002 100644
--- a/Doc/Zsh/compwid.yo
+++ b/Doc/Zsh/compwid.yo
@@ -54,91 +54,162 @@ widget is active, these parameters are reseton each function exit to
 the values they had when the function was entered.
 
 startitem()
-item(tt(argv))(
-The positional parameters are set to the arguments on the command line
-when the widget function is invoked from the completion code.
+item(tt(words))(
+This array contains the words from the line.
 )
 item(tt(CURRENT))(
 This is the number of the current word, i.e. the word the cursor is
-currently on in the tt(argv) array.
+currently on in the tt(words) array. Note that this value is only
+correct, if the tt(ksharrays) options is not set.
 )
-item(tt(CONTEXT))(
+item(tt(PREFIX))(
+This should be set to that part of the current word that should be
+taken as the string every possible match has to begin with. Initially
+this will be set to the part of the current word from the beginning of
+the word up to the position of the cursor. When 
+)
+item(tt(IPREFIX))(
+When a part of the current word should not be considered part of the
+matches, this part should be taken from the tt(PREFIX) parameter and
+appended to this parameter. This will initially be set to the empty
+string when called from the completion code.
+)
+item(tt(SUFFIX))(
+This should be set to that part of the current word that should be
+taken as the string every possible match has to end with. The
+completion code sets this to the part of the current word from the
+cursor position to the end.
+)
+item(tt(compstate))(
+This is an associative array with various keys and values the
+completion uses to give informtaion to the completion widget and to
+get information regarding the further processing from it. The keys
+are:
+
+startitem()
+item(tt(context))(
 This will be set by the completion code to the overall context
 completion is attempted in. Possible values are:
 
 startitem()
 item(tt(command))(
-when completing in a command position, e.g. in the first word on the
-command line
-)
-item(tt(argument))(
-when completing an argument for a command
+when completing for a normal command (in a command position or for an
+argument)
 )
 item(tt(redirect))(
-when completing after a redirection operator; in this case the
-positional parameters contain not only the arguments but also the
-command name itself as the first element
+when completing after a redirection operator
 )
 item(tt(condition))(
 when completing inside a `tt([[)...tt(]])' conditional expressing; in
-this case the positional parameters are set to the words inside the
-conditional expressions
+this case the tt(words) array contains the words inside the
+conditional expression
 )
 item(tt(math))(
 when completing in a mathematical environment such as a
 `tt(LPAR()LPAR())...tt(RPAR()RPAR())' construct
 )
 item(tt(value))(
-when completing the value of a parameter assignment; in case of an
-array value the positional parameters are set to the words in
-parentheses
+when completing the value of a parameter assignment
+)
+item(tt(array_value))(
+when completing inside the value of an array parameter assignment; in
+this case the tt(words) array contains the words inside the parentheses
 )
 item(tt(subscript))(
-when completing inside a parameter expansion subscript
+when completing inside a parameter subscript
+)
+item(tt(parameter))(
+when the name of a parameter in a parameter expansion
+)
+item(tt(brace_parameter))(
+when the name of a parameter in a parameter expansion that started
+with tt(${)
 )
 enditem()
 )
-item(tt(COMMAND))(
-In most cases this is set to name of the command for which completion
-is tried. When completing after a redirection operator it contains the 
-string forming that operator. Also, when completing in the value of a
-parameter assignment or in a parameter subscript it is set to the name
-of the parameter.
+item(tt(parameter))(
+The name of the parameter when completing in a subscript or in the
+value of a parameter assignment.
 )
-item(tt(PREFIX))(
-This should be set to that part of the current word that should be
-taken as the string every possible match has to begin with. Initially
-this will be set to the part of the current word from the beginning of
-the word up to the position of the cursor. When 
+item(tt(redirect))(
+The redirection operator when completing in a redirection position.
 )
-item(tt(IPREFIX))(
-When a part of the current word should not be considered part of the
-matches, this part should be taken from the tt(PREFIX) parameter and
-appended to this parameter. This will initially be set to the empty
-string when called from the completion code.
+item(tt(quoting))(
+If completion is done inside single quotes, this is set to the string
+tt(single). When completing inside double quotes this is set to
+tt(double). When completing inside backticks it is set to tt(backtick).
+Otherwise it is unset.
 )
-item(tt(SUFFIX))(
-This should be set to that part of the current word that should be
-taken as the string every possible match has to end with. The
-completion code sets this to the part of the current word from the
-cursor position to the end.
+item(tt(quote))(
+When completing inside quotes, this contains the quotation character
+(i.e. either a single quote, a double quote, or a backtick).
 )
-item(tt(NMATCHES))(
+item(tt(nmatches))(
 This is always set to the number of matches generated and accepted by
 the completion code so far.
 )
-item(tt(MATCHER))(
+item(tt(matcher))(
 When completion is used with a global match specification (i.e. a
-tt(compctl) with only a tt(-M) option), this parameter is set to the
+tt(compctl) with only a tt(-M) option), this contains the
 number of the specification string which is currently used.
 )
+item(tt(matcher_string))(
+This is set to the global match specification string currently used.
+)
+item(tt(total_matchers))(
+The total number of global match specifications.
+)
+item(tt(restore))(
+This is set to tt(auto) before a function is entered. If a function
+unsets it or sets it to any other string, the special parameters
+mentioned above (tt(words), tt(CURRENT), tt(PREFIX), tt(IPREFIX), and
+tt(SUFFIX)) will not be restored to their previous values when the
+function exits as is normally done.
+)
+item(tt(list))(
+On entry to the completion widget this will be unset, if the set of
+matches generated will not be listed. It is set to tt(list),
+tt(autolist), or tt(ambiguous) if the matches will always be listed,
+if they will be listed due to tt(AUTO_LIST) being set, or if they will 
+be listed if there is no unambiguous string to insert and
+tt(LIST_AMBIGUOUS) is set, respectively. Inside the completion widget
+it may be set to any of these values to make the completion code as if 
+the appropriate options had been set.
+)
+item(tt(insert))(
+This will be unset by the completon code if the contents of the
+command line will not be changed. It is set to tt(unambiguous),
+tt(menu), or tt(automenu) if a common unambiguous string will be
+inserted or if the first match will be inserted and menu completion
+will be started (due to tt(MENU_COMPLETE) or tt(AUTO_MENU) being set), 
+respectively.
+)
+item(tt(exact))(
+This is set to tt(accept) if an exact match would be accepted by the
+completion code due to tt(REC_EXACT) being set or it is unset if an
+exact match would not be accepted.
+)
+item(tt(exact_string))(
+This is set to the string of an exact match if one was found and unset 
+otherwise.
+)
+item(tt(pattern_match))(
+If the option tt(GLOB_COMPLETE) is set, this is initially set to
+tt(yes) and unset otherwise. If the completion widget sets it to a
+non-empty string, the completion code will from then on behave as if
+tt(GLOB_COMPLETE) is set, i.e.. if the strings in tt(PREFIX) and
+tt(SUFFIX) contain unquoted metacharacters, they will be treated as
+patterns.
+)
+enditem()
+)
 enditem()
 
 texinode(Builtin Commands)(Condition Codes)(Special Parameters)(Completion Widgets)
 sect(Builtin Commands)
 startitem()
-findex(complist)
-item(tt(complist) var(flags ...))(
+findex(compgen)
+item(tt(compgen) var(flags ...))(
 
 Generate matches according to the given var(flags) which can be any of 
 the option flags supported by the tt(compctl) builtin command (see
@@ -154,9 +225,12 @@ flags. The completion code will consider only those matches as
 possible completions that match the prefix and suffix from the special 
 parameters desribed above. These strings will be compared with the
 generated matches using the normal matching rules and any matching
-specifications given with the tt(-M) flag to tt(complist) and the
+specifications given with the tt(-M) flag to tt(compgen) and the
 global matching specifications given to the tt(compctl) builtin
 command.
+
+The return value can be used to test if matches were added. It is zero 
+if at least one match was added and non-zero otherwise.
 )
 xitem(tt(compadd) [ tt(-qQfnUam) ] [ tt(-F) var(array) ])
 xitem([ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ])
@@ -168,13 +242,38 @@ item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])(
 
 This builtin command can be used to add matches and directly control
 all the information the completion code stores with each possible
-match.
+match. The return value is zero if at least one match was added and
+non-zero if no matches were added.
+
+The completion code breaks the string to complete into six fields in
+the order: 
+
+indent(
+var(<ipre><apre><hpre><word><hsuf><asuf>)
+)
+
+The first field
+is an ignored prefix taken from the line, the contents of the
+tt(IPREFIX) parameter plus the string given with the tt(-i)
+option. With the tt(-U) option given, only the string from the tt(-i)
+option is used. The field var(<apre>) is a optional prefix string that 
+should automatically be added by the completion code, this is what can 
+be gievn with the tt(-P) option. The var(<hpre>) field is a string
+that is considered part of the match but that should not be shown when 
+listing completions, it is given with the tt(-p) option. E.g. for
+functions that do filename generation, one might want to use this for
+a common path prefix. var(<word>) is the part of the match that should 
+appear in the list of completions, one of the tt(words) given at the
+end. The field var(<hsuf>) is like var(<hpre>) but gives a suffix that 
+should be matched but will not be listed. Finally, var(<asuf>) is the
+suffix given with tt(-S) that should automatically be added by the
+completion code.
 
 The supported flags are:
 
 startitem()
 item(tt(-P) var(prefix))(
-The same as for tt(compctl) and tt(complist), it gives a string that
+The same as for tt(compctl) and tt(compgen), it gives a string that
 should be inserted before the given words when they are completed. The
 string given is not considered to be part of the match.
 )
@@ -183,7 +282,9 @@ 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 inserted in the line before the
-match but that should not appear in the list of matches.
+match but that should not appear in the list of matches. Unless the
+tt(-U) option is given, the string on the line has to match this
+string.
 )
 item(tt(-s) var(hidden-suffix))(
 Like `tt(-p)', but gives a string to insert after the match.
@@ -195,7 +296,7 @@ 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
+As for tt(compctl) and tt(compgen) this gives the name of the group
 of matches the words should be stored in.
 )
 item(tt(-V) var(name))(
@@ -206,7 +307,7 @@ 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),
+This flag has the same meaning as for tt(compctl) and tt(compgen),
 too. It makes the suffix given with tt(-S) be automatically removed if 
 the next character typed is a blank or does not insert anything or if
 the suffix consists of only one character and the next character typed 
@@ -246,7 +347,7 @@ completed.
 )
 item(tt(-W) var(file-prefix))(
 This option has the same meaning as for the tt(compctl) and
-tt(complist) builtin commands. Here, however, only one string may be
+tt(compgen) builtin commands. Here, however, only one string may be
 given, not an array. This string is used as a pathname that will be
 prepended to the given words and the prefix given with the tt(-p)
 option to perform the file-tests when showing completion
@@ -254,7 +355,7 @@ listings. Hence it is only useful if combined with the tt(-f) flag,
 since the tests will only be performed if that flag is given.
 )
 item(tt(-a))(
-When used by tt(compctl) or tt(complist) the completion code normally
+When used by tt(compctl) or tt(compgen) the completion code normally
 builds two sets of matches: the normal one where words with one of the 
 suffixes in the array parameter tt(fignore) are not considered
 possible matches, and the alternate set where the words excluded
@@ -279,22 +380,13 @@ the name of an array is given, the elements of the array are taken as
 the suffixes.
 )
 item(tt(-Q))(
-As for tt(compctl) and tt(complist) this flag instructs the completion 
+As for tt(compctl) and tt(compgen) this flag instructs the completion 
 code not to quote any metacharacters in the words when inserting them
 in the command line.
 )
-item(tt(-m))(
-Normally the matches added by tt(compadd) will not be compared with
-what is already on the line. If this flag is given, this comparison is 
-performed as usual and the match specifications given with the tt(-M)
-option to tt(compadd) and the global match specifications defined with 
-tt(compctl) will be used. This means that probably not all the word
-given will be stored as matches since some of them may not match the
-string on the line.
-)
 item(tt(-M) var(match-spec))(
 This option allows one to give local match specifications with the
-same meaning and format as for the tt(compctl) and tt(complist)
+same meaning and format as for the tt(compctl) and tt(compgen)
 builtin commands. Note that they will only be used if the tt(-m) is
 given, too.
 )
@@ -303,9 +395,13 @@ Words added with tt(compadd) with this flag will be used as possible
 matches as usual but they not appear in the completion listing.
 )
 item(tt(-U))(
-If this flag is given to one of the calls to tt(compadd) and the
-option tt(AUTO_MENU) is set, the completion code will immediatly
-switch to menucompletion.
+If this flag is given, all words given will be accepted, no matching
+will be done by the completion code. Normally this is used in
+functions that do the matching themselves.
+
+Note that with tt(compadd) this option does not automatically turn on
+menu completion if tt(AUTO_LIST) is set as the same options for the
+tt(compctl) and tt(compgen) builtin command do.
 )
 item(tt(-), tt(--))(
 This flag ends the list of flags and options. All arguments after it
@@ -317,7 +413,7 @@ enditem()
 item(tt(compcall) [ tt(-TD) ])(
 
 This allows one to use completion definitions given with the
-tt(compctl) builtin from within completion widgets. It makes
+tt(compctl) builtin from within completion widgets. It makes the
 completion code complete the current word according to the
 tt(compctl)s defined. Normally only tt(compctl)s given for specific
 commands are used. To make the code use the completion flags given to
@@ -325,6 +421,10 @@ the tt(-T) option of tt(compctl), one can give the tt(-T) flag to
 tt(compctl). Likewise, the tt(-D) flag to tt(compcall) makes the
 default completion flags given to tt(compctl) with the tt(-D) option
 be used.
+
+The return value can be used to test if a matching tt(compctl)
+definition was found. It is non-zero if a tt(compctl) was found and
+zero otherwise.
 )
 enditem()
 
@@ -352,12 +452,14 @@ item(tt(-position) var(beg) [ var(end) ])(
 true if tt(CURRENT) is equal to var(beg) or, if var(end) is given,
 equal to or greater than var(beg) and equal to or less than var(end);
 both of var(beg) and var(end) may be arithmetic expressions, if they
-are less than zero the number of words in tt(argv) are added to them
+are less than zero the number of words in tt(words) are added to them
 before comparing them to tt(CURRENT); thus, tt(-1) is the last word,
-tt(-2) is the word before that and so on
+tt(-2) is the word before that and so on; note that positions are
+taken as indexes into the tt(words) array and thus are counted as if
+the tt(ksharray) is not set
 )
 item(tt(-word) var(index) var(string))(
-true if the word number var(index) in tt(argv) is equal to
+true if the word number var(index) in tt(words) is equal to
 var(string); again, var(index) may be negative, counting backwards
 )
 item(tt(-mword) var(index) var(pattern))(
@@ -375,7 +477,7 @@ true if the current word contains var(string); anything up to the last
 occurrence of this string will be ingnored by removing it from
 tt(PREFIX) and adding it to tt(IPREFIX); if var(number) is given,
 anything up to the var(number)'th occurrence of the var(string) will
-be ignored; again, var(nmuber) may be any arithmetic expression and
+be ignored; again, var(number) may be any arithmetic expression and
 negative values count backward
 )
 item(tt(-class) [ var(number) ] var(class))(
@@ -391,7 +493,7 @@ 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); this
 removes all words up to and including the matched word from the
-positional parameters
+tt(words) array
 )
 item(tt(-mafter) var(pattern))(
 like tt(-after) but using pattern matching
@@ -401,16 +503,16 @@ true if the cursor is after a word that is equal to var(string1), if
 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
+the tt(words) array
 )
 item(tt(-mbetween) var(pattern1) var(pattern2))(
 like tt(-between) but using pattern matching
 )
 item(tt(-nmatches) var(number))(
-true if the the value of tt(NMATCHES) is equal to var(number)
+true if the the value of tt(compstate[nmatches]) is equal to var(number)
 )
 item(tt(-matcher) var(number))(
-true if the value of tt(MATCHER) is equal to var(number)
+true if the value of tt(compstate[matcher]) is equal to var(number)
 )
 enditem()
 
@@ -433,7 +535,7 @@ after typing control-X and TAB. The function should then generte the
 matches, e.g.:
 
 indent(nofill(
-tt(complete-history LPAR()RPAR() { complist -H 0 '' })))
+tt(complete-history LPAR()RPAR() { compgen -H 0 '' })))
 
 In this the function will complete words from the history matching the 
 current word.
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index fa56bc0af..4fd64981f 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -227,7 +227,7 @@ Note the same record of the last var(l) and var(r) is maintained
 across all forms of expansion.
 
 By default, a history reference with no event specification refers to the same
-line as the last history reference on that command line, unless it is the
+line as the previous history reference on that command line, unless it is the
 first history reference in a command.  In that case, a history reference
 with no event specification always refers to the previous command.  However,
 if the option tt(CSH_JUNKIE_HISTORY) is set,
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index 41dd91510..bfb2238ed 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -155,6 +155,11 @@ if combined with `tt(r)', `tt(R)', `tt(i)' or `tt(I)', makes them give
 the var(n)th or var(n)th last match (if var(expr) evaluates to
 var(n)).  This flag is ignored when the array is associative.
 )
+item(tt(b:)var(expr)tt(:))(
+if combined with `tt(r)', `tt(R)', `tt(i)' or `tt(I)', makes them begin
+at the var(n)th or var(n)th last element, word, or character (if var(expr)
+evaluates to var(n)).  This flag is ignored when the array is associative.
+)
 enditem()
 texinode(Positional Parameters)(Local Parameters)(Array Parameters)(Parameters)
 sect(Positional Parameters)
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index c372c58eb..439caa2f8 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -154,6 +154,10 @@ key. Control-keys are reported with a leading `tt(^)', as in `tt(^A)',
 and meta-keys are repoted with a leading `tt(M-)', as in `tt(M-a)' and 
 `tt(M-^A)'.
 )
+vindex(NUMERIC)
+item(tt(NUMERIC) (integer))(
+The numeric argument.
+)
 enditem()
 sect(Standard Widgets)
 cindex(widgets, standard)
diff --git a/INSTALL b/INSTALL
index 1ed6847e3..f8200feff 100644
--- a/INSTALL
+++ b/INSTALL
@@ -56,10 +56,11 @@ Controlling what is compiled into the main zsh binary
 
 By default the comp1, compctl, zle, sched and rlimits modules are compiled
 into non-dynamic zsh and no modules are compiled into the main binary if
-dynamic loading is available.  This can be overridden by creating the
-Src/modules-bltin file with the list of modules which are to be compiled
-into the main binary.  See the zshmodules manual page for the list of
-available modules.
+dynamic loading is available.  This can be overridden by creating the file
+mymods.conf in the compilation directory (Src, unless you have told
+configure to use another directory) with the list of modules which are to
+be compiled into the main binary.  See the zshmodules manual page for the
+list of available modules.
 
 Compiler Options or Using a Different Compiler
 ----------------------------------------------
diff --git a/Src/Makefile.in b/Src/Makefile.in
index 1b5256e16..0babdf47b 100644
--- a/Src/Makefile.in
+++ b/Src/Makefile.in
@@ -112,8 +112,10 @@ FORCE:
 
 # ========== LINKING IN MODULES ==========
 
-modules-bltin:
-	if test @D@ = N; then \
+modules-bltin: Makefile
+	if test -f mymods.conf; then \
+	    cat mymods.conf > $@; \
+	elif test @D@ = N; then \
 	    cat $(sdir)/xmods.conf > $@; \
 	elif test @RTLD_GLOBAL_OK@ != yes; then \
 	    echo comp1 > $@; \
@@ -175,18 +177,21 @@ uninstall.bin-L:
 
 # ========== DEPENDENCIES FOR CLEANUP ==========
 
-@@clean.mk@@
+# Since module cleanup rules depend on Makemod, they come first.  This
+# forces module stuff to get cleaned before Makemod itself gets
+# deleted.
 
 mostlyclean-here:
 	rm -f stamp-modobjs stamp-modobjs.tmp
 
 clean-here:
 	rm -f modules.index.tmp modules.stamp zsh ansi2knr.o ansi2knr
+	rm -f modules.index modules-bltin
 	rm -f libzsh-*.$(DL_EXT)
 
 distclean-here:
 	rm -f TAGS tags
-	rm -f modules.index modules-bltin Makefile
+	rm -f Makefile mymods.conf
 
 mostlyclean: mostlyclean-modules
 clean: clean-modules
@@ -196,6 +201,8 @@ realclean: realclean-modules
 mostlyclean-modules clean-modules distclean-modules realclean-modules: Makemod
 	@$(MAKE) -f Makemod $(MAKEDEFS) `echo $@ | sed 's/-modules//'`
 
+@@clean.mk@@
+
 # ========== RECURSIVE MAKES ==========
 
 install.modules uninstall.modules \
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 76ac67114..d7f3610f1 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -103,6 +103,7 @@ struct compctl {
     char *glob;			/* for -g (globbing)                       */
     char *str;			/* for -s (expansion)                      */
     char *func;			/* for -K (function)                       */
+    char *widget;		/* for -i (function)                       */
     char *explain;		/* for -X (explanation)                    */
     char *ylist;		/* for -y (user-defined desc. for listing) */
     char *prefix, *suffix;	/* for -P and -S (prefix, suffix)          */
@@ -284,7 +285,37 @@ struct cline {
 /* Flags for compadd and addmatches(). */
 
 #define CAF_QUOTE    1
-#define CAF_MENU     2
-#define CAF_NOSORT   4
-#define CAF_ALT      8
-#define CAF_MATCH   16
+#define CAF_NOSORT   2
+#define CAF_ALT      4
+#define CAF_MATCH    8
+
+/* Flags for special parameters. */
+
+#define CP_WORDS      (1 <<  0)
+#define CP_CURRENT    (1 <<  1)
+#define CP_PREFIX     (1 <<  2)
+#define CP_SUFFIX     (1 <<  3)
+#define CP_IPREFIX    (1 <<  4)
+#define CP_COMPSTATE  (1 <<  5)
+
+#define CP_REALPARAMS        6
+
+#define CP_NMATCHES   (1 <<  6)
+#define CP_MATCHER    (1 <<  7)
+#define CP_MATCHERSTR (1 <<  8)
+#define CP_MATCHERTOT (1 <<  9)
+#define CP_CONTEXT    (1 << 10)
+#define CP_PARAMETER  (1 << 11)
+#define CP_REDIRECT   (1 << 12)
+#define CP_QUOTE      (1 << 13)
+#define CP_QUOTING    (1 << 14)
+#define CP_RESTORE    (1 << 15)
+#define CP_LIST       (1 << 16)
+#define CP_INSERT     (1 << 17)
+#define CP_EXACT      (1 << 18)
+#define CP_EXACTSTR   (1 << 19)
+#define CP_PATMATCH   (1 << 20)
+
+#define CP_NUM              21
+
+#define CP_ALLMASK    ((1 << CP_NUM) - 1)
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index 72f3cea53..ccccf5a34 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -46,10 +46,13 @@ Cmlist cmatcher;
 /**/
 void (*makecompparamsptr) _((void));
 
+/**/
+void (*comp_setunsetptr) _((int, int));
+
 /* 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 *, char **));
+int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **));
 
 /**/
 char *(*comp_strptr) _((int*, int*, int));
@@ -58,7 +61,7 @@ char *(*comp_strptr) _((int*, int*, int));
 int (*getcpatptr) _((char *, int, char *, int));
 
 /**/
-void (*makecomplistcallptr) _((Compctl));
+int (*makecomplistcallptr) _((Compctl));
 
 /**/
 int (*makecomplistctlptr) _((int));
@@ -96,14 +99,29 @@ int incompfunc;
 /**/
 long compcurrent,
      compnmatches,
-     compmatcher;
+     compmatcher,
+     compmatchertot;
 
 /**/
-char *compcontext,
-     *compcommand,
+char **compwords,
      *compprefix,
      *compsuffix,
-     *compiprefix;
+     *compiprefix,
+     *compmatcherstr,
+     *compcontext,
+     *compparameter,
+     *compredirect,
+     *compquote,
+     *compquoting,
+     *comprestore,
+     *complist,
+     *compinsert,
+     *compexact,
+     *compexactstr,
+     *comppatmatch;
+
+/**/
+Param *comppms;
 
 /* The function rembslash() came from zle_tricky.c, but is now used *
  * in compctl.c, too.                                               */
@@ -154,6 +172,7 @@ freecompctl(Compctl cc)
     zsfree(cc->glob);
     zsfree(cc->str);
     zsfree(cc->func);
+    zsfree(cc->widget);
     zsfree(cc->explain);
     zsfree(cc->ylist);
     zsfree(cc->prefix);
@@ -408,9 +427,14 @@ setup_comp1(Module m)
     cc_first.refc = 10000;
     cc_first.mask = 0;
     cc_first.mask2 = CC_CCCONT;
-    compcontext = compcommand = compprefix = compsuffix =
-	compiprefix = NULL;
+    comppms = NULL;
+    compwords = NULL;
+    compprefix = compsuffix = compiprefix = compmatcherstr = 
+	compcontext = compparameter = compredirect = compquote =
+	compquoting = comprestore = complist = compinsert =
+	compexact = compexactstr = comppatmatch = NULL;
     makecompparamsptr = NULL;
+    comp_setunsetptr = NULL;
     return 0;
 }
 
@@ -437,11 +461,22 @@ finish_comp1(Module m)
     deletehashtable(compctltab);
     zfree(clwords, clwsize * sizeof(char *));
     compctlreadptr = fallback_compctlread;
-    zsfree(compcontext);
-    zsfree(compcommand);
+    freearray(compwords);
     zsfree(compprefix);
-    zsfree(compiprefix);
     zsfree(compsuffix);
+    zsfree(compiprefix);
+    zsfree(compmatcherstr);
+    zsfree(compcontext);
+    zsfree(compparameter);
+    zsfree(compredirect);
+    zsfree(compquote);
+    zsfree(compquoting);
+    zsfree(comprestore);
+    zsfree(complist);
+    zsfree(compinsert);
+    zsfree(compexact);
+    zsfree(compexactstr);
+    zsfree(comppatmatch);
     return 0;
 }
 
diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export
index 278006b6a..35b63e7d3 100644
--- a/Src/Zle/comp1.export
+++ b/Src/Zle/comp1.export
@@ -13,12 +13,27 @@ compcommand
 compcontext
 compctltab
 compcurrent
+compexact
+compexactstr
+compinsert
 compiprefix
+complist
 compmatcher
+compmatcherstr
+compmatchertot
 compnmatches
+compparameter
+comppatmatch
+comppms
 compprefix
+compredirect
+compquote
+compquoting
+comprestore
+comp_setunsetptr
 comp_strptr
 compsuffix
+compwords
 freecmatcher
 freecmlist
 freecompcond
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index f71d67510..b5c8e4b3f 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -140,7 +140,7 @@ get_gmatcher(char *name, char **argv)
 	while (*argv) {
 	    if ((m = parse_cmatcher(name, *argv)) == pcm_err)
 		return 2;
-	    *q = n = (Cmlist) halloc(sizeof(struct cmlist));
+	    *q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
 	    n->next = NULL;
 	    n->matcher = m;
 	    n->str = *argv++;
@@ -578,6 +578,19 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl)
 		    *argv = "" - 1;
 		}
 		break;
+	    case 'i':
+		if ((*argv)[1]) {
+		    cct.widget = (*argv) + 1;
+		    *argv = "" - 1;
+		} else if (!argv[1]) {
+		    zwarnnam(name, "function name expected after -%c", NULL,
+			    **argv);
+		    return 1;
+		} else {
+		    cct.widget = *++argv;
+		    *argv = "" - 1;
+		}
+		break;
 	    case 'Y':
 		cct.mask |= CC_EXPANDEXPL;
 		goto expl;
@@ -1197,6 +1210,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
     zsfree(cc->glob);
     zsfree(cc->str);
     zsfree(cc->func);
+    zsfree(cc->widget);
     zsfree(cc->explain);
     zsfree(cc->ylist);
     zsfree(cc->prefix);
@@ -1217,6 +1231,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
     cc->glob = ztrdup(cct->glob);
     cc->str = ztrdup(cct->str);
     cc->func = ztrdup(cct->func);
+    cc->widget = ztrdup(cct->widget);
     cc->explain = ztrdup(cct->explain);
     cc->ylist = ztrdup(cct->ylist);
     cc->prefix = ztrdup(cct->prefix);
@@ -1423,6 +1438,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
 	printif(cc->gname, 'J');
     printif(cc->keyvar, 'k');
     printif(cc->func, 'K');
+    printif(cc->widget, 'i');
     printif(cc->explain, (cc->mask & CC_EXPANDEXPL) ? 'Y' : 'X');
     printif(cc->ylist, 'y');
     printif(cc->prefix, 'P');
@@ -1644,7 +1660,7 @@ bin_compctl(char *name, char **argv, char *ops, int func)
 
 /**/
 static int
-bin_complist(char *name, char **argv, char *ops, int func)
+bin_compgen(char *name, char **argv, char *ops, int func)
 {
     Compctl cc;
     int ret = 0;
@@ -1663,7 +1679,7 @@ bin_complist(char *name, char **argv, char *ops, int func)
 	zerrnam(name, "command names illegal", NULL, 0);
 	ret = 1;
     } else
-	makecomplistcallptr(cc);
+	ret = makecomplistcallptr(cc);
 
     freecompctl(cc);
     return ret;
@@ -1677,7 +1693,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
     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, *expl = NULL;
-    int f = 0, a = 0, dm;
+    int f = 0, a = CAF_MATCH, dm;
     Cmatcher match = NULL;
 
     if (incompfunc != 1) {
@@ -1710,7 +1726,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 		f |= CMF_NOLIST;
 		break;
 	    case 'U':
-		a |= CAF_MENU;
+		a &= ~CAF_MATCH;
 		break;
 	    case 'P':
 		sp = &pre;
@@ -1749,9 +1765,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 	    case 'a':
 		a |= CAF_ALT;
 		break;
-	    case 'm':
-		a |= CAF_MATCH;
-		break;
 	    case 'M':
 		sp = &m;
 		e = "matching specification expected after -%c";
@@ -1805,11 +1818,11 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 	return 1;
 
     match = cpcmatcher(match);
-    addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group,
-		  rs, rf, ign, f, a, match, expl, argv);
+    a = addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group,
+		      rs, rf, ign, f, a, match, expl, argv);
     freecmatcher(match);
 
-    return 0;
+    return a;
 }
 
 /**/
@@ -1824,34 +1837,54 @@ bin_compcall(char *name, char **argv, char *ops, int func)
 			      (ops['D'] ? 0 : CFN_DEFAULT));
 }
 
+/* Definitions for the special parameters. Note that these have to match the
+ * order of the CP_* bits in comp.h */
+
 #define VAR(X) ((void *) (&(X)))
 static struct compparam {
     char *name;
     int type;
     void *var;
 } compparams[] = {
+    { "words", PM_ARRAY, VAR(compwords) },
     { "CURRENT", PM_INTEGER, VAR(compcurrent) },
-    { "CONTEXT", PM_SCALAR, VAR(compcontext) },
-    { "COMMAND", PM_SCALAR, VAR(compcommand) },
     { "PREFIX", PM_SCALAR, VAR(compprefix) },
     { "SUFFIX", PM_SCALAR, VAR(compsuffix) },
     { "IPREFIX", PM_SCALAR, VAR(compiprefix) },
-    { "NMATCHES", PM_INTEGER, VAR(compnmatches) },
-    { "MATCHER", PM_INTEGER, VAR(compmatcher) },
+    { NULL, 0, NULL },
+
+    { "nmatches", PM_INTEGER, VAR(compnmatches) },
+    { "matcher", PM_INTEGER, VAR(compmatcher) },
+    { "matcher_string", PM_SCALAR, VAR(compmatcherstr) },
+    { "total_matchers", PM_INTEGER, VAR(compmatchertot) },
+    { "context", PM_SCALAR, VAR(compcontext) },
+    { "parameter", PM_SCALAR, VAR(compparameter) },
+    { "redirect", PM_SCALAR, VAR(compredirect) },
+    { "quote", PM_SCALAR, VAR(compquote) },
+    { "quoting", PM_SCALAR, VAR(compquoting) },
+    { "restore", PM_SCALAR, VAR(comprestore) },
+    { "list", PM_SCALAR, VAR(complist) },
+    { "insert", PM_SCALAR, VAR(compinsert) },
+    { "exact", PM_SCALAR, VAR(compexact) },
+    { "exact_string", PM_SCALAR, VAR(compexactstr) },
+    { "pattern_match", PM_SCALAR, VAR(comppatmatch) },
     { NULL, 0, NULL }
 };
 
-/**/
-void makecompparams(void)
+#define COMPSTATENAME "compstate"
+
+static struct compparam *
+addcompparams(struct compparam *cp)
 {
-    struct compparam *cp;
+    Param *pp = comppms + (cp - compparams);
 
-    for (cp = compparams; cp->name; cp++) {
+    for (; cp->name; cp++, pp++) {
 	Param pm = createparam(cp->name, cp->type | PM_SPECIAL|PM_REMOVABLE);
 	if (!pm)
 	    pm = (Param) paramtab->getnode(paramtab, cp->name);
-	DPUTS(!pm, "param not set in makecompparams");
+	DPUTS(!pm, "param not set in addcompparams");
 
+	*pp = pm;
 	pm->level = locallevel;
 	pm->u.data = cp->var;
 	switch(PM_TYPE(cp->type)) {
@@ -1862,18 +1895,115 @@ void makecompparams(void)
 	case PM_INTEGER:
 	    pm->sets.ifn = intvarsetfn;
 	    pm->gets.ifn = intvargetfn;
+	    pm->ct = 10;
+	    break;
+	case PM_ARRAY:
+	    pm->sets.afn = arrvarsetfn;
+	    pm->gets.afn = arrvargetfn;
 	    break;
 	}
 	pm->unsetfn = compunsetfn;
     }
+    return cp;
+}
+
+/**/
+void
+makecompparams(void)
+{
+    struct compparam *cp;
+    Param cpm;
+    HashTable tht;
+
+    cp = addcompparams(compparams);
+
+    if (!(cpm = createparam(COMPSTATENAME, PM_SPECIAL|PM_REMOVABLE|PM_HASHED)))
+	cpm = (Param) paramtab->getnode(paramtab, COMPSTATENAME);
+    DPUTS(!cpm, "param not set in makecompparams");
+
+    comppms[cp - compparams] = cpm;
+    tht = paramtab;
+    cpm->level = locallevel;
+    cpm->gets.hfn = get_compstate;
+    cpm->sets.hfn = set_compstate;
+    cpm->unsetfn = compunsetfn;
+    cpm->u.hash = paramtab = newparamtable(17, COMPSTATENAME);
+    addcompparams(cp + 1);
+    paramtab = tht;
+}
+
+/**/
+static HashTable
+get_compstate(Param pm)
+{
+    return pm->u.hash;
+}
+
+/**/
+static void
+set_compstate(Param pm, HashTable ht)
+{
+    struct compparam *cp;
+    Param *pp;
+    HashNode hn;
+    int i;
+    struct value v;
+    char *str;
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next)
+	    for (cp = compparams + CP_REALPARAMS,
+		 pp = comppms + CP_REALPARAMS; cp->name; cp++, pp++)
+		if (!strcmp(hn->nam, cp->name)) {
+		    v.isarr = v.inv = v.a = 0;
+		    v.b = -1;
+		    v.arr = NULL;
+		    v.pm = (Param) hn;
+		    if (cp->type == PM_INTEGER)
+			*((long *) cp->var) = getintvalue(&v);
+		    else if ((str = getstrvalue(&v))) {
+			zsfree(*((char **) cp->var));
+			*((char **) cp->var) = ztrdup(str);
+		    }
+		    (*pp)->flags &= ~PM_UNSET;
+
+		    break;
+		}
 }
 
 /**/
 static void
 compunsetfn(Param pm, int exp)
 {
-    if (exp)
-	stdunsetfn(pm, exp);
+    if (exp) {
+	if (PM_TYPE(pm->flags) == PM_SCALAR) {
+	    zsfree(*((char **) pm->u.data));
+	    *((char **) pm->u.data) = ztrdup("");
+	} else if (PM_TYPE(pm->flags) == PM_ARRAY) {
+	    freearray(*((char ***) pm->u.data));
+	    *((char ***) pm->u.data) = zcalloc(sizeof(char *));
+	}
+	pm->flags |= PM_UNSET;
+    }
+}
+
+/**/
+void
+comp_setunset(int set, int unset)
+{
+    Param *p;
+
+    if (!comppms)
+	return;
+
+    set &= CP_ALLMASK;
+    unset &= CP_ALLMASK;
+    for (p = comppms; set || unset; set >>= 1, unset >>= 1, p++) {
+	if (set & 1)
+	    (*p)->flags &= ~PM_UNSET;
+	if (unset & 1)
+	    (*p)->flags |= PM_UNSET;
+    }
 }
 
 /**/
@@ -1883,29 +2013,51 @@ comp_wrapper(List list, FuncWrap w, char *name)
     if (incompfunc != 1)
 	return 1;
     else {
-	char *octxt, *ocmd, *opre, *osuf, *oipre;
+	char *orest, *opre, *osuf, *oipre, **owords;
 	long ocur;
-
+	int unset = 0, m, sm;
+	Param *pp;
+
+	m = CP_WORDS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | 
+	    CP_IPREFIX | CP_RESTORE;
+	for (pp = comppms, sm = 1; m; pp++, m >>= 1, sm <<= 1) {
+	    if ((m & 1) && ((*pp)->flags & PM_UNSET))
+		unset |= sm;
+	}
+	orest = comprestore;
+	comprestore = ztrdup("auto");
 	ocur = compcurrent;
-	octxt = dupstring(compcontext);
-	ocmd = dupstring(compcommand);
 	opre = dupstring(compprefix);
 	osuf = dupstring(compsuffix);
 	oipre = dupstring(compiprefix);
 
+	HEAPALLOC {
+	    owords = arrdup(compwords);
+	} LASTALLOC;
+
 	runshfunc(list, w, name);
 
-	compcurrent = ocur;
-	zsfree(compcontext);
-	compcontext = ztrdup(octxt);
-	zsfree(compcommand);
-	compcommand = ztrdup(ocmd);
-	zsfree(compprefix);
-	compprefix = ztrdup(opre);
-	zsfree(compsuffix);
-	compsuffix = ztrdup(osuf);
-	zsfree(compiprefix);
-	compiprefix = ztrdup(oipre);
+	if (comprestore && !strcmp(comprestore, "auto")) {
+	    compcurrent = ocur;
+	    zsfree(compprefix);
+	    compprefix = ztrdup(opre);
+	    zsfree(compsuffix);
+	    compsuffix = ztrdup(osuf);
+	    zsfree(compiprefix);
+	    compiprefix = ztrdup(oipre);
+	    freearray(compwords);
+	    PERMALLOC {
+		compwords = arrdup(owords);
+	    } LASTALLOC;
+	    comp_setunset(CP_COMPSTATE |
+			  (~unset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
+				     CP_SUFFIX | CP_IPREFIX | CP_RESTORE)),
+			  unset);
+	} else
+	    comp_setunset(CP_COMPSTATE | (~unset & CP_RESTORE),
+			  (unset & CP_RESTORE));
+	zsfree(comprestore);
+	comprestore = orest;
 
 	return 0;
     }
@@ -1942,20 +2094,14 @@ comp_check(void)
 static void
 restrict_range(int b, int e)
 {
-    int i = e - b;
+    int i = e - b + 1;
     char **p = (char **) zcalloc((i + 1) * sizeof(char *)), **q, **pp;
 
-    for (q = p, pp = pparams + b + 1; i; i--, q++, pp++)
+    for (q = p, pp = compwords + b; i; i--, q++, pp++)
 	*q = ztrdup(*pp);
-    zsfree(compcommand);
-    compcommand = ztrdup(pparams[b]);
-    freearray(pparams);
-    pparams = p;
-    zsfree(compcontext);
-    if ((compcurrent -= b + 1))
-	compcontext = ztrdup("argument");
-    else
-	compcontext = ztrdup("command");
+    freearray(compwords);
+    compwords = p;
+    compcurrent -= b;
 }
 
 /**/
@@ -1988,7 +2134,7 @@ cond_position(char **a, int id)
 {
     if (comp_check()) {
 	int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : b);
-	int l = arrlen(pparams), t, i = compcurrent - 1;
+	int l = arrlen(compwords), t, i = compcurrent - 1;
 
 	if (b > 0)
 	    b--;
@@ -2018,7 +2164,7 @@ cond_word(char **a, int id)
 {
     if (comp_check()) {
 	int o = ((id & 2) ? compcurrent : 0) + cond_val(a, 0);
-	int l = arrlen(pparams);
+	int l = arrlen(compwords);
 	char *s;
 
 	if (o < 0)
@@ -2028,7 +2174,7 @@ cond_word(char **a, int id)
 	if (o < 0 || o >= l)
 	    return 0;
 
-	s = pparams[o];
+	s = compwords[o];
 	return ((id & 1) ? cond_match(a, 1, s) : !strcmp(s, cond_str(a, 1)));
     }
     return 0;
@@ -2068,7 +2214,7 @@ cond_words(char **a, int id)
 {
     if (comp_check()) {
 	int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : -1);
-	int l = arrlen(pparams);
+	int l = arrlen(compwords);
 
 	return (l >= b && l <= e);
     }
@@ -2081,7 +2227,7 @@ cond_range(char **a, int id)
 {
     if (comp_check()) {
 	char *s, **p;
-	int i, l = arrlen(pparams), t = 0, b = 0, e = l - 1;
+	int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1;
 	Comp c;
 
 	i = compcurrent - 1;
@@ -2095,7 +2241,7 @@ cond_range(char **a, int id)
 	} else
 	    s = cond_str(a, 0);
 
-	for (i--, p = pparams + i; i >= 0; p--, i--) {
+	for (i--, p = compwords + i; i >= 0; p--, i--) {
 	    if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) {
 		b = i + 1;
 		t = 1;
@@ -2112,7 +2258,7 @@ cond_range(char **a, int id)
 	    } else
 		s = cond_str(a, 1);
 
-	    for (i++, p = pparams + i; i < l; p++, i++) {
+	    for (i++, p = compwords + i; i < l; p++, i++) {
 		if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) {
 		    e = i - 1;
 		    tt = 1;
@@ -2151,7 +2297,7 @@ cond_matcher(char **a, int id)
 
 static struct builtin bintab[] = {
     BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL),
-    BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL),
+    BUILTIN("compgen", 0, bin_compgen, 1, -1, 0, NULL, NULL),
     BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL),
     BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL),
 };
@@ -2185,6 +2331,7 @@ setup_compctl(Module m)
 {
     compctltab->printnode = printcompctlp;
     makecompparamsptr = makecompparams;
+    comp_setunsetptr = comp_setunset;
     return 0;
 }
 
@@ -2217,6 +2364,7 @@ finish_compctl(Module m)
 {
     compctltab->printnode = NULL;
     makecompparamsptr = NULL;
+    comp_setunsetptr = NULL;
     return 0;
 }
 
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index a4b3866e5..2def5f03a 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -653,7 +653,7 @@ get_isrch_spot(int num, int *hlp, int *posp, int *csp, int *lenp, int *dirp, int
 static void
 doisearch(int dir)
 {
-    char *s, *ibuf = halloc(80), *sbuf = ibuf + FIRST_SEARCH_CHAR;
+    char *s, *ibuf = zhalloc(80), *sbuf = ibuf + FIRST_SEARCH_CHAR;
     int sbptr = 0, top_spot = 0, pos, sibuf = 80;
     int nomatch = 0, skip_line = 0, skip_pos = 0;
     int odir = dir, sens = zmult == 1 ? 3 : 1;
@@ -936,7 +936,7 @@ static int visrchsense;
 static int
 getvisrchstr(void)
 {
-    char *sbuf = halloc(80);
+    char *sbuf = zhalloc(80);
     int sptr = 1, ret = 0, ssbuf = 80;
     Thingy cmd;
     char *okeymap = curkeymapname;
@@ -1001,7 +1001,7 @@ getvisrchstr(void)
 	    }
 	  ins:
 	    if(sptr == ssbuf - 1) {
-		char *newbuf = halloc(ssbuf *= 2);
+		char *newbuf = zhalloc(ssbuf *= 2);
 		strcpy(newbuf, sbuf);
 		statusline = sbuf = newbuf;
 	    }
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 277d154a6..97d012f7b 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -154,10 +154,14 @@ zsetterm(void)
 #  ifdef OXTABS
     ti.tio.c_oflag &= ~OXTABS;
 #  else
+#   ifdef XTABS
     ti.tio.c_oflag &= ~XTABS;
+#   endif
 #  endif
 # endif
+#ifdef ONLCR
     ti.tio.c_oflag |= ONLCR;
+#endif
     ti.tio.c_cc[VQUIT] =
 # ifdef VDISCARD
 	ti.tio.c_cc[VDISCARD] =
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index ea8874010..1c25cd7eb 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -567,7 +567,7 @@ makequote(char *str, size_t *len)
 	if (*l == '\'')
 	    qtct++;
     *len += 2 + qtct*3;
-    l = ol = (char *)halloc(*len);
+    l = ol = (char *)zhalloc(*len);
     *l++ = '\'';
     for (; str < end; str++)
 	if (*str == '\'') {
@@ -613,7 +613,7 @@ executenamedcommand(char *prmt)
     char *okeymap = curkeymapname;
 
     clearlist = 1;
-    cmdbuf = halloc(l + NAMLEN + 2);
+    cmdbuf = zhalloc(l + NAMLEN + 2);
     strcpy(cmdbuf, prmt);
     statusline = cmdbuf;
     selectkeymap("main", 1);
@@ -794,7 +794,7 @@ makeparamsuffix(int br, int n)
     if(br) {
 	suffixlen['#'] = suffixlen['%'] = suffixlen['?'] = n;
 	suffixlen['-'] = suffixlen['+'] = suffixlen['='] = n;
-	/*{*/ suffixlen['}'] = n;
+	/*{*/ suffixlen['}'] = suffixlen['/'] = n;
     }
 }
 
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index 7e15d3d8b..2a35ac416 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -67,6 +67,8 @@ static struct zleparam {
         zleunsetfn, NULL },
     { "keys", PM_ARRAY | PM_READONLY, NULL, FN(get_keys),
         zleunsetfn, NULL },
+    { "NUMERIC", PM_INTEGER | PM_READONLY, FN(set_numeric), FN(get_numeric),
+        zleunsetfn, NULL },
     { NULL, 0, NULL, NULL, NULL, NULL }
 };
 
@@ -97,6 +99,7 @@ makezleparams(int ro)
 	    case PM_INTEGER:
 		pm->sets.ifn = (void (*) _((Param, long))) zp->setfn;
 		pm->gets.ifn = (long (*) _((Param))) zp->getfn;
+		pm->ct = 10;
 		break;
 	}
 	pm->unsetfn = zp->unsetfn;
@@ -225,9 +228,9 @@ get_keys(Param pm)
 {
     char **r, **q, *p, *k, c;
 
-    r = (char **) halloc((strlen(keybuf) + 1) * sizeof(char *));
+    r = (char **) zhalloc((strlen(keybuf) + 1) * sizeof(char *));
     for (q = r, p = keybuf; (c = *p); q++, p++) {
-	k = *q = (char *) halloc(5);
+	k = *q = (char *) zhalloc(5);
 	if (c & 0x80) {
 	    *k++ = 'M';
 	    *k++ = '-';
@@ -244,3 +247,17 @@ get_keys(Param pm)
 
     return r;
 }
+
+/**/
+static void
+set_numeric(Param pm, long x)
+{
+    zmult = x;
+}
+
+/**/
+static long
+get_numeric(Param pm)
+{
+    return zmult;
+}
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 9e07676e8..b9f39b70b 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -266,7 +266,11 @@ zrefresh(void)
 
 /* Nov 96: <mason>  I haven't checked how complete this is.  sgtty stuff may
    or may not work */
+#if defined(SGTABTYPE)
     oxtabs = ((SGTTYFLAG & SGTABTYPE) == SGTABTYPE);
+#else
+    oxtabs = 0;
+#endif
 
     cleareol = 0;		/* unset */
     more_start = more_end = 0;	/* unset */
@@ -615,7 +619,7 @@ refreshline(int ln)
     if (cleareol 		/* request to clear to end of line */
 	|| !nllen 		/* no line buffer given */
 	|| (ln == 0 && (put_rpmpt != oput_rpmpt))) {	/* prompt changed */
-	p1 = halloc(winw + 2);
+	p1 = zhalloc(winw + 2);
 	if (nllen)
 	    strncpy(p1, nl, nllen);
 	memset(p1 + nllen, ' ', winw - nllen);
@@ -627,7 +631,7 @@ refreshline(int ln)
 	    nl = p1;		/* don't keep the padding for prompt line */
 	nllen = winw;
     } else if (ollen > nllen) { /* make new line at least as long as old */
-	p1 = halloc(ollen + 1);
+	p1 = zhalloc(ollen + 1);
 	strncpy(p1, nl, nllen);
 	memset(p1 + nllen, ' ', ollen - nllen);
 	p1[ollen] = '\0';
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 4b42640e1..f01ffbf1c 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -73,9 +73,10 @@ static int wb, we;
 static int offs;
 
 /* These control the type of completion that will be done.  They are    *
- * affected by the choice of ZLE command and by relevant shell options. */
+ * affected by the choice of ZLE command and by relevant shell options. *
+ * usemenu is set to 2 if we have to start automenu.                    */
 
-static int usemenu, useglob;
+static int usemenu, useglob, useexact, useline, uselist;
 
 /* != 0 if we are in the middle of a menu completion */
 
@@ -125,7 +126,7 @@ static int validlist;
 
 /* This flag is non-zero if we are completing a pattern (with globcomplete) */
 
-static int ispattern;
+static int ispattern, haspattern;
 
 /* Two patterns used when doing glob-completion.  The first one is built *
  * from the whole word we are completing and the second one from that    *
@@ -168,12 +169,6 @@ static int addwhat;
 
 static char *qword;
 
-/* This is non-zero if we are doing a menu-completion and this is not the *
- * first call (e.g. when automenu is set and menu-completion was entered  *
- * due to this). */
-
-static int amenu;
-
 /* The current group of matches. */
 
 static Cmgroup mgroup;
@@ -322,7 +317,7 @@ completecall(void)
 void
 completeword(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     if (c == '\t' && usetab())
 	selfinsert();
@@ -351,7 +346,7 @@ menucomplete(void)
 void
 listchoices(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     docomplete(COMP_LIST_COMPLETE);
 }
@@ -371,7 +366,7 @@ deletecharorlist(void)
     Cmgroup mg = menugrp;
     Cmatch *mc = menucur;
 
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     if (cs != ll) {
 	fixsuffix();
@@ -398,7 +393,7 @@ expandword(void)
 void
 expandorcomplete(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     if (c == '\t' && usetab())
 	selfinsert();
@@ -427,7 +422,7 @@ menuexpandorcomplete(void)
 void
 listexpand(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     docomplete(COMP_LIST_EXPAND);
 }
@@ -492,9 +487,9 @@ acceptandmenucomplete(void)
 }
 
 /* These are flags saying if we are completing in the command *
- * position or in a redirection.                              */
+ * position, in a redirection, or in a parameter expansion.   */
 
-static int lincmd, linredir;
+static int lincmd, linredir, ispar;
 
 /* The string for the redirection operator. */
 
@@ -513,10 +508,10 @@ static char *varname;
 
 static int insubscr;
 
-/* 1 if we are completing in a string */
+/* 1 if we are completing in a quoted string (or inside `...`) */
 
 /**/
-int instring;
+int instring, inbackt;
 
 /* Convenience macro for calling bslashquote() (formerly quotename()). *
  * This uses the instring variable above.                              */
@@ -601,6 +596,87 @@ cmphaswilds(char *str)
     return 0;
 }
 
+/* Check if we have to complete a parameter name. */
+
+static char *
+check_param(char *s, int set)
+{
+    char *p;
+
+    ispar = 0;
+    /* Try to find a `$'. */
+    for (p = s + offs; p > s && *p != String; p--);
+    if (*p == String) {
+	/* Handle $$'s */
+	while (p > s && p[-1] == String)
+	    p--;
+	while (p[1] == String && p[2] == String)
+	    p += 2;
+    }
+    if (*p == String &&	p[1] != Inpar && p[1] != Inbrack) {
+	/* This is really a parameter expression (not $(...) or $[...]). */
+	char *b = p + 1, *e = b;
+	int n = 0, br = 1;
+
+	if (*b == Inbrace) {
+	    /* If this is a ${...}, ignore the possible (...) flags. */
+	    b++, br++;
+	    n = skipparens(Inpar, Outpar, &b);
+	}
+
+	/* Ignore the stuff before the parameter name. */
+	for (; *b; b++)
+	    if (*b != '^' && *b != Hat &&
+		*b != '=' && *b != Equals &&
+		*b != '~' && *b != Tilde)
+		break;
+	if (*b == '#' || *b == Pound || *b == '+')
+	    b++;
+
+	e = b;
+	/* Find the end of the name. */
+	if (*e == Quest || *e == Star || *e == String || *e == Qstring ||
+	    *e == '?'   || *e == '*'  || *e == '$'    ||
+	    *e == '-'   || *e == '!'  || *e == '@')
+	    e++;
+	else if (idigit(*e))
+	    while (idigit(*e))
+		e++;
+	else if (iident(*e))
+	    while (iident(*e) ||
+		   (comppatmatch && *comppatmatch &&
+		    (*e == Star || *e == Quest)))
+		e++;
+
+	/* Now make sure that the cursor is inside the name. */
+	if (offs <= e - s && offs >= b - s && n <= 0) {
+	    /* It is. */
+	    /* If we were called from makecomplistflags(), we have to set the
+	     * global variables. */
+	    if (set) {
+		if (br >= 2)
+		    mflags |= CMF_PARBR;
+
+		/* Get the prefix (anything up to the character before the name). */
+		lpsuf = dupstring(quotename(e, NULL, NULL, NULL));
+		*e = '\0';
+		lpsl = strlen(lpsuf);
+		ripre = dupstring(s);
+		ripre[b - s] = '\0';
+		ipre = dupstring(quotename(ripre, NULL, NULL, NULL));
+		untokenize(ipre);
+	    }
+	    /* And adjust wb, we, and offs again. */
+	    offs -= b - s;
+	    wb = cs - offs;
+	    we = wb + e - b;
+	    ispar = (br >= 2 ? 2 : 1);
+	    return b;
+	}
+    }
+    return NULL;
+}
+
 /* The main entry point for completion. */
 
 /**/
@@ -625,9 +701,9 @@ docomplete(int lst)
 
     /* Check if we have to start a menu-completion (via automenu). */
 
-    if ((amenu = (isset(AUTOMENU) && lastambig &&
-		  (!isset(BASHAUTOLIST) || lastambig == 2))))
-	usemenu = 1;
+    if (isset(AUTOMENU) && lastambig &&
+	(!isset(BASHAUTOLIST) || lastambig == 2))
+	usemenu = 2;
 
     /* Expand history references before starting completion.  If anything *
      * changed, do no more.                                               */
@@ -910,7 +986,7 @@ addx(char **ptmp)
 	(instring && (line[cs] == '"' || line[cs] == '\'')) ||
 	(addspace = (comppref && !iblank(line[cs])))) {
 	*ptmp = (char *)line;
-	line = (unsigned char *)halloc(strlen((char *)line) + 3 + addspace);
+	line = (unsigned char *)zhalloc(strlen((char *)line) + 3 + addspace);
 	memcpy(line, *ptmp, cs);
 	line[cs] = 'x';
 	if (addspace)
@@ -999,6 +1075,7 @@ get_comp_string(void)
 	else if (*p == '\\' && p[1] && !(k & 1))
 	    p++;
     instring = (j & 1) ? 2 : (k & 1);
+    inbackt = (i & 1);
     addx(&tmp);
     if (instring) {
 	/* Yes, we are in a string. */
@@ -1010,7 +1087,7 @@ get_comp_string(void)
 	 * What??  Why that??  Well, we want to be able to complete *
 	 * inside strings.  The lexer code gives us no help here,   *
 	 * so we have to cheat.  We remove the quotes, the lexer    *
-	 * will than treat the words in the strings normally and we *
+	 * will then treat the words in the strings normally and we *
 	 * can complete them.                                       *
 	 * This is completely the wrong thing to do, but it's       *
 	 * occasionally useful, and we can't handle quotes properly *
@@ -1551,7 +1628,7 @@ getcline(char *l, int ll, char *w, int wl, int fl)
     if ((r = freecl))
 	freecl = r->next;
     else
-	r = (Cline) halloc(sizeof(*r));
+	r = (Cline) zhalloc(sizeof(*r));
 
     r->next = NULL;
     r->line = l;
@@ -1626,7 +1703,7 @@ add_bmatchers(Cmatcher m)
     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));
+	    *q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
 	    n->matcher = m;
 	    q = &(n->next);
 	}
@@ -1796,7 +1873,7 @@ join_strs(int la, char *sa, int lb, char *sb)
 	    if (!t)
 		break;
 	} else {
-	    if (rr <= mp->llen) {
+	    if (rr <= 1) {
 		char *or = rs;
 
 		rs = realloc(rs, (rl += 20));
@@ -1850,7 +1927,7 @@ join_ends(Cline o, Cline n, int *olp, int *nlp)
 	} else {
 	    /* Different anchors, see if we can find matching anchors
 	     * further down the lists. */
-	    Cline to, tn;
+	    Cline to, tn = NULL;
 	    int t = 0;
 
 	    /* But first build the common prefix. */
@@ -3337,6 +3414,7 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp)
 	}
     }
     while (ll && lw) {
+	t = 0;
 	/* First try the matchers. */
 	for (ms = mstack; ms; ms = ms->next) {
 	    for (mp = ms->matcher; mp; mp = mp->next) {
@@ -3578,6 +3656,7 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp)
 	}
     }
     while (ll && lw) {
+	t = 0;
 	for (ms = mstack; ms; ms = ms->next) {
 	    for (mp = ms->matcher; mp; mp = mp->next) {
 		if (lm == mp)
@@ -3774,7 +3853,7 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl
 		 * in the cline struct in the middle. */
 		pml = strlen(p);
 		sml = strlen(s);
-		r = (char *) halloc(pml + sml + last->llen + 1);
+		r = (char *) zhalloc(pml + sml + last->llen + 1);
 		strcpy(r, p);
 		strncpy(r + pml, last->line, last->llen);
 		strcpy(r + pml + last->llen, s);
@@ -3824,7 +3903,7 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl
 static void
 inststrlen(char *str, int move, int len)
 {
-    if (!len)
+    if (!len || !str)
 	return;
     if (len == -1)
 	len = strlen(str);
@@ -3902,30 +3981,28 @@ instmatch(Cmatch m)
  * the matches. */
 
 /**/
-void
+int
 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 *exp, char **argv)
 {
-    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;
+    char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre = NULL, *lsuf = NULL;
+    char **aign = NULL;
+    int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
+    Aminfo ai = NULL;
     Cline lc = NULL;
-    LinkList l;
+    LinkList l = NULL;
     Cmatch cm;
     struct cmlist mst;
     Cmlist oms = mstack;
-
-    /* Use menu-completion (-U)? */
-    if ((aflags & CAF_MENU) && isset(AUTOMENU))
-	usemenu = 1;
+    Comp cp = NULL;
 
     /* 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 = (Cexpl) zhalloc(sizeof(struct cexpl));
 		expl->count = expl->fcount = 0;
 		expl->str = dupstring(exp);
 	    } else
@@ -3954,9 +4031,30 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 	    if (aflags & CAF_MATCH) {
 		lipre = dupstring(compiprefix);
 		lpre = dupstring(compprefix);
-		llpl = strlen(lpre);
 		lsuf = dupstring(compsuffix);
+		llpl = strlen(lpre);
 		llsl = strlen(lsuf);
+		/* Test if there is an existing -P prefix. */
+		if (pre && *pre) {
+		    pl = pfxlen(pre, lpre);
+		    llpl -= pl;
+		    lpre += pl;
+		}
+		if (comppatmatch && *comppatmatch) {
+		    char *tmp = (char *) zhalloc(2 + llpl + llsl);
+
+		    strcpy(tmp, lpre);
+		    tmp[llpl] = 'x';
+		    strcpy(tmp + llpl + 1, lsuf);
+
+		    tokenize(tmp);
+		    remnulargs(tmp);
+		    if (haswilds(tmp)) {
+			tmp[llpl] = Star;
+			if ((cp = parsereg(tmp)))
+			    haspattern = 1;
+		    }
+		}
 	    }
 	    /* Now duplicate the strings we have from the command line. */
 	    if (ipre)
@@ -3973,50 +4071,71 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		lsl = strlen(psuf);
 	    } else
 		lsl = 0;
-	    if (pre)
-		pre = dupstring(pre);
-	    if (suf)
-		suf = dupstring(suf);
-	    if (!prpre && (prpre = ppre)) {
-		singsub(&prpre);
-		untokenize(prpre);
-	    } else
-		prpre = dupstring(prpre);
-	    /* Select the group in which to store the matches. */
-	    if (group) {
-		endcmgroup(NULL);
-		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 (aflags & CAF_MATCH) {
+		s = ppre ? ppre : "";
+		if (llpl <= lpl && strpfx(lpre, s)) {
+		    llpl = 0;
+		    lpre = "";
+		} else if (llpl > lpl && strpfx(s, lpre)) {
+		    llpl -= lpl;
+		    lpre += lpl;
+		} else
+		    *argv = NULL;
+		s = psuf ? psuf : "";
+		if (llsl <= lsl && strsfx(lsuf, s)) {
+		    llsl = 0;
+		    lsuf = "";
+		} else if (llsl > lsl && strsfx(s, lsuf)) {
+		    lsuf[llsl - lsl] = '\0';
+		    llsl -= lsl;
+		} else
+		    *argv = NULL;
 	    }
-	    if (remf) {
-		remf = dupstring(remf);
-		rems = NULL;
-	    } else if (rems)
-		rems = dupstring(rems);
-	    /* Build the common -P prefix. */
-    	    if (ai->pprefix) {
+	    if (*argv) {
 		if (pre)
-		    ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0';
-		else
-		    ai->pprefix[0] = '\0';
-	    } else
-		ai->pprefix = dupstring(pre ? pre : "");
-
+		    pre = dupstring(pre);
+		if (suf)
+		    suf = dupstring(suf);
+		if (!prpre && (prpre = ppre)) {
+		    singsub(&prpre);
+		    untokenize(prpre);
+		} else
+		    prpre = dupstring(prpre);
+		/* Select the group in which to store the matches. */
+		if (group) {
+		    endcmgroup(NULL);
+		    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);
+		    rems = NULL;
+		} else if (rems)
+		    rems = dupstring(rems);
+		/* Build the common -P prefix. */
+		if (ai->pprefix) {
+		    if (pre)
+			ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0';
+		    else
+			ai->pprefix[0] = '\0';
+		} else
+		    ai->pprefix = dupstring(pre ? pre : "");
+	    }
 	    /* Walk through the matches given. */
 	    for (; (s = dupstring(*argv)); argv++) {
-		sl = strlen(s);
+		sl = pl = strlen(s);
 		lc = NULL;
 		ms = NULL;
 		bpl = brpl;
@@ -4042,19 +4161,26 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		}
 		if (aflags & CAF_MATCH) {
 		    /* Do the matching. */
-		    test = (sl >= llpl + llsl &&
-			    strpfx(lpre, s) && strsfx(lsuf, s));
-		    if (!test && mstack &&
-			(ms = comp_match(lpre, lsuf, s,
-					 &lc, (aflags & CAF_QUOTE),
-					 &bpl, &bsl)))
-			test = 1;
-
-		    if (!test)
-			continue;
-		    pl = sl - llsl;
-		    me = s + sl - llsl;
-		    e = s + llpl;
+		    if (cp) {
+			if ((test = domatch(s, cp, 0)))
+			    e = me = s + sl;
+			else
+			    continue;
+		    } else {
+			test = (sl >= llpl + llsl &&
+				strpfx(lpre, s) && strsfx(lsuf, s));
+			if (!test && mstack &&
+			    (ms = comp_match(lpre, lsuf, s,
+					     &lc, (aflags & CAF_QUOTE),
+					     &bpl, &bsl)))
+			    test = 1;
+
+			if (!test)
+			    continue;
+			pl = sl - llsl;
+			me = s + sl - llsl;
+			e = s + llpl;
+		    }
 		} else {
 		    e = s;
 		    me = s + sl;
@@ -4072,14 +4198,15 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		if (!ms) {
 		    if (sl < ai->minlen)
 			ai->minlen = sl;
-		    if (!mstack && ai->firstm &&
+		    if (!cp && !mstack && ai->firstm &&
 			(i = sfxlen(ai->firstm->str, s)) < ai->suflen)
 			ai->suflen = i;
 		}
 		t = s;
 		if (ppre)
 		    t = dyncat(ppre, t);
-		if (!ms && mstack) {
+		lc = NULL;
+		if (!cp && !ms && (mstack || psuf)) {
 		    int bl = ((aflags & CAF_MATCH) ? llpl : 0);
 		    Cline *clp = &lc, tlc;
 		    char *ss = dupstring(s), *ee = me + (ss - s);
@@ -4109,7 +4236,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 			clp = &(tlc->next);
 		    }
 		    *clp = NULL;
-		} else if (mstack) {
+		} else if (!cp && mstack) {
 		    Cline tlc;
 
 		    if (ppre && *ppre) {
@@ -4148,7 +4275,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		    lc = tlc;
 		} else
 		    ai->iprefix = "";
-		if (!ms && !mstack) {
+		if (!ms && !mstack && !lc) {
 		    if ((aflags & CAF_MATCH) || ai->cpl > pl)
 			ai->cpl = pl;
 		    if ((aflags & CAF_MATCH) || ai->csl > lsl)
@@ -4164,12 +4291,12 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		ai->count++;
 
 		/* Finally add the match. */
-		cm = (Cmatch) halloc(sizeof(struct cmatch));
+		cm = (Cmatch) zhalloc(sizeof(struct cmatch));
 		cm->ppre = ppre;
 		cm->psuf = psuf;
 		cm->prpre = prpre;
 		cm->str = (ms ? ms : dupstring(s));
-		cm->ipre = cm->ripre = ipre;
+		cm->ipre = cm->ripre = (ipre && *ipre ? ipre : NULL);
 		cm->pre = pre;
 		cm->suf = suf;
 		cm->flags = flags;
@@ -4179,7 +4306,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		cm->rems = rems;
 		addlinknode(l, cm);
 
-		if (expl) {
+		if (exp) {
 		    if (l == matches)
 			expl->count++;
 		    else
@@ -4188,12 +4315,24 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		if (!ms) {
 		    if (!ai->firstm)
 			ai->firstm = cm;
-		    if ((aflags & CAF_MATCH) && !(e - (s + pl))) {
-			if (!ai->exact)
+		    if (!cp && (aflags & CAF_MATCH) && !(e - (s + pl))) {
+			if (!ai->exact) {
 			    ai->exact = 1;
-			else {
+			    zsfree(compexactstr);
+			    compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1);
+			    if (ppre) {
+				strcpy(e, ppre);
+				e += lpl;
+			    }
+			    strcpy(e, s);
+			    e += sl;
+			    if (psuf)
+				strcpy(e, psuf);
+			    comp_setunsetptr(CP_EXACTSTR, 0);
+			} else {
 			    ai->exact = 2;
 			    cm = NULL;
+			    comp_setunsetptr(0, CP_EXACTSTR);
 			}
 			ai->exactm = cm;
 		    }
@@ -4208,6 +4347,8 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
     /* We switched back to the current heap, now restore the stack of
      * matchers. */
     mstack = oms;
+
+    return (mnum == nm);
 }
 
 /* This adds a match to the list of matches.  The string to add is given   *
@@ -4252,6 +4393,7 @@ addmatch(char *s, char *t)
 
     if (incompfunc)
 	s = dupstring(s);
+    e = s + sl;
     if (!addwhat) {
 	test = 1;
     } else if (addwhat == -1 || addwhat == -5 || addwhat == -6 ||
@@ -4318,7 +4460,7 @@ addmatch(char *s, char *t)
 		e += s - t;
 	    }
 	    if (cc) {
-		tt = (char *)halloc(lppl + lpsl + sl + 1);
+		tt = (char *)zhalloc(lppl + lpsl + sl + 1);
 		tt[0] = '\0';
 		if (lppre)
 		    strcpy(tt, lppre);
@@ -4353,7 +4495,7 @@ addmatch(char *s, char *t)
 		 (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) ||
 		  ((addwhat & CC_EXCMDS)  && !(hn->flags & DISABLED)))) ||
 		((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) {
-	if (sl >= rpl + rsl || mstack) {
+	if (sl >= rpl + rsl || mstack || cp) {
 	    if (cp) {
 		test = domatch(s, patcomp, 0);
 		e = s + sl;
@@ -4413,7 +4555,7 @@ addmatch(char *s, char *t)
     t = s;
     if (lppre)
 	t = dyncat(lppre, t);
-    if (!ms && mstack) {
+    if (!ispattern && !ms && mstack) {
 	Cline *clp = &lc, tlc;
 	char *ss = dupstring(s), *ee = e + (ss - s);
 
@@ -4481,7 +4623,7 @@ addmatch(char *s, char *t)
     ai->count++;
 
     /* Allocate and fill the match structure. */
-    cm = (Cmatch) halloc(sizeof(struct cmatch));
+    cm = (Cmatch) zhalloc(sizeof(struct cmatch));
     if (ispattern) {
 	if (lpsuf && *lpsuf && strsfx(lpsuf, s)) {
 	    s[sl - lpsl] = '\0';
@@ -4532,11 +4674,29 @@ addmatch(char *s, char *t)
 
 	/* Do we have an exact match? More than one? */
 	if (!ispattern && !(e - (s + pl))) {
-	    if (!ai->exact)
+	    if (!ai->exact) {
 		ai->exact = 1;
-	    else {
+		if (incompfunc) {
+		    int lpl = (cm->ppre ? strlen(cm->ppre) : 0);
+		    int lsl = (cm->psuf ? strlen(cm->psuf) : 0);
+
+		    zsfree(compexactstr);
+		    compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1);
+		    if (cm->ppre) {
+			strcpy(e, cm->ppre);
+			e += lpl;
+		    }
+		    strcpy(e, s);
+		    e += sl;
+		    if (cm->psuf)
+			strcpy(e, cm->psuf);
+		    comp_setunsetptr(CP_EXACTSTR, 0);
+		}
+	    } else {
 		ai->exact = 2;
 		cm = NULL;
+		if (incompfunc)
+		    comp_setunsetptr(0, CP_EXACTSTR);
 	    }
 	    ai->exactm = cm;
 	}
@@ -4688,7 +4848,6 @@ dumphashtable(HashTable ht, int what)
     for (i = 0; i < ht->hsize; i++)
 	for (hn = ht->nodes[i]; hn; hn = hn->next)
 	    addmatch(hn->nam, (char *) hn);
-
 }
 
 /* ScanFunc used by maketildelist() et al. */
@@ -4797,7 +4956,7 @@ gen_matches_files(int dirs, int execs, int all)
 			strcpy(p + o, psuf);
 
 			/* Do we have to use globbing? */
-			if (ispattern || (ns && isset(GLOBCOMPLETE))) {
+			if (ispattern || (ns && comppatmatch && *comppatmatch)) {
 			    /* Yes, so append a `*' if needed. */
 			    if (ns) {
 				int tl = strlen(p);
@@ -4847,6 +5006,15 @@ docompletion(char *s, int lst, int incmd)
 	ainfo = fainfo = NULL;
 	matchers = newlinklist();
 
+	useline = (lst != COMP_LIST_COMPLETE);
+	useexact = (isset(RECEXACT) && usemenu != 1);
+	uselist = (useline ?
+		   ((isset(AUTOLIST) && !isset(BASHAUTOLIST)) ? 
+		    (isset(LISTAMBIGUOUS) ? 3 : 2) : 0) : 1);
+	zsfree(comppatmatch);
+	comppatmatch = ztrdup(useglob ? "yes" : "");
+	haspattern = 0;
+
 	/* Make sure we have the completion list and compctl. */
 	if (makecomplist(s, incmd, lst)) {
 	    /* Error condition: feeeeeeeeeeeeep(). */
@@ -4854,23 +5022,26 @@ docompletion(char *s, int lst, int incmd)
 	    clearlist = 1;
 	    goto compend;
 	}
-	if (lst == COMP_LIST_COMPLETE)
+	if (!useline && uselist)
 	    /* All this and the guy only wants to see the list, sigh. */
 	    showinglist = -2;
-	else {
+	else if (useline) {
 	    /* We have matches. */
 	    if (nmatches > 1)
-		/* There are more than one match. */
+		/* There is more than one match. */
 		do_ambiguous();
 
 	    else if (nmatches == 1) {
 		/* Only one match. */
-		while (!amatches->mcount)
-		    amatches = amatches->next;
-		do_single(amatches->matches[0]);
+		Cmgroup m = amatches;
+
+		while (!m->mcount)
+		    m = m->next;
+		do_single(m->matches[0]);
 		invalidatelist();
 	    }
-	}
+	} else
+	    invalidatelist();
 
 	/* Print the explanation strings if needed. */
 	if (!showinglist && validlist && nmatches != 1) {
@@ -4928,33 +5099,47 @@ callcompfunc(char *s, char *fn)
     int lv = lastval;
     
     if ((list = getshfunc(fn)) != &dummy_list) {
-	LinkList args = newlinklist();
 	char **p, *tmp;
-	int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
-	
-	addlinknode(args, fn);
-	
+	int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
+	Param *ocpms = comppms;
+
+	comppms = (Param *) zalloc(CP_NUM * sizeof(Param));
+
+	set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
+		     CP_EXACTSTR | (useglob ? 0 : CP_PATMATCH));
 	zsfree(compcontext);
-	zsfree(compcommand);
-	compcommand = "";
-	if (inwhat == IN_MATH) {
+	zsfree(compparameter);
+	zsfree(compredirect);
+	compparameter = compredirect = "";
+	if (ispar)
+	    compcontext = (ispar == 2 ? "brace_parameter" : "parameter");
+	else if (inwhat == IN_MATH) {
 	    if (insubscr) {
 		compcontext = "subscript";
-		compcommand = varname ? varname : "";
+		if (varname) {
+		    compparameter = varname;
+		    set |= CP_PARAMETER;
+		}
 	    } else
 		compcontext = "math";
 	    usea = 0;
-	} else if (lincmd)
-	    compcontext = (insubscr ? "subscript" : "command");
-	else if (linredir) {
+	} else if (lincmd) {
+	    if (insubscr) {
+		compcontext = "subscript";
+		set |= CP_PARAMETER;
+	    } else
+		compcontext = "command";
+	} else if (linredir) {
 	    compcontext = "redirect";
 	    if (rdstr)
-		compcommand = rdstr;
+		compredirect = rdstr;
+	    set |= CP_REDIRECT;
 	} else
 	    switch (inwhat) {
 	    case IN_ENV:
-		compcontext = "value";
-		compcommand = varname;
+		compcontext = "array_value";
+		compparameter = varname;
+		set |= CP_PARAMETER;
 		if (!clwpos) {
 		    clwpos = 1;
 		    zsfree(clwords[1]);
@@ -4966,61 +5151,141 @@ callcompfunc(char *s, char *fn)
 		compcontext = "condition";
 		break;
 	    default:
-		if (cmdstr) {
-		    compcontext = "argument";
-		    compcommand = cmdstr;
-		} else {
+		if (cmdstr)
+		    compcontext = "command";
+		else {
 		    compcontext = "value";
+		    set |= CP_PARAMETER;
 		    if (clwords[0])
-			compcommand = clwords[0];
+			compparameter = clwords[0];
+		    aadd = 1;
 		}
-		aadd = 1;
 	    }
 	compcontext = ztrdup(compcontext);
-	tmp = quotename(compcommand, NULL, NULL, NULL);
-	untokenize(tmp);
-	compcommand = ztrdup(tmp);
-	if (usea && (!aadd || clwords[0]))
-	    for (p = clwords + aadd; *p; p++) {
-		tmp = dupstring(*p);
-		untokenize(tmp);
-		addlinknode(args, tmp);
+	if (compwords)
+	    freearray(compwords);
+	if (usea && (!aadd || clwords[0])) {
+	    char **q;
+
+	    PERMALLOC {
+		q = compwords = (char **)
+		    zalloc((clwnum - aadd + 1) * sizeof(char *));
+		for (p = clwords + aadd; *p; p++, q++) {
+		    tmp = dupstring(*p);
+		    untokenize(tmp);
+		    *q = ztrdup(tmp);
+		}
+		*q = NULL;
+	    } LASTALLOC;
+	} else
+	    compwords = (char **) zcalloc(sizeof(char *));
+
+	compparameter = ztrdup(compparameter);
+	compredirect = ztrdup(compredirect);
+	zsfree(compquote);
+	zsfree(compquoting);
+	if (instring) {
+	    if (instring == 1) {
+		compquote = ztrdup("\'");
+		compquoting = ztrdup("single");
+	    } else {
+		compquote = ztrdup("\"");
+		compquoting = ztrdup("double");
 	    }
+	    set |= CP_QUOTE | CP_QUOTING;
+	} else if (inbackt) {
+	    compquote = ztrdup("`");
+	    compquoting = ztrdup("backtick");
+	} else {
+	    compquote = ztrdup("");
+	    compquoting = ztrdup("");
+	}
+	untokenize(s = dupstring(s));
 	zsfree(compprefix);
 	zsfree(compsuffix);
 	if (unset(COMPLETEINWORD)) {
-	    tmp = quotename(s, NULL, NULL, NULL);
-	    untokenize(tmp);
-	    compprefix = ztrdup(tmp);
+	    compprefix = ztrdup(s);
 	    compsuffix = ztrdup("");
 	} else {
 	    char *ss = s + offs, sav;
-	    
-	    tmp = quotename(s, &ss, NULL, NULL);
+
 	    sav = *ss;
 	    *ss = '\0';
-	    untokenize(tmp);
-	    compprefix = ztrdup(tmp);
+	    compprefix = ztrdup(s);
 	    *ss = sav;
-	    untokenize(ss);
 	    compsuffix = ztrdup(ss);
 	}
 	zsfree(compiprefix);
 	compiprefix = ztrdup("");
-	compcurrent = (usea ? (clwpos + 1 - aadd) : 1);
+	compcurrent = (usea ? (clwpos + 1 - aadd) : 0);
 	compnmatches = mnum;
+
+	zsfree(complist);
+	switch (uselist) {
+	case 0: complist = ""; set &= ~CP_LIST; break;
+	case 1: complist = "list"; break;
+	case 2: complist = "autolist"; break;
+	case 3: complist = "ambiguous"; break;
+	}
+	complist = ztrdup(complist);
+	zsfree(compinsert);
+	if (useline) {
+	    switch (usemenu) {
+	    case 0: compinsert = "unambiguous"; break;
+	    case 1: compinsert = "menu"; break;
+	    case 2: compinsert = "automenu"; break;
+	    }
+	} else {
+	    compinsert = "";
+	    set &= ~CP_INSERT;
+	}
+	compinsert = ztrdup(compinsert);
+	if (useexact)
+	    compexact = ztrdup("accept");
+	else {
+	    compexact = ztrdup("");
+	    set &= ~CP_EXACT;
+	}
 	incompfunc = 1;
 	startparamscope();
 	makecompparamsptr();
+	comp_setunsetptr(set, ~set);
 	makezleparams(1);
 	sfcontext = SFC_CWIDGET;
 	NEWHEAPS(compheap) {
-	    doshfunc(fn, list, args, 0, 1);
+	    doshfunc(fn, list, NULL, 0, 1);
 	} OLDHEAPS;
 	sfcontext = osc;
 	endparamscope();
 	lastcmd = 0;
 	incompfunc = icf;
+
+	if (!complist)
+	    uselist = 0;
+	else if (!strcmp(complist, "list"))
+	    uselist = 1;
+	else if (!strcmp(complist, "auto") || !strcmp(complist, "autolist"))
+	    uselist = 2;
+	else if (!strcmp(complist, "ambig") || !strcmp(complist, "ambiguous"))
+	    uselist = 3;
+	else
+	    uselist = 0;
+	if (!compinsert)
+	    useline = 0;
+	else if (!strcmp(compinsert, "unambig") ||
+		 !strcmp(compinsert, "unambiguous"))
+	    useline = 1, usemenu = 0;
+	else if (!strcmp(compinsert, "menu"))
+	    useline = 1, usemenu = 1;
+	else if (!strcmp(compinsert, "auto") ||
+		 !strcmp(compinsert, "automenu"))
+	    useline = 1, usemenu = 2;
+	else
+	    useline = usemenu = 0;
+	useexact = (compexact && !strcmp(compexact, "accept"));
+
+	zfree(comppms, CP_NUM * sizeof(Param));
+	comppms = ocpms;
     }
     lastval = lv;
 }
@@ -5047,7 +5312,11 @@ makecomplist(char *s, int incmd, int lst)
 {
     struct cmlist ms;
     Cmlist m;
-    char *os = s;
+    char *p, *os = s;
+
+    /* Inside $... ? */
+    if ((p = check_param(s, 0)))
+	os = s = p;
 
     /* 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
@@ -5055,22 +5324,27 @@ makecomplist(char *s, int incmd, int lst)
 
     if ((m = cmatcher)) {
 	Cmlist mm, *mp = &mm;
+	int n;
 
-	for (; m; m = m->next) {
-	    *mp = (Cmlist) halloc(sizeof(struct cmlist));
+	for (n = 0; m; m = m->next, n++) {
+	    *mp = (Cmlist) zhalloc(sizeof(struct cmlist));
 	    (*mp)->matcher = m->matcher;
 	    (*mp)->next = NULL;
+	    (*mp)->str = dupstring(m->str);
 	    mp = &((*mp)->next);
 	    addlinknode(matchers, m->matcher);
 	    m->matcher->refc++;
 	}
 	m = mm;
-    }
-    compmatcher = 1;
+	compmatcher = 1;
+	compmatchertot = n;
+    } else
+	compmatcher = 0;
 
     /* Walk through the global matchers. */
     for (;;) {
 	bmatchers = NULL;
+	zsfree(compmatcherstr);
 	if (m) {
 	    ms.next = NULL;
 	    ms.matcher = m->matcher;
@@ -5080,9 +5354,11 @@ makecomplist(char *s, int incmd, int lst)
 	     * when building new parts for the string to insert into the 
 	     * line. */
 	    add_bmatchers(m->matcher);
-	} else
+	    compmatcherstr = ztrdup(m->str);
+	} else {
 	    mstack = NULL;
-
+	    compmatcherstr = ztrdup("");
+	}
 	ainfo = (Aminfo) hcalloc(sizeof(struct aminfo));
 	fainfo = (Aminfo) hcalloc(sizeof(struct aminfo));
 
@@ -5140,33 +5416,6 @@ makecomplist(char *s, int incmd, int lst)
 /* This should probably be moved into tokenize(). */
 
 /**/
-static char *
-ctokenize(char *p)
-{
-    char *r = p;
-    int bslash = 0;
-
-    tokenize(p);
-
-    for (p = r; *p; p++) {
-	if (*p == '\\')
-	    bslash = 1;
-	else {
-	    if (*p == '$' || *p == '=' || *p == '{' || *p == '}') {
-		if (bslash)
-		    p[-1] = Bnull;
-		else
-		    *p = (*p == '$' ? String :
-			  (*p == '=' ? Equals :
-			   (*p == '{' ? Inbrace : Outbrace)));
-	    }
-	    bslash = 0;
-	}
-    }
-    return r;
-}
-
-/**/
 char *
 comp_str(int *ipl, int *pl, int untok)
 {
@@ -5177,17 +5426,17 @@ comp_str(int *ipl, int *pl, int untok)
     int lp, ls, lip;
 
     if (!untok) {
-	ctokenize(p);
+	tokenize(p);
 	remnulargs(p);
-	ctokenize(s);
+	tokenize(s);
 	remnulargs(s);
-	ctokenize(ip);
+	tokenize(ip);
 	remnulargs(ip);
     }
     ls = strlen(s);
     lip = strlen(ip);
     lp = strlen(p);
-    str = halloc(lip + lp + ls + 1);
+    str = zhalloc(lip + lp + ls + 1);
     strcpy(str, ip);
     strcat(str, p);
     strcat(str, s);
@@ -5201,9 +5450,11 @@ comp_str(int *ipl, int *pl, int untok)
 }
 
 /**/
-void
+int
 makecomplistcall(Compctl cc)
 {
+    int nm = mnum;
+
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
 	    int ooffs = offs, lip, lp;
@@ -5217,6 +5468,8 @@ makecomplistcall(Compctl cc)
 	    compnmatches = mnum;
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
+
+    return (mnum == nm);
 }
 
 /* A simple counter to avoid endless recursion between old and new style *
@@ -5243,24 +5496,20 @@ makecomplistctl(int flags)
 	    char *os = cmdstr, **ow = clwords, **p, **q;
 	    int on = clwnum, op = clwpos;
 
-	    clwnum = arrlen(pparams) + 1;
+	    clwnum = arrlen(compwords);
 	    clwpos = compcurrent - 1;
-	    cmdstr = ztrdup(compcommand);
+	    cmdstr = ztrdup(compwords[0]);
 	    clwords = (char **) zalloc((clwnum + 1) * sizeof(char *));
-	    clwords[0] = ztrdup(cmdstr);
-	    for (p = pparams, q = clwords + 1; *p; p++, q++) {
+	    for (p = compwords, q = clwords; *p; p++, q++) {
 		t = dupstring(*p);
-		ctokenize(t);
+		tokenize(t);
 		remnulargs(t);
 		*q = ztrdup(t);
 	    }
 	    *q = NULL;
 	    offs = lip + lp;
 	    incompfunc = 2;
-	    ret = makecomplistglobal(str,
-				     (!clwpos &&
-				      !strcmp(compcontext, "command")),
-				     COMP_COMPLETE, flags);
+	    ret = makecomplistglobal(str, !clwpos, COMP_COMPLETE, flags);
 	    incompfunc = 1;
 	    offs = ooffs;
 	    compnmatches = mnum;
@@ -5499,7 +5748,7 @@ makecomplistext(Compctl occ, char *os, int incmd)
     Compcond or, cc;
     Comp comp;
     int compadd, m = 0, d = 0, t, tt, i, j, a, b;
-    char *sc, *s, *ss;
+    char *sc = NULL, *s, *ss;
 
     /* This loops over the patterns separated by `-'s. */
     for (compc = occ->ext; compc; compc = compc->next) {
@@ -5669,7 +5918,7 @@ findnode(LinkList list, void *dat)
 static void
 makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 {
-    int t, sf1, sf2, ooffs, um = usemenu, delit, ispar = 0;
+    int t, sf1, sf2, ooffs, um = usemenu, delit, oaw;
     char *p, *sd = NULL, *tt, *s1, *s2, *os =  dupstring(s);
     struct cmlist ms;
 
@@ -5678,6 +5927,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if (incompfunc != 1 && findnode(ccstack, cc))
 	return;
 
+    MUSTUSEHEAP("complistflags");
+
     addlinknode(ccstack, cc);
 
     if (incompfunc != 1 && allccs) {
@@ -5711,7 +5962,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if (cc->mask2 & CC_NOSORT)
 	mgroup->flags |= CGF_NOSORT;
     if (cc->explain) {
-	expl = (Cexpl) halloc(sizeof(struct cexpl));
+	expl = (Cexpl) zhalloc(sizeof(struct cexpl));
 	expl->count = expl->fcount = 0;
     }
     else
@@ -5781,79 +6032,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    s[suffixll - sl] = '\0';
     }
     /* Do we have one of the special characters `~' and `=' at the beginning? */
-    if ((ic = *s) != Tilde && ic != Equals)
+    if (incompfunc || ((ic = *s) != Tilde && ic != Equals))
 	ic = 0;
 
     /* Check if we have to complete a parameter name... */
-
-    /* Try to find a `$'. */
-    for (p = s + offs; p > s && *p != String; p--);
-    if (*p == String) {
-	/* Handle $$'s */
-	while (p > s && p[-1] == String)
-	    p--;
-	while (p[1] == String && p[2] == String)
-	    p += 2;
-    }
-    if (*p == String &&	p[1] != Inpar && p[1] != Inbrack) {
-	/* This is really a parameter expression (not $(...) or $[...]). */
-	char *b = p + 1, *e = b;
-	int n = 0, br = 1;
-
-	if (*b == Inbrace) {
-	    /* If this is a ${...}, ignore the possible (...) flags. */
-	    b++, br++;
-	    n = skipparens(Inpar, Outpar, &b);
-	}
-
-	/* Ignore the stuff before the parameter name. */
-	for (; *b; b++)
-	    if (*b != '^' && *b != Hat &&
-		*b != '=' && *b != Equals &&
-		*b != '~' && *b != Tilde)
-		break;
-	if (*b == '#' || *b == Pound || *b == '+')
-	    b++;
-
-	e = b;
-	/* Find the end of the name. */
-	if (*e == Quest || *e == Star || *e == String || *e == Qstring ||
-	    *e == '?'   || *e == '*'  || *e == '$'    ||
-	    *e == '-'   || *e == '!'  || *e == '@')
-	    e++;
-	else if (idigit(*e))
-	    while (idigit(*e))
-		e++;
-	else if (iident(*e))
-	    while (iident(*e) ||
-		   (useglob && (*e == Star || *e == Quest)))
-		e++;
-
-	/* Now make sure that the cursor is inside the name. */
-	if (offs <= e - s && offs >= b - s && n <= 0) {
-	    /* It is. */
-	    if (br >= 2)
-		mflags |= CMF_PARBR;
-
-	    /* Get the prefix (anything up to the character before the name). */
-	    lpsuf = dupstring(quotename(e, NULL, NULL, NULL));
-	    *e = '\0';
-	    lpsl = strlen(lpsuf);
-	    ripre = dupstring(s);
-	    ripre[b - s] = '\0';
-	    ipre = dupstring(quotename(ripre, NULL, NULL, NULL));
-	    untokenize(ipre);
-	    ispar = 1;
-	    /* And adjust wb, we, and offs again. */
-	    offs -= b - s;
-	    wb = cs - offs;
-	    we = wb + e - b;
-	    s = b;
-	    /* And now make sure that we complete parameter names. */
-	    cc = &cc_dummy;
-	    cc_dummy.refc = 10000;
-	    cc_dummy.mask = CC_PARAMS | CC_ENVVARS;
-	}
+    if (!incompfunc && (p = check_param(s, 1))) {
+	s = p;
+	/* And now make sure that we complete parameter names. */
+	cc = &cc_dummy;
+	cc_dummy.refc = 10000;
+	cc_dummy.mask = CC_PARAMS | CC_ENVVARS;
     }
     ooffs = offs;
     /* If we have to ignore the word, do that. */
@@ -5861,12 +6049,13 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	delit = 1;
 	*s = '\0';
 	offs = 0;
-	if (isset(AUTOMENU)) usemenu = 1;
+	if (isset(AUTOMENU))
+	    usemenu = 1;
     }
 
     /* Compute line prefix/suffix. */
     lpl = offs;
-    lpre = halloc(lpl + 1);
+    lpre = zhalloc(lpl + 1);
     memcpy(lpre, s, lpl);
     lpre[lpl] = '\0';
     lsuf = dupstring(s + offs);
@@ -5905,6 +6094,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    if (!s1)
 		s1 = p;
 	}
+    rsl = strlen(rsuf);
     for (s2 = NULL, sf2 = t = 0, p = rsuf; *p && (!t || !sf2); p++)
 	if (itok(*p))
 	    t |= sf2 ? 4 : 2;
@@ -5917,7 +6107,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
     /* But if we were asked not to do glob completion, we never treat the *
      * thing as a pattern.                                                */
-    if (!useglob)
+    if (!comppatmatch || !*comppatmatch)
 	ispattern = 0;
 
     if (ispattern) {
@@ -5930,6 +6120,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	} else
 	    strcpy(p + rpl, rsuf);
 	patcomp = parsereg(p);
+	haspattern = 1;
     }
     if (!patcomp) {
 	untokenize(rpre);
@@ -5963,6 +6154,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    line[cs] = 0;
 	    lppre = dupstring((char *) (line + wb));
 	    line[cs] = save;
+	    if (brbeg && *brbeg)
+		strcpy(lppre + brpl, lppre + brpl + strlen(brbeg));
 	    if ((p = strrchr(lppre, '/'))) {
 		p[1] = '\0';
 		lppl = strlen(lppre);
@@ -5979,8 +6172,14 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    char save = line[we];
 
 	    line[we] = 0;
-	    lpsuf = strchr(dupstring((char *) (line + cs)), '/');
+	    lpsuf = dupstring((char *) (line + cs));
 	    line[we] = save;
+	    if (brend && *brend) {
+		char *p = lpsuf + brsl - (cs - wb);
+
+		strcpy(p, p + strlen(brend));
+	    }
+	    lpsuf = strchr(lpsuf, '/');
 	    lpsl = (lpsuf ? strlen(lpsuf) : 0);
 	}
 	else {
@@ -5994,7 +6193,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	/* And the suffix. */
 	fsuf = dupstrpfx(rsuf, s2 - rsuf);
 
-	if (useglob && (ispattern & 2)) {
+	if (comppatmatch && *comppatmatch && (ispattern & 2)) {
 	    int t2;
 
 	    /* We have to use globbing, so compute the pattern from *
@@ -6079,10 +6278,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
 		    if ((pp = get_user_var(cc->withd))) {
 			dirs = npp =
-			    (char**) halloc(sizeof(char *)*(arrlen(pp)+1));
+			    (char**) zhalloc(sizeof(char *)*(arrlen(pp)+1));
 			while (*pp) {
 			    pl = strlen(*pp);
-			    tp = (char *) halloc(strlen(*pp) + tl);
+			    tp = (char *) zhalloc(strlen(*pp) + tl);
 			    strcpy(tp, *pp);
 			    tp[pl] = '/';
 			    strcpy(tp + pl + 1, ppre);
@@ -6098,7 +6297,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 			char *tp;
 			int pl = strlen(cc->withd);
 
-			ta[0] = tp = (char *) halloc(strlen(ppre) + pl + 2);
+			ta[0] = tp = (char *) zhalloc(strlen(ppre) + pl + 2);
 			strcpy(tp, cc->withd);
 			tp[pl] = '/';
 			strcpy(tp + pl + 1, ppre);
@@ -6270,7 +6469,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	if (isset(AUTOCD) && isset(CDABLEVARS))
 	    dumphashtable(paramtab, -4);
     }
-    addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG;
+    oaw = addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG;
 
     if (cc->mask & CC_NAMED)
 	/* Add named directories. */
@@ -6278,12 +6477,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if (cc->mask & CC_OPTIONS)
 	/* Add option names. */
 	dumphashtable(optiontab, addwhat);
-    if (cc->mask & CC_VARS)
+    if (cc->mask & CC_VARS) {
 	/* And parameter names. */
 	dumphashtable(paramtab, -9);
-    if (cc->mask & CC_BINDINGS)
+	addwhat = oaw;
+    }
+    if (cc->mask & CC_BINDINGS) {
 	/* And zle function names... */
 	dumphashtable(thingytab, CC_BINDINGS);
+	addwhat = oaw;
+    }
     if (cc->keyvar) {
 	/* This adds things given to the compctl -k flag *
 	 * (from a parameter or a list of words).        */
@@ -6293,54 +6496,53 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    while (*usr)
 		addmatch(*usr++, NULL);
     }
-    if (cc->mask & CC_USERS)
+    if (cc->mask & CC_USERS) {
 	/* Add user names. */
 	maketildelist();
+	addwhat = oaw;
+    }
+    if (cc->widget)
+	callcompfunc(os, cc->widget);
     if (cc->func) {
-	if (cc->func[0] == ' ')
-	    /* Temporary hack for access to new style completione. */
-	    callcompfunc(os, cc->func + 1);
-	else {
-	    /* This handles the compctl -K flag. */
-	    List list;
-	    char **r;
-	    int lv = lastval;
+	/* This handles the compctl -K flag. */
+	List list;
+	char **r;
+	int lv = lastval;
 	    
-	    /* Get the function. */
-	    if ((list = getshfunc(cc->func)) != &dummy_list) {
-		/* We have it, so build a argument list. */
-		LinkList args = newlinklist();
-		int osc = sfcontext;
-		
-		addlinknode(args, cc->func);
+	/* Get the function. */
+	if ((list = getshfunc(cc->func)) != &dummy_list) {
+	    /* We have it, so build a argument list. */
+	    LinkList args = newlinklist();
+	    int osc = sfcontext;
 		
-		if (delit) {
-		    p = dupstrpfx(os, ooffs);
-		    untokenize(p);
-		    addlinknode(args, p);
-		    p = dupstring(os + ooffs);
-		    untokenize(p);
-		    addlinknode(args, p);
-		} else {
-		    addlinknode(args, lpre);
-		    addlinknode(args, lsuf);
-		}
+	    addlinknode(args, cc->func);
 		
-		/* This flag allows us to use read -l and -c. */
-		if (incompfunc != 1)
-		    incompctlfunc = 1;
-		sfcontext = SFC_COMPLETE;
-		/* Call the function. */
-		doshfunc(cc->func, list, args, 0, 1);
-		sfcontext = osc;
-		incompctlfunc = 0;
-		/* And get the result from the reply parameter. */
-		if ((r = get_user_var("reply")))
-		    while (*r)
-			addmatch(*r++, NULL);
+	    if (delit) {
+		p = dupstrpfx(os, ooffs);
+		untokenize(p);
+		addlinknode(args, p);
+		p = dupstring(os + ooffs);
+		untokenize(p);
+		addlinknode(args, p);
+	    } else {
+		addlinknode(args, lpre);
+		addlinknode(args, lsuf);
 	    }
-	    lastval = lv;
+		
+	    /* This flag allows us to use read -l and -c. */
+	    if (incompfunc != 1)
+		incompctlfunc = 1;
+	    sfcontext = SFC_COMPLETE;
+	    /* Call the function. */
+	    doshfunc(cc->func, list, args, 0, 1);
+	    sfcontext = osc;
+	    incompctlfunc = 0;
+	    /* And get the result from the reply parameter. */
+	    if ((r = get_user_var("reply")))
+		while (*r)
+		    addmatch(*r++, NULL);
 	}
+	lastval = lv;
     }
     if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) {
 	/* Get job names. */
@@ -6378,7 +6580,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	 * get the words we have to expand.                        */
 	zleparse = 1;
 	lexsave();
-	tmpbuf = (char *)halloc(strlen(cc->str) + 5);
+	tmpbuf = (char *)zhalloc(strlen(cc->str) + 5);
 	sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */
 	inpush(tmpbuf, 0, NULL);
 	strinbeg();
@@ -6456,9 +6658,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if ((t = cc->mask & CC_BUILTINS))
 	/* Add builtins. */
 	dumphashtable(builtintab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
-    if ((t = cc->mask & CC_EXTCMDS))
+    if ((t = cc->mask & CC_EXTCMDS)) {
 	/* Add external commands */
+	if (isset(HASHLISTALL))
+	    cmdnamtab->filltable(cmdnamtab);
 	dumphashtable(cmdnamtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
+    }
     if ((t = cc->mask & CC_RESWDS))
 	/* Add reserved words */
 	dumphashtable(reswdtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
@@ -6486,7 +6691,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    for (ln = firstnode(matches); ln; ln = nextnode(ln)) {
 		m = (Cmatch) getdata(ln);
 		if (m->ppre) {
-		    char *p = (char *) halloc(strlen(m->ppre) + strlen(m->str) +
+		    char *p = (char *) zhalloc(strlen(m->ppre) + strlen(m->str) +
 					      strlen(m->psuf) + 1);
 
 		    sprintf(p, "%s%s%s", m->ppre, m->str, m->psuf);
@@ -6654,7 +6859,7 @@ get_user_var(char *nam)
 
 	if ((val = getsparam(nam))) {
 	    arr = (char **)ncalloc(2*sizeof(char *));
-	    arr[0] = val;
+	    arr[0] = (incompfunc ? dupstring(val) : val);
 	    arr[1] = NULL;
 	}
 	return arr;
@@ -6763,7 +6968,10 @@ makearray(LinkList l, int s, int *np, int *nlp)
 	    if ((*ap)->flags & CMF_NOLIST)
 		nl++;
 	*cp = NULL;
-    }
+    } else
+	for (ap = rp; *ap; ap++)
+	    if ((*ap)->flags & CMF_NOLIST)
+		nl++;
     if (np)
 	*np = n;
     if (nlp)
@@ -6795,7 +7003,7 @@ begcmgroup(char *n, int nu)
 	    p = p->next;
 	}
     }
-    mgroup = (Cmgroup) halloc(sizeof(struct cmgroup));
+    mgroup = (Cmgroup) zhalloc(sizeof(struct cmgroup));
     mgroup->name = dupstring(n);
     mgroup->flags = mgroup->lcount = mgroup->mcount = 0;
     mgroup->matches = NULL;
@@ -6858,8 +7066,8 @@ dupmatch(Cmatch m)
     r->ppre = ztrdup(m->ppre);
     r->psuf = ztrdup(m->psuf);
     r->prpre = ztrdup(m->prpre);
-    r->pre = m->pre;
-    r->suf = m->suf;
+    r->pre = ztrdup(m->pre);
+    r->suf = ztrdup(m->suf);
     r->flags = m->flags;
     r->brpl = m->brpl;
     r->brsl = m->brsl;
@@ -6975,6 +7183,8 @@ freematch(Cmatch m)
     zsfree(m->ripre);
     zsfree(m->ppre);
     zsfree(m->psuf);
+    zsfree(m->pre);
+    zsfree(m->suf);
     zsfree(m->prpre);
     zsfree(m->rems);
     zsfree(m->remf);
@@ -7030,15 +7240,14 @@ freematches(void)
 static void
 do_ambiguous(void)
 {
-    int p = (usemenu || ispattern), atend = (cs == we);
+    int p = (usemenu || haspattern), atend = (cs == we);
 
     menucmp = 0;
 
     /* 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 & FC_LINE) &&
-	(usemenu == 0 || unset(AUTOMENU))) {
+    if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) {
 	do_single(ainfo->exactm);
 	invalidatelist();
 	return;
@@ -7049,7 +7258,7 @@ do_ambiguous(void)
      * unambiguous prefix.                                               */
     lastambig = 1;
 
-    if(p) {
+    if (p) {
 	/* p is set if we are in a position to start using menu completion *
 	 * due to one of the menu completion options, or due to the        *
 	 * menu-complete-word command, or due to using GLOB_COMPLETE which *
@@ -7152,7 +7361,7 @@ do_ambiguous(void)
 	 * prefix was inserted, return now, bypassing the list-displaying  *
 	 * code.  On the way, invalidate the list and note that we don't   *
 	 * want to enter an AUTO_MENU imediately.                          */
-	if(isset(LISTAMBIGUOUS) && la) {
+	if (uselist == 3 && la) {
 	    int fc = fromcomp;
 
 	    invalidatelist();
@@ -7165,8 +7374,7 @@ do_ambiguous(void)
      * if it is needed.                                                     */
     if (isset(LISTBEEP))
 	feep();
-    if (isset(AUTOLIST) && !isset(BASHAUTOLIST) && !amenu && !showinglist &&
-	smatches >= 2)
+    if (uselist && usemenu != 2 && !showinglist && smatches >= 2)
 	showinglist = -2;
 }
 
@@ -7264,7 +7472,7 @@ do_single(Cmatch m)
 	    struct stat buf;
 
 	    /* Build the path name. */
-	    if (ispattern || ic || m->ripre) {
+	    if (haspattern || ic || m->ripre) {
 		int ne = noerrs;
 
 		noerrs = 1;
@@ -7620,14 +7828,14 @@ listmatches(void)
 	char **pp = g->ylist;
 
 	if ((e = g->expls)) {
-	    if (pnl) {
-		putc('\n', shout);
-		pnl = 0;
-	    }
 	    while (*e) {
 		if ((*e)->count) {
+		    if (pnl) {
+			putc('\n', shout);
+			pnl = 0;
+		    }
 		    printfmt((*e)->str, (*e)->count, 1);
-		    putc('\n', shout);
+		    pnl = 1;
 		}
 		e++;
 	    }
@@ -7670,7 +7878,7 @@ listmatches(void)
 	    }
 	}
 	else if (g->lcount) {
-	    int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a;
+	    int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a = 0;
 	    Cmatch *q;
 
 	    if (n && pnl) {
@@ -7691,7 +7899,7 @@ listmatches(void)
 			struct stat buf;
 			char *pb;
 
-			pb = (char *) halloc((m->prpre ? strlen(m->prpre) : 0) +
+			pb = (char *) zhalloc((m->prpre ? strlen(m->prpre) : 0) +
 					     3 + strlen(m->str));
 			sprintf(pb, "%s%s", (m->prpre ? m->prpre : "./"),
 				m->str);
diff --git a/Src/Zle/zle_word.c b/Src/Zle/zle_word.c
index afd860066..f446d1769 100644
--- a/Src/Zle/zle_word.c
+++ b/Src/Zle/zle_word.c
@@ -465,7 +465,7 @@ transposewords(void)
 	    return;
 	}
 	for (p1 = p2; p1 && iword(line[p1 - 1]); p1--);
-	pp = temp = (char *)halloc(p4 - p1 + 1);
+	pp = temp = (char *)zhalloc(p4 - p1 + 1);
 	struncpy(&pp, (char *) line + p3, p4 - p3);
 	struncpy(&pp, (char *) line + p2, p3 - p2);
 	struncpy(&pp, (char *) line + p1, p2 - p1);
diff --git a/Src/builtin.c b/Src/builtin.c
index fc9b113ca..c042537f4 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1072,12 +1072,14 @@ fixdir(char *src)
 	    *dest = '\0';
 	    return;
 	}
-	if (dest > d0 + 1 && src[0] == '.' && src[1] == '.' &&
+	if (src[0] == '.' && src[1] == '.' &&
 	  (src[2] == '\0' || src[2] == '/')) {
-	    /* remove a foo/.. combination */
-	    for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--);
-	    if (dest[-1] != '/')
-		dest--;
+	    if (dest > d0 + 1) {
+		/* remove a foo/.. combination */
+		for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--);
+		if (dest[-1] != '/')
+		    dest--;
+	    }
 	    src++;
 	    while (*++src == '/');
 	} else if (src[0] == '.' && (src[1] == '/' || src[1] == '\0')) {
diff --git a/Src/compat.c b/Src/compat.c
index b1bcbc21b..53ab6b7a3 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -115,7 +115,7 @@ zgetdir(struct dirsav *d)
     struct stat sbuf;
     ino_t pino;
     dev_t pdev;
-#ifndef __CYGWIN__
+#if !defined(__CYGWIN__) && !defined(USE_GETCWD)
     struct dirent *de;
     DIR *dir;
     dev_t dev;
@@ -123,7 +123,7 @@ zgetdir(struct dirsav *d)
     int len;
 #endif
 
-    buf = halloc(bufsiz = PATH_MAX);
+    buf = zhalloc(bufsiz = PATH_MAX);
     pos = bufsiz - 1;
     buf[pos] = '\0';
     strcpy(nbuf, "../");
@@ -142,7 +142,7 @@ zgetdir(struct dirsav *d)
 #ifdef HAVE_FCHDIR
     else
 #endif
-#ifndef __CYGWIN__
+#if !defined(__CYGWIN__) && !defined(USE_GETCWD)
 	holdintr();
 
     for (;;) {
@@ -202,7 +202,7 @@ zgetdir(struct dirsav *d)
 	len = strlen(nbuf + 2);
 	pos -= len;
 	while (pos <= 1) {
-	    char *newbuf = halloc(2*bufsiz);
+	    char *newbuf = zhalloc(2*bufsiz);
 	    memcpy(newbuf + bufsiz, buf, bufsiz);
 	    buf = newbuf;
 	    pos += bufsiz;
@@ -228,7 +228,7 @@ zgetdir(struct dirsav *d)
 	zchdir(buf + pos + 1);
     noholdintr();
 
-#else  /* __CYGWIN__ case */
+#else  /* __CYGWIN__, USE_GETCWD cases */
 
     if (!getcwd(buf, bufsiz)) {
 	if (d) {
diff --git a/Src/glob.c b/Src/glob.c
index 47fa63567..738753377 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -2177,7 +2177,7 @@ get_match_ret(char *s, int b, int e, int fl, char *replstr)
     if (replstr) {
 	if ((fl & SUB_GLOBAL) && repllist) {
 	    /* We are replacing the chunk, just add this to the list */
-	    Repldata rd = (Repldata) halloc(sizeof(*rd));
+	    Repldata rd = (Repldata) zhalloc(sizeof(*rd));
 	    rd->b = b;
 	    rd->e = e;
 	    addlinknode(repllist, rd);
@@ -2481,7 +2481,7 @@ getmatch(char **sp, char *pat, int fl, int n, char *replstr)
 	    i = rd->e;		/* start of next chunk of *sp */
 	}
 	lleft += l - i;	/* final chunk from *sp */
-	start = t = halloc(lleft+1);
+	start = t = zhalloc(lleft+1);
 	i = 0;
 	for (nd = firstnode(repllist); nd; incnode(nd)) {
 	    rd = (Repldata) getdata(nd);
diff --git a/Src/mem.c b/Src/mem.c
index 703920215..ee0f5635f 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -34,7 +34,7 @@
 	There are two ways to allocate memory in zsh.  The first way is
 	to call zalloc/zcalloc, which call malloc/calloc directly.  It
 	is legal to call realloc() or free() on memory allocated this way.
-	The second way is to call halloc/hcalloc, which allocates memory
+	The second way is to call zhalloc/hcalloc, which allocates memory
 	from one of the memory pools on the heap stack.  Such memory pools 
 	will automatically created when the heap allocation routines are
 	called.  To be sure that they are freed at appropriate times
@@ -55,7 +55,7 @@
 	it will all be freed when the pool is destroyed.  In fact,
 	attempting to free this memory may result in a core dump.
 	The pair of pointers ncalloc and alloc may point to either
-	zalloc & zcalloc or halloc & hcalloc; permalloc() sets them to the
+	zalloc & zcalloc or zhalloc & hcalloc; permalloc() sets them to the
 	former, and heapalloc() sets them to the latter. This can be useful.
 	For example, the dupstruct() routine duplicates a syntax tree,
 	allocating the new memory for the tree using alloc().  If you want
@@ -78,7 +78,7 @@
 /**/
 int useheap;
 
-/* Current allocation pointers.  ncalloc() is either zalloc() or halloc(); *
+/* Current allocation pointers.  ncalloc() is either zalloc() or zhalloc(); *
  * alloc() is either zcalloc() or hcalloc().                               */
 
 /**/
@@ -110,7 +110,7 @@ global_heapalloc(void)
     int luh = useheap;
 
     alloc = hcalloc;
-    ncalloc = halloc;
+    ncalloc = zhalloc;
     useheap = 1;
     return luh;
 }
@@ -262,7 +262,7 @@ popheap(void)
 
 /**/
 void *
-halloc(size_t size)
+zhalloc(size_t size)
 {
     Heap h;
     size_t n;
@@ -329,7 +329,7 @@ hrealloc(char *p, size_t old, size_t new)
     if (old == new)
 	return p;
     if (!old && !p)
-	return halloc(new);
+	return zhalloc(new);
 
     /* find the heap with p */
 
@@ -343,7 +343,7 @@ hrealloc(char *p, size_t old, size_t new)
 
     if (p + old < arena(h) + h->used) {
 	if (new > old) {
-	    char *ptr = (char *) halloc(new);
+	    char *ptr = (char *) zhalloc(new);
 	    memcpy(ptr, p, old);
 #ifdef ZSH_MEM_DEBUG
 	    memset(p, 0xff, old);
@@ -380,7 +380,7 @@ hrealloc(char *p, size_t old, size_t new)
 	h->used += new - old;
 	return p;
     } else {
-	char *t = halloc(new);
+	char *t = zhalloc(new);
 	memcpy(t, p, old > new ? new : old);
 	h->used -= old;
 #ifdef ZSH_MEM_DEBUG
@@ -398,7 +398,7 @@ hcalloc(size_t size)
 {
     void *ptr;
 
-    ptr = halloc(size);
+    ptr = zhalloc(size);
     memset(ptr, 0, size);
     return ptr;
 }
diff --git a/Src/params.c b/Src/params.c
index e8182815e..eb50c0b7e 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -680,6 +680,7 @@ 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, ishash;
+    int beg = 0, hasbeg = 0;
     char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt;
     long r = 0;
     Comp c;
@@ -731,6 +732,18 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 		*t = sav;
 		s = t;
 		break;
+	    case 'b':
+		hasbeg = 1;
+		t = get_strarg(++s);
+		if (!*t)
+		    goto flagerr;
+		sav = *t;
+		*t = '\0';
+		if ((beg = mathevalarg(s + 1, &d)) > 0)
+		    beg--;
+		*t = sav;
+		s = t;
+		break;
 	    case 'p':
 		escapes = 1;
 		break;
@@ -767,14 +780,15 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
     else if (v->isarr & SCANPM_WANTVALS)
 	*inv = 0;
     else {
-	if (ind) {
-	    v->isarr |= SCANPM_WANTKEYS;
-	    v->isarr &= ~SCANPM_WANTVALS;
-	} else if (rev) {
-	    v->isarr |= SCANPM_WANTVALS;
+	if (v->isarr) {
+	    if (ind) {
+		v->isarr |= SCANPM_WANTKEYS;
+		v->isarr &= ~SCANPM_WANTVALS;
+	    } else if (rev)
+		v->isarr |= SCANPM_WANTVALS;
+	    if (!down && ishash)
+		v->isarr &= ~SCANPM_MATCHMANY;
 	}
-	if (!down && ishash)
-	    v->isarr &= ~SCANPM_MATCHMANY;
 	*inv = ind;
     }
 
@@ -869,6 +883,8 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 	tokenize(s);
 
 	if ((c = parsereg(s))) {
+	    int len;
+
 	    if (v->isarr) {
 		if (ishash) {
 		    scancomp = c;
@@ -887,28 +903,43 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 		    ta = getarrvalue(v);
 		if (!ta || !*ta)
 		    return 0;
-		if (down)
-		    for (r = -1, p = ta + arrlen(ta) - 1; p >= ta; r--, p--) {
-			if (domatch(*p, c, 0) && !--num)
-			    return r;
-		} else
-		    for (r = 1, p = ta; *p; r++, p++)
-			if (domatch(*p, c, 0) && !--num)
-			    return r;
+		len = arrlen(ta);
+		if (beg < 0)
+		    beg += len;
+		if (beg >= 0 && beg < len) {
+		    if (down) {
+			if (!hasbeg)
+			    beg = len - 1;
+			for (r = 1 + beg, p = ta + beg; p >= ta; r--, p--) {
+			    if (domatch(*p, c, 0) && !--num)
+				return r;
+			}
+		    } else
+			for (r = 1 + beg, p = ta + beg; *p; r++, p++)
+			    if (domatch(*p, c, 0) && !--num)
+				return r;
+		}
 	    } else if (word) {
 		ta = sepsplit(d = s = getstrvalue(v), sep, 1);
-		if (down) {
-		    for (p = ta + (r = arrlen(ta)) - 1; p >= ta; p--, r--)
-			if (domatch(*p, c, 0) && !--num)
-			    break;
-		    if (p < ta)
-			return 0;
-		} else {
-		    for (r = 1, p = ta; *p; r++, p++)
-			if (domatch(*p, c, 0) && !--num)
-			    break;
-		    if (!*p)
-			return 0;
+		len = arrlen(ta);
+		if (beg < 0)
+		    beg += len;
+		if (beg >= 0 && beg < len) {
+		    if (down) {
+			if (!hasbeg)
+			    beg = len - 1;
+			for (r = 1 + beg, p = ta + beg; p >= ta; p--, r--)
+			    if (domatch(*p, c, 0) && !--num)
+				break;
+			if (p < ta)
+			    return 0;
+		    } else {
+			for (r = 1 + beg, p = ta + beg; *p; r++, p++)
+			    if (domatch(*p, c, 0) && !--num)
+				break;
+			if (!*p)
+			    return 0;
+		    }
 		}
 		if (a2)
 		    r++;
@@ -924,35 +955,46 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 		d = getstrvalue(v);
 		if (!d || !*d)
 		    return 0;
-		if (a2) {
-		    if (down)
-			for (r = -2, t = d + strlen(d) - 1; t >= d; r--, t--) {
-			    sav = *t;
-			    *t = '\0';
-			    if (domatch(d, c, 0) && !--num) {
+		len = strlen(d);
+		if (beg < 0)
+		    beg += len;
+		if (beg >= 0 && beg < len) {
+		    if (a2) {
+			if (down) {
+			    if (!hasbeg)
+				beg = len - 1;
+			    for (r = beg, t = d + beg; t >= d; r--, t--) {
+				sav = *t;
+				*t = '\0';
+				if (domatch(d, c, 0) && !--num) {
+				    *t = sav;
+				    return r;
+				}
 				*t = sav;
-				return r;
 			    }
-			    *t = sav;
-		    } else
-			for (r = 0, t = d; *t; r++, t++) {
-			    sav = *t;
-			    *t = '\0';
-			    if (domatch(d, c, 0) && !--num) {
+			} else
+			    for (r = beg, t = d + beg; *t; r++, t++) {
+				sav = *t;
+				*t = '\0';
+				if (domatch(d, c, 0) && !--num) {
+				    *t = sav;
+				    return r;
+				}
 				*t = sav;
-				return r;
 			    }
-			    *t = sav;
-			}
-		} else {
-		    if (down)
-			for (r = -1, t = d + strlen(d) - 1; t >= d; r--, t--) {
-			    if (domatch(t, c, 0) && !--num)
-				return r;
-		    } else
-			for (r = 1, t = d; *t; r++, t++)
-			    if (domatch(t, c, 0) && !--num)
-				return r;
+		    } else {
+			if (down) {
+			    if (!hasbeg)
+				beg = len - 1;
+			    for (r = beg + 1, t = d + beg; t >= d; r--, t--) {
+				if (domatch(t, c, 0) && !--num)
+				    return r;
+			    }
+			} else
+			    for (r = beg + 1, t = d + beg; *t; r++, t++)
+				if (domatch(t, c, 0) && !--num)
+				    return r;
+		    }
 		}
 		return 0;
 	    }
@@ -1177,7 +1219,8 @@ getstrvalue(Value v)
 	    }
 	    LASTALLOC_RETURN s;
 	case PM_INTEGER:
-	    convbase(s = buf, v->pm->gets.ifn(v->pm), v->pm->ct);
+	    convbase(buf, v->pm->gets.ifn(v->pm), v->pm->ct);
+	    s = dupstring(buf);
 	    break;
 	case PM_SCALAR:
 	    s = v->pm->gets.cfn(v->pm);
diff --git a/Src/subst.c b/Src/subst.c
index 2e9b84718..6445776d1 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -529,7 +529,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, char
     if (lr == ls)
 	return str;
 
-    r = ret = (char *)halloc(lr + 1);
+    r = ret = (char *)zhalloc(lr + 1);
 
     if (prenum) {
 	if (postnum) {
@@ -1831,7 +1831,7 @@ modify(char **str, char **ptr)
 		    tc = *tt;
 		    *tt = '\0';
 		    nl = al + strlen(t) + strlen(copy);
-		    ptr1 = tmp = (char *)halloc(nl + 1);
+		    ptr1 = tmp = (char *)zhalloc(nl + 1);
 		    if (all)
 			for (ptr2 = all; *ptr2;)
 			    *ptr1++ = *ptr2++;
diff --git a/Src/system.h b/Src/system.h
index 650690b51..2babafa7a 100644
--- a/Src/system.h
+++ b/Src/system.h
@@ -51,7 +51,7 @@
 #endif
 
 #ifndef HAVE_ALLOCA
-# define alloca halloc
+# define alloca zhalloc
 #else
 # ifdef __GNUC__
 #  define alloca __builtin_alloca
diff --git a/Src/utils.c b/Src/utils.c
index 4ff4a91ba..d010df4e0 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -93,7 +93,7 @@ zerrnam(const char *cmd, const char *fmt, const char *str, int num)
 	    case 'l': {
 		char *s;
 		num = metalen(str, num);
-		s = halloc(num + 1);
+		s = zhalloc(num + 1);
 		memcpy(s, str, num);
 		s[num] = '\0';
 		nicezputs(s, stderr);
@@ -2807,7 +2807,7 @@ metafy(char *buf, int len, int heap)
 	    break;
 	case META_USEHEAP:
 	case META_HEAPDUP:
-	    buf = memcpy(halloc(len + meta + 1), buf, len);
+	    buf = memcpy(zhalloc(len + meta + 1), buf, len);
 	    break;
 	case META_STATIC:
 #ifdef DEBUG
@@ -3372,7 +3372,7 @@ getkeystring(char *s, int *len, int fromwhere, int *misc)
     int meta = 0, control = 0;
 
     if (fromwhere != 4)
-	buf = halloc(strlen(s) + 1);
+	buf = zhalloc(strlen(s) + 1);
     else {
 	buf = s;
 	s += 2;
diff --git a/Src/zsh.export b/Src/zsh.export
index d31e7902e..dcee683f6 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -5,6 +5,8 @@ addconddefs
 addedx
 addhashnode
 addwrapper
+arrvargetfn
+arrvarsetfn
 aliastab
 alloc_stackp
 appstr
@@ -69,6 +71,7 @@ getaparam
 gethashnode
 gethashnode2
 gethparam
+getintvalue
 getiparam
 getkeystring
 getlinknode
@@ -82,7 +85,6 @@ global_heapalloc
 global_permalloc
 globlist
 gotwordptr
-halloc
 hasam
 hashcmd
 hasher
@@ -135,6 +137,7 @@ ncalloc
 new_heaps
 newhashtable
 newlinklist
+newparamtable
 nicechar
 nicezputs
 niceztrdup
@@ -250,6 +253,7 @@ zexit
 zfree
 zgetdir
 zgetenv
+zhalloc
 zjoin
 zleactive
 zleparse
diff --git a/acconfig.h b/acconfig.h
index 506441635..bcd111c8c 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -73,6 +73,9 @@
 /* Define to 1 if you have RFS superroot directory. */
 #undef HAVE_SUPERROOT
 
+/* Define to 1 if you need to use the native getcwd */
+#undef USE_GETCWD
+
 /* Define to the path of the /dev/fd filesystem */
 #undef PATH_DEV_FD
 
diff --git a/config.sub b/config.sub
index 7e9735ea7..00bea6e6a 100755
--- a/config.sub
+++ b/config.sub
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Configuration validation subroutine script, version 1.1.
-#   Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+#   Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
 # can handle that machine.  It does not imply ALL GNU software can.
@@ -149,19 +149,20 @@ esac
 case $basic_machine in
 	# Recognize the basic CPU types without company name.
 	# Some are omitted here because they have special meanings below.
-	tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \
-		| arme[lb] | pyramid \
-		| tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \
-		| alpha | we32k | ns16k | clipper | i370 | sh \
-		| powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \
-		| pdp11 | mips64el | mips64orion | mips64orionel \
-		| sparc | sparclet | sparclite | sparc64)
+	tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+		| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+		| 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \
+		| alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
+		| i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
+		| mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+		| mipstx39 | mipstx39el \
+		| sparc | sparclet | sparclite | sparc64 | v850)
 		basic_machine=$basic_machine-unknown
 		;;
 	# We use `pc' rather than `unknown'
 	# because (1) that's what they normally are, and
 	# (2) the word "unknown" tends to confuse beginning users.
-	i[3456]86)
+	i[34567]86)
 	  basic_machine=$basic_machine-pc
 	  ;;
 	# Object if more than one company name word.
@@ -170,14 +171,18 @@ case $basic_machine in
 		exit 1
 		;;
 	# Recognize the basic CPU types with company name.
-	vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
-	      | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
-	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
-	      | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
-	      | hppa-* | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
-	      | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
-	      | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \
-	      | mips64el-* | mips64orion-* | mips64orionel-* | f301-*)
+	vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+	      | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+	      | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
+	      | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
+	      | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
+	      | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+	      | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+	      | sparc64-* | mips64-* | mipsel-* \
+	      | mips64el-* | mips64orion-* | mips64orionel-*  \
+	      | mipstx39-* | mipstx39el-* \
+	      | f301-*)
 		;;
 	# Recognize the various machine names and aliases which stand
 	# for a CPU type and a company and sometimes even an OS.
@@ -204,9 +209,9 @@ case $basic_machine in
 	amiga | amiga-*)
 		basic_machine=m68k-cbm
 		;;
-	amigados)
+	amigaos | amigados)
 		basic_machine=m68k-cbm
-		os=-amigados
+		os=-amigaos
 		;;
 	amigaunix | amix)
 		basic_machine=m68k-cbm
@@ -345,19 +350,19 @@ case $basic_machine in
 		os=-mvs
 		;;
 # I'm not sure what "Sysv32" means.  Should this be sysv3.2?
-	i[3456]86v32)
+	i[34567]86v32)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-sysv32
 		;;
-	i[3456]86v4*)
+	i[34567]86v4*)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-sysv4
 		;;
-	i[3456]86v)
+	i[34567]86v)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-sysv
 		;;
-	i[3456]86sol2)
+	i[34567]86sol2)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-solaris2
 		;;
@@ -389,6 +394,14 @@ case $basic_machine in
 	miniframe)
 		basic_machine=m68000-convergent
 		;;
+	mipsel*-linux*)
+		basic_machine=mipsel-unknown
+		os=-linux-gnu
+		;;
+	mips*-linux*)
+		basic_machine=mips-unknown
+		os=-linux-gnu
+		;;
 	mips3*-*)
 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
 		;;
@@ -456,25 +469,23 @@ case $basic_machine in
         pc532 | pc532-*)
 		basic_machine=ns32k-pc532
 		;;
-	pentium | p5)
-		basic_machine=i586-intel
+	pentium | p5 | k5 | nexen)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | k6 | 6x86)
+		basic_machine=i686-pc
 		;;
-	pentiumpro | p6)
-		basic_machine=i686-intel
+	pentiumii | pentium2)
+		basic_machine=i786-pc
 		;;
-	pentium-* | p5-*)
+	pentium-* | p5-* | k5-* | nexen-*)
 		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
-	pentiumpro-* | p6-*)
+	pentiumpro-* | p6-* | k6-* | 6x86-*)
 		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
-	k5)
-		# We don't have specific support for AMD's K5 yet, so just call it a Pentium
-		basic_machine=i586-amd
-		;;
-	nexen)
-		# We don't have specific support for Nexgen yet, so just call it a Pentium
-		basic_machine=i586-nexgen
+	pentiumii-* | pentium2-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
 	pn)
 		basic_machine=pn-gould
@@ -558,6 +569,12 @@ case $basic_machine in
 		basic_machine=i386-sequent
 		os=-dynix
 		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
 	tower | tower-32)
 		basic_machine=m68k-ncr
 		;;
@@ -577,7 +594,7 @@ case $basic_machine in
 		basic_machine=vax-dec
 		os=-vms
 		;;
-       vpp*|vx|vx-*)
+	vpp*|vx|vx-*)
                basic_machine=f301-fujitsu
                ;;
 	vxworks960)
@@ -607,7 +624,11 @@ case $basic_machine in
 # Here we handle the default manufacturer of certain CPU types.  It is in
 # some cases the only manufacturer, in others, it is the most popular.
 	mips)
-		basic_machine=mips-mips
+		if [ x$os = x-linux-gnu ]; then
+			basic_machine=mips-unknown
+		else
+			basic_machine=mips-mips
+		fi
 		;;
 	romp)
 		basic_machine=romp-ibm
@@ -668,9 +689,12 @@ case $os in
 	-solaris)
 		os=-solaris2
 		;;
-	-unixware* | svr4*)
+	-svr4*)
 		os=-sysv4
 		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
 	-gnu/linux*)
 		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
 		;;
@@ -681,17 +705,21 @@ case $os in
 	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
-	      | -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
 	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
 	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
-	      | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-	      | -linux* | -uxpv* | -rhapsody* )
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -uxpv* | -beos*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
 	-sunos5*)
 		os=`echo $os | sed -e 's|sunos5|solaris2|'`
 		;;
@@ -799,6 +827,9 @@ case $basic_machine in
 	sparc-* | *-sun)
 		os=-sunos4.1.1
 		;;
+	*-be)
+		os=-beos
+		;;
 	*-ibm)
 		os=-aix
 		;;
@@ -812,7 +843,7 @@ case $basic_machine in
 		os=-sysv
 		;;
 	*-cbm)
-		os=-amigados
+		os=-amigaos
 		;;
 	*-dg)
 		os=-dgux
diff --git a/configure.in b/configure.in
index dd6bfee4b..5cfaec326 100644
--- a/configure.in
+++ b/configure.in
@@ -618,12 +618,6 @@ zsh_STRUCT_MEMBER([
 #endif
 ], struct direct, d_stat)
 
-dnl ---------------
-dnl CHECK FUNCTIONS
-dnl ---------------
-AC_FUNC_GETPGRP
-AC_FUNC_STRCOLL
-
 dnl need to integrate this function
 dnl AC_FUNC_STRFTIME
 
@@ -633,7 +627,22 @@ AC_CHECK_FUNCS(memcpy memmove \
               sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \
               sigprocmask setuid seteuid setreuid setresuid setsid strerror \
               nis_list initgroups fchdir cap_get_proc readlink nice \
-	      getgrgid getgrnam getpwent getpwnam getpwuid)
+	      getgrgid getgrnam getpwent getpwnam getpwuid setpgrp)
+
+dnl ---------------
+dnl CHECK FUNCTIONS
+dnl ---------------
+if test $ac_cv_func_setpgrp = yes; then
+  AC_FUNC_GETPGRP
+else
+  dnl If there is no setpgrp, the test for getpgrp(void) will fail
+  dnl because the program will not compile.  However, in that case
+  dnl we can be reasonably confident we are not dealing with a
+  dnl Berkeleyesque system, so assume getpgrp does take void.
+  ac_cv_func_getpgrp_void=yes
+  AC_DEFINE(GETPGRP_VOID)
+fi
+AC_FUNC_STRCOLL
 
 if test $dynamic = yes; then
   AC_CHECK_FUNCS(dlopen dlerror dlsym dlclose load loadquery loadbind unload \
@@ -824,6 +833,17 @@ if test $zsh_cv_sys_superroot = yes; then
   AC_DEFINE(HAVE_SUPERROOT)
 fi
 
+dnl CHECK FOR SYSTEMS REQUIRING GETCWD
+AC_CACHE_CHECK(whether we should use the native getcwd,
+zsh_cv_use_getcwd,
+[case "${host_cpu}-${host_vendor}-${host_os}" in
+    *QNX*) zsh_cv_use_getcwd=no ;;
+    *) zsh_cv_use_getcwd=yes ;;
+ esac])
+if test $zsh_cv_use_getcwd = yes; then
+  AC_DEFINE(USE_GETCWD)
+fi
+
 dnl -------------
 dnl CHECK FOR NIS
 dnl -------------
diff --git a/patchlist.txt b/patchlist.txt
index 0497dee80..3d76dd023 100644
--- a/patchlist.txt
+++ b/patchlist.txt
@@ -562,3 +562,104 @@ 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.
+
+  pws-11
+
+pws: 5557: configure.in for making sure signals really are defined in the
+file found.  This was in pws-10, but the patch didn't appear on the list
+for four days.
+
+Larry P. Schrof: 5550: last -> previous in history documentation
+
+Sven: 5560: subscripting fixes in params.c: flags for scalars and
+converting integer AA element to string
+
+pws: 5561: attempted (untested) fix for QNX4 compilation; halloc() is now
+zhalloc().  (By private email from probin@qnx.co.uk, it seems the QNX
+problems are more considerable with 3.1.5.)
+
+Sven: 5564, 5577, 5579: massive new completion reworking with $words,
+$compstate, etc., etc.
+
+Sven: 5565, 5576: $NUMERIC gives the numeric argument in a zle widget
+
+Sven: 5566: $foo[(b.<index>.i)<match>] starts searching $foo for for
+<match> at <index>
+
+Sven: 5571: Functions/Builtins/_cd tests if $cdpath is set
+
+Sven: 5574, 5578: Completion/README notes
+
+Sven: 5582: _path_files will expand /u/ -> /usr/ even if /u exists if
+nothing later on would match otherwise (got that?)
+
+pws: 5583: post-patch restructuring of _mh, _zftp, _most_recent_file.
+
+Sven: 5586: addmatch fix (old completion wasn't working)
+
+Sven: 5588: fix _most_recent_file idiocy
+
+Sven: 5590: compadd -p, -s and -P fixes
+
+Sven: 5593: _path_files -w
+
+Matt: 5596: Makefile dependencies for module compilation
+
+pws; 5597: Use separate file mymods.conf for your own builtin modules
+rather than the automatically generated modules-bltin.
+
+Sven: 5598: a neater way of handling compadd -p/-P
+
+Sven: 5599: _comp_parts, _path_files tweaks
+
+Sven: 5601: compstate[exact_string] and compstate[total_matchers]
+
+pws: 5602: _tar
+
+Sven: 5603: compstat[pattern_match]
+
+Sven: 5604: approximate completion.  (this is it.  every other shell is out
+of the game.)
+
+Sven: 5605: explanation listing fix
+
+Sven: 5613: copy scalar variable used for compgen -y
+
+Bart: 5614: Completion/Base/_match_test works out of the box
+
+Sven: 5620: fix for completion inside expansible braces
+
+Sven: 5621: manual for nmatches and matcher
+
+Sven: 5622: zshcompwid manual: clarifications
+
+Sven: 5623: -X strings with compadd were mishandled
+
+Sven: 5624: CCORIG required to be offered original string when correcting
+using COMPCORRECT
+
+pws: 5628: _builtin, _cd, _most_recent_file
+
+Sven: 5629: approximate correction patches
+
+Sven: 5631: compilation warnings
+
+Sven: 5637: mustuseheap check in complistflags
+
+Sven: 5640: _multi_parts, _path_files, _tar
+
+Andrej: 5650: more tricks with _configure
+
+Sven: 5651: widespread completion fixes
+
+Sven: 5659: globcomplete changes
+
+Sven: 5662: / following brace parameter
+
+Sven: 5663: compctl -i _completion_function
+
+Sven: 5665: return values from completion functions
+
+Sven: 5666: calling inststrlen() with a null string
+
+pws: from autoconf 2.13: new config.sub