about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-09-22 12:35:20 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-09-22 12:35:20 +0000
commitd139ae56432a82a3dbe11f4be89ba7d886f2c177 (patch)
treef2cd4d874fe13fe923490dd69bd92a0fb3314381
parentfdb8d5b45550835c00f40591e6ee5b6f6f6fd868 (diff)
downloadzsh-3.1.6-pws-5.tar.gz
zsh-3.1.6-pws-5.tar.xz
zsh-3.1.6-pws-5.zip
zsh-3.1.6-pws-5 zsh-3.1.6-pws-5
-rw-r--r--ChangeLog210
-rw-r--r--Completion/Base/.distfiles7
-rw-r--r--Completion/Builtins/.distfiles4
-rw-r--r--Completion/Builtins/_compdef22
-rw-r--r--Completion/Core/_multi_parts62
-rw-r--r--Completion/Core/_path_files35
-rw-r--r--Completion/Core/_sep_parts6
-rw-r--r--Completion/Linux/_rpm4
-rw-r--r--Completion/User/.distfiles13
-rw-r--r--Completion/User/_dirs3
-rw-r--r--Completion/User/_hosts3
-rw-r--r--Completion/User/_mailboxes7
-rw-r--r--Completion/User/_man6
-rw-r--r--Completion/X/.distfiles7
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Zsh/zftpsys.yo2
-rw-r--r--Etc/FAQ.yo84
-rw-r--r--Functions/Zftp/zfinit2
-rw-r--r--Functions/Zle/.distfiles4
-rw-r--r--Src/Zle/zle_tricky.c318
-rw-r--r--Src/glob.c4
-rw-r--r--Src/math.c125
-rw-r--r--Src/module.c6
-rw-r--r--Src/subst.c3
-rw-r--r--Src/zsh.export6
25 files changed, 701 insertions, 246 deletions
diff --git a/ChangeLog b/ChangeLog
index 3b54a2c65..3fbd37855 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,215 @@
+1999-09-20  Peter Stephenson  <pws@ibmth.df.unipi.it>
+
+	* pws: Config/version.mk: version 3.1.6-pws-5
+
+	* Sven: 7953: Completion/Commands/_expand_word,
+	  Completion/Core/_expand, Doc/Zsh/compsys.yo: expand_completions
+	  configuration key.
+
+	* pws: 7952: Completion/X/_xutils: xrdb should complete file
+	  arguments.
+
+	* Sven: 7951: Src/subst.c, Doc/Zsh/expn.yo: parameter expansion flags
+	  for quoting with single or double quotes.
+
+	* Sven: 7950: Src/utils.c, Src/Zle/complist.c: more careful
+	  with VARARR's.
+
+	* Sven: 7949: 7949: Completion/X/_x_color,
+	  Completion/X/_x_extension, Completion/X/_x_window,
+	  Completion/X/_xutils: completion for standard X utilities.
+
+	* pws: 7948: Src/glob.c, Src/pattern.c: indexes weren't
+	  calculate properly in $mbegin, $mend, $MBEGIN, $MEND because
+	  of Meta bytes.
+
+	* Sven: 7947: Src/Zle/zle_tricky.c, Doc/Zsh/compwid.yo:
+	  compstate[insert] can be all to insert all matches.
+
+	* Sven: 7944: Src/Zle/zle_tricky.c, Completion/Core/_multi_parts,
+	  Completion/Core/_path_files, Completion/Core/_sep_parts:
+	  new heuristic for deciding whether to add strings under match
+	  control or if they are too ambiguous to be useful.
+
+	* Sven: 7943: Doc/Zsh/compsys.yo: docs for long args syntax
+	  in _arguments.
+
+	* Bart: zsh-users/2610: Completion/Builtins/_kill,
+	  Completion/Builtins/_wait, Completion/User/_gdb: split words
+	  for ps arguments (replaces 2609).
+
+	* Bart: 7938: Completion/Base/_arg_compile, Completion/Base/_describe:
+	  pre-compiler for _arguments and typo in describe.
+
+	* Tanaka Akira: 7937: Completion/User/_cvs, Completion/User/_lynx,
+	  Completion/User/_wget: it's good to have _values.
+
+	* Bart: 7934: Completion/User/_telnet: improvement.
+
+	* Bart: 7932: Completion/User/_mailboxes: more generic.
+
+	* Bart: 7929: Src/hist.c, Src/Zle/zle_tricky.c: handle gaps
+	  in history when scanning through it.
+
+	* Bart: 7928: Doc/Zsh/builtins.yo: typo in float stuff.
+
+	* Bart: 7925: Functions/Misc/run-help: various functions and
+	  builtins in manual pages other than zshbuiltins.
+
+	* Adam: 7923: Completion/Core/compinit: compconf quoting tweak.
+
+1999-09-17  Peter Stephenson  <pws@ibmth.df.unipi.it>
+
+	* pws: 7921: Src/glob.c: bad test in rarely used
+	  (string/)# globbing construct.
+
+	* Oliver: 7919: Completion/User/_man: try to find a manpath if
+	  none (slightly adapted).
+
+	* Sven: 7917: Src/loop.c: hunk missed from 7915.
+
+	* pws: 7915: Doc/Zsh/arith.yo, Doc/Zsh/builtins.yo,
+	  Src/Modules/parameter.c, Src/builtin.c, Src/cond.c, Src/exec.c,
+	  Src/math.c, Src/mem.c, Src/params.c, Src/subst.c, Src/zsh.h,
+	  configure.in:  Floating point support via typeset -F and
+	  typeset -E for variables and in matheval().  mnumber struct
+	  passes around float or integer.
+
+	* Sven: 7903: Completion/Builtins/_cd: more careful with
+	  things from cdablevars.
+
+	* Sven: 7902, 7912: Completion/Base/_arguments,
+	  Doc/Zsh/compsys.yo: autodescribe_options.
+
+	* Sven: 7900: Completion/Commands/_history_complete_word,
+	  Doc/Zsh/compsys.yo:  history_stop config opt stops history
+	  cycling past end.
+
+	* Sven: 7896: Src/Zle/zle_tricky.c: cursor positioning.
+
+	* Adam: 7892: Completion/User/_webbrowser: initial
+	  implementation of completion for web browsers.
+
+	* Adam: 7891: Completion/Core/compinit: error message in compdef.
+
+	* Tanaka Akira: 7888: Completion/User/_wget: completion for wget.
+
+	* Tanaka Akira; 7887: Completion/User/_telnet: try to get
+	  valid telnet options.
+
+	* Tanaka Akira: 7886: Completion/Base/_describe,
+	  Completion/Debian/_apt, Completion/User/_cvs: -d option for
+	  descriptions.
+
+	* Adam: 7882: Doc/Zsh/expn.yo: parentheses.
+
+1999-09-16  Peter Stephenson  <pws@ibmth.df.unipi.it>
+
+	* Adam: 7871: Completion/User/_perl_basepods,
+	  Completion/User/_perl_builtin_funcs,
+	  Completion/User/_perl_modules, Completion/User/_perldoc:
+	  perl completion.
+
+	* Sven: 7864: Src/Zle/zle_tricky.c: crash when browsing
+	  directory hierarchies with select and selecting an entry.
+
+	* Sven: 7863: Doc/Zsh/mod_parameter.yo, Src/Modules/parameter.c,
+	  Src/Modules/parameter.mdd: $dirstack and $modules special
+	  parameters.
+	
+	* Sven: 7866: Doc/Zsh/compsys.yo, Completion/User/_mutt:
+	  action necessary.
+
+	* Sven: 7862: Completion/Base/_arguments, Completion/User/_gcc,
+	  Doc/Zsh/compsys.yo, Src/Zle/zle_tricky.c: completion for gcc,
+	  -M match spec for _arguments, remove duplicate matches.
+
+	* Clint: 7860: Completion/User/_mailboxes, Completion/User/_mutt:
+	  mutt support.
+
+1999-09-15  Peter Stephenson  <pws@ibmth.df.unipi.it>
+
+	* pws: 7855: Doc/Zsh/zftpsys.yo, Functions/Zftp/zfopen:
+	  failed zfopen with arguments deletes the stored open parameters.
+
+	* Oliver: 7852: Completion/Builtins/_compdef,
+	  Completion/User/_man: new compdef support, _man works for whatis
+	  and apropos.
+
+	* Sven: 7850: Completion/Base/_arguments: minor cleanup.
+
+	* Sven: 7844: Src/Zle/complist.c, Src/Zle/zle_tricky.c,
+	  Doc/Zsh/compsys.yo, Etc/completion-style-guide,
+	  Completion/Base/_arguments, Completion/Base/_describe,
+	  Completion/Base/_subscript, Completion/Base/_tilde,
+	  Completion/Base/_values, Completion/Builtins/_cd,
+	  Completion/Builtins/_kill, Completion/Builtins/_wait,
+	  Completion/Core/_approximate, Completion/Core/_expand,
+	  Completion/User/_gdb: various matching display bugs
+	  (with compadd -d) and enhancements to correction and
+	  approximation keys.
+
+	* Tanaka Akira: 7840: Completion/Base/_tilde,
+	  Completion/Builtins/_cd: use compadd -d.
+
+	* pws: 7836: Src/Modules/zftp.c: bug from 7767: zftp rmsession
+	  incremented node pointer wrongly and assigned new session
+	  wrongly.
+
+	* pws: 7834: Src/pattern.c: bug from 7825, pure string path
+	  segments wouldn't approximate.
+
+1999-09-14  Peter Stephenson  <pws@ibmth.df.unipi.it>
+
+	* Sven: 7827: Src/Zle/comp.h, Src/Zle/compctl.c,
+	  Src/Zle/complist.c, Src/Zle/zle_tricky.c, Doc/Zsh/compsys.yo,
+	  Doc/Zsh/compwid.yo, Completion/Base/_arguments,
+	  Completion/Base/_values, Completion/Core/_display,
+	  Completion/User/_mount: compadd -d for list of elements
+	  to display instead of matches, -l to show one per line,
+	  plus changes in _display and uses thereof; typos in _mount.
+
+	* pws: 7825, 7848: Doc/Zsh/expn.yo, Src/glob.c, Src/pattern.c,
+	  Src/subst.c, Src/zsh.h: (#b) and (#m) globbing flags and
+	  inverses; speed up compilation of pure string patterns.
+
+	* Sven: 7823: Src/Zle/zle_tricky.c: improve joining of completion
+	  strings with different match control behaviour.
+
+	* Sven: 7824: Completion/Base/_arguments, Completion/Core/_message:
+	  improve `no more arguments' message.
+
+	* Sven: 7819: Completion/Base/_arguments, Doc/Zsh/compsys.yo:
+	  use of $options for single character options.
+
+	* Tanaka Akira: 7817: Completion/Debian/_apt,
+	  Completion/User/_socket, Completion/User/_perl_builtin_funcs:
+	  several improvements.
+
+	* Tanaka Akira: 7815: Completion/User/_combination,
+	  Completion/User/_ports, Completion/User/_socket,
+	  Completion/User/_telnet: more sophisticated port/user
+	  combinations via general combination mechanism.
+
+	* Bart: 7813: Src/subst.c: correct incorrect application of
+	  correction in 7697.
+
+	* Tanaka Akira: 7740: Completion/User/_man: handle gzipped and
+	  SGML manual pages.
+
 1999-09-13  Peter Stephenson  <pws@ibmth.df.unipi.it>
 
+	* pws: zsh-users/2598: Functions/Zle/incarg: zle function to
+	  increment number under cursor.
+
+	* pws: 7812: Completion/X/_xrdb: now exists.
+
+	* Tanaka Akira: 7809: Completion/Debian/_apt, Completion/User/_patch:
+	  new apt options and typo in _patch.
+
+	* Sven: 7808: Completion/Base/_arguments: don't add long options
+	  sometimes.
+
 	* pws: Config/version.mk: 3.1.6-pws-4.
 
 	* Tanaka Akira: 7806: Completion/Users/_pbm: missing backslash.
diff --git a/Completion/Base/.distfiles b/Completion/Base/.distfiles
index 1c2c49fa2..14bab9676 100644
--- a/Completion/Base/.distfiles
+++ b/Completion/Base/.distfiles
@@ -1,7 +1,6 @@
 DISTFILES_SRC='
     .distfiles 
-    _arguments _brace_parameter _command_names
-    _condition _default _equal _first
-    _math _parameter _precommand _redirect _regex_arguments _subscript
-    _tilde _values _vars 
+    _arg_compile _arguments _brace_parameter _command_names _condition
+    _default _describe _equal _first _math _parameter _precommand _redirect
+    _regex_arguments _subscript _tilde _values _vars
 '
diff --git a/Completion/Builtins/.distfiles b/Completion/Builtins/.distfiles
index e0d0f3e99..633dc2d01 100644
--- a/Completion/Builtins/.distfiles
+++ b/Completion/Builtins/.distfiles
@@ -1,7 +1,7 @@
 DISTFILES_SRC='
     .distfiles
     _aliases _arrays _autoload _bg_jobs _bindkey _builtin _cd _command
-    _dirs _disable _echotc _enable _fc _functions _hash _jobs _kill
+    _compdef _disable _echotc _enable _fc _functions _hash _jobs _kill
     _limits _sched _set _setopt _source _stat _trap _unhash _unsetopt
-    _vars_eq _wait _which _zftp _zle _zmodload 
+    _vars_eq _wait _which _zftp _zle _zmodload
 '
diff --git a/Completion/Builtins/_compdef b/Completion/Builtins/_compdef
new file mode 100644
index 000000000..1df5758b3
--- /dev/null
+++ b/Completion/Builtins/_compdef
@@ -0,0 +1,22 @@
+#compdef compdef
+
+local func base=2
+
+while [[ $words[base] = -* ]]; do
+  case $words[base] in
+    -d) delete=yes ;;
+    -p) type=pattern ;;
+    -k) type=key ;;
+  esac  
+  (( base++ ))
+done
+
+if [ "$delete" ]; then
+  compadd ${(k)_comps}
+else
+  if [[ CURRENT -eq base  ]]; then
+    for func in ${^~fpath:/.}/_(|*[^~])(N:t); compadd -P_ - ${func#_}
+  else
+    compgen -c
+  fi
+fi
diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts
index d51130391..30a68d312 100644
--- a/Completion/Core/_multi_parts
+++ b/Completion/Core/_multi_parts
@@ -7,7 +7,7 @@
 # The parts of words from the array that are separated by the
 # separator character are then completed independently.
 
-local sep matches pref npref i tmp1 group expl menu pre suf
+local sep matches pref npref i tmp1 group expl menu pre suf opre osuf cpre
 typeset -U tmp2
 
 # Get the options.
@@ -40,6 +40,8 @@ fi
 
 pre="$PREFIX"
 suf="$SUFFIX"
+opre="$PREFIX"
+osuf="$SUFFIX"
 orig="$PREFIX$SUFFIX"
 
 # Special handling for menucompletion?
@@ -100,14 +102,17 @@ while true; do
         matches=( "${(@M)matches:#${tmp1[1]}*}" )
 	tmp2=( "${(@M)matches:#${tmp1[1]}${sep}*}" )
 
+	PREFIX="${cpre}${pre}"
+	SUFFIX="$suf"
+
 	if (( $#tmp2 )); then
-	  compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	          -p "$pref" -qS "$sep" - "$tmp1[1]"
+	  compadd "$group[@]" "$expl[@]" -p "$pref" -qS "$sep" \
+                  -M "r:|${sep}=* r:|=*" - "$tmp1[1]"
         else
-	  compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	          -p "$pref" - "$tmp1[1]"
+	  compadd "$group[@]" "$expl[@]" -p "$pref" \
+                  -M "r:|${sep}=* r:|=*" - "$tmp1[1]"
         fi
-	return 1
+	return 0
       fi
     elif (( $#tmp1 )); then
 
@@ -118,6 +123,14 @@ while true; do
       SUFFIX="$suf"
       compadd -O matches -M "r:|${sep}=* r:|=*" - "$matches[@]"
 
+      if [[ "$pre" = *${sep}* ]]; then
+ 	PREFIX="${cpre}${pre%%${sep}*}"
+	SUFFIX="${sep}${pre#*${sep}}${suf}"
+      else
+        PREFIX="${cpre}${pre}"
+	SUFFIX="$suf"
+      fi
+
       if [[ -n "$menu" ]]; then
         # With menucompletion we just add matches for the matching
         # components with the prefix we collected and the rest from the
@@ -125,11 +138,12 @@ while true; do
 
         tmp2="$pre$suf"
         if [[ "$tmp2" = *${sep}* ]]; then
-          compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	          -p "$pref" -s "${sep}${tmp2#*${sep}}" - "$tmp1[@]"
+          compadd "$group[@]" "$expl[@]" \
+                  -p "$pref" -s "${sep}${tmp2#*${sep}}" \
+                  -M "r:|${sep}=* r:|=*" - "$tmp1[@]"
         else
-          compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	          -p "$pref" - "$tmp1[@]"
+          compadd "$group[@]" "$expl[@]" -p "$pref"\
+                  -M "r:|${sep}=* r:|=*" - "$tmp1[@]"
         fi
       else
         # With normal completion we add all matches one-by-one with
@@ -138,11 +152,12 @@ while true; do
 
         for i in "${(@M)matches:#(${(j:|:)~tmp1})*}"; do
 	  if [[ "$i" = *${sep}* ]]; then
-            compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	            -S '' -p "$pref" -s "${i#*${sep}}" - "${i%%${sep}*}${sep}"
+            compadd "$group[@]" "$expl[@]" -S '' \
+	            -p "$pref" -s "${i#*${sep}}" \
+                    -M "r:|${sep}=* r:|=*" - "${i%%${sep}*}${sep}"
           else
-            compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	            -S '' -p "$pref" - "$i"
+            compadd "$group[@]" "$expl[@]" -S '' -p "$pref" \
+                    -M "r:|${sep}=* r:|=*" - "$i"
           fi
         done
       fi
@@ -154,12 +169,15 @@ while true; do
 
       [[ "$orig" = "$pref$pre$suf" ]] && return 1
 
+      PREFIX="${cpre}${pre}"
+      SUFFIX="$suf"
+
       if [[ -n "$suf" ]]; then
-        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	        -s "$suf" - "$pref$pre"
+        compadd "$group[@]" "$expl[@]" -s "$suf" \
+                -M "r:|${sep}=* r:|=*" - "$pref$pre"
       else
-        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	        -S '' - "$pref$pre$suf"
+        compadd "$group[@]" "$expl[@]" -S '' \
+                -M "r:|${sep}=* r:|=*" - "$pref$pre"
       fi
       return 0
     fi
@@ -175,8 +193,10 @@ while true; do
   # Now we set `pre' and `suf' to their new values.
 
   if [[ "$pre" = *${sep}* ]]; then
+    cpre="${cpre}${pre%%${sep}*}${sep}"
     pre="${pre#*${sep}}"
   elif [[ "$suf" = *${sep}* ]]; then
+    cpre="${cpre}${pre}${suf%%${sep}*}${sep}"
     pre="${suf#*${sep}}"
     suf=""
   else
@@ -184,9 +204,11 @@ while true; do
     # unambiguous prefix and that differs from the original string,
     # we insert it.
 
+    PREFIX="${opre}${osuf}"
+    SUFFIX=""
+
     [[ -n "$pref" && "$orig" != "$pref" ]] &&
-        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	        -S '' - "$pref"
+        compadd "$group[@]" "$expl[@]" -S '' -M "r:|${sep}=* r:|=*" - "$pref"
 
     return
   fi
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index b017d78e5..b4b6fff97 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -24,7 +24,7 @@
 #    menucompletion.
 
 local linepath realpath donepath prepath testpath exppath
-local tmp1 tmp2 tmp3 tmp4 i orig pre suf tpre tsuf
+local tmp1 tmp2 tmp3 tmp4 i orig pre suf tpre tsuf opre osuf cpre
 local pats haspats=no ignore group expl addpfx addsfx remsfx
 local nm=$compstate[nmatches] menu
 
@@ -118,6 +118,8 @@ fi
 
 pre="$PREFIX"
 suf="$SUFFIX"
+opre="$PREFIX"
+osuf="$SUFFIX"
 orig="${PREFIX}${SUFFIX}"
 
 [[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
@@ -291,6 +293,8 @@ for prepath in "$prepaths[@]"; do
 
       if [[ "$haspats" = no && -z "$tpre$tsuf" &&
 	"$pre" = */ && -z "$suf" ]]; then
+	PREFIX="${opre}${osuf}"
+	SUFFIX=""
         compadd -nQS '' - "$linepath$donepath$orig"
         tmp4=-
       fi
@@ -349,19 +353,27 @@ for prepath in "$prepaths[@]"; do
       # collected as the suffixes to make the completion code expand
       # it as far as possible.
 
+      if [[ "$tmp3" = */* ]]; then
+        PREFIX="${linepath}${cpre}${tmp3%%/*}"
+	SUFFIX="/${tmp3#*/}"
+      else
+        PREFIX="${linepath}${cpre}${tmp3}"
+	SUFFIX=""
+      fi
+
       if [[ -n $menu ]]; then
         [[ -n "$compconfig[path_cursor]" ]] && compstate[to_end]=''
         if [[ "$tmp3" = */* ]]; then
 	  compadd -QUf -p "$linepath${testpath:q}" -s "/${tmp3#*/}" \
 	          -W "$prepath$realpath$testpath" "$ignore[@]" \
 		  "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" -M 'r:|/=* r:|=*' \
-		  "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
++ 		  "$group[@]" "$expl[@]" \
 		  - "${(@)${(@)tmp1%%/*}:q}"
 	else
 	  compadd -QUf -p "$linepath${testpath:q}" \
 	          -W "$prepath$realpath$testpath" "$ignore[@]" \
 		   "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-		   "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+		   "$group[@]" "$expl[@]" \
 		   - "${(@)tmp1:q}"
 	fi
       else
@@ -370,14 +382,14 @@ for prepath in "$prepaths[@]"; do
 	    compadd -QUf -p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \
 		    -W "$prepath$realpath$testpath" "$ignore[@]" \
 		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" -M 'r:|/=* r:|=*' \
-		    "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+		    "$group[@]" "$expl[@]" \
 		    - "${${i%%/*}:q}"
 	  done
         else
 	  compadd -QUf -p "$linepath${testpath:q}" \
 		  -W "$prepath$realpath$testpath" "$ignore[@]" \
 		  "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-		  "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+		  "$group[@]" "$expl[@]" \
 		  - "${(@)tmp1:q}"
         fi
       fi
@@ -399,14 +411,17 @@ for prepath in "$prepaths[@]"; do
     testpath="${testpath}${tmp1[1]%%/*}/"
     tmp1=( "${(@)tmp1#*/}" )
 
+    cpre="${cpre}${tmp3%%/*}/"
     tmp3="${tmp3#*/}"
   done
 
-  if [[ -z "$tmp4" ]]; then
-    compadd -QUf -p "$linepath${testpath:q}" \
+  if [[ -z "$tmp4" ]]; then 
+     PREFIX="${opre}${osuf}"
+     SUFFIX=""
+     compadd -QUf -p "$linepath${testpath:q}" \
 	    -W "$prepath$realpath$testpath" "$ignore[@]" \
 	    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-	    "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	    "$group[@]" "$expl[@]" \
 	    - "${(@)tmp1:q}"
   fi
 done
@@ -419,7 +434,9 @@ exppaths=( "${(@)exppaths:#$orig}" )
 
 if [[ -n "$compconfig[path_expand]" &&
       $#exppaths -gt 0 && nm -eq compstate[nmatches] ]]; then
-  compadd -QU -S '' "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+   PREFIX="${opre}${osuf}"
+   SUFFIX=""
+   compadd -Q -S '' "$group[@]" "$expl[@]" \
           -M 'r:|/=* r:|=*' -p "$linepath" - "$exppaths[@]"
 fi
 
diff --git a/Completion/Core/_sep_parts b/Completion/Core/_sep_parts
index 6f2595120..0a8cae28f 100644
--- a/Completion/Core/_sep_parts
+++ b/Completion/Core/_sep_parts
@@ -18,7 +18,7 @@
 # `-X explanation' options.
 
 local str arr sep test testarr tmparr prefix suffixes matchers autosuffix
-local matchflags opt group expl nm=$compstate[nmatches]
+local matchflags opt group expl nm=$compstate[nmatches] opre osuf
 
 # Get the options.
 
@@ -34,6 +34,8 @@ shift OPTIND-1
 
 # Get the string from the line.
 
+opre="$PREFIX"
+osuf="$SUFFIX"
 str="$PREFIX$SUFFIX"
 SUFFIX=""
 prefix=""
@@ -144,6 +146,8 @@ done
 
 # Add the matches for each of the suffixes.
 
+PREFIX="$pre"
+SUFFIX="$suf"
 for i in "$suffixes[@]"; do
   compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \
           -i "$IPREFIX" -I "$ISUFFIX" -p "$prefix" -s "$i" - "$testarr[@]"
diff --git a/Completion/Linux/_rpm b/Completion/Linux/_rpm
index 4a54eddfa..5f6843267 100644
--- a/Completion/Linux/_rpm
+++ b/Completion/Linux/_rpm
@@ -148,7 +148,7 @@ while [[ -n "$state" ]]; do
       '*:RPM package:->package' && ret=0
     ;;
   build_b)
-    tmp=( '*:spec file:_path_files -/ -g \*.spec' )
+    tmp=( '*:spec file:_files -g \*.spec' )
     ;&
   build_t)
     (( $#tmp )) || tmp=( '*:tar file:_files -g \*.\(\#i\)tar\(.\*\|\)' )
@@ -195,7 +195,7 @@ while [[ -n "$state" ]]; do
       _hosts -S/ && ret=0
     else
       _description expl 'RPM package file'
-      _path_files "$expl[@]" -/ -g '*.(#i)rpm' && ret=0
+      _files "$expl[@]" -g '*.(#i)rpm' && ret=0
       _description expl 'ftp URL prefix'
       compadd "$expl[@]" ftp://
     fi
diff --git a/Completion/User/.distfiles b/Completion/User/.distfiles
index b17ca6488..579d947f0 100644
--- a/Completion/User/.distfiles
+++ b/Completion/User/.distfiles
@@ -1,9 +1,10 @@
 DISTFILES_SRC='
     .distfiles
-    _a2ps _bison _bunzip2 _bzip2 _chown _compress _configure _cvs _dd
-    _dir_list _dvi _find _flex _gdb _gprof _groups _gs _gunzip _gv _gzip
-    _hosts _ispell _lynx _make _man _man.old _mh _mount _nslookup _patch
-    _pbm _pdf _perl_basepods _perl_builtin_funcs _perl_modules _perldoc _ps
-    _pspdf _rcs _rlogin _sh _socket _ssh _strip _stty _su _tar _tar_archive
-    _telnet _tex _tiff _uncompress _urls _use_lo _users _xargs _yodl _yp
+    _a2ps _bison _bunzip2 _bzip2 _chown _combination _compress _configure
+    _cvs _dd _dir_list _dirs _dvi _find _flex _gcc _gdb _gprof _groups _gs
+    _gunzip _gv _gzip _hosts _ispell _lynx _mailboxes _make _man _mh _mount
+    _mutt _nslookup _patch _pbm _pdf _perl_basepods _perl_builtin_funcs
+    _perl_modules _perldoc _ports _ps _pspdf _rcs _rlogin _sh _socket _ssh
+    _strip _stty _su _tar _tar_archive _telnet _tex _tiff _uncompress _urls
+    _use_lo _users _webbrowser _wget _xargs _yodl _yp
 '
diff --git a/Completion/User/_dirs b/Completion/User/_dirs
new file mode 100644
index 000000000..04c4b75d9
--- /dev/null
+++ b/Completion/User/_dirs
@@ -0,0 +1,3 @@
+#compdef rmdir df du dircmp
+
+_files -/
diff --git a/Completion/User/_hosts b/Completion/User/_hosts
index bbc1e88b2..9f5a39cca 100644
--- a/Completion/User/_hosts
+++ b/Completion/User/_hosts
@@ -4,8 +4,5 @@ local expl
 
 : ${(A)hosts:=${(s: :)${(ps:\t:)${${(f)"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}}
 
-# Let the user add her own hosts in if she wants
-hosts=( $hostnames $hosts )
-
 _description expl host
 compadd -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' "$@" "$expl[@]" - "$hosts[@]"
diff --git a/Completion/User/_mailboxes b/Completion/User/_mailboxes
index eee6c6f35..08dbec816 100644
--- a/Completion/User/_mailboxes
+++ b/Completion/User/_mailboxes
@@ -12,7 +12,7 @@ local maildirectory="${maildirectory:-~/Mail}"
 
 if (( ! $+_mailbox_cache )) then
 
-test ${~muttrc} && [[ -f ${~muttrc} ]] && muttboxes=( ${$(grep mailboxes ${~muttrc})[2,-1]} )
+[[ -f "${~muttrc}" ]] && muttboxes=( ${$(grep mailboxes ${~muttrc})[2,-1]} )
 
 mboxes=( ${~maildirectory}/*(^/) ${~pinedirectory}/**/*(.) )
 dirboxes=( ${~maildirectory}/*(/) )
@@ -33,11 +33,8 @@ do
     fi
 done
 
-[[ -n "$muttboxes" ]] || [[ -d ~/.elm ]] &&
+[[ -n "$muttboxes" ]] &&
     _mailbox_cache=(\! \< \> $muttboxes)
-[[ -n "$mailpath" ]] &&
-    _mailbox_cache=($_mailbox_cache ${mailpath//\?*/})
-
 _mailbox_cache=($_mailbox_cache $mboxes $maildirboxes $MHboxes)
 
 fi
diff --git a/Completion/User/_man b/Completion/User/_man
index ffdac91cd..88d2118c0 100644
--- a/Completion/User/_man
+++ b/Completion/User/_man
@@ -14,11 +14,11 @@ if [[ -n $_comp_correct ]]; then
   approx="(#a${_comp_correct})"
 fi
 
-# `sman' is the SGML manual directory for Solaris 7.
-
-[ "$manpath" ] || manpath=$(manpath 2>/dev/null) || \
+(( $#manpath )) || manpath=$(manpath 2>/dev/null) ||
   manpath=( /usr/man(-/N) /(opt|usr)/(dt|share|X11R6|local)/(cat|)man(-/N) )
 
+# `sman' is the SGML manual directory for Solaris 7.
+
 if [[ $words[2] = (<->*|ln) ]]; then
   rep=(
   $manpath/(sman|man|cat)${words[2]}/${~approx}$PREFIX${~star}$SUFFIX.<->*(N:t) )
diff --git a/Completion/X/.distfiles b/Completion/X/.distfiles
index 10cebc77c..0865ed4ec 100644
--- a/Completion/X/.distfiles
+++ b/Completion/X/.distfiles
@@ -1,6 +1,7 @@
 DISTFILES_SRC='
     .distfiles
-    _x_borderwidth _x_color _x_cursor _x_display _x_font _x_geometry
-    _x_locale _x_name _x_arguments _x_resource _x_selection_timeout
-    _x_title _xdvi _xfig _xsetroot _xt_arguments _xt_session_id _xterm _xv
+    _x_arguments _x_borderwidth _x_color _x_cursor _x_display _x_extension
+    _x_font _x_geometry _x_locale _x_name _x_resource _x_selection_timeout
+    _x_title _x_window _xdvi _xfig _xt_arguments _xt_session_id _xterm
+    _xutils _xv
 '
diff --git a/Config/version.mk b/Config/version.mk
index b1ff631b4..238e58636 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.6-pws-4
-VERSION_DATE='September 6, 1999'
+VERSION=3.1.6-pws-5
+VERSION_DATE='September 20, 1999'
diff --git a/Doc/Zsh/zftpsys.yo b/Doc/Zsh/zftpsys.yo
index b2f53810b..ed68739b6 100644
--- a/Doc/Zsh/zftpsys.yo
+++ b/Doc/Zsh/zftpsys.yo
@@ -107,7 +107,7 @@ recorded for later re-opening, either by a tt(zfopen) with no arguments, or
 automatically (see below).  With the option `tt(-1)', no information is
 stored.  Also, if an open command with arguments failed, the parameters
 will not be retained (and any previous parameters will also be deleted).
-A tt(zfopen) on its own, or a tt(zftopen -1), never alters the stored
+A tt(zfopen) on its own, or a tt(zfopen -1), never alters the stored
 parameters.
 
 Both tt(zfopen) and tt(zfanon) (but not tt(zfparams)) understand URLs of
diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo
index 90d35954f..ba85615df 100644
--- a/Etc/FAQ.yo
+++ b/Etc/FAQ.yo
@@ -47,21 +47,13 @@ myreport(Z-Shell Frequently-Asked Questions)(Peter Stephenson)(1999/05/24)
 COMMENT(-- the following are for Usenet and must appear first)\
 description(\
 mydit(Archive-Name:) unix-faq/shell/zsh
-mydit(Last-Modified:) 1999/07/24
+mydit(Last-Modified:) 1999/07/30
 mydit(Submitted-By:) email(pws@ibmth.df.unipi.it (Peter Stephenson))
-mydit(Version:) $Id: FAQ.yo,v 1.1.1.9 1999/09/17 02:58:59 akr Exp $
+mydit(Version:) $Id: FAQ.yo,v 1.1.1.10 1999/09/22 12:36:12 akr Exp $
 mydit(Posting-Frequency:) Monthly
 mydit(Copyright:) (C) P.W. Stephenson, 1995--1999 (see end of document)
 )
 
-bf(Changes since issue posted June 1999:)
-description(
-mydit(1.6)  FTP site changes
-mydit(3.9)  delete bogus claim that ttyctl code may be updated some day;
-     add note about possible termcap deinitialization sequences
-mydit(5.1)  80-column display bug.
-)
-
 This document contains a list of frequently-asked (or otherwise
 significant) questions concerning the Z-shell, a command interpreter
 for many UNIX systems which is freely available to anyone with FTP
@@ -300,17 +292,17 @@ sect(On what machines will it run?)
 sect(What's the latest version?)
 
   Zsh 3.0.6 is the latest production version. The new major number 3.0
-  largely reflects the considerable internal changes in zsh to make it
-  more reliable, consistent and (where possible) compatible.  Those
-  planning on upgrading their zsh installation should take a look at
-  the list of incompatibilities at the end of link(5.1)(51).  This is
-  longer than usual due to enhanced sh, ksh and POSIX compatibility.
-
-  The beta version 3.1.6 is also available, and has many new features.
-  Development of zsh is usually patch by patch, with each intermediate
-  version publicly available.  Note that this `open' development
-  system does mean bugs are sometimes introduced into the most recent
-  archived version.  These are usually fixed quickly.
+  largely reflects the considerable internal changes in zsh to make it more
+  reliable, consistent and (where possible) compatible.  Those planning on
+  upgrading their zsh installation should take a look at the list of
+  incompatibilities at the end of link(5.1)(51).  This is longer than usual
+  due to enhanced sh, ksh and POSIX compatibility.
+
+  The beta version 3.1.6 is also available.  Development of zsh is usually
+  patch by patch, with each intermediate version publicly available.  Note
+  that this `open' development system does mean bugs are sometimes
+  introduced into the most recent archived version.  These are usually
+  fixed quickly.
 
   Note also that as the shell changes, it may become incompatible with
   older versions; see the end of question link(5.1)(51) for a partial list.
@@ -365,18 +357,20 @@ url(http://www.math.technion.ac.il/mirror/ftp.zsh.org/pub/zsh/)
 (http://www.math.technion.ac.il/mirror/ftp.zsh.org/pub/zsh/)
     mydit(Italy)     url(ftp://ftp.unina.it/pub/Unix/pkgs/shell/zsh/)
 (ftp://ftp.unina.it/pub/Unix/pkgs/shell/zsh/)
-    mydit(Japan)     url(ftp://ftp.tohoku.ac.jp/mirror/zsh/)
-(ftp://ftp.tohoku.ac.jp/mirror/zsh/)
-    mydit()          url(ftp://ftp.nisiq.net/pub/shells/zsh/)
+    mydit(Japan)     url(ftp://ftp.nisiq.net/pub/shells/zsh/)
 (ftp://ftp.nis.co.jp/pub/shells/zsh/)
     mydit()          url(ftp://ftp.win.ne.jp/pub/shell/zsh/)
 (ftp://ftp.win.ne.jp/pub/shell/zsh/)
     mydit(Norway)    url(ftp://ftp.uit.no/pub/unix/shells/zsh/)
 (ftp://ftp.uit.no/pub/unix/shells/zsh/)
+    mydit(Poland)    url(ftp://sunsite.icm.edu.pl/pub/unix/shells/zsh/)
+(ftp://sunsite.icm.edu.pl/pub/unix/shells/zsh/)
     mydit(Romania)   url(ftp://ftp.roedu.net/pub/mirrors/ftp.zsh.org/pub/zsh/)
 (ftp://ftp.roedu.net/pub/mirrors/ftp.zsh.org/pub/zsh/)
-    mydit(Slovenia)  url(ftp://ftp.siol.net/pub/unix/shells/zsh/)
-(ftp://ftp.siol.net/pub/unix/shells/zsh/)
+    mydit()          url(ftp://ftp.kappa.ro/pub/mirrors/ftp.zsh.org/pub/zsh/)
+(ftp://ftp.kappa.ro/pub/mirrors/ftp.zsh.org/pub/zsh/)
+    mydit(Slovenia)  url(ftp://ftp.siol.net/mirrors/zsh/)
+(ftp://ftp.siol.net/mirrors/zsh/)
     mydit(Sweden)    url(ftp://ftp.lysator.liu.se/pub/unix/zsh/)
 (ftp://ftp.lysator.liu.se/pub/unix/zsh/)
     mydit(UK)        url(ftp://ftp.net.lut.ac.uk/zsh/)
@@ -384,9 +378,7 @@ url(http://www.math.technion.ac.il/mirror/ftp.zsh.org/pub/zsh/)
     mydit()          (also by FSP at port 21)
     mydit()          url(ftp://sunsite.org.uk/packages/zsh/)
 (ftp://sunsite.org.uk/packages/zsh/)
-    mydit(USA)       url(ftp://ftp.math.gatech.edu/pub/zsh/)
-(ftp://ftp.math.gatech.edu/pub/zsh/)
-    mydit()          url(ftp://uiarchive.uiuc.edu/pub/packages/shells/zsh/)
+    mydit(USA)       url(ftp://uiarchive.uiuc.edu/pub/packages/shells/zsh/)
 (ftp://uiarchive.uiuc.edu/pub/packages/shells/zsh/)
     mydit()          url(ftp://ftp.rge.com/pub/shells/zsh/)
 (ftp://ftp.rge.com/pub/shells/zsh/)
@@ -645,7 +637,7 @@ link(2.3)(23).
   )
     it() Traps and signals:
   itemize(
-    it()* Traps are not local to functions.  The option LOCAL_TRAPS will
+    it()* Traps are not local to functions.  The option LOCAL_TRAPS is
           be available from 3.1.6.
     it()  TRAPERR has become TRAPZERR (this was forced by UNICOS which
         has SIGERR).
@@ -661,8 +653,8 @@ link(2.3)(23).
         release either.)
     it()  Management of histories in multiple shells is different:
         the history list is not saved and restored after each command.
-        (The option tt(SHARE_HISTORY) will appear in 3.1.6 and will be
-        set in ksh compatibility mode to remedy this.)
+        The option tt(SHARE_HISTORY) appeared in 3.1.6 and is set in ksh
+        compatibility mode to remedy this.
     it()  mytt(\) does not escape editing chars (use mytt(^V)).
     it()  Not all ksh bindings are set (e.g. mytt(<ESC>#); try mytt(<ESC>q)).
     it()* mytt(#) in an interactive shell is not treated as a comment by
@@ -1368,13 +1360,14 @@ label(313)
   mytt(unsetopt cshjunkiequotes) and mytt(setopt cshjunkiequotes), or put it
   in your tt(.zshrc) before the option is set.
 
-  Arguably the prompt code should handle `print'-like escapes.  Feel
-  free to write this :-CHAR(41).  Otherwise, you can use
+  In all recent versions of zsh, there is a form of quoting which will
+  interpret print sequences like `tt(\n)' but otherwise acts like single
+  quotes: surround the string with tt($'...').  Hence:
   verb(
-    PROMPT=$(print "Hi Joe,\nwhat now?%# ")
+    PROMPT=$'Hi Joe,\nwhat now?%# '
   )
-  in your initialisation file.
-
+  is a neat way of doing what you want.  Note that it is the quotes, not
+  the prompt expansion, which turns the `tt(\n)' into a newline.
 
 sect(Why does mytt(bindkey ^a command-name) or mytt(stty intr ^-) do something funny?)
 
@@ -1543,7 +1536,7 @@ sect(How do I get a variable's value to be evaluated as another variable?)
   )
   produces the same result.
 
-  Versions 3.1.6 of zsh will allow you to do this directly with a new flag;
+  Versions 3.1.6 of allows you to do this directly with a new flag;
   mytt(${(P)E}).
 
   As a slight aside, sometimes people note that the syntax mytt(${${E}})
@@ -1591,8 +1584,8 @@ sect(What's wrong with cut and paste on my xterm?)
      which was used only on systems where the problem was known to exist,
      so it is possible some other systems were not handled (for example,
      certain versions of IRIX, it appears); also, continuation lines were
-     not handled properly.  A more reliable approach will appear in
-     versions 3.0.6 and 3.1.6.
+     not handled properly.  A more reliable approach appears from versions
+     3.0.6 and 3.1.6.
   myeit() When the shell is waiting for input, and you paste in a chunk of
      text consisting of more than one complete set of commands.
      Unfortunately, this is a much harder problem: the line editor is
@@ -1931,7 +1924,7 @@ this applies
      are mostly fixed in 3.1.6.
   it() Zsh's notion of the current line number (via tt($LINENO)) is
      sometimes not well handled, particularly when using functions and traps.
-     This should also work reliably from 3.1.6.
+     This should also work reliably from 3.0.6 and 3.1.6.
   it() In vi mode, mytt(u) can go past the original modification point.
   it() The singlelinezle option has problems with prompts containing escapes.
   it() The mytt(r) command does not work inside mytt($(...)) or mytt(`...`)
@@ -1971,9 +1964,9 @@ this applies
      mytt(compress file) any more.  For this reason, mytt(\M-n) and
      mytt(\M-p) use tt(history-beginning-search-{forward,backward}) which
      search for a line with the same prefix up to the cursor position.
-     From 3.1.6, there will be a different implementation which
-     makes this closer (though not identical) to the old behaviour.
-     The story for the tt({up,down}-line-or-search) commands is similar.
+     From 3.1.6, there is a different implementation which makes this
+     closer (though not identical) to the old behaviour. The story for the
+     tt({up,down}-line-or-search) commands is similar.
   it() In vi insert mode, the cursor keys no longer work.  The following
      will bind them:
       COMMENT(-- note space after backslash --)
@@ -2110,8 +2103,7 @@ sect(What's on the wish-list?)
   lexing/parsing/execution might also be an advantage.  Volunteers are
   particularly welcome for these tasks.
 
-  Here are some things which are definitely happening, and will probably
-  appear in zsh 3.1.6.
+  Here are the latest changes, which appeared in zsh 3.1.6.
   itemize(
   it() Even more powerful new completion system, based on shell functions,
      allowing much more detailed control both over generation of matches
diff --git a/Functions/Zftp/zfinit b/Functions/Zftp/zfinit
index f650b7bbb..256ef1d2f 100644
--- a/Functions/Zftp/zfinit
+++ b/Functions/Zftp/zfinit
@@ -43,7 +43,7 @@ if [[ ${#_patcomps} -eq 0 || ${_patcomps[(i)zf*]} -gt ${#_patcomps} ]]; then
     -x 'W[1,-*n*]' \
     -s '$(awk -F, '\''NR > 2 { print $1 }'\'' ~/.ncftp/bookmarks)' -- \
     zfgoto zfmark
-  compctl -s '${$(zftp session):#$ZFTP_SESSION}' -- zfsession
+  compctl -s '${$(zftp session):#$ZFTP_SESSION}' zfsession
   # in _zftp for new completion, but hard to inline into a compctl
   zftransfer_match() {
     local sess=${1%%:*} oldsess=$ZFTP_SESSION
diff --git a/Functions/Zle/.distfiles b/Functions/Zle/.distfiles
index b7ee01e1f..ec40bba3f 100644
--- a/Functions/Zle/.distfiles
+++ b/Functions/Zle/.distfiles
@@ -1,4 +1,4 @@
 DISTFILES_SRC='
-    .distfiles history-search-end incremental-complete-word insert-files
-    predict-on
+    .distfiles history-search-end incremental-complete-word
+    incarg insert-files predict-on
 '
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 0d6127c6f..dc12ecc89 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -159,6 +159,10 @@ int validlist;
 
 static int ispattern, haspattern;
 
+/* Non-zero if at least one match was added without -U. */
+
+static int hasmatched;
+
 /* 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    *
  * part of the word that was identified as a possible filename.          */
@@ -230,6 +234,10 @@ static int unambig_mnum;
 
 static int mflags;
 
+/* Length of longest/shortest match. */
+
+static int maxmlen, minmlen;
+
 /* This holds the explanation strings we have to print in this group and *
  * a pointer to the current cexpl structure. */
 
@@ -287,6 +295,7 @@ struct cline {
     int olen;
     int slen;
     Cline prefix, suffix;
+    int min, max;
 };
 
 #define CLF_MISS  1
@@ -2003,6 +2012,39 @@ cp_cline(Cline l)
     return r;
 }
 
+/* Calculate the length of a cline and its sub-lists. */
+
+static int
+cline_sublen(Cline l)
+{
+    int len = ((l->flags & CLF_LINE) ? l->llen : l->wlen);
+
+    if (l->olen && !((l->flags & CLF_SUF) ? l->suffix : l->prefix))
+	len += l->olen;
+    else {
+	Cline p;
+
+	for (p = l->prefix; p; p = p->next)
+	    len += ((p->flags & CLF_LINE) ? p->llen : p->wlen);
+	for (p = l->suffix; p; p = p->next)
+	    len += ((p->flags & CLF_LINE) ? p->llen : p->wlen);
+    }
+    return len;
+}
+
+/* Set the lengths in the cline lists. */
+
+static void
+cline_setlens(Cline l, int both)
+{
+    while (l) {
+	l->max = cline_sublen(l);
+	if (both)
+	    l->min = l->max;
+	l = l->next;
+    }
+}
+
 /* This reverts the order of the elements of the given cline list and
  * returns a pointer to the new head. */
 
@@ -2217,8 +2259,8 @@ add_match_part(Cmatcher m, char *l, char *w, int wl,
     if (!strncmp(l, w, wl))
 	l = NULL;
 
-    /* Split the new part into parts and turn the last one into a `suffix'
-     * if we have a left anchor. */
+    /* Split the new part into parts and turn the last one into a
+     * `suffix' if we have a left anchor. */
 
     p = bld_parts(s, sl, osl, &lp);
 
@@ -2234,8 +2276,21 @@ add_match_part(Cmatcher m, char *l, char *w, int wl,
 	p = revert_cline(lp = p);
     /* Now add the sub-clines we already had. */
     if (matchsubs) {
-	matchlastsub->next = p->prefix;
-	p->prefix = matchsubs;
+	if (sfx) {
+	    Cline q;
+
+	    if ((q = lp->prefix)) {
+		while (q->next)
+		    q = q->next;
+		q->next = matchsubs;
+	    } else
+		lp->prefix = matchsubs;
+
+	    matchlastsub->next = NULL;
+	} else {
+	    matchlastsub->next = p->prefix;
+	    p->prefix = matchsubs;
+	}
 	matchsubs = matchlastsub = NULL;
     }
     /* Store the arguments in the last part-cline. */
@@ -2284,13 +2339,15 @@ add_match_sub(Cmatcher m, char *l, int ll, char *w, int wl)
  * matched prefix or suffix, not including the stuff before or after
  * the last anchor is given. When sfx is non-zero matching is done from
  * the ends of the strings backward, if test is zero, the global variables
- * above are used to build the string for the match and the cline. */
+ * above are used to build the string for the match and the cline. If
+ * part is non-zero, we are satisfied if only a part of the line-string
+ * is used (and return the length used). */
 
 static int
-match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
+match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test, int part)
 {
     int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw;
-    int il = 0, iw = 0, t, ind, add, bc = (bp ? *bp : 0);
+    int il = 0, iw = 0, t, ind, add, bc = (bp ? *bp : 0), he = 0;
     VARARR(unsigned char, ea, ll + 1);
     char *ow;
     Cmlist ms;
@@ -2368,7 +2425,8 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 		    if (ap) {
 			if (!pattern_match(ap, l + aoff, NULL, NULL) ||
 			    (both && (!pattern_match(ap, w + aoff, NULL, NULL) ||
-				      !match_parts(l + aoff, w + aoff, alen))))
+				      !match_parts(l + aoff, w + aoff, alen,
+						   part))))
 				continue;
 		    } else if (!both || il || iw)
 			continue;
@@ -2382,18 +2440,21 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 		    for (t = 0, tp = w, ct = 0, ict = lw - alen + 1;
 			 ict;
 			 tp += add, ct++, ict--) {
-			if (both ||
-			    (pattern_match(ap, tp - moff, NULL, NULL) &&
-			     match_parts(l + aoff , tp - moff, alen))) {
+			if ((both &&
+			     (!ap || !test ||
+			      !pattern_match(ap, tp + aoff, NULL, NULL))) ||
+			    (!both &&
+			     pattern_match(ap, tp - moff, NULL, NULL) &&
+			     match_parts(l + aoff , tp - moff, alen, part))) {
 			    if (sfx) {
 				savw = tp[-zoff];
 				tp[-zoff] = '\0';
 				t = match_str(l - ll, w - lw,
-					      NULL, NULL, 1, 2);
+					      NULL, NULL, 1, 2, part);
 				tp[-zoff] = savw;
 			    } else
 				t = match_str(l + llen + moff, tp + moff,
-					      NULL, NULL, 0, 1);
+					      NULL, NULL, 0, 1, part);
 			    if (t || !both)
 				break;
 			}
@@ -2409,7 +2470,7 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 
 		    /* Yes, add the strings and clines if this is a 
 		     * top-level call. */
-		    if (!test) {
+		    if (!test && (!he || (llen + alen))) {
 			char *op, *lp, *map, *wap, *wmp;
 			int ol;
 
@@ -2469,16 +2530,21 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 		    lw -= alen; iw += alen;
 		    bc -= llen;
 
-		    if (!test && bc <= 0 && bp) {
+		    if (!test && bp && bc <= 0) {
 			*bp = matchbufadded + bc;
 			bp = NULL;
 		    }
 		    ow = w;
 
-		    if (!llen && !alen)
+		    if (!llen && !alen) {
 			lm = mp;
-		    else
-			lm = NULL;
+			if (he)
+			    mp = NULL;
+			else
+			    he = 1;
+		    } else {
+			lm = NULL; he = 0;
+		    }
 		    break;
 		} else if (ll >= mp->llen && lw >= mp->wlen) {
 		    /* Non-`*'-pattern. */
@@ -2561,12 +2627,13 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 		    ll -= mp->llen; lw -= mp->wlen;
 		    bc -= mp->llen;
 
-		    if (!test && bc <= 0 && bp) {
+		    if (!test && bp && bc <= 0) {
 			*bp = matchbufadded + bc;
 			bp = NULL;
 		    }
 		    ow = w;
 		    lm = NULL;
+		    he = 0;
 		    break;
 		}
 	    }
@@ -2586,6 +2653,7 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 		bp = NULL;
 	    }
 	    lm = NULL;
+	    he = 0;
 	} else {
 	    /* No matcher and different characters: l does not match w. */
 	    if (test)
@@ -2598,7 +2666,10 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
     }
     /* If this is a recursive call, we just return if l matched w or not. */
     if (test)
-	return !ll;
+	return (part || !ll);
+
+    if (part)
+	return il;
 
     /* In top-level calls, if ll is non-zero (unmatched portion in l),
      * we have to free the collected clines. */
@@ -2643,13 +2714,13 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 
 /**/
 static int
-match_parts(char *l, char *w, int n)
+match_parts(char *l, char *w, int n, int part)
 {
     char lsav = l[n], wsav = w[n];
     int ret;
 
     l[n] = w[n] = '\0';
-    ret = match_str(l, w, NULL, NULL, 0, 1);
+    ret = match_str(l, w, NULL, NULL, 0, 1, part);
     l[n] = lsav;
     w[n] = wsav;
 
@@ -2704,7 +2775,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp,
 	/* Always try to match the prefix. */
 
 	*bpl = (qu ? qbrpl : brpl);
-	if ((mpl = match_str(pfx, w, bpl, &rpl, 0, 0)) < 0)
+	if ((mpl = match_str(pfx, w, bpl, &rpl, 0, 0, 0)) < 0)
 	    return NULL;
 
 	if (sfx && *sfx) {
@@ -2729,7 +2800,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp,
 
 	    /* The try to match the suffix. */
 	    *bsl = (qu ? qbrsl : brsl);
-	    if ((msl = match_str(sfx, w + mpl, bsl, &rsl, 1, 0)) < 0) {
+	    if ((msl = match_str(sfx, w + mpl, bsl, &rsl, 1, 0, 0)) < 0) {
 		free_cline(pli);
 
 		return NULL;
@@ -3398,6 +3469,7 @@ sub_join(Cline a, Cline b, Cline e, int anew)
 {
     if (!e->suffix && a->prefix) {
 	Cline op = e->prefix, n = NULL, *p = &n, t, ca;
+	int min = 0, max = 0;
 
 	for (; b != e; b = b->next) {
 	    if ((*p = t = b->prefix)) {
@@ -3407,6 +3479,8 @@ sub_join(Cline a, Cline b, Cline e, int anew)
 	    }
 	    b->suffix = b->prefix = NULL;
 	    b->flags &= ~CLF_SUF;
+	    min += b->min;
+	    max += b->max;
 	    *p = b;
 	    p = &(b->next);
 	}
@@ -3419,13 +3493,22 @@ sub_join(Cline a, Cline b, Cline e, int anew)
 
 	    if (anew) {
 		join_psfx(e, a, NULL, NULL, 0);
-		if (e->prefix)
+		if (e->prefix) {
+		    e->min += min;
+		    e->max += max;
 		    break;
+		}
 	    } else {
 		join_psfx(e, a, NULL, NULL, 0);
-		if (a->prefix)
+		if (a->prefix) {
+		    a->min += min;
+		    a->max += max;
 		    break;
+		}
 	    }
+	    min -= n->min;
+	    max -= n->max;
+
 	    n = n->next;
 	}
     }
@@ -3437,6 +3520,8 @@ sub_join(Cline a, Cline b, Cline e, int anew)
 static Cline
 join_clines(Cline o, Cline n)
 {
+    cline_setlens(n, 1);
+
     /* First time called, just return the new list. On further invocations
      * we will get it as the first argument. */
     if (!o)
@@ -3562,7 +3647,17 @@ join_clines(Cline o, Cline n)
 		    }
 		}
 	    }
-	    /* Ok, they are equal, now join the sub-lists. */
+	    /* Ok, they are equal, now copy the information about the
+             * original string if needed, calculate minimum and maximum
+	     * lengths, and join the sub-lists. */
+	    if (!o->orig && !o->olen) {
+		o->orig = n->orig;
+		o->olen = n->olen;
+	    }
+	    if (n->min < o->min)
+		o->min = n->min;
+	    if (n->max > o->max)
+		o->max = n->max;
 	    if (o->flags & CLF_MID)
 		join_mid(o, n);
 	    else
@@ -3599,6 +3694,7 @@ add_match_data(int alt, char *str, Cline line,
     Cmatch cm;
     Aminfo ai = (alt ? fainfo : ainfo);
     int palen, salen, qipl, ipl, pl, ppl, qisl, isl, psl;
+    int sl, lpl, lsl, ml;
 
     palen = salen = qipl = ipl = pl = ppl = qisl = isl = psl = 0;
 
@@ -3791,6 +3887,16 @@ add_match_data(int alt, char *str, Cline line,
     if (!ai->firstm)
 	ai->firstm = cm;
 
+    sl = strlen(str);
+    lpl = (cm->ppre ? strlen(cm->ppre) : 0);
+    lsl = (cm->psuf ? strlen(cm->psuf) : 0);
+    ml = sl + lpl + lsl;
+
+    if (ml < minmlen)
+	minmlen = ml;
+    if (ml > maxmlen)
+	maxmlen = ml;
+
     /* Do we have an exact match? More than one? */
     if (exact) {
 	if (!ai->exact) {
@@ -3799,13 +3905,10 @@ add_match_data(int alt, char *str, Cline line,
 		/* If a completion widget is active, we make the exact
 		 * string available in `compstate'. */
 
-		int sl = strlen(str);
-		int lpl = (cm->ppre ? strlen(cm->ppre) : 0);
-		int lsl = (cm->psuf ? strlen(cm->psuf) : 0);
 		char *e;
 
 		zsfree(compexactstr);
-		compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1);
+		compexactstr = e = (char *) zalloc(ml + 1);
 		if (cm->ppre) {
 		    strcpy(e, cm->ppre);
 		    e += lpl;
@@ -3854,7 +3957,8 @@ addmatches(Cadata dat, char **argv)
     char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
     char **aign = NULL, **dparr = NULL, oaq = autoq, *oppre = dat->ppre;
     char *oqp = qipre, *oqs = qisuf, qc, **disp = NULL;
-    int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
+    int lpl, lsl, pl, sl, bpl, bsl, bppl = -1, bssl = -1;
+    int llpl = 0, llsl = 0, nm = mnum;
     int oisalt = 0, isalt, isexact, doadd, ois = instring, oib = inbackt;
     Cline lc = NULL;
     Cmatch cm;
@@ -3886,7 +3990,9 @@ addmatches(Cadata dat, char **argv)
      * was invoked. */
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
-	    doadd = (!dat->apar && !dat->opar && !dat->dpar);
+	    if ((doadd = (!dat->apar && !dat->opar && !dat->dpar)) &&
+		(dat->aflags & CAF_MATCH))
+		hasmatched = 1;
 	    if (dat->apar)
 		aparl = newlinklist();
 	    if (dat->opar)
@@ -3993,20 +4099,35 @@ addmatches(Cadata dat, char **argv)
 	    } else
 		lsl = 0;
 	    if (dat->aflags & CAF_MATCH) {
+		int ml;
+
 		s = dat->ppre ? dat->ppre : "";
-		if (llpl <= lpl && strpfx(lpre, s))
-		    lpre = "";
-		else if (llpl > lpl && strpfx(s, lpre))
-		    lpre += lpl;
-		else
-		    *argv = NULL;
+		bppl = brpl;
+		if ((ml = match_str(lpre, s, &bppl, NULL, 0, 0, 1)) >= 0)
+		    lpre += ml;
+		else {
+		    bppl = -1;
+		    if (llpl <= lpl && strpfx(lpre, s))
+			lpre = "";
+		    else if (llpl > lpl && strpfx(s, lpre))
+			lpre += lpl;
+		    else
+			*argv = NULL;
+		}
+
 		s = dat->psuf ? dat->psuf : "";
-		if (llsl <= lsl && strsfx(lsuf, s))
-		    lsuf = "";
-		else if (llsl > lsl && strsfx(s, lsuf))
-		    lsuf[llsl - lsl] = '\0';
-		else
-		    *argv = NULL;
+		bssl = brsl;
+		if ((ml = match_str(lsuf, s, &bssl, NULL, 0, 0, 1)) >= 0)
+		    lsuf[llsl - ml] = '\0';
+		else {
+		    bssl = -1;
+		    if (llsl <= lsl && strsfx(lsuf, s))
+			lsuf = "";
+		    else if (llsl > lsl && strsfx(s, lsuf))
+			lsuf[llsl - lsl] = '\0';
+		    else
+			*argv = NULL;
+		}
 	    }
 	    if (*argv) {
 		if (dat->pre)
@@ -4090,7 +4211,9 @@ addmatches(Cadata dat, char **argv)
 		    cm = add_match_data(isalt, ms, lc, dat->ipre, NULL,
 					dat->isuf, dat->pre, dat->prpre,
 					dat->ppre, dat->psuf, dat->suf,
-					bpl, bsl, dat->flags, isexact);
+					(bppl >= 0 ? bppl : bpl),
+					(bssl >= 0 ? bssl : bsl),
+					dat->flags, isexact);
 		    cm->rems = dat->rems;
 		    cm->remf = dat->remf;
 		    if (disp)
@@ -4587,6 +4710,9 @@ docompletion(char *s, int lst, int incmd)
 				"yes" : "");
 	movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1);
 	showinglist = 0;
+	hasmatched = 0;
+	minmlen = 1000000;
+	maxmlen = -1;
 
 	/* Make sure we have the completion list and compctl. */
 	if (makecomplist(s, incmd, lst)) {
@@ -6255,6 +6381,9 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     untokenize(lpre);
     untokenize(lsuf);
 
+    if (!(cc->mask & CC_DELETE))
+	hasmatched = 1;
+
     /* Handle completion of files specially (of course). */
 
     if ((cc->mask & (CC_FILES | CC_DIRS | CC_COMMPATH)) || cc->glob) {
@@ -7458,6 +7587,86 @@ inststrlen(char *str, int move, int len)
     return len;
 }
 
+/* This cuts the cline list before the stuff that isn't worth
+ * inserting in the line. */
+
+static Cline
+cut_cline(Cline l)
+{
+    Cline p, e = NULL, maxp = NULL;
+    int sum = 0, max = 0, tmp, ls = 0;
+
+    /* If no match was added with matching, we don't really know
+     * which parts of the unambiguous string are worth keeping,
+     * so for now we keep everything (in the hope that this
+     * produces a string containing at least everything that was 
+     * originally on the line). */
+
+    if (!hasmatched) {
+	cline_setlens(l, 0);
+	return l;
+    }
+    e = l = cp_cline(l);
+
+    /* First, search the last struct for which we have something on
+     * the line. Anything before that is kept. */
+
+    for (p = l; p; p = p->next)
+	if (p->orig || p->olen)
+	    e = p->next;
+
+    /* Then keep all structs without missing characters. */
+
+    while (e && !(e->flags & CLF_MISS))
+	e = e->next;
+
+    if (e) {
+	/* Then we see if there is another struct with missing
+	 * characters. If not, we keep the whole list. */
+
+	for (p = e->next; p && !(p->flags & CLF_MISS); p = p->next);
+
+	if (p) {
+	    for (p = e; p; p = p->next) {
+		if (!(p->flags & CLF_MISS))
+		    sum += p->max;
+		else {
+		    tmp = cline_sublen(p);
+		    if (tmp > 2 && tmp > ((p->max + p->min) >> 1))
+			sum += tmp - (p->max - tmp);
+		    else if (tmp < p->min)
+			sum -= (((p->max + p->min) >> 1) - tmp) << (tmp < 2);
+		}
+		if (sum > max) {
+		    max = sum;
+		    maxp = p;
+		}
+	    }
+	    if (max)
+		e = maxp;
+	    else {
+		int len = 0;
+
+		cline_setlens(l, 0);
+		ls = 1;
+
+		for (p = e; p; p = p->next)
+		    len += p->max;
+
+		if (len > ((minmlen << 1) / 3))
+		    return l;
+	    }
+	    e->line = e->word = NULL;
+	    e->llen = e->wlen = e->olen = 0;
+	    e->next = NULL;
+	}
+    }
+    if (!ls)
+	cline_setlens(l, 0);
+
+    return l;
+}
+
 /* This builds the unambiguous string. If ins is non-zero, it is
  * immediatly inserted in the line. Otherwise csp is used to return
  * the relative cursor position in the string returned. */
@@ -7466,11 +7675,13 @@ static char *
 cline_str(Cline l, int ins, int *csp)
 {
     Cline s;
-    int ocs = cs, ncs, pcs, pm, sm, d, b, i, j, li = 0;
+    int ocs = cs, ncs, pcs, pm, pmax, sm, smax, d, b, i, j, li = 0;
     int pl, sl, hasp, hass, ppos, spos, plen, slen;
 
+    l = cut_cline(l);
+
     ppos = spos = plen = slen = hasp = hass = 0;
-    pm = sm = d = b = pl = sl = -1;
+    pm = pmax = sm = smax = d = b = pl = sl = -1;
 
     /* Get the information about the brace beginning and end we have
      * to re-insert. */
@@ -7532,8 +7743,10 @@ cline_str(Cline l, int ins, int *csp)
 	}
 	/* Remember the position if this is the first prefix with
 	 * missing characters. */
-	if ((l->flags & CLF_MISS) && !(l->flags & CLF_SUF))
-	    pm = cs;
+	if ((l->flags & CLF_MISS) && !(l->flags & CLF_SUF) &&
+	    (pmax < (l->min - l->max))) {
+	    pm = cs; pmax = l->min - l->max;
+	}
 	pcs = cs;
 	/* Insert the anchor. */
 	if (l->flags & CLF_LINE)
@@ -7553,8 +7766,9 @@ cline_str(Cline l, int ins, int *csp)
 	if (l->flags & CLF_MISS) {
 	    if (l->flags & CLF_MID)
 		b = cs;
-	    else if (l->flags & CLF_SUF)
-		sm = cs;
+	    else if ((l->flags & CLF_SUF) && smax < (l->min - l->max)) {
+		sm = cs; smax = l->min - l->max;
+	    }
 	}
 	/* And now insert the suffix or the original string. */
 	if (l->olen && (l->flags & CLF_SUF) && !l->suffix) {
diff --git a/Src/glob.c b/Src/glob.c
index 55cc96a52..07336986d 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -2001,7 +2001,7 @@ getmatcharr(char ***ap, char *pat, int fl, int n, char *replstr)
 static int
 igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 {
-    char *s = *sp, *t, *start, sav;
+    char *s = *sp, *t, sav;
     int i, l = strlen(*sp), ml = ztrlen(*sp), matched = 1;
 
     MUSTUSEHEAP("igetmatch");	/* presumably covered by prefork() test */
@@ -2210,7 +2210,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 	LinkNode nd;
 	Repldata rd;
 	int lleft = 0;		/* size of returned string */
-	char *ptr;
+	char *ptr, *start;
 
 	i = 0;			/* start of last chunk we got from *sp */
 	for (nd = firstnode(repllist); nd; incnode(nd)) {
diff --git a/Src/math.c b/Src/math.c
index e044cbd9f..f91a58ea8 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -57,37 +57,24 @@ static int unary = 1;
  * RL = right-to-left associativity *
  * BOOL = short-circuiting boolean   */
 
-#define LR   0x0000
-#define RL   0x0001
-#define BOOL 0x0002
+#define LR 0
+#define RL 1
+#define BOOL 2
 
 #define MTYPE(x)  ((x) & 3)
 
 /*
- * OP_A2    2 arguments
- * OP_A2IR  2 arguments, return integer
- * OP_A2IO  2 arguments, must be integer, return integer
- * OP_E2    2 arguments with assignment
- * OP_E2IO  2 arguments with assignment, must be integer, return integer
- * OP_OP    None of the above, but occurs where we are expecting an operator
- *          rather than an operand.
- * OP_OPF   Followed by an operator, not an operand.
- *
- * OP_A2*, OP_E2*, OP_OP*:
- *   Occur when we need an operator; the next object must be an operand,
- *   unless OP_OPF is also supplied.
- *
- * Others:
- *   Occur when we need an operand; the next object must also be an operand,
- *   unless OP_OPF is also supplied.
+ * OP_A2 2 argument
+ * OP_A2IR 2 argument with return type integer
+ * OP_A2IO 2 arguments, must be integer, returning integer
+ * OP_E2 2 argument with assignment
+ * OP_E2IO 2 arguments with assignment, must be integer, return integer
  */
-#define OP_A2   0x0004
-#define OP_A2IR 0x0008
-#define OP_A2IO 0x0010
-#define OP_E2   0x0020
-#define OP_E2IO 0x0040
-#define OP_OP   0x0080
-#define OP_OPF  0x0100
+#define OP_A2   4
+#define OP_A2IR 8
+#define OP_A2IO 16
+#define OP_E2   32
+#define OP_E2IO 64
 
 #define M_INPAR 0
 #define M_OUTPAR 1
@@ -165,17 +152,17 @@ static int prec[TOKCOUNT] =
 
 static int type[TOKCOUNT] =
 {
-/*  0 */  LR, LR|OP_OP|OP_OPF, RL, RL, RL|OP_OP|OP_OPF,
-/*  5 */  RL|OP_OP|OP_OPF, RL, RL, LR|OP_A2IO, LR|OP_A2IO,
-/* 10 */  LR|OP_A2IO, LR|OP_A2, LR|OP_A2, LR|OP_A2IO, LR|OP_A2,
-/* 15 */  LR|OP_A2, LR|OP_A2IO, LR|OP_A2IO, LR|OP_A2IR, LR|OP_A2IR,
-/* 20 */  LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, BOOL|OP_A2IO,
-/* 25 */  BOOL|OP_A2IO, LR|OP_A2IO, RL|OP_OP, RL|OP_OP, RL|OP_E2,
-/* 30 */  RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2IO,
-/* 35 */  RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO,
-/* 40 */  BOOL|OP_E2IO, BOOL|OP_E2IO, RL|OP_A2IO, RL|OP_A2, RL|OP_OP,
-/* 45 */  RL, RL, LR|OP_OPF, LR|OP_OPF, RL|OP_A2,
-/* 50 */  LR|OP_OPF, RL|OP_E2
+/*  0 */    LR, LR, RL, RL, RL,
+/*  5 */    RL, RL, RL, LR|OP_A2IO, LR|OP_A2IO,
+/* 10 */    LR|OP_A2IO, LR|OP_A2, LR|OP_A2, LR|OP_A2IO, LR|OP_A2,
+/* 15 */    LR|OP_A2, LR|OP_A2IO, LR|OP_A2IO, LR|OP_A2IR, LR|OP_A2IR,
+/* 20 */    LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, BOOL|OP_A2IO,
+/* 25 */    BOOL|OP_A2IO, LR|OP_A2IO, RL, RL, RL|OP_E2,
+/* 30 */    RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2IO,
+/* 35 */    RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO,
+/* 40 */    BOOL|OP_E2IO, BOOL|OP_E2IO, RL|OP_A2IO, RL|OP_A2, RL,
+/* 45 */    RL, RL, LR, LR, RL|OP_A2,
+/* 50 */    LR, RL|OP_E2
 };
 
 #define LVCOUNT 32
@@ -201,6 +188,7 @@ zzlex(void)
 		return (unary) ? PREPLUS : POSTPLUS;
 	    }
 	    if (*ptr == '=') {
+		unary = 1;
 		ptr++;
 		return PLUSEQ;
 	    }
@@ -211,16 +199,19 @@ zzlex(void)
 		return (unary) ? PREMINUS : POSTMINUS;
 	    }
 	    if (*ptr == '=') {
+		unary = 1;
 		ptr++;
 		return MINUSEQ;
 	    }
 	    return (unary) ? UMINUS : MINUS;
 	case '(':
+	    unary = 1;
 	    return M_INPAR;
 	case ')':
 	    return M_OUTPAR;
 	case '!':
 	    if (*ptr == '=') {
+		unary = 1;
 		ptr++;
 		return NEQ;
 	    }
@@ -228,6 +219,7 @@ zzlex(void)
 	case '~':
 	    return COMP;
 	case '&':
+	    unary = 1;
 	    if (*ptr == '&') {
 		if (*++ptr == '=') {
 		    ptr++;
@@ -240,6 +232,7 @@ zzlex(void)
 	    }
 	    return AND;
 	case '|':
+	    unary = 1;
 	    if (*ptr == '|') {
 		if (*++ptr == '=') {
 		    ptr++;
@@ -252,6 +245,7 @@ zzlex(void)
 	    }
 	    return OR;
 	case '^':
+	    unary = 1;
 	    if (*ptr == '^') {
 		if (*++ptr == '=') {
 		    ptr++;
@@ -264,6 +258,7 @@ zzlex(void)
 	    }
 	    return XOR;
 	case '*':
+	    unary = 1;
 	    if (*ptr == '*') {
 		if (*++ptr == '=') {
 		    ptr++;
@@ -277,18 +272,21 @@ zzlex(void)
 	    }
 	    return MUL;
 	case '/':
+	    unary = 1;
 	    if (*ptr == '=') {
 		ptr++;
 		return DIVEQ;
 	    }
 	    return DIV;
 	case '%':
+	    unary = 1;
 	    if (*ptr == '=') {
 		ptr++;
 		return MODEQ;
 	    }
 	    return MOD;
 	case '<':
+	    unary = 1;
 	    if (*ptr == '<') {
 		if (*++ptr == '=') {
 		    ptr++;
@@ -301,6 +299,7 @@ zzlex(void)
 	    }
 	    return LES;
 	case '>':
+	    unary = 1;
 	    if (*ptr == '>') {
 		if (*++ptr == '=') {
 		    ptr++;
@@ -313,12 +312,14 @@ zzlex(void)
 	    }
 	    return GRE;
 	case '=':
+	    unary = 1;
 	    if (*ptr == '=') {
 		ptr++;
 		return DEQ;
 	    }
 	    return EQ;
 	case '$':
+	    unary = 0;
 	    yyval.u.l = mypid;
 	    return NUM;
 	case '?':
@@ -327,15 +328,20 @@ zzlex(void)
 		unary = 0;
 		return NUM;
 	    }
+	    unary = 1;
 	    return QUEST;
 	case ':':
+	    unary = 1;
 	    return COLON;
 	case ',':
+	    unary = 1;
 	    return COMMA;
 	case '\0':
+	    unary = 1;
 	    ptr--;
 	    return EOI;
 	case '[':
+	    unary = 0;
 	    {
 		int base = zstrtol(ptr, &ptr, 10);
 
@@ -350,6 +356,7 @@ zzlex(void)
 	    break;
 	case '0':
 	    if (*ptr == 'x' || *ptr == 'X') {
+		unary = 0;
 		/* Should we set lastbase here? */
 		yyval.u.l = zstrtol(++ptr, &ptr, lastbase = 16);
 		return NUM;
@@ -358,6 +365,7 @@ zzlex(void)
 	default:
 	    if (idigit(*--ptr) || *ptr == '.') {
 		char *nptr;
+		unary = 0;
 		for (nptr = ptr; idigit(*nptr); nptr++);
 
 		if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') {
@@ -387,6 +395,7 @@ zzlex(void)
 		    ptr++;
 		    ptr = getkeystring(ptr, NULL, 6, &v);
 		    yyval.u.l = v;
+		    unary = 0;
 		    return NUM;
 		}
 		cct = 1;
@@ -399,6 +408,7 @@ zzlex(void)
 		    zerr("too many identifiers (complain to author)", NULL, 0);
 		    return EOI;
 		}
+		unary = 0;
 		while (iident(*++ptr));
 		if (*ptr == '[') {
 		    int l;
@@ -419,6 +429,7 @@ zzlex(void)
 	    }
 	    else if (cct) {
 		yyval.u.l = poundgetfn(NULL);
+		unary = 0;
 		return NUM;
 	    }
 	    return EOI;
@@ -504,8 +515,6 @@ op(int what)
     LV lv;
     int tp = type[what];
 
-    if (errflag)
-	return;
     if (sp < 0) {
 	zerr("bad math expression: stack empty", NULL, 0);
 	return;
@@ -895,40 +904,6 @@ mathevalarg(char *s, char **ss)
     return (x.type & MN_FLOAT) ? (zlong)x.u.d : x.u.l;
 }
 
-/*
- * Make sure we have an operator or an operand, whatever is expected.
- * For this purpose, unary operators constitute part of an operand.
- */
-
-/**/
-static void
-checkunary(int tp, char *ptr)
-{
-    int errmsg = 0;
-    if (tp & (OP_A2|OP_A2IR|OP_A2IO|OP_E2|OP_E2IO|OP_OP)) {
-	if (unary)
-	    errmsg = 1;
-    } else {
-	if (!unary)
-	    errmsg = 2;
-    }
-    if (errmsg) {
-	char errbuf[40];
-	int len, over = 0;
-	while (inblank(*ptr))
-	    ptr++;
-	len = strlen(ptr);
-	if (len > 10) {
-	    len = 10;
-	    over = 1;
-	}
-	sprintf(errbuf, "bad math expression: %s expected at `%%l%s'",
-		errmsg == 2 ? "operator" : "operand",
-		over ? "..." : ""); 
-	zerr(errbuf, ptr, len);
-    }
-    unary = !(tp & OP_OPF);
-}
 
 /* operator-precedence parse the string and execute */
 
@@ -938,12 +913,10 @@ mathparse(int pc)
 {
     zlong q;
     int otok, onoeval;
-    char *optr = ptr;
 
     if (errflag)
 	return;
     mtok = zzlex();
-    checkunary(type[mtok], optr);
     while (prec[mtok] <= pc) {
 	if (errflag)
 	    return;
@@ -991,8 +964,6 @@ mathparse(int pc)
 	    op(otok);
 	    continue;
 	}
-	optr = ptr;
 	mtok = zzlex();
-	checkunary(type[mtok], optr);
     }
 }
diff --git a/Src/module.c b/Src/module.c
index dab2c0350..d10206155 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -1181,13 +1181,13 @@ bin_zmodload(char *nam, char **args, char *ops, int func)
 		nicezputs((char *) getdata(node), stdout);
 		putchar('\n');
 	    }
-	    return 0;
 	} else {
 	    for (; *args; args++)
 		for (node = firstnode(bltinmodules); node; incnode(node))
-		    if (!strcmp(*args, (char *) getdata(node)))
-			return 0;
+		    if (strcmp(*args, (char *) getdata(node)))
+			return 1;
 	}
+	return 0;
     }
     /* Otherwise we return 1 -- different from the dynamic version. */
     return 1;
diff --git a/Src/subst.c b/Src/subst.c
index 5b08d0bfb..b0bb885c9 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -152,8 +152,7 @@ stringsubst(LinkList list, LinkNode node, int ssub)
 	    *str++ = '\0';
 	    if (endchar == Outpar && str2[1] == '(' && str[-2] == ')') {
 		/* Math substitution of the form $((...)) */
-		str[-2] = '\0';
-		str = arithsubst(str2 + 2, &str3, str);
+		str = arithsubst(str2 + 1, &str3, str);
 		setdata(node, (void *) str3);
 		continue;
 	    }
diff --git a/Src/zsh.export b/Src/zsh.export
index 92844d39d..625fef331 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -19,6 +19,7 @@ arrlen
 attachtty
 bangchar
 bin_notavail
+bltinmodules
 breaks
 bslashquote
 bufstack
@@ -33,6 +34,7 @@ compctlreadptr
 cond_match
 cond_str
 cond_val
+condtab
 convbase
 coprocin
 coprocout
@@ -50,6 +52,7 @@ deletehookfunc
 deleteparamdefs
 deleteparamtable
 deletewrapper
+dirstack
 dosetopt
 doshfunc
 down_histent
@@ -78,6 +81,7 @@ findcmd
 freearray
 freeheap
 freelinklist
+freestr
 freestruct
 getaparam
 gethashnode
@@ -149,6 +153,7 @@ metadiffer
 metafy
 metalen
 mode_to_octal
+modules
 movefd
 movehistent
 mypgrp
@@ -195,6 +200,7 @@ pushheap
 putshout
 pwd
 quietgethist
+quietgethistent
 quotedzputs
 readoutput
 realparamtab