about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog179
-rw-r--r--Completion/Base/_brace_parameter2
-rw-r--r--Completion/Base/_vars19
-rw-r--r--Completion/Builtins/_jobs2
-rw-r--r--Completion/Builtins/_kill3
-rw-r--r--Completion/Builtins/_limits2
-rw-r--r--Completion/Builtins/_wait2
-rw-r--r--Completion/Builtins/_zftp13
-rw-r--r--Completion/Core/_normal2
-rw-r--r--Completion/Core/_path_files4
-rw-r--r--Completion/Core/compdump2
-rw-r--r--Completion/Core/compinit4
-rw-r--r--Completion/Makefile.in16
-rw-r--r--Config/defs.mk.in1
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Makefile.in6
-rw-r--r--Doc/Zsh/arith.yo53
-rw-r--r--Doc/Zsh/builtins.yo13
-rw-r--r--Doc/Zsh/compctl.yo110
-rw-r--r--Doc/Zsh/compsys.yo49
-rw-r--r--Doc/Zsh/compwid.yo45
-rw-r--r--Doc/Zsh/expn.yo25
-rw-r--r--Doc/Zsh/files.yo2
-rw-r--r--Doc/Zsh/func.yo3
-rw-r--r--Doc/Zsh/grammar.yo5
-rw-r--r--Doc/Zsh/guide.yo4
-rw-r--r--Doc/Zsh/jobs.yo2
-rw-r--r--Doc/Zsh/metafaq.yo2
-rw-r--r--Doc/Zsh/mod_compctl.yo2
-rw-r--r--Doc/Zsh/mod_mapfile.yo8
-rw-r--r--Doc/Zsh/mod_zftp.yo16
-rw-r--r--Doc/Zsh/params.yo18
-rw-r--r--Doc/Zsh/redirect.yo20
-rw-r--r--Doc/Zsh/zftpsys.yo104
-rw-r--r--Doc/Zsh/zle.yo6
-rw-r--r--Doc/zman.yo10
-rw-r--r--Doc/zsh.yo2
-rw-r--r--Doc/ztexi.yo10
-rw-r--r--Etc/MACHINES10
-rw-r--r--Functions/Makefile.in16
-rw-r--r--Functions/Zftp/.distfiles2
-rw-r--r--Functions/Zftp/zfgoto0
-rw-r--r--Functions/Zftp/zfinit14
-rw-r--r--Functions/Zftp/zfmark0
-rw-r--r--Functions/Zftp/zftp_chpwd1
-rw-r--r--INSTALL24
-rw-r--r--Src/Builtins/rlimits.c17
-rw-r--r--Src/Makefile.in8
-rw-r--r--Src/Modules/zftp.c11
-rw-r--r--Src/Zle/zle_misc.c5
-rw-r--r--Src/Zle/zle_tricky.c91
-rw-r--r--Src/builtin.c63
-rw-r--r--Src/cond.c91
-rw-r--r--Src/exec.c396
-rw-r--r--Src/glob.c24
-rw-r--r--Src/hashtable.c4
-rw-r--r--Src/hist.c110
-rw-r--r--Src/init.c31
-rw-r--r--Src/jobs.c35
-rw-r--r--Src/lex.c76
-rw-r--r--Src/linklist.c4
-rw-r--r--Src/loop.c64
-rw-r--r--Src/math.c14
-rw-r--r--Src/mem.c55
-rw-r--r--Src/params.c21
-rw-r--r--Src/parse.c56
-rw-r--r--Src/signals.c2
-rw-r--r--Src/subst.c4
-rw-r--r--Src/text.c36
-rw-r--r--Src/utils.c641
-rw-r--r--Src/zsh.export3
-rw-r--r--Src/zsh.h14
-rw-r--r--Src/zsh.mdd11
-rw-r--r--Util/zsh-development-guide18
-rw-r--r--acconfig.h5
-rw-r--r--aczsh.m424
-rw-r--r--configure.in118
77 files changed, 1652 insertions, 1237 deletions
diff --git a/ChangeLog b/ChangeLog
index 48818fe3d..8daf08449 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,182 @@
+1999-06-15  Peter Stephenson  <pws@ibmth.difi.unipi.it>
+
+	* Oliver: 6636: Completion/Builtins/_limits: wasn't working
+
+	* Bart: 6617 + minor changes: Src/utils.c: Be more careful keeping
+	  $COLUMNS and $LINES correct, particularly if exported.
+
+	* Sven: zsh-users/2388: Src/jobs.c:  while loops etc. in shells
+	  running without MONITOR were hard to kill.
+
+	* Bart: 6628: Src/params.c: setting slices of unset array
+	  caused a crash.
+
+1999-06-14  Peter Stephenson  <pws@ibmth.difi.unipi.it>
+
+	* pws: 6626: Src/mem.c: in zsh's malloc, try to make sure when
+	  sbrk'ing that it's sufficiently well aligned.
+
+	* Oliver: 6624: Completion/Builtins/_kill,
+	  Completion/Builtins/_wait: more widely functioning process
+	  handling
+
+	* pws: 6623: Completion/Makefile.in, Config/defs.mk.in,
+	  Functions/Makefile.in, INSTALL, Src/init.c, Src/zsh.mdd,
+	  configure.in: --enable-function-subdirs allows installation
+	  into subdirectories of the function directory and sets the
+	  initial $fpath appropriately.
+
+	* Oliver: 6620: Completion/Builtins/_jobs: handle disown, too.
+
+	* pws: 6618: Doc/Zsh/func.yo, Doc/Zsh/grammar.yo, Src/lex.c:
+	  with SH_GLOB set, function definition parentheses after the
+	  first word on the line allow spaces inside.
+
+	* Sven: 6614: Src/Zle/zle_tricky.c, Completion/Brace/_brace_parameter:
+	  completion after quotes in parameters
+	
+	* pws: 6610: Src/glob.c: globbing flags shouldn't be active
+	  without extendedglob.
+
+	* Bart: 6608: Doc/Zsh files compctl.yo, compsys.yo, compwid.yo,
+	  expn.yo, files.yo, mod_mapfile.yo, mod_zftp.yo, params.yo,
+	  zftpsys.yo, zle.yo: spelling corrections
+
+1999-06-12  Peter Stephenson  <pws@ibmth.difi.unipi.it>
+
+	* pws: 6601: Src/Makefile.in: don't remake Makemod just
+	  to clean up files
+
+	* pws: 6600: Doc/Zsh/arith.yo, Doc/Zsh/compctl.yo,
+	  Doc/Zsh/compsys.yo, Doc/Zsh/compwid.yo, Doc/Zsh/expn.yo,
+	  Doc/Zsh/guide.yo, Doc/Zsh/jobs.yo, Doc/Zsh/metafaq.yo,
+	  Doc/Zsh/mod_compctl.yo, Doc/Zsh/mod_zftp.yo, Doc/Zsh/params.yo,
+	  Doc/Zsh/redirect.yo, Doc/Zsh/zftpsys.yo, Doc/Zsh/zle.yo,
+	  Doc/zman.yo, Doc/ztexi.yo, Util/zsh-development-guide:
+	  Formatting of unfilled text now handled by three distinct
+	  macros example(), indent(), nofill(); compctl description node
+	  is now called `Programmable Completion Using compctl' to
+	  distinguish it from widget completion; don't put chapters on
+	  separate pages because many are too short.
+
+	* Wayne: 6599: Src/Zle/zle_tricky.c: unitialised variable warnings
+	  from gcc
+
+1999-06-11  Peter Stephenson  <pws@ibmth.difi.unipi.it>
+
+	* pws: 6598: Doc/Zsh/zftpsys.yo, Functions/Zftp/zfinit,
+	  Functions/Zftp/zfgoto, Functions/Zftp/zfmark,
+	  Functions/Zftp/zftp_chpwd, Completion/Builtins/_zftp:
+	  add zfmark and zfgoto implementing bookmarks (including use
+	  ncftp bookmarks) for zftp function suite; autoload functions
+	  from zfinit; patcomps -> _patcomps.
+
+	* pws: 6596: Doc/Zsh/arith.yo: update on size of integers and
+	  increase in clarity of presentation
+
+	* Sven: 6589: Completion/Core/_path_files: use :h and :t instead
+	  of pattern matching
+
+	* Sven: 6587, 6588: Src/Zle/zle_misc.c, Doc/Zsh/options.yo: < and
+	  > shouldn't remove a suffix, but | does
+
+	* Sven: 6586: Src/exec.c, Src/lex.c, Src/loop.c: don't modify
+	  struct cmd to insert cmd args and flags, always pass those
+	  separately
+
+1999-06-10  Peter Stephenson  <pws@ibmth.difi.unipi.it>
+
+	* Andrej: 6581: Doc/Makefile: dependencies for manuals
+
+	* Sven: 6579: Src/exec.c: old hack of storing shell function
+	  args in struct cmd doesn't work any more
+
+	* Sven: 6577: Src/exec.c, Src/text.c, Src/utils.c: expunge
+	  simplifyright(), which appears no longer to have an effect
+	
+	* pws: 6575: Doc/Zsh/mod_mapfile.yo: avoid mapping long files
+
+	* pws: 6571: Src/Builtins/rlimits.c: use appropriate printf()
+	  routine in printulimit() instead of just casting to long
+
+	* pws: 6570: configure.in, INSTALL: some systems have
+	  sizeof(off_t) or sizeof(ino_t) == 8 and sizeof(long) == 4 even
+	  without explicit enabling, so check and if so use the
+	  --enable-lfs code.
+
+	* pws/Sven: 6567, 6568: Completion/Base/_vars: complete assoc
+	  array keys
+
+	* pws: 6566: Src/params.c: junk testhash assoc array
+
+	* pws: 6563: sporadic: minor changes affecting casts, sizes
+	  of integers, unused variables; add index for subscripts in
+	  manual
+
+	* Bart: email: Src/zsh.h: alternative definition for zulong
+
+	* Bart: 6558: Src/builtins.c: printing functions with the
+	  UNALIASED flag
+
+	* Sven: 6557: Doc/zsh/compsys.yo: a few typos
+
+1999-06-09  Peter Stephenson  <pws@ibmth.difi.unipi.it>
+
+	* Andrej: 6556: aczsh.m4: don't disable setting variables
+	  for --enable-lfs just because some other variables were set
+
+	* Sven: 6554: Src/Zle/zle_tricky.c: display bugs with compadd -X:
+	  newline missing and display unnecessarily altered
+
+	* pws: 6552: configure.in, aczsh.m4, acconfig.h, Src/zsh.h:
+	  define separate unsigned 64-bit integer; try __int64_t and
+	  __uint64_t.
+
+	* Sven: 6548: Src/Zle/zle_tricky.c: fix `compctl -l'
+
+	* Andrej: 6544: configure displays info on function installation
+
+	* Sven: 6542: Src/builtin.c, Src/exec.c, Src/hist.c, Src/init.c,
+	  Src/lex.c: when not using interactive history, don't allocate
+	  history at all
+
+	* Andrej: 6541: configure.in: add missing `test'
+
+	* Sven: 6535: Completion/core/_normal: an eval was unnecessary
+
+	* Bart: 6534: Completion/Core/compdump, Completion/Core/compinit,
+	  Doc/Zsh/builtins.yo, Src/builtin.c, Src/exec.c, Src/zsh.h:
+	  autoload -U defines functions which don't use expand aliases
+	  during loading; used in new completion code to protect
+	  functions.
+
+	* Sven: 6527: Src/builtin.c, Src/cond.c, Src/exec.c, Src/glob.c,
+	  Src/hashtable.c, Src/init.c, Src/jobs.c, Src/lex.c,
+	  Src/linklist.c, Src/loop.c, Src/math.c, Src/mem.c, Src/params.c,
+	  Src/parse.c, Src/signals.c, Src/text.c, Src/utils.c, Src/zsh.h:
+	  various sets of patches:
+	  - make zhalloc() use a pointer to the first free heap
+	  - make zsh-mem allocators keep some memory back when freeing
+	  - reduce the amount of allocation work done in the exec.c
+	    execution hierarchy
+	  - don't duplicate execution trees any more than necessary, e.g.
+	    execute functions from stored tree
+	
+	* pws: Etc/MACHINES: Danek Duvall reports --enable-dynamic OK
+	  on Solaris 2.7, despite previous reports; Sven says on Digital
+	  UNIX 4.0, you need special DLLD and LDFLAGS.
+
 1999-06-08  Peter Stephenson  <pws@ibmth.difi.unipi.it>
 
+	* pws: 6525: Src/lex.c (gettokstr): allow parentheses after
+	  first character in command word
+
+	* Tanaka Akira: 6522: configure.in: help string for --enable-fndir
+	  had wrong default directory
+
+	* pws: 6520: configure.in: --enable-fndir might be yes,
+	  so turn it into ${datadir}/zsh/functions
+
 	* 3.1.5-pws-21 made available
 
 	* Sven: 6515: Src/Zle/zle_tricky.c: fix memory problems with 6492
@@ -38,7 +215,7 @@
 	  `compctl -h' takes a command line from inside a quoted string;
 	  the compctl tests q[s], q[d], q[b] are true if we are in single,
 	  double, back quotes; compset -q tests quotes and splits the word,
-	  affecting $PREFIX, $SUFFX and setting $IQPREFIX, $IQSUFFIX for
+	  affecting $PREFIX, $SUFFIX and setting $IQPREFIX, $IQSUFFIX for
 	  the bits which will now be ignored.
 
 	* pws: 6490: Completion/Core/compinit: nounset workaround
diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter
index f688e175a..5993aecba 100644
--- a/Completion/Base/_brace_parameter
+++ b/Completion/Base/_brace_parameter
@@ -16,4 +16,6 @@ ls="$RBUFFER[${#SUFFIX}+1,-1]"
 n=${(M)#ls##\"#}
 q=${(M)lp%%\"#}
 
+[[ n -gt 0 ]] && suf=''
+
 _parameters -s "${q[1,-n-1]}" -S "$suf" -r '-:?#%+=[/'
diff --git a/Completion/Base/_vars b/Completion/Base/_vars
index f06562694..a40df7699 100644
--- a/Completion/Base/_vars
+++ b/Completion/Base/_vars
@@ -1,3 +1,20 @@
 #compdef getopts read unset vared
 
-compgen -v
+# This will handle completion of keys of associative arrays, e.g. at
+# `vared compconfig[<TAB>'.  However, in this version the [ must be
+# added by hand.
+
+if [[ $PREFIX = *\[* ]]; then
+  local var=${PREFIX%%\[*}
+  local elt="${PREFIX#*\]}${SUFFIX%\]}"
+  local addclose
+  compset -p $(( ${#var} + 1 ))
+  if ! compset -S \]; then
+    addclose=(-S ']')
+  fi
+  if [[ ${(tP)var} = assoc* ]]; then
+    compadd $addclose - ${(kP)var}
+  fi
+else
+  compgen -v
+fi
diff --git a/Completion/Builtins/_jobs b/Completion/Builtins/_jobs
index bce005b4e..9e2da24c6 100644
--- a/Completion/Builtins/_jobs
+++ b/Completion/Builtins/_jobs
@@ -1,3 +1,3 @@
-#compdef fg jobs
+#compdef disown fg jobs
 
 compgen -j -P '%'
diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill
index 979c87804..4f8c1db6d 100644
--- a/Completion/Builtins/_kill
+++ b/Completion/Builtins/_kill
@@ -9,7 +9,8 @@ else
 
   compgen -P '%' -j && ret=0
   list=("$(ps 2>/dev/null)")
-  compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`' && ret=0
+  compgen -y '$list' -s '${${${(f)"$(ps 2>/dev/null)"}[2,-1]## #}%% *}' && 
+    ret=0
 
   return ret
 fi
diff --git a/Completion/Builtins/_limits b/Completion/Builtins/_limits
index be5c35593..6835a6244 100644
--- a/Completion/Builtins/_limits
+++ b/Completion/Builtins/_limits
@@ -1,3 +1,3 @@
 #compdef limit unlimit
 
-compgen -k "(${(j: :)${(f)$(limit)}%% *})"
+compgen -s '${${(f)"$(limit)"}%% *}'
diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait
index 0fadc087b..41d09c9b2 100644
--- a/Completion/Builtins/_wait
+++ b/Completion/Builtins/_wait
@@ -4,6 +4,6 @@ local list ret=1
 
 compgen -P '%' -j && ret=0
 list=("$(ps 2>/dev/null)")
-compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`' && ret=0
+compgen -y '$list' -s '${${${(f)"$(ps 2>/dev/null)"}[2,-1]## #}%% *}' && ret=0
 
 return ret
diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp
index 71404fb2b..8792e21a7 100644
--- a/Completion/Builtins/_zftp
+++ b/Completion/Builtins/_zftp
@@ -43,6 +43,19 @@ case $subcom in
   compgen -k hosts
   ;;
 
+  *(goto|mark))
+  # complete bookmarks.  First decide if ncftp mode is go.
+  if [[ $words[2] = -*n* ]]; then
+    if [[ -f ~/.ncftp/bookmarks ]]; then
+      compadd - $(awk -F, 'NR > 2 { print $1 }' ~/.ncftp/bookmarks)
+    fi
+  else
+    if [[ -f ${ZFTP_BMFILE:=${ZDOTDIR:-$HOME}/.zfbkmarks} ]]; then
+      compadd - $(awk '{print $1}' $ZFTP_BMFILE)
+    fi
+  fi
+  ;;
+
   *)
   # dunno... try ordinary completion after all.
   unset _compskip
diff --git a/Completion/Core/_normal b/Completion/Core/_normal
index ed7243bb1..ba7f2123f 100644
--- a/Completion/Core/_normal
+++ b/Completion/Core/_normal
@@ -20,7 +20,7 @@ elif [[ "$command" == */* ]]; then
   cmd2="${command:t}"
 else
   cmd1="$command"
-  eval cmd2=$(whence -p $command)
+  cmd2=$(whence -p $command)
 fi
 
 # See if there are any matching pattern completions.
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 332aba017..d0d1c6a0a 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -231,7 +231,7 @@ for prepath in "$prepaths[@]"; do
       # See which of them match what's on the line.
 
       tmp2=("$tmp1[@]")
-      compadd -D tmp1 "$ignore[@]" - "${(@)tmp1##*/}"
+      compadd -D tmp1 "$ignore[@]" - "${(@)tmp1:t}"
 
       # If no file matches, save the expanded path and continue with
       # the outer loop.
@@ -240,7 +240,7 @@ for prepath in "$prepaths[@]"; do
  	if [[ "$tmp2[1]" = */* ]]; then
 	  tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
 	  if [[ "$tmp2[1]" = */* ]]; then
-	    exppaths=( "$exppaths[@]" ${^tmp2%/*}/${tpre}${tsuf} )
+	    exppaths=( "$exppaths[@]" ${^tmp2:h}/${tpre}${tsuf} )
           else
 	    exppaths=( "$exppaths[@]" ${tpre}${tsuf} )
 	  fi
diff --git a/Completion/Core/compdump b/Completion/Core/compdump
index 8288ccdd4..5ee04e028 100644
--- a/Completion/Core/compdump
+++ b/Completion/Core/compdump
@@ -74,7 +74,7 @@ done))
 # print them out:  about five to a line looks neat
 
 while (( $#_d_als )); do
-  print -n autoload
+  print -n autoload -U
   for (( _i = 0; _i < 5; _i++ )); do
     if (( $#_d_als )); then
       print -n " $_d_als[1]"
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index af2467bec..23bc94cf9 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -194,7 +194,7 @@ compdef() {
     # and probably do autoloading.
 
     func="$1"
-    [[ -n "$autol" ]] && autoload "$func"
+    [[ -n "$autol" ]] && autoload -U "$func"
     shift
 
     case "$type" in
@@ -363,7 +363,7 @@ if [[ -z "$_i_done" ]]; then
 	fi
 	;;
       (\#autoload)
-	autoload ${_i_file:t}
+	autoload -U ${_i_file:t}
 	;;
       esac
     done
diff --git a/Completion/Makefile.in b/Completion/Makefile.in
index 8b7776a7f..0ac4de304 100644
--- a/Completion/Makefile.in
+++ b/Completion/Makefile.in
@@ -55,7 +55,14 @@ install.fns:
 	  $(sdir_top)/mkinstalldirs $(fndir) || exit 1; \
 	  for file in $(FUNCTIONS_INSTALL); do \
 	    if test -f $$file; then \
-	      $(INSTALL_DATA) $$file $(fndir) || exit 1; \
+	      if test x$(FUNCTIONS_SUBDIRS) != x -a \
+	      x$(FUNCTIONS_SUBDIRS) != xno; then \
+	        subdir="`echo $$file | sed -e 's%/.*%%'`"; \
+	        $(sdir_top)/mkinstalldirs $(fndir)/$$subdir || exit 1; \
+	        $(INSTALL_DATA) $$file $(fndir)/$$subdir || exit 1; \
+	      else \
+	        $(INSTALL_DATA) $$file $(fndir) || exit 1; \
+	      fi; \
 	    fi; \
 	  done; \
 	fi; \
@@ -65,7 +72,12 @@ uninstall.fns:
 	if test x$(fndir) != x && test x$(fndir) != xno; then \
 	  for file in $(FUNCTIONS_INSTALL); do \
 	    if test -f $$file; then \
-	      rm -f "$(fndir)/`echo $$file | sed -e 's%^.*/%%'`"; \
+	      if test x$(FUNCTIONS_SUBDIRS) != x -a \
+              x$(FUNCTIONS_SUBDIRS) != xno; then \
+	        rm -f $(fndir)/$$file; \
+	      else \
+	        rm -f "$(fndir)/`echo $$file | sed -e 's%^.*/%%'`"; \
+	      fi; \
 	    fi; \
 	  done; \
 	fi; \
diff --git a/Config/defs.mk.in b/Config/defs.mk.in
index 27c9aea99..bbc42b236 100644
--- a/Config/defs.mk.in
+++ b/Config/defs.mk.in
@@ -68,6 +68,7 @@ INSTALL_DATA    = @INSTALL_DATA@
 
 # variables used in determining what to install
 FUNCTIONS_INSTALL = @FUNCTIONS_INSTALL@
+FUNCTIONS_SUBDIRS = @FUNCTIONS_SUBDIRS@
 
 # flags passed to recursive makes in subdirectories
 MAKEDEFS = \
diff --git a/Config/version.mk b/Config/version.mk
index 3e6726141..21d3d6e24 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-21
-VERSION_DATE='June 6, 1999'
+VERSION=3.1.5-pws-22
+VERSION_DATE='June 13, 1999'
diff --git a/Doc/Makefile.in b/Doc/Makefile.in
index c0ae8d80d..83bba17f8 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -57,7 +57,7 @@ Zsh/filelist.yo Zsh/files.yo Zsh/func.yo Zsh/grammar.yo Zsh/guide.yo \
 Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \
 Zsh/modules.yo Zsh/mod_cap.yo Zsh/compwid.yo Zsh/compsys.yo \
 Zsh/mod_clone.yo Zsh/mod_comp1.yo Zsh/mod_compctl.yo Zsh/mod_deltochar.yo \
-Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_stat.yo \
+Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_mapfile.yo Zsh/mod_stat.yo \
 Zsh/mod_zle.yo Zsh/options.yo \
 Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo Zsh/restricted.yo \
 Zsh/seealso.yo Zsh/zftpsys.yo Zsh/zle.yo
@@ -132,8 +132,8 @@ zshmisc.1: Zsh/grammar.yo Zsh/redirect.yo Zsh/exec.yo Zsh/func.yo \
 
 zshmodules.1: Zsh/modules.yo Zsh/mod_cap.yo Zsh/mod_clone.yo \
               Zsh/mod_comp1.yo Zsh/mod_compctl.yo Zsh/mod_deltochar.yo \
-              Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_sched.yo \
-              Zsh/mod_stat.yo Zsh/mod_zftp.yo Zsh/mod_zle.yo
+              Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_mapfile.yo \
+              Zsh/mod_sched.yo Zsh/mod_stat.yo Zsh/mod_zftp.yo Zsh/mod_zle.yo
 
 zshoptions.1: Zsh/options.yo
 
diff --git a/Doc/Zsh/arith.yo b/Doc/Zsh/arith.yo
index f08deb372..f22b35794 100644
--- a/Doc/Zsh/arith.yo
+++ b/Doc/Zsh/arith.yo
@@ -5,16 +5,42 @@ sect(Arithmetic Evaluation)
 )\
 cindex(arithmetic evaluation)
 cindex(evaluation, arithmetic)
-An ability to perform integer arithmetic is provided with the builtin tt(let).
 findex(let, use of)
-Evaluations are performed using em(long) arithmetic.
+The shell can perform integer arithmetic, either using the builtin tt(let),
+or via a substitution of the form tt($((...))).  Usually arithmetic is
+performed with em(long) integers; however, on certain systems where a
+em(long) has 4-byte precision, zsh may be compiled to use 8-byte precision
+instead.  This can be tested, for example, by giving the command
+`tt(print - $(( 12345678901 )))'; if the number appears unchanged, the
+precision is at least 8 bytes.
+
+The tt(let) builtin command takes arithmetic expressions as arguments; each
+is evaluated separately.  Since many of the arithmetic operators, as well
+as spaces, require quoting, an alternative form is provided: for any
+command which begins with a `tt(LPAR()LPAR())', all the characters until a
+matching `tt(RPAR()RPAR())' are treated as a quoted expression and
+arithmetic expansion performed as for an argument of tt(let).  More
+precisely, `tt(LPAR()LPAR())var(...)tt(RPAR()RPAR())' is equivalent to
+`tt(let ")var(...)tt(")'.  For example, the following statement
+
+example((( val = 2 + 1 )))
+
+is equivalent to
+
+example(let "val = 2 + 1")
+
+both assigning the value 3 to the shell variable tt(foo) and returning a
+zero status.
+
+cindex(bases, in arithmetic)
+Numbers can be in bases other than 10.
 A leading `tt(0x)' or `tt(0X)' denotes hexadecimal.
-Otherwise, numbers are of the form `[var(base)tt(#)]var(n)',
+Numbers may also be of the form `var(base)tt(#)var(n)',
 where var(base) is a decimal number between two and thirty-six
 representing the arithmetic base and var(n)
 is a number in that base (for example, `tt(16#ff)' is 255 in hexadecimal).
-If var(base) is omitted
-then base 10 is used.  For backwards compatibility the form
+The var(base)tt(#) may also be omitted, in which case
+base 10 is used.  For backwards compatibility the form
 `tt([)var(base)tt(])var(n)' is also accepted.
 
 cindex(arithmetic operators)
@@ -50,10 +76,17 @@ and XOR operators.
 An expression of the form `tt(#\)var(x)' where var(x) is any character
 gives the ascii value of this character and an expression of the form
 `tt(#)var(foo)' gives the ascii value of the first character of the value
+of the parameter var(foo).  Note that this is different from the expression
+`tt($#)var(foo)', a standard parameter substitution which gives the length
 of the parameter var(foo).
 
 Named parameters and subscripted arrays can be referenced by name within an
-arithmetic expression without using the parameter expansion syntax.
+arithmetic expression without using the parameter expansion syntax.  For
+example,
+
+example((((val2 = val1 * 2))))
+
+assigns twice the value of tt($val1) to the parameter named tt(val2).
 
 An internal integer representation of a named parameter
 can be specified with the tt(integer) builtin.
@@ -63,11 +96,3 @@ findex(integer, use of)
 Arithmetic evaluation is performed on the value of each
 assignment to a named parameter declared integer
 in this manner.
-
-Since many of the arithmetic operators require
-quoting, an alternative form of the tt(let) command is provided.
-For any command which begins with a tt(LPAR()LPAR()),
-all the characters until a matching tt(RPAR()RPAR())
-are treated as a quoted expression.
-More precisely, `tt(LPAR()LPAR()) ... tt(RPAR()RPAR())'
-is equivalent to `tt(let ")...tt(")'.
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 157b3420d..49c9dc26c 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -981,12 +981,13 @@ shown.
 )
 item(tt(-f))(
 The names refer to functions rather than parameters.  No assignments
-can be made, and the only other valid flags are tt(-t)
-and tt(-u).  The flag tt(-t) turns on execution tracing for this
-function.  The flag tt(-u) causes this function to be marked
-for autoloading.  The tt(fpath) parameter will be searched to find the
-function definition when the function is first referenced; see
-noderef(Functions).
+can be made, and the only other valid flags are tt(-t), tt(-u) and
+tt(-U).  The flag tt(-t) turns on execution tracing for this
+function.  The tt(-u) and tt(-U) flags cause the function to be
+marked for autoloading; tt(-U) also causes alias expansion to be
+suppressed when the function is loaded.  The tt(fpath) parameter
+will be searched to find the function definition when the function
+is first referenced; see noderef(Functions).
 )
 item(tt(-i))(
 Use an internal integer representation.  If var(n) is nonzero it
diff --git a/Doc/Zsh/compctl.yo b/Doc/Zsh/compctl.yo
index 4fecce92f..48c7bf629 100644
--- a/Doc/Zsh/compctl.yo
+++ b/Doc/Zsh/compctl.yo
@@ -1,5 +1,5 @@
-texinode(Programmable Completion)(Completion Widgets)(Zsh Line Editor)(Top)
-chapter(Programmable Completion)
+texinode(Programmable Completion Using compctl)(Completion Widgets)(Zsh Line Editor)(Top)
+chapter(Programmable Completion Using compctl)
 cindex(completion, programmable)
 cindex(completion, controlling)
 findex(compctl)
@@ -33,7 +33,7 @@ menu(Matching Control)
 menu(Example)
 endmenu()
 
-texinode(Command Flags)(Option Flags)()(Programmable Completion)
+texinode(Command Flags)(Option Flags)()(Programmable Completion Using compctl)
 sect(Command Flags)
 Completion of the arguments of a command may be different for each
 command or may use the default.  The behavior when completing the
@@ -56,7 +56,7 @@ from immediate expansion; for example the command string tt('foo*')
 arranges for completion of the words of any command beginning with
 tt(foo).  When completion is attempted, all pattern completions are
 tried in the reverse order of their definition until one matches.  By
-default, completion then procedes as normal, i.e. the shell will try to
+default, completion then proceeds as normal, i.e. the shell will try to
 generate more matches for the specific command on the command line; this
 can be overridden by including tt(-tn) in the flags for the pattern
 completion.
@@ -88,9 +88,7 @@ the standard behavior for all commands.  For example, if your access
 to the user database is too slow and/or it contains too many users (so
 that completion after `tt(~)' is too slow to be usable), you can use
 
-indent(
-tt(compctl -T -x 's[~] C[0,[^/]#]' -k friends -S/ -tn)
-)
+example(compctl -T -x 's[~] C[0,[^/]#]' -k friends -S/ -tn)
 
 to complete the strings in the array tt(friends) after a `tt(~)'.
 The tt(C[...]) argument is necessary so that this form of ~-completion is
@@ -118,7 +116,7 @@ options specified by the tt(-D) flag.
 The form with tt(-M) as the first and only option defines global
 matching specifications, as described below in noderef(Matching Control).
 
-texinode(Option Flags)(Alternative Completion)(Command Flags)(Programmable Completion)
+texinode(Option Flags)(Alternative Completion)(Command Flags)(Programmable Completion Using compctl)
 sect(Option Flags)
 startlist()
 list([ tt(-fcFBdeaRGovNAIOPZEnbjrzu/) ])
@@ -256,10 +254,8 @@ of space- or comma-separated values in parentheses, in which any
 delimiter may be escaped with a backslash; in this case the argument
 should be quoted.  For example,
 
-indent(
-nofill(tt(compctl -k "(cputime filesize datasize stacksize
-	       coredumpsize resident descriptors)" limit))
-)
+example(compctl -k "(cputime filesize datasize stacksize
+	       coredumpsize resident descriptors)" limit)
 )
 item(tt(-g) var(globstring))(
 The var(globstring) is expanded using filename globbing; it should be
@@ -281,7 +277,7 @@ resulting files.  Note that tt(-g) is faster for filenames.
 )
 item(tt(-K) var(function))(
 Call the given function to get the completions.  Unless the name
-starts with an underscode, the function is
+starts with an underscore, 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
@@ -293,10 +289,8 @@ should not be made local to the function.  From such a function the
 command line can be accessed with the tt(-c) and tt(-l) flags to
 the tt(read) builtin.  For example,
 
-indent(
-nofill(tt(function whoson { reply=(`users`); }
-compctl -K whoson talk))
-)
+example(function whoson { reply=(`users`); }
+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.
@@ -315,9 +309,7 @@ zero or negative the whole history is searched and if var(pattern) is
 the empty string all words are taken (as with `tt(*)').  A typical
 use is
 
-indent(
-tt(compctl -D -f PLUS() -H 0 '')
-)
+example(compctl -D -f PLUS() -H 0 '')
 
 which forces completion to look back in the history list for a word if
 no filename matches.
@@ -345,9 +337,7 @@ The var(prefix) is inserted just before the completed string; any
 initial part already typed will be completed and the whole var(prefix)
 ignored for completion purposes.  For example,
 
-indent(
-tt(compctl -j -P "%" kill)
-)
+example(compctl -j -P "%" kill)
 
 inserts a `%' after the kill command and then completes job names.
 )
@@ -362,9 +352,7 @@ With directory var(file-prefix):  for command, file, directory and
 globbing completion (options tt(-c), tt(-f), tt(-/), tt(-g)), the file
 prefix is implicitly added in front of the completion.  For example,
 
-indent(
-tt(compctl -/ -W ~/Mail maildirs)
-)
+example(compctl -/ -W ~/Mail maildirs)
 
 completes any subdirectories to any depth beneath the directory
 tt(~/Mail), although that prefix does not appear on the command line.
@@ -393,9 +381,7 @@ option. If the var(cmd) string is empty the first word in the range
 is instead taken as the command name, and command name completion
 performed on the first word in the range.  For example,
 
-indent(
-tt(compctl -x 'r[-exec,;]' -l '' -- find)
-)
+example(compctl -x 'r[-exec,;]' -l '' -- find)
 
 completes arguments between `tt(-exec)' and the following `tt(;)' (or the end
 of the command line if there is no such string) as if they were
@@ -419,7 +405,7 @@ tt(-K) option) which can examine the word components passed to it
 use its own criteria to decide what matches.  If there is no
 completion, the original word is retained.  Since the produced 
 possible completions seldom seldom have interesting common prefixes
-and suffixes, menucompletion is started immediatly if tt(AUTO_MENU) is
+and suffixes, menucompletion is started immediately if tt(AUTO_MENU) is
 set and this flag is used.
 )
 item(tt(-y) var(func-or-var))(
@@ -499,9 +485,7 @@ group name are stored in that group.
 This can be useful with non-exclusive alternative completions.  For
 example, in
 
-indent(
-tt(compctl -f -J files -t+ + -v -J variables foo)
-)
+example(compctl -f -J files -t+ + -v -J variables foo)
 
 both files and variables are possible completions, as the tt(-t+) forces
 both sets of alternatives before and after the tt(+) to be considered at
@@ -521,7 +505,7 @@ of the var(match-spec) string is described below in noderef(Matching Control).
 )
 enditem()
 
-texinode(Alternative Completion)(Extended Completion)(Option Flags)(Programmable Completion)
+texinode(Alternative Completion)(Extended Completion)(Option Flags)(Programmable Completion Using compctl)
 sect(Alternative Completion)
 startlist()
 list(tt(compctl) [ tt(-CDT) ] var(options) tt(PLUS()) var(options) [ tt(PLUS()) ... ] \
@@ -536,7 +520,7 @@ up to that point, default completion is tried.
 If the list of flags contains a tt(-t) with a tt(PLUS()) character, the next
 list of flags is used even if the current list produced matches.
 
-texinode(Extended Completion)(Matching Control)(Alternative Completion)(Programmable Completion)
+texinode(Extended Completion)(Matching Control)(Alternative Completion)(Programmable Completion Using compctl)
 sect(Extended Completion)
 startlist()
 list(nofill(tt(compctl) [ tt(-CDT) ] var(options) \
@@ -612,9 +596,7 @@ considered part of the completion, but the rest will.  var(index) may
 be negative to count from the end: in most cases, var(index) will be
 1 or -1.  For example,
 
-indent(
-tt(compctl -s '`users`' -x 'n[1,@]' -k hosts -- talk)
-)
+example(compctl -s '`users`' -x 'n[1,@]' -k hosts -- talk)
 
 will usually complete usernames, but if you insert an tt(@) after the
 name, names from the array var(hosts) (assumed to contain hostnames,
@@ -648,7 +630,7 @@ completion is done in backticks and var(str) starts with a `b'.
 )
 enditem()
 
-texinode(Matching Control)(Example)(Extended Completion)(Programmable Completion)
+texinode(Matching Control)(Example)(Extended Completion)(Programmable Completion Using compctl)
 sect(Matching Control)
 
 It is possible by use of the tt(-M) var(spec) flag to specify how the
@@ -732,10 +714,10 @@ following alters the matching rules so that the prefix tt(no) and any
 underscore are ignored when trying to match the trial completions
 generated and uppercase letters on the line match the corresponding
 lowercase letters in the words:
-indent(
-nofill(tt(compctl -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ 
-  -o setopt unsetopt))
-)
+
+example(compctl -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ 
+  -o setopt unsetopt)
+
 The first part says that the pattern `tt([nN][oO])' at the beginning
 (the empty anchor before the pipe symbol) of the string on the
 line matches the empty string in the list of words generated by
@@ -752,14 +734,13 @@ The second example makes completion case insensitive.  By using
 tt(compctl) with the tt(-M) option alone this applies to every
 completion.  This is just the same as in the tt(setopt) example, except
 here we wish to retain the characters in the list of completions:
-indent(
-tt(compctl -M 'm:{a-z}={A-Z}')
-)
+
+example(compctl -M 'm:{a-z}={A-Z}')
+
 This makes lowercase letters match their uppercase counterparts.
 To make uppercase letters match the lowercase forms as well:
-indent(
-tt(compctl -M 'm:{a-zA-Z}={A-Za-z}')
-)
+
+example(compctl -M 'm:{a-zA-Z}={A-Za-z}')
 
 A nice example for the use of tt(*) patterns is partial word
 completion. Sometimes you would like to make strings like tt(c.s.u)
@@ -770,10 +751,10 @@ however, that the case where each part of the word, i.e. tt(comp),
 tt(source) and tt(unix) in this example, is to be completed separately
 is a different problem to be solved by extended completion.  The
 example can be handled by:
-indent(
-nofill(tt(compctl -M 'r:|.=* r:|=*' \ 
-  -k '(comp.sources.unix comp.sources.misc ...)' ngroups))
-)
+
+example(compctl -M 'r:|.=* r:|=*' \ 
+  -k '(comp.sources.unix comp.sources.misc ...)' ngroups)
+
 The first specification says that tt(lpat) is the empty string, while
 tt(anchor) is a dot; tt(tpat) is tt(*), so this can match anything
 except for the `tt(.)' from the anchor in
@@ -795,9 +776,9 @@ empty string at the end of the string on the line matches any characters
 at the end of the trial completion.
 
 More generally, the specification
-indent(
-tt(compctl -M 'r:|[.,_-]=* r:|=*')
-)
+
+example(compctl -M 'r:|[.,_-]=* r:|=*')
+
 allows one to complete words with abbreviations before any of the
 characters in the square brackets in any completion.  For example, to
 complete tt(veryverylongfile.c) rather than tt(veryverylongheader.h)
@@ -817,9 +798,9 @@ the string on the command line as a substring, not just at the
 beginning.  Since this might produce more matches than we want,
 we arrange for it to be tried only if the matchers described above don't
 produce any matches:
-indent(
-tt(compctl -M 'r:|[.,_-]=* r:|=*' 'l:|=* r:|=*')
-)
+
+example(compctl -M 'r:|[.,_-]=* r:|=*' 'l:|=* r:|=*')
+
 Here, if the string on the command line is tt(foo.bar), tt(compctl)
 first tries matching tt(foo)var(anything)tt(.bar)var(anything), as
 with the previous example.  If that fails, the two descriptions in the
@@ -828,13 +809,12 @@ and end of the string on the command line can match any set of
 characters at the beginning or end of the trial completion, so it will
 look for var(anything)tt(foo.bar)var(anything).
 
-texinode(Example)()(Matching Control)(Programmable Completion)
+texinode(Example)()(Matching Control)(Programmable Completion Using compctl)
 sect(Example)
-indent(
-nofill(
-tt(compctl -u -x 's[tt(PLUS())] c[-1,-f],s[-f+PLUS()]' \ 
-  -g '~/Mail/*(:t)' - 's[-f],c[-1,-f]' -f -- mail))
-)
+
+example(compctl -u -x 's[tt(PLUS())] c[-1,-f],s[-f+PLUS()]' \ 
+  -g '~/Mail/*(:t)' - 's[-f],c[-1,-f]' -f -- mail)
+
 This is to be interpreted as follows:
 
 If the current command is tt(mail), then
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 94533415e..572660de3 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -51,7 +51,7 @@ sect(Initialisation)
 
 The script tt(compinstall) can be run by a user to set up the completion
 system for use.  It will usually insert code into tt(.zshrc), although if
-that is not writeable it will save it in another file and tell you that
+that is not writable it will save it in another file and tell you that
 file's locations.  Note that it is up to you to make sure that the lines
 added to tt(.zshrc) are actually run; you may, for example, need to move
 them to an earlier place in the file if tt(.zshrc) usually returns early.
@@ -89,13 +89,13 @@ To speed up the running of tt(compinit), it can be made to produce a dumped
 configuration which will be read in on future invocations.  The easiest way
 to do this is by adding the option tt(-d) whenever tt(compinit) is sourced.
 In this case the dumped file will have the same name as the sourced file,
-but with tt(.dump) appended to the end, or, if that is not writeable by the
+but with tt(.dump) appended to the end, or, if that is not writable by the
 user, the file tt(.zcompdump) in the same directory as the startup files
 (i.e. tt($ZDOTDIR) or tt($HOME)); alternatively, an explicit file name can
 be given following the tt(-d).  On the next call to tt(compinit -d), the
 dumped file will be read instead.
 
-The other option accepted by tt(compinit) is tt(-f var(dir)), which gives
+The other option accepted by tt(compinit) is tt(-f )var(dir), which gives
 the directory in which tt(compinit) resides.  If you source tt(compinit) by
 its full pathname, and the option tt(FUNCTION_ARGZERO) is set, as it is by
 default unless tt(zsh) is emulating tt(sh) or tt(ksh), this is unnecessary
@@ -106,7 +106,7 @@ the completion functions (see below).
 
 If the number of completion files changes, tt(compinit) will recognise this
 and produce a new dump file.  However, if the name of a function or the
-arguments in the first line of a tt(#compdef) funcion (as described below)
+arguments in the first line of a tt(#compdef) function (as described below)
 change, it is easiest to delete the dump file by hand so that the next time
 tt(compinit) will re-create it.
 
@@ -153,7 +153,7 @@ var(pattern) (a standard globbing pattern).  Note that only one
 var(pattern) may be given.
 )
 item(tt(#compdef -k) var(style key-sequences...))(
-This can be used bind special completion functions to the
+This can be used to bind special completion functions to the
 var(key-sequences).  It creates a widget behaving like the builtin widget
 var(style), which must be one of those that perform completion, namely
 tt(complete-word), tt(delete-char-or-list), tt(expand-or-complete),
@@ -252,9 +252,7 @@ set of functions to try is taken from the colon-separated list in the
 configuration key tt(completer). For example, to use normal
 completion and correction if that doesn't generate any matches:
 
-indent(
-nofill(tt(compconf completer=_complete:_correct))
-)
+example(compconf completer=_complete:_correct)
 
 after sourcing tt(compinit). The default value for this configuration key
 set up in tt(compinit) is `tt(_complete)', i.e. normally only ordinary
@@ -355,9 +353,7 @@ counted. The resulting list of corrected and completed strings is then
 presented to the user. The intended use of this completer function is to
 try after the normal tt(_complete) completer by setting:
 
-indent(
-nofill(tt(compconf completer=_complete:_approximate))
-)
+example(compconf completer=_complete:_approximate)
 
 This will give correcting completion if and only if
 normal completion doesn't yield any possible completions. When
@@ -379,9 +375,7 @@ If the value for this key contains a lower- or upper-case `tt(n)', the
 completer function will take any numeric argument as the
 maximum number of errors allowed. For example, with
 
-indent(
-nofill(tt(compconf approximate_accept=2n))
-)
+example(compconf approximate_accept=2n)
 
 two errors will be allowed if no numeric argument is given. However,
 with a numeric argument of six (as in `tt(ESC-6 TAB)'), up to six
@@ -443,10 +437,8 @@ configuration parameters beginning tt(correct_) are used.
 
 For example, with:
 
-indent(tt(
-nofill(compconf completer=_complete:_correct:_approximate)
-nofill(compconf correct_accept='2n!' approximate_accept=3n))
-)
+example(compconf completer=_complete:_correct:_approximate
+compconf correct_accept='2n!' approximate_accept=3n)
 
 correction will accept up to two errors. If a numeric argument is
 given, correction will not be performed, but correcting completion will be,
@@ -464,7 +456,7 @@ generated by the tt(_correct) completer -- and probably more.
 item(tt(_match))(
 This completer is intended to be used after the tt(_complete)
 completer. It allows one to give patterns on the command line and
-to complete all strings metching these patterns from the set of possible
+to complete all strings matching these patterns from the set of possible
 completions for the context the cursor is in, without having to set
 the tt(GLOB_COMPLETE) option.
 
@@ -498,9 +490,7 @@ non-empty string it should be an expression usable inside a `tt($((...)))'
 arithmetical expression. In this case, expansion of substitutions will
 be done if the expression evaluates to `tt(1)'. For example, with
 
-indent(
-nofill(tt(compconf expand_substitute='NUMERIC != 1'))
-)
+example(compconf expand_substitute='NUMERIC != 1')
 
 substitution will be performed only if given an explicit numeric
 argument other than `tt(1)', as by typing `tt(ESC 2 TAB)'.
@@ -556,9 +546,7 @@ should be set to an expression usable inside a `tt($((...)))'
 arithmetical expression. In this case, delaying will be done if the
 expression evaluates to `tt(1)'. For example, with
 
-indent(
-nofill(tt(compconf list_condition='NUMERIC != 1'))
-)
+example(compconf list_condition='NUMERIC != 1')
 
 delaying will be done only if given an explicit numeric argument
 other than `tt(1)'.
@@ -614,6 +602,7 @@ continues with the existing list of completions.  If this key is set to
 tt(never), however, a new completion is started if the old list was
 generated by a different completion command (the behaviour without the
 tt(_oldlist) completer).
+
 For example, suppose you type tt(^Xc) to generate a list of corrections,
 and menu completion is started in one of the usual ways.  Usually, typing
 tt(TAB) at this point would start trying to complete the line as it now
@@ -704,7 +693,7 @@ over which filenames should be ignored as done by the tt(fignore)
 parameter in normal completion.
 
 The function tt(_files) calls tt(_path_files) with all the arguments
-it was passed and, if that generated no matches, call tt(_path_files) again
+it was passed and, if that generated no matches, calls tt(_path_files) again
 without any tt(-g) or tt(-/) option, thus generating all filenames.
 
 These functions also accept the `tt(-J)', `tt(-V)', `tt(-X)', `tt(-P)',
@@ -764,11 +753,9 @@ not start with a square bracket or parenthesis, it should be the name of a
 command (probably with arguments) that should be invoked to complete 
 after the equal sign. Example:
 
-indent(
-nofill(tt(_long_options '*\*'     '(yes no)' \))
-nofill(tt(              '*=FILE*' '_files' \))
-nofill(tt(              '*=DIR*'  '_files -/'))
-)
+example(_long_options '*\*'     '(yes no)' \ 
+              '*=FILE*' '_files' \ 
+              '*=DIR*'  '_files -/')
 
 Here, `tt(yes)' and `tt(no)' will be completed as the argument of
 options whose description ends in a star, file names for options that
diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo
index d30adc0f1..7f5ffe442 100644
--- a/Doc/Zsh/compwid.yo
+++ b/Doc/Zsh/compwid.yo
@@ -1,4 +1,4 @@
-texinode(Completion Widgets)(Zsh Modules)(Programmable Completion)(Top)
+texinode(Completion Widgets)(Zsh Modules)(Programmable Completion Using compctl)(Top)
 chapter(Completion Widgets)
 cindex(completion, widgets)
 cindex(completion, programmable)
@@ -10,9 +10,7 @@ ifzman(zmanref(zshzle))\
 ifnzman(noderef(The zle Module))\
 ). For example,
 
-indent(
-nofill(tt(zle -C complete expand-or-complete completer))
-)
+example(zle -C complete expand-or-complete completer)
 
 defines a widget named tt(complete). When this widget is bound to a key
 using the tt(bindkey) builtin command defined in the tt(zle) module
@@ -73,10 +71,8 @@ not considered part of the list of matches.  Typically, a string is
 transferred from the beginning of tt(PREFIX) to the end of tt(IPREFIX), for
 example:
 
-tt(indent(
-nofill(IPREFIX=${PREFIX%%\=*}=)
-nofill(PREFIX=${PREFIX#*=})
-))
+example(IPREFIX=${PREFIX%%\=*}=
+PREFIX=${PREFIX#*=})
 
 causes the part of the prefix up to and including the first equal sign not
 to be treated as part of a matched string.
@@ -182,9 +178,7 @@ item(tt(matcher))(
 When completion is performed with a global match specification as defined
 by
 
-indent(
-nofill(tt(compctl -M) var(spec1 ... specN ...))
-)
+indent(tt(compctl -M) var(spec1 ... specN ...))
 
 this gives the number of the specification string currently in use.
 In this case, matching is performed with each specification in turn.
@@ -229,7 +223,7 @@ the tt(ALWAYS_LAST_PROMPT) option.
 )
 item(tt(insert))(
 This controls the manner in which a match is inserted into the command
-line.  On entry to the widget fuction, if it is unset the command line is
+line.  On entry to the widget function, if it is unset the command line is
 not to be changed; if set to tt(unambiguous), any prefix common to all
 matches is to be inserted; if set to tt(menu) or tt(automenu) the usual
 behaviour of the tt(MENU_COMPLETE) or tt(AUTO_MENU) options, respectively,
@@ -262,7 +256,7 @@ item(tt(old_list))(
 This is set to tt(yes) if there is still a valid list of completions
 from a previous completion at the time the widget is invoked.  This will
 usually be the case if and only if the previous editing operation was a
-completion widget or one of the builtin completion fuctions.  If there is a
+completion widget or one of the builtin completion functions.  If there is a
 valid list and it is also currently shown on the screen, the value of this
 key is tt(shown).
 
@@ -330,7 +324,7 @@ Generate matches according to the given var(flags).  These can be any of
 the normal option flags (not those for extended completion) supported by
 the tt(compctl) builtin command (see
 ifzman(zmanref(zshcompctl))\
-ifnzman(noderef(Programmable Completion))\
+ifnzman(noderef(Programmable Completion Using compctl))\
 ) except for the tt(-t) and tt(-l) flags.  However, when using the tt(-K)
 flag, the function given as argument to it cannot access the command
 line with the tt(read) builtin command.
@@ -339,7 +333,7 @@ The matches will be generated in the same way as if the completion code
 generated them directly from a tt(compctl)-definition with the same
 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
+parameters described 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(compgen) and the
 global matching specifications given via the tt(compctl -M )var(spec1 ...)
@@ -366,9 +360,7 @@ non-zero if no matches were added.
 The completion code breaks the string to complete into seven fields in
 the order: 
 
-indent(
-var(<ipre><apre><hpre><word><hsuf><asuf><isuf>)
-)
+indent(var(<ipre><apre><hpre><word><hsuf><asuf><isuf>))
 
 The first field
 is an ignored prefix taken from the command line, the contents of the
@@ -620,20 +612,18 @@ testing and modification is performed as if it were not given.
 )
 item(tt(-q))(
 If the cursor is currently inside single or double quotes, the word
-currenly being completed is split in separate words at the spaces. The 
+currently being completed is split in separate words at the spaces. The 
 resulting words are stored in the tt(words) array, and tt(PREFIX),
 tt(SUFFIX), tt(QIPREFIX), and tt(QISUFFIX) are modified to reflect the 
 word part that is completed.
 )
 enditem()
 
-In all the above cases the return value is zero if the test succeded
+In all the above cases the return value is zero if the test succeeded
 and the parameters were modified and non-zero otherwise. This allows
 one to use this builtin in tests such as:
 
-indent(
-tt(if compset -P '*\='; then ...)
-)
+example(if compset -P '*\='; then ...)
 
 This forces anything up to and including the last equal sign to be
 ignored by the completion code.
@@ -685,21 +675,18 @@ sect(Examples)
 
 The first step is to define the widget:
 
-indent(nofill(
-tt(zle -C complete complete-word complete-history)))
+example(zle -C complete complete-word complete-history)
 
 Then the widget can be bound to a key using the tt(bindkey) builtin
 command:
 
-indent(nofill(
-tt(bindkey '^X\t' complete)))
+example(bindkey '^X\t' complete)
 
 After that the shell function tt(complete-history) will be invoked
 after typing control-X and TAB. The function should then generate the
 matches, e.g.:
 
-indent(nofill(
-tt(complete-history LPAR()RPAR() { compgen -H 0 '' })))
+example(complete-history LPAR()RPAR() { compgen -H 0 '' })
 
 This function will complete words from the history matching the 
 current word.
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 7fdf973b4..5cc9fe4e3 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -277,7 +277,8 @@ If tt(<) is used, then the file passed as an argument will
 be a named pipe connected to the output of the var(list) process.
 For example,
 
-nofill(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() | tee >LPAR())var(process1)tt(RPAR() >LPAR())var(process2)tt(RPAR() >/dev/null))
+nofill(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() |
+tee >LPAR())var(process1)tt(RPAR() >LPAR())var(process2)tt(RPAR() >/dev/null))
 
 cuts fields 1 and 3 from the files var(file1) and var(file2) respectively,
 pastes the results together, and sends it to the processes
@@ -427,9 +428,9 @@ the flags tt(M), tt(R), tt(B), tt(E) and tt(N) are not useful.
 
 For example,
 
-nofill(tt(foo="twinkle twinkle little star" sub="t*e" rep="spy")
-tt(print ${foo//${~sub}/$rep})
-tt(print ${(S)foo//${~sub}/$rep}))
+example(foo="twinkle twinkle little star" sub="t*e" rep="spy"
+print ${foo//${~sub}/$rep}
+print ${(S)foo//${~sub}/$rep})
 
 Here, the `tt(~)' ensures that the text of tt($sub) is treated as a
 pattern rather than a plain string.  In the first case, the longest
@@ -728,7 +729,7 @@ account of whether the current value is a scalar or an array, whether the
 whole substitution is in double quotes, and what flags are supplied to the
 current level of substitution, just as if the nested substitution were the
 outermost.  The flags are not propagated up to enclosing
-substitutions; the nested subsitution will return either a scalar or an
+substitutions; the nested substitution will return either a scalar or an
 array as determined by the flags, possibly adjusted for quoting.  All the
 following steps take place where applicable at all levels of substitution.
 Note that, unless the `tt((P))' flag is present, the flags and any subscripts
@@ -1221,11 +1222,11 @@ matching the pattern var(foo).
 As a shorthand, `tt(**/)' is equivalent to `tt((*/)#)'.
 Thus:
 
-nofill(tt(ls (*/)#bar))
+example(ls (*/)#bar)
 
 or
 
-nofill(tt(ls **/bar))
+example(ls **/bar)
 
 does a recursive directory search for files named `tt(bar)', not following
 symbolic links.  To follow links, use `tt(***/)'.
@@ -1468,26 +1469,26 @@ name of any existing file can be followed by a modifier of the form
 `tt((:..))' even if no actual filename generation is performed.
 Thus:
 
-nofill(tt(ls *(-/)))
+example(ls *(-/))
 
 lists all directories and symbolic links that point to directories,
 and
 
-nofill(tt(ls *(%W)))
+example(ls *(%W))
 
 lists all world-writable device files in the current directory, and
 
-nofill(tt(ls *(W,X)))
+example(ls *(W,X))
 
 lists all files in the current directory that are
 world-writable or world-executable, and
 
-nofill(tt(echo /tmp/foo*(u0^@:t)))
+example(echo /tmp/foo*(u0^@:t))
 
 outputs the basename of all root-owned files beginning with the string
 `tt(foo)' in tt(/tmp), ignoring symlinks, and
 
-nofill(tt(ls *.*~(lex|parse).[ch](^D^l1)))
+example(ls *.*~(lex|parse).[ch](^D^l1))
 
 lists all files having a link count of one whose names contain a dot
 (but not those starting with a dot, since tt(GLOB_DOTS) is explicitly
diff --git a/Doc/Zsh/files.yo b/Doc/Zsh/files.yo
index 17b29677b..54fa800dc 100644
--- a/Doc/Zsh/files.yo
+++ b/Doc/Zsh/files.yo
@@ -26,7 +26,7 @@ tt($ZDOTDIR/.zlogin) are read.
 
 When a login shell exits, the files tt($ZDOTDIR/.zlogout) and then
 tt(/etc/zlogout) are read.  This happens with either an explicit exit
-via the tt(exit) or tt(logout) commands, or an implict exit by reading
+via the tt(exit) or tt(logout) commands, or an implicit exit by reading
 end-of-file from the terminal.  However, if the shell terminates due
 to tt(exec)'ing another process, the logout files are not read.
 These are also affected by the tt(RCS) and tt(GLOBAL_RCS) options.
diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo
index c2fc71d55..0b32acc4a 100644
--- a/Doc/Zsh/func.yo
+++ b/Doc/Zsh/func.yo
@@ -5,7 +5,8 @@ sect(Functions)
 )\
 cindex(functions)
 findex(function)
-The tt(function) reserved word is used to define shell functions.
+Shell functions are defined with the tt(function) reserved word or the
+special syntax `var(funcname) tt(())'.
 Shell functions are read in and stored internally.
 Alias names are resolved when the function is read.
 Functions are executed like commands with the arguments
diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo
index 51783dc70..80c132ab7 100644
--- a/Doc/Zsh/grammar.yo
+++ b/Doc/Zsh/grammar.yo
@@ -203,6 +203,11 @@ Normally, only one var(word) is provided; multiple var(word)s
 are usually only useful for setting traps.
 The body of the function is the var(list) between
 the tt({) and tt(}).  See noderef(Functions).
+
+If the option tt(SH_GLOB) is set for compatibility with other shells, then
+whitespace may appear between between the left and right parentheses when
+there is a single var(word);  otherwise, the parentheses will be treated as
+forming a globbing pattern in that case.
 )
 cindex(timing)
 item(tt(time) [ var(pipeline) ])(
diff --git a/Doc/Zsh/guide.yo b/Doc/Zsh/guide.yo
index f9c485875..d1f3e3aa9 100644
--- a/Doc/Zsh/guide.yo
+++ b/Doc/Zsh/guide.yo
@@ -28,7 +28,7 @@ menu(Parameters)
 menu(Options)
 menu(Shell Builtin Commands)
 menu(Zsh Line Editor)
-menu(Programmable Completion)
+menu(Programmable Completion Using compctl)
 menu(Completion Widgets)
 menu(Zsh Modules)
 menu(Completion System)
@@ -98,7 +98,7 @@ menu(Arguments)
 menu(Completion)
 menu(Miscellaneous)
 
-Programmable Completion
+Programmable Completion Using compctl
 
 menu(Command Flags)
 menu(Option Flags)
diff --git a/Doc/Zsh/jobs.yo b/Doc/Zsh/jobs.yo
index 752181f02..62e945f23 100644
--- a/Doc/Zsh/jobs.yo
+++ b/Doc/Zsh/jobs.yo
@@ -9,7 +9,7 @@ command, and assigns them small integer numbers.
 When a job is started asynchronously with `tt(&)',
 the shell prints a line which looks like:
 
-nofill(tt([1] 1234))
+example([1] 1234)
 
 indicating that the job which was started asynchronously was job number
 1 and had one (top-level) process, whose process ID was 1234.
diff --git a/Doc/Zsh/metafaq.yo b/Doc/Zsh/metafaq.yo
index 569d91716..c8273da47 100644
--- a/Doc/Zsh/metafaq.yo
+++ b/Doc/Zsh/metafaq.yo
@@ -12,7 +12,7 @@ cindex(author)
 Zsh was originally written by Paul Falstad tt(<pf@zsh.org>).
 Zsh is now maintained by the members of the zsh-workers mailing
 list tt(<zsh-workers@sunsite.auc.dk>).  The development is currently
-coordinated by Andrew Main (Zefram) tt(<zefram@zsh.org>).  The coordinator
+coordinated by Peter Stephenson tt(<pws@zsh.org>).  The coordinator
 can be contacted at tt(<coordinator@zsh.org>), but matters relating to
 the code should generally go to the mailing list.
 texinode(Availability)(Mailing Lists)(Author)(Introduction)
diff --git a/Doc/Zsh/mod_compctl.yo b/Doc/Zsh/mod_compctl.yo
index cfd615b2d..91f6112ee 100644
--- a/Doc/Zsh/mod_compctl.yo
+++ b/Doc/Zsh/mod_compctl.yo
@@ -3,7 +3,7 @@ sect(The compctl Module)
 The tt(compctl) module makes available several builtin commands. tt(compctl),
 is the standard way to control completions for ZLE.  See
 ifzman(zmanref(zshcompctl))\
-ifnzman(noderef(Programmable Completion))\
+ifnzman(noderef(Programmable Completion Using compctl))\
 .
 The other builtin commands can be used in user-defined completion widgets,
 see
diff --git a/Doc/Zsh/mod_mapfile.yo b/Doc/Zsh/mod_mapfile.yo
index 6d0475711..e6c388823 100644
--- a/Doc/Zsh/mod_mapfile.yo
+++ b/Doc/Zsh/mod_mapfile.yo
@@ -34,11 +34,13 @@ handled, zsh's internal memory management may be arbitrarily baroque.  Thus
 it should not automatically be assumed that use of tt(mapfile) represents a
 gain in efficiency over use of other mechanisms.  Note in particular that
 the whole contents of the file will always reside physically in memory when
-accessed (possibly multiple times, due to standard parameter subsitution
-operations).
+accessed (possibly multiple times, due to standard parameter substitution
+operations).  In particular, this means handling of sufficiently long files
+(greater than the machine's swap space, or than the range of the pointer
+type) will be incorrect.
 
 No errors are printed or flagged for non-existent, unreadable, or
-unwriteable files, as the parameter mechanism is too low in the shell
+unwritable files, as the parameter mechanism is too low in the shell
 execution hierarchy to make this convenient.
 
 It is unfortunate that the mechanism for loading modules does not yet allow
diff --git a/Doc/Zsh/mod_zftp.yo b/Doc/Zsh/mod_zftp.yo
index ec16aa531..7b64882b4 100644
--- a/Doc/Zsh/mod_zftp.yo
+++ b/Doc/Zsh/mod_zftp.yo
@@ -80,7 +80,7 @@ will be deleted if the tt(zftp) module is unloaded.
 
 For example,
 
-nofill(tt(zftp params ftp.elsewhere.xx juser '?'))
+example(zftp params ftp.elsewhere.xx juser '?')
 
 will store the host tt(ftp.elsewhere.xx) and the user tt(juser) and
 then prompt the user for the corresponding password.
@@ -89,8 +89,8 @@ This command may also be used to set up a transfer which then takes
 place completely in the background, freeing tt(zftp) for concurrent
 foreground use.  For example,
 
-nofill(tt(zftp params ftp.soreeyes.ca bubble squeak))
-nofill(tt(LPAR()zftp open; zftp get foo >bar; zftp close)tt(RPAR() &))
+example(zftp params ftp.soreeyes.ca bubble squeak
+(zftp open; zftp get foo >bar; zftp close) &)
 
 --- here, the connection is restricted to a background subshell and
 you are free to open a simultaneous connection in the foreground.
@@ -110,7 +110,7 @@ supported on this system) is printed instead.
 
 It is useful to put the code
 
-nofill(tt([[ -n $ZFTP_HOST ]] && zftp test))
+example([[ -n $ZFTP_HOST ]] && zftp test)
 
 into the shell function tt(precmd) for testing the connection before
 every prompt.  However, tt(zftp) will call tt(test) at the start of any
@@ -209,7 +209,7 @@ item(tt(mkdir) var(directory))(
 Create a new directory var(directory) on the server.
 )
 item(tt(rmdir) var(directory))(
-Delete the diretory var(directory)  on the server.
+Delete the directory var(directory)  on the server.
 )
 item(tt(rename) var(old-name) var(new-name))(
 Rename file var(old-name) to var(new-name) on the server.
@@ -221,7 +221,7 @@ only need this if instructed by the server to use it.
 item(tt(quote) var(args...))(
 Send the raw FTP command sequence to the server.  You should be
 familiar with the FTP command set as defined in RFC959 before doing
-this.  Useful comands may include tt(STAT) and tt(HELP).  Note also
+this.  Useful commands may include tt(STAT) and tt(HELP).  Note also
 the mechanism for returning messages as described for the variable
 tt(ZFTP_VERBOSE) below, in particular that all messages from the
 control connection are sent to standard error.
@@ -335,7 +335,7 @@ digit reply code is defined by RFC959 to correspond to:
 
 startitem()
 item(1.)(
-A positive prelimnary reply.
+A positive preliminary reply.
 )
 item(2.)(
 A positive completion reply.
@@ -442,7 +442,7 @@ until the next call to tt(zftp).  Other status changes in subshells
 will not be reflected by changes to the variables (but should
 be otherwise harmless).
 
-On some operatings systems, the control connection is not valid after a
+On some operating systems, the control connection is not valid after a
 fork(), so that operations in subshells or on the left hand side of a
 pipeline are not possible.
 
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index bfb2238ed..be820f160 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -16,7 +16,7 @@ To assign an array value, use `tt(set -A) var(name) var(value) ...'.
 findex(set, use of)
 The value of a parameter may also be assigned by writing:
 
-nofill(var(name)tt(=)var(value))
+indent(var(name)tt(=)var(value))
 
 If the integer attribute, tt(-i), is set for var(name), the var(value)
 is subject to arithmetic evaluation.  See noderef(Array Parameters)
@@ -38,19 +38,19 @@ texinode(Array Parameters)(Positional Parameters)()(Parameters)
 sect(Array Parameters)
 The value of an array parameter may be assigned by writing:
 
-nofill(var(name)tt(=LPAR())var(value) ...tt(RPAR()))
+indent(var(name)tt(=LPAR())var(value) ...tt(RPAR()))
 
 If no parameter var(name) exists, an ordinary array parameter is created.
 Associative arrays must be declared first, by `tt(typeset -A) var(name)'.
 When var(name) refers to an associative array, the parenthesized list is
 interpreted as alternating keys and values:
 
-nofill(var(name)tt(=LPAR())var(key) var(value) ...tt(RPAR()))
+indent(var(name)tt(=LPAR())var(key) var(value) ...tt(RPAR()))
 
 Every var(key) must have a var(value) in this case.  To create an empty
 array or associative array, use:
 
-nofill(var(name)tt(=LPAR()RPAR()))
+indent(var(name)tt(=LPAR()RPAR()))
 
 Individual elements of an array may be selected using a
 subscript.  A subscript of the form `tt([)var(exp)tt(])'
@@ -59,6 +59,7 @@ an arithmetic expression which will be subject to arithmetic
 expansion as if it were surrounded by `tt($LPAR()LPAR())...tt(RPAR()RPAR())'.
 The elements are numbered beginning with 1 unless the
 tt(KSH_ARRAYS) option is set when they are numbered from zero.
+cindex(subscripts)
 pindex(KSH_ARRAYS, use of)
 
 The same subscripting syntax is used for associative arrays,
@@ -72,9 +73,8 @@ except when they appear within double quotes.
 
 A subscript of the form `tt([)var(exp1)tt(,)var(exp2)tt(])'
 selects all elements in the range var(exp1) to var(exp2),
-inclusive.
-(Associative arrays are unordered, and so do not support ranges.)
-If one of the subscripts evaluates to a negative number,
+inclusive. (Associative arrays are unordered, and so do not support
+ranges.) If one of the subscripts evaluates to a negative number,
 say tt(-)var(n), then the var(n)th element from the end
 of the array is used.  Thus `tt($foo[-3])' is the third element
 from the end of the array tt(foo), and
@@ -95,7 +95,7 @@ element or range is replaced by the expression on the right side.  An
 array (but not an associative array) may be created by assignment to a
 range or element.  Arrays do not nest, so assigning a parenthesized list
 of values to an element or range changes the number of elements in the
-array, shifting the other elements to accomodate the new values.  (This
+array, shifting the other elements to accommodate the new values.  (This
 is not supported for associative arrays.)
 
 To delete an element of an ordinary array, assign `tt(LPAR()RPAR())' to
@@ -180,7 +180,7 @@ values) any of the positions from 1 to var(n) that do not already have
 values.  Note that, because the positional parameters form an array, an
 array assignment of the form `var(n)tt(=LPAR())var(value) ...tt(RPAR())' is
 allowed, and has the effect of shifting all the values at positions greater
-than var(n) by as many positions as necessary to accomodate the new values.
+than var(n) by as many positions as necessary to accommodate the new values.
 
 texinode(Local Parameters)(Parameters Set By The Shell)(Positional Parameters)(Parameters)
 sect(Local Parameters)
diff --git a/Doc/Zsh/redirect.yo b/Doc/Zsh/redirect.yo
index b642f1b5f..b44b07e63 100644
--- a/Doc/Zsh/redirect.yo
+++ b/Doc/Zsh/redirect.yo
@@ -107,7 +107,7 @@ The shell evaluates each redirection in terms of the
 association at the time of evaluation.
 For example:
 
-nofill(... tt(1>)var(fname) tt(2>&1))
+indent(... tt(1>)var(fname) tt(2>&1))
 
 first associates file descriptor 1 with file var(fname).
 It then associates file descriptor 2 with the file associated with file
@@ -123,12 +123,12 @@ the shell opens the file descriptor as a pipe to a process that copies
 its input to all the specified outputs, similar to bf(tee),
 provided the tt(MULTIOS) option is set.  Thus:
 
-nofill(tt(date >foo >bar))
+example(date >foo >bar)
 
 writes the date to two files, named `tt(foo)' and `tt(bar)'.
 Note that a pipe is an implicit redirection; thus
 
-nofill(tt(date >foo | cat))
+example(date >foo | cat)
 
 writes the date to the file `tt(foo)', and also pipes it to cat.
 
@@ -136,14 +136,14 @@ If the tt(MULTIOS)
 option is set, the word after a redirection operator is also subjected
 to filename generation (globbing).  Thus
 
-nofill(tt(: > *))
+example(: > *)
 
 will truncate all files in the current directory,
 assuming there's at least one.  (Without the tt(MULTIOS)
 option, it would create an empty file called `tt(*)'.)
 Similarly, you can do
 
-nofill(tt(echo exit 0 >> *.sh))
+example(echo exit 0 >> *.sh)
 
 If the user tries to open a file descriptor for reading more than once,
 the shell opens the file descriptor as a pipe to a process that copies
@@ -151,17 +151,17 @@ all the specified inputs to its output in the order
 specified, similar to bf(cat),
 provided the tt(MULTIOS) option is set.  Thus
 
-nofill(tt(sort <foo <fubar))
+example(sort <foo <fubar)
 
 or even
 
-nofill(tt(sort <f{oo,ubar}))
+example(sort <f{oo,ubar})
 
 is equivalent to `tt(cat foo fubar | sort)'.
 
 Note that a pipe is an implicit redirection; thus
 
-nofill(tt(cat bar | sort <foo))
+example(cat bar | sort <foo)
 
 is equivalent to `tt(cat bar foo | sort)' (note the order of the inputs).
 
@@ -169,7 +169,7 @@ If the tt(MULTIOS) option is em(un)set,
 each redirection replaces the previous redirection for that file descriptor.
 However, all files redirected to are actually opened, so
 
-nofill(tt(echo foo > bar > baz))
+example(echo foo > bar > baz)
 
 when tt(MULTIOS) is unset will truncate bar, and write `tt(foo)' into baz.
 
@@ -178,6 +178,6 @@ and zero or more parameter assignments, but no command name,
 the command named in the shell variable tt(READNULLCMD) is assumed.
 (If tt(READNULLCMD) is empty or not set, `tt(cat)' is used.)  Thus
 
-nofill(tt(< file))
+example(< file)
 
 copies the contents of tt(file) to the standard output.
diff --git a/Doc/Zsh/zftpsys.yo b/Doc/Zsh/zftpsys.yo
index 6983dedb9..60f5be60d 100644
--- a/Doc/Zsh/zftpsys.yo
+++ b/Doc/Zsh/zftpsys.yo
@@ -8,7 +8,7 @@ distribution as an interface to the tt(zftp) builtin command, allowing you
 to perform FTP operations from the shell command line or within functions
 or scripts.  The interface is similar to a traditional FTP client (e.g. the
 tt(ftp) command itself, see manref(ftp)(1)), but as it is entirely done
-within the shell all the familar completion, editing and globbing features,
+within the shell all the familiar completion, editing and globbing features,
 and so on, are present, and macros are particularly simple to write as they
 are just ordinary shell functions.
 
@@ -45,21 +45,22 @@ You should make sure all the functions from the tt(Functions/Zftp)
 directory of the source distribution are available; they all begin with the
 two letters `tt(zf)'.  They may already have been installed on your system;
 otherwise, you will need to find them and copy them.  The directory should
-appear as one of the elements of the tt($fpath) array, and the functions
-should be autoloaded.  Finally, to initialise the use of the system you
-need to call the tt(zfinit) function.  The following code in your
-tt(.zshrc) will arrange for this; assume the functions are stored in the
-directory tt(~/myfns):
-
-tt(indent(
-nofill(fpath=(~/myfns $fpath))
-nofill(autoload ~/myfns/zf*(:t))
-nofill(zfinit)
-))
+appear as one of the elements of the tt($fpath) array (this should already
+be the case if they were installed), and at least the function tt(zfinit)
+should be autoloaded; it will autoload the rest.  Finally, to initialise
+the use of the system you need to call the tt(zfinit) function.  The
+following code in your tt(.zshrc) will arrange for this; assume the
+functions are stored in the directory tt(~/myfns):
+
+example(fpath=(~/myfns $fpath)
+autoload zfinit
+zfinit)
 
 Note that tt(zfinit) assumes you are using the tt(zmodload) method to
 load the tt(zftp) command.  If it is already built into the shell, change
-tt(zfinit) to tt(zfinit -n).
+tt(zfinit) to tt(zfinit -n).  It is helpful (though not essential) if the
+call to tt(zfinit) appears after any code to initialise the new completion
+system, else unnecessary tt(compctl) commands will be given.
 
 texinode(Zftp Functions)(Miscellaneous Features)(Installation)(Zftp Function System)
 sect(Functions)
@@ -115,7 +116,7 @@ have many of the features of the shell builtin tt(cd).
 
 In the first form with var(dir) present, change to the directory var(dir).
 The command `tt(zfcd ..)' is treated specially, so is guaranteed to work on
-non-UNIX servers (note this is handled internall by tt(zftp)).  If var(dir)
+non-UNIX servers (note this is handled internally by tt(zftp)).  If var(dir)
 is omitted, has the effect of `tt(zfcd ~)'.
 
 The second form changes to the directory previously current.
@@ -274,13 +275,48 @@ then tt(zfpcp) will retry using the second form.
 )
 enditem()
 
-subsect(Closing the connectino)
+subsect(Closing the connection)
 startitem()
 item(tt(zfclose))(
 Close the connection.
 )
 enditem()
 
+subsect(Bookmarks)
+The two functions tt(zfmark) and tt(zfgoto) allow you to `bookmark' the
+present location (host, user and directory) of the current FTP connection
+for later use.  The file to be used for storing and retrieving bookmarks is
+given by the parameter tt($ZFTP_BMFILE); if not set when one of the two
+functions is called, it will be set to the file tt(.zfbfmarks) in the
+directory where your zsh startup files live (usually tt(~)).
+
+startitem()
+item(tt(zfmark [ )var(bookmark)tt( ]))(
+If given an argument, mark the current host, user and directory under the
+name var(bookmark) for later use by tt(zfgoto).  If there is no connection
+open, use the values for the last connection immediately before it was
+closed; it is an error if there is none.  Any existing bookmark
+under the same name will be silently replaced.
+
+If not given an argument, list the existing bookmarks and the points to
+which they refer in the form var(user)tt(@)var(host)tt(:)var(directory).
+)
+item(tt(zfgoto [ -n ] )var(bookmark))(
+Return to the location given by var(bookmark), as previously set by
+tt(zfmark).  If the location has user `tt(ftp)' or `tt(anonymous)', open
+the connection with tt(zfanon), so that no password is required.  If the
+user and host parameters match those currently stored, those will be used,
+and again no password is required.  Otherwise a password will be prompted
+for.
+
+With the option tt(-n), the bookmark is taken to be a nickname stored by
+the tt(ncftp) program in its bookmark file, which is assumed to be
+tt(~/.ncftp/bookmarks).  The function works identically in other ways.
+Note that there is no mechanism for adding or modifying tt(ncftp) bookmarks
+from the zftp functions.
+)
+enditem()
+
 subsect(Other functions)
 Mostly, these functions will not be called directly (apart from
 tt(zfinit)), but are described here for completeness.  You may wish to
@@ -288,7 +324,7 @@ alter tt(zftp_chpwd) and tt(zftp_progress), in particular.
 
 startitem()
 item(tt(zfinit [ -n ]))(
-As decribed above, this is used to initialise the zftp function system.
+As described above, this is used to initialise the zftp function system.
 The tt(-n) option should be used if the zftp command is already built into
 the shell.
 )
@@ -320,7 +356,7 @@ var(prefix) and var(suffix) set appropriately.
 item(tt(zfrglob var(varname)))(
 Perform remote globbing, as describes in more detail below.  var(varname)
 is the name of a variable containing the pattern to be expanded; if there
-were any matches, the same variable will be set to the exanded set of
+were any matches, the same variable will be set to the expanded set of
 filenames on return.
 )
 item(tt(zfrtime var(lfile) var(rfile) [ var(time) ]))(
@@ -339,15 +375,13 @@ tt(xterm) or tt(sun-cmd) terminal emulator to reflect the local and remote
 hostnames and current directories.  It works best when combined with the
 function tt(chpwd).  In particular, a function of the form
 
-tt(indent(
-nofill(chpwd() {)
-nofill(  if [[ -n $ZFTP_USER ]]; then)
-nofill(    zftp_chpwd)
-nofill(  else)
-nofill(    # usual chpwd e.g put host:directory in title bar)
-nofill(  fi)
-nofill(})
-))
+example(chpwd() {
+  if [[ -n $ZFTP_USER ]]; then
+    zftp_chpwd
+  else
+    # usual chpwd e.g put host:directory in title bar
+  fi
+})
 
 fits in well.
 )
@@ -378,7 +412,7 @@ remote server does not support the UNIX directory semantics, directory
 handling is problematic and it is recommended that globbing only be used
 within the current directory.  The list of files in the current directory,
 if retrieved, will be cached, so that subsequent globs in the same
-directory without an interventing tt(zfcd) are fast.
+directory without an intervening tt(zfcd) are fast.
 
 If the variable tt($zfrglob) is set to a non-zero length, globbing is
 instead performed on the remote host:  the server is asked for a list of
@@ -415,10 +449,8 @@ never close the connection automatically.
 Information about the previous connection is given by the tt(zfstat)
 function.  So, for example, if that reports:
 
-tt(indent(
-nofill(Not connected.)
-nofill(Last session:   ftp.bar.com:/pub/textfiles)
-))
+example(Not connected.
+Last session:   ftp.bar.com:/pub/textfiles)
 
 then the command tt(zfget file.txt) will attempt to reopen a connection to
 tt(ftp.bar.com), retrieve the file tt(/pub/textfiles/file.txt), and
@@ -427,9 +459,9 @@ will open the connection in the directory tt(/pub) and leave it open.
 
 subsect(Completion)
 
-Completion of remote files and directories is supported.  The older,
-tt(compctl)-style completion is defined when tt(zfinit) is called; support
-for the new widget-based completion system is provided in the function
-tt(Completion/Builtins/_zftp), which should be installed with the other
-functions of the completion system and hence should automatically be
+Completion of remote files, directories and bookmarks is supported.  The
+older, tt(compctl)-style completion is defined when tt(zfinit) is called;
+support for the new widget-based completion system is provided in the
+function tt(Completion/Builtins/_zftp), which should be installed with the
+other functions of the completion system and hence should automatically be
 available.
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index c4809b02d..743fb7f93 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -1,4 +1,4 @@
-texinode(Zsh Line Editor)(Programmable Completion)(Shell Builtin Commands)(Top)
+texinode(Zsh Line Editor)(Programmable Completion Using compctl)(Shell Builtin Commands)(Top)
 chapter(Zsh Line Editor)
 cindex(line editor)
 cindex(editor, line)
@@ -83,7 +83,7 @@ simply to perform some small action.  The ZLE commands that key sequences
 in keymaps are bound to are in fact widgets.  Widgets can be user-defined
 or built in.
 
-There are 162 standard widgets built in to ZLE (see sectref(Standard Widgets)).
+There are 162 standard widgets built in to ZLE (see Standard Widgets below).
 Other built-in widgets can be defined by other modules (see
 ifzman(zmanref(zshmodules))\
 ifnzman(noderef(Zsh Modules))\
@@ -157,7 +157,7 @@ vindex(keys)
 item(tt(keys) (array))(
 The keys typed to invoke this widget, one element per
 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 
+and meta-keys are reported with a leading `tt(M-)', as in `tt(M-a)' and 
 `tt(M-^A)'.
 )
 vindex(NUMERIC)
diff --git a/Doc/zman.yo b/Doc/zman.yo
index 7d7fc120e..657e046a6 100644
--- a/Doc/zman.yo
+++ b/Doc/zman.yo
@@ -162,6 +162,12 @@ def(itemiz)(1)(\
 
 COMMENT(--- special effects ---)
 
+def(example)(1)(\
+  NOTRANS(.RS)NL()NOTRANS(.nf)NL()\
+  NOTRANS(\fB)ARG1NOTRANS(\fP)\
+  NL()NOTRANS(.fi)NL()NOTRANS(.RE)\
+)
+
 def(nofill)(1)(\
   NOTRANS(.nf)NL()\
   ARG1\
@@ -169,9 +175,9 @@ def(nofill)(1)(\
 )
 
 def(indent)(1)(\
-  NOTRANS(.RS)\
+  NOTRANS(.RS)NL()NOTRANS(.nf)NL()\
   ARG1\
-  NOTRANS(.RE)\
+  NL()NOTRANS(.fi)NL()NOTRANS(.RE)\
 )
 
 COMMENT(--- hyperlink menus ---)
diff --git a/Doc/zsh.yo b/Doc/zsh.yo
index 98cb9e340..b9279e660 100644
--- a/Doc/zsh.yo
+++ b/Doc/zsh.yo
@@ -17,7 +17,7 @@ def(ifzshall)(1)()\
 )\
 ifztexi(\
 texinfo(zsh.info)(zsh)
-NOTRANS(@setchapternewpage odd
+NOTRANS(@setchapternewpage off
 @iftex
 @finalout
 @afourpaper
diff --git a/Doc/ztexi.yo b/Doc/ztexi.yo
index 231a70b84..c3c1928cf 100644
--- a/Doc/ztexi.yo
+++ b/Doc/ztexi.yo
@@ -11,7 +11,7 @@ def(CMT)(0)(NOTRANS(@c))
 
 ATEXIT(\
   NL()\
-  NOTRANS(@setchapternewpage odd)NL()\
+  NOTRANS(@setchapternewpage off)NL()\
   NOTRANS(@contents)NL()\
   NOTRANS(@bye)NL()\
 )
@@ -207,8 +207,16 @@ def(nofill)(1)(\
   USECHARTABLE(standard)\
 )
 
+def(example)(1)(\
+  NOTRANS(@example)NL()\
+  ARG1\
+  NL()NOTRANS(@end example)\
+)
+
 def(indent)(1)(\
+  NOTRANS(@display)NL()\
   ARG1\
+  NL()NOTRANS(@end display)\
 )
 
 COMMENT(--- hyperlink menus ---)
diff --git a/Etc/MACHINES b/Etc/MACHINES
index 27e21f330..89ec474c9 100644
--- a/Etc/MACHINES
+++ b/Etc/MACHINES
@@ -38,6 +38,10 @@ DEC: OSF/1 1.2, 1.3, 2.0, 3.*, DEC Unix 4.* (Alpha)
 	This problem is not related to zsh.  If you have such problems,
 	remove the bogus strip and use /bin/strip instead.
 
+        On Digital UNIX 4.0, compilation with gcc and with --enable-dynamic
+        apparently needs configuring with explicit flags:
+          DLLD=gcc LDFLAGS='-g -rpath <path-to-.so-files>' ./configure ...
+
 FreeBSD: FreeBSD 2.2.7 [3.1.4]
 	Should build `out-of-the-box'.
 
@@ -102,5 +106,7 @@ Sun: Solaris 2.*
 	to /usr/ucblib in your LD_LIBRARY_PATH.  You can easily do this
 	by just unsetting LD_LIBRARY_PATH before building zsh.
 
-	Under Solaris 2.7, dynamically loaded library support with
-	--enable-dynamic currently does not work.
+	Under Solaris 2.7, problems have been reported with dynamically
+        loaded library support using --enable-dynamic.  However, other
+        users have been successful with the standard Sun compiler.
+        More details of any problems would be appreciated.
diff --git a/Functions/Makefile.in b/Functions/Makefile.in
index d6344dd62..75ec418a0 100644
--- a/Functions/Makefile.in
+++ b/Functions/Makefile.in
@@ -55,7 +55,14 @@ install.fns:
 	  $(sdir_top)/mkinstalldirs $(fndir) || exit 1; \
 	  for file in $(FUNCTIONS_INSTALL); do \
 	    if test -f $$file; then \
-	      $(INSTALL_DATA) $$file $(fndir) || exit 1; \
+	      if test x$(FUNCTIONS_SUBDIRS) != x -a \
+	      x$(FUNCTIONS_SUBDIRS) != xno; then \
+	        subdir="`echo $$file | sed -e 's%/.*%%'`"; \
+	        $(sdir_top)/mkinstalldirs $(fndir)/$$subdir || exit 1; \
+	        $(INSTALL_DATA) $$file $(fndir)/$$subdir || exit 1; \
+	      else \
+	        $(INSTALL_DATA) $$file $(fndir) || exit 1; \
+	      fi; \
 	    fi; \
 	  done; \
 	fi; \
@@ -65,7 +72,12 @@ uninstall.fns:
 	if test x$(fndir) != x && test x$(fndir) != xno; then \
 	  for file in $(FUNCTIONS_INSTALL); do \
 	    if test -f $$file; then \
-	      rm -f "$(fndir)/`echo $$file | sed -e 's%^.*/%%'`"; \
+	      if test x$(FUNCTIONS_SUBDIRS) != x -a \
+	      x$(FUNCTIONS_SUBDIRS) != xno; then \
+	        rm -f $(fndir)/$$file; \
+	      else \
+	        rm -f "$(fndir)/`echo $$file | sed -e 's%^.*/%%'`"; \
+	      fi; \
 	    fi; \
 	  done; \
 	fi; \
diff --git a/Functions/Zftp/.distfiles b/Functions/Zftp/.distfiles
index c45e8d1c8..e5aad61ea 100644
--- a/Functions/Zftp/.distfiles
+++ b/Functions/Zftp/.distfiles
@@ -1,7 +1,7 @@
 DISTFILES_SRC='
     .distfiles
     zfanon zfautocheck zfcd zfcd_match zfcget zfclose zfcput zfdir
-    zfgcp zfget zfget_match zfhere zfinit zfls zfopen zfparams
+    zfgcp zfget zfget_match zfgoto zfhere zfinit zfls zfmark zfopen zfparams
     zfpcp zfput zfrglob zfrtime zfstat zftp_chpwd zftp_progress
     zftype zfuget zfuput
 '
diff --git a/Functions/Zftp/zfgoto b/Functions/Zftp/zfgoto
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Functions/Zftp/zfgoto
diff --git a/Functions/Zftp/zfinit b/Functions/Zftp/zfinit
index be827c6ac..fbe6c5979 100644
--- a/Functions/Zftp/zfinit
+++ b/Functions/Zftp/zfinit
@@ -1,3 +1,5 @@
+emulate -L zsh
+
 [[ $1 = -n ]] || zmodload -ia zftp
 
 alias zfcd='noglob zfcd'
@@ -6,6 +8,11 @@ alias zfls='noglob zfls'
 alias zfdir='noglob zfdir'
 alias zfuget='noglob zfuget'
 
+autoload -U zfanon zfautocheck zfcd zfcd_match zfcget zfclose zfcput
+autoload -U zfdir zfgcp zfget zfget_match zfgoto zfhere zfinit zfls
+autoload -U zfmark zfopen zfparams zfpcp zfput zfrglob zfrtime zfstat
+autoload -U zftp_chpwd zftp_progress zftype zfuget zfuput
+
 # only way of getting that noglob out of the way: this is unnecessary with
 # widget-based completion and can be commented out.
 setopt completealiases
@@ -14,7 +21,7 @@ setopt completealiases
 # zftp completions: only use these if new-style completion is not
 # active.
 #
-if [[ ${#patcomps} -eq 0 || ${patcomps[(i)zf*]} -gt ${#patcomps} ]]; then
+if [[ ${#_patcomps} -eq 0 || ${_patcomps[(i)zf*]} -gt ${#_patcomps} ]]; then
   compctl -f -x 'p[1]' \
     -k '(open params user login type ascii binary mode put putat
     get getat append appendat ls dir local remote mkdir rmdir delete
@@ -25,4 +32,9 @@ if [[ ${#patcomps} -eq 0 || ${patcomps[(i)zf*]} -gt ${#patcomps} ]]; then
   compctl -K zfcd_match -S/ -q zfcd zfdir zfls
   compctl -K zfget_match zfget zfgcp zfuget zfcget
   compctl -k hosts zfanon zfopen zfparams
+  compctl -s \
+    '$(awk '\''{print $1}'\'' ${ZFTP_BMFILE:-${ZDOTDIR:-$HOME}/.zfbkmarks})' \
+    -x 'W[1,-*n*]' \
+    -s '$(awk -F, '\''NR > 2 { print $1 }'\'' ~/.ncftp/bookmarks)' -- \
+    zfgoto zfmark
 fi
diff --git a/Functions/Zftp/zfmark b/Functions/Zftp/zfmark
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Functions/Zftp/zfmark
diff --git a/Functions/Zftp/zftp_chpwd b/Functions/Zftp/zftp_chpwd
index 0df199cfb..f1c2d5311 100644
--- a/Functions/Zftp/zftp_chpwd
+++ b/Functions/Zftp/zftp_chpwd
@@ -24,6 +24,7 @@ if [[ -z $ZFTP_USER ]]; then
 else
   [[ -n $ZFTP_PWD ]] && zflastdir=$ZFTP_PWD
   zflastsession="$ZFTP_HOST:$ZFTP_PWD"
+  zflastuser="$ZFTP_USER"
   local args
   if [[ -t 1 && -t 2 ]]; then
     local str=$zflastsession
diff --git a/INSTALL b/INSTALL
index c793ff827..569246e92 100644
--- a/INSTALL
+++ b/INSTALL
@@ -220,11 +220,12 @@ turn off both installation of functions and the setting of a default value
 for $fpath/$FPATH.
 
 You can control the functions which get installed by setting
-FUNCTIONS_INSTALL, either when running configure or when running `make
-install' or `make install.fns'.  It includes a list of files relative to
-either the Completion or Functions subdirectories.  By default, all the
-functions for the Completion system will be installed (see the zshcompsys
-manual page), i.e.
+FUNCTIONS_INSTALL, either when running configure (e.g.
+`FUNCTIONS_INSTALL="..." configure ...') or when running `make install' or
+`make install.fns'.  It includes a list of files relative to either the
+Completion or Functions subdirectories.  By default, all the functions for
+the Completion system will be installed (see the zshcompsys manual page),
+i.e.
   FUNCTIONS_INSTALL='Core/* Base/* Builtins/* User/* Commands/*'
 and if the --enable-dynamic option was given, the functions in
 Functions/Zftp, which require the zftp module to be available (see the
@@ -233,6 +234,11 @@ miscellaneous functions with documentation in comments; the complete set
 of functions can be installed with
   FUNCTIONS_INSTALL='Core/* Base/* Builtins/* User/* Commands/* Misc/* Zftp/*'
 
+You can also set --enable-function-subdirs to allow shell
+functions to be installed into subdirectories of the function directory,
+i.e. `Core/*' files will be installed into `FNDIR/Core', and so on.
+This also initialises $fpath/$FPATH appropriately.
+
 Support for large files and integers
 ------------------------------------
 
@@ -257,6 +263,11 @@ type; it does not require that support for large files is actually
 enabled.  Hence you might consider using --enable-lfs on any 32-bit system
 with a suitable compiler such as gcc.
 
+Also note that if `configure' finds out that either of the types off_t or
+ino_t are 64-bit quantities, but that long integers are only 32 bits, all
+the above will be enabled automatically.  This is necessary to ensure
+correct handling of these types.
+
 None of this is relevant for 64-bit systems; zsh should compile and run
 without problems if (sizeof(long) == 8).
 
@@ -300,6 +311,7 @@ Features:
      zlogin=pathname     # the full pathname of the global zlogin script
      zprofile=pathname   # the full pathname of the global zprofile script
      zlogout=pathname    # the full pathname of the global zlogout script
-     fns=directory       # the directory where shell functions will go
+     fndir=directory     # the directory where shell functions will go
+     function-subdirs    # if functions will be installed into subdirectories
      dynamic             # allow dynamically loaded binary modules
      lfs                 # allow configure check for large files
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index f8167a106..505b024e4 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -222,8 +222,21 @@ printulimit(int lim, int hard, int head)
     /* display the limit */
     if (limit == RLIM_INFINITY)
 	printf("unlimited\n");
-    else
-	printf("%ld\n", (long)limit);
+    else {
+# ifdef RLIM_T_IS_QUAD_T
+	printf("%qd\n", limit);
+# else
+#  ifdef RLIM_T_IS_LONG_LONG
+	printf("%lld\n", limit);
+#  else
+#   ifdef RLIM_T_IS_UNSIGNED
+	printf("%lu\n", limit);
+#   else
+	printf("%ld\n", limit);
+#   endif /* RLIM_T_IS_UNSIGNED */
+#  endif /* RLIM_T_IS_LONG_LONG */
+# endif /* RLIM_T_IS_QUAD_T */
+    }
 }
 
 /* limit: set or show resource limits.  The variable hard indicates *
diff --git a/Src/Makefile.in b/Src/Makefile.in
index dd96aaf90..e98a696e4 100644
--- a/Src/Makefile.in
+++ b/Src/Makefile.in
@@ -205,8 +205,12 @@ clean: clean-modules
 distclean: distclean-modules
 realclean: realclean-modules
 
-mostlyclean-modules clean-modules distclean-modules realclean-modules: Makemod
-	@$(MAKE) -f Makemod $(MAKEDEFS) `echo $@ | sed 's/-modules//'`
+# Don't remake Makemod just to delete things, even if it doesn't exist.
+mostlyclean-modules clean-modules distclean-modules realclean-modules:
+	if test -f Makemod; then \
+	  @$(MAKE) -f Makemod $(MAKEDEFS) `echo $@ | sed 's/-modules//'`; \
+	fi; \
+	exit 0
 
 @CLEAN_MK@
 
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 873617e95..63bca854c 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -230,7 +230,7 @@ static char *lastmsg, lastcodestr[4];
 static int lastcode;
 
 /* flag for remote system is UNIX --- useful to know as things are simpler */
-static int zfis_unix, zfpassive_conn;
+static int zfpassive_conn;
 
 /* remote system has size, mdtm commands */
 enum {
@@ -1786,7 +1786,6 @@ zftp_open(char *name, char **args, int flags)
 	return 1;
     }
 
-    zfis_unix = 0;
     zfhas_size = zfhas_mdtm = ZFCP_UNKN;
     zdfd = -1;
     /* initial status: open, ASCII data, stream mode 'n' stuff */
@@ -2039,14 +2038,12 @@ zftp_login(char *name, char **args, int flags)
 		/*
 		 * Use binary for transfers.  This simple test saves much
 		 * hassle for all concerned, particularly me.
+		 *
+		 * We could set this based just on the UNIX part,
+		 * but I don't really know the consequences of that.
 		 */
 		zfstatus |= ZFST_IMAG;
-		zfis_unix = 1;
 	    }
-	    /*
-	     * we could set zfis_unix based just on the UNIX part,
-	     * but I don't really know the consequences of that.
-	     */
 	    zfsetparam("ZFTP_SYSTEM", systype, ZFPM_READONLY);
 	}
 	zfstatus |= ZFST_SYST;
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index c12c5894b..e2ccfbc46 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -788,9 +788,8 @@ static char *suffixfunc;
 void
 makesuffix(int n)
 {
-    suffixlen[256] = suffixlen[' '] = suffixlen['\t'] = suffixlen['\n'] =
-	suffixlen[';'] = suffixlen['|'] = suffixlen['&'] = 
-	suffixlen['<'] = suffixlen['>'] = n;
+    suffixlen[256] = suffixlen[' '] = suffixlen['\t'] = suffixlen['\n'] = 
+	suffixlen[';'] = suffixlen['&'] = suffixlen['|'] = n;
 }
 
 /* Set up suffix for parameter names: the last n characters are a suffix *
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 281fe211d..8c2ae7bb6 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -681,12 +681,11 @@ cmphaswilds(char *str)
 /* Check if we have to complete a parameter name. */
 
 static char *
-check_param(char *s, int set, char **ep)
+check_param(char *s, int set, int test)
 {
     char *p;
-    int bq = 0, eq = 0, i;
 
-    if (!ep)
+    if (!test)
 	ispar = parq = eparq = 0;
     /* Try to find a `$'. */
     for (p = s + offs; p > s && *p != String && *p != Qstring; p--);
@@ -726,9 +725,9 @@ check_param(char *s, int set, char **ep)
 
 	e = b;
 	if (br) {
-	    while (*e == (ep ? Dnull : '"'))
-		e++, parq++, bq++;
-	    if (!ep)
+	    while (*e == (test ? Dnull : '"'))
+		e++, parq++;
+	    if (!test)
 		b = e;
 	}
 	/* Find the end of the name. */
@@ -749,14 +748,12 @@ check_param(char *s, int set, char **ep)
 	if (offs <= e - s && offs >= b - s && n <= 0) {
 	    if (br) {
 		p = e;
-		while (*p == (ep ? Dnull : '"'))
-		    p++, parq--, eparq++, eq++;
+		while (*p == (test ? Dnull : '"'))
+		    p++, parq--, eparq++;
 	    }
 	    /* It is. */
-	    if (ep) {
-		*ep = e;
+	    if (test)
 		return b;
-	    }
 	    /* If we were called from makecomplistflags(), we have to set the
 	     * global variables. */
 
@@ -765,21 +762,12 @@ check_param(char *s, int set, char **ep)
 		    mflags |= CMF_PARBR;
 
 		/* Get the prefix (anything up to the character before the name). */
-		for (i = eq, p = e; i; i--, p++)
-		    *p = '.';
-		isuf = quotename(e, NULL);
-		for (i = eq, p = isuf; i; i--, p++)
-		    *p = '"';
+		isuf = dupstring(e);
+		untokenize(isuf);
 		*e = '\0';
 		ripre = dupstring(s);
 		ripre[b - s] = '\0';
-		for (i = bq, p = ripre + (b - s) - 1; i; i--, p--)
-		    *p = '.';
-		ipre = quotename(ripre, NULL);
-		for (i = bq, p = ripre + strlen(ripre) - 1; i; i--, p--)
-		    *p = '"';
-		for (i = bq, p = ipre + strlen(ipre) - 1; i; i--, p--)
-		    *p = '"';
+		ipre = dupstring(ripre);
 		untokenize(ipre);
 	    }
 	    else
@@ -1231,8 +1219,7 @@ get_comp_string(void)
 	clwpos = -1;
 	lexsave();
 	inpush(dupstrspace((char *) linptr), 0, NULL);
-	strinbeg();
-	stophist = 2;
+	strinbeg(0);
 	i = tt0 = cp = rd = ins = oins = linarr = parct = ia = 0;
 
 	/* This loop is possibly the wrong way to do this.  It goes through *
@@ -1535,11 +1522,12 @@ get_comp_string(void)
 	/* This variable will hold the current word in quoted form. */
 	qword = ztrdup(s);
 	offs = cs - wb;
-	if ((p = check_param(s, 0, &tt))) {
-	    for (; *p == Dnull; p++)
-		*p = '"';
-	    for (; *tt == Dnull; tt++)
-		*tt = '"';
+	if ((p = check_param(s, 0, 1))) {
+	    for (p = s; *p; p++)
+		if (*p == Dnull)
+		    *p = '"';
+		else if (*p == Snull)
+		    *p = '\'';
 	}
 	if (*s == Snull || *s == Dnull) {
 	    char *q = (*s == Snull ? "'" : "\""), *n = tricat(qipre, q, "");
@@ -3427,7 +3415,7 @@ add_match_data(int alt, char *str, Cline line,
     Aminfo ai = (alt ? fainfo : ainfo);
     int palen, salen, qipl, ipl, pl, ppl, qisl, isl, psl;
 
-    palen = salen = qipl = ipl = pl = ppl = isl = psl = 0;
+    palen = salen = qipl = ipl = pl = ppl = qisl = isl = psl = 0;
 
     DPUTS(!line, "BUG: add_match_data() without cline");
 
@@ -4369,10 +4357,10 @@ docompletion(char *s, int lst, int incmd)
 	    invalidatelist();
 
 	/* Print the explanation strings if needed. */
-	if (!showinglist && validlist && nmatches != 1) {
+	if (!showinglist && validlist && usemenu != 2 && nmatches != 1) {
 	    Cmgroup g = amatches;
 	    Cexpl *e;
-	    int up = 0, tr = 1;
+	    int up = 0, tr = 1, nn = 0;
 
 	    if (!nmatches)
 		feep();
@@ -4385,7 +4373,12 @@ docompletion(char *s, int lst, int incmd)
 				trashzle();
 				tr = 0;
 			    }
+			    if (nn) {
+				up++;
+				putc('\n', shout);
+			    }
 			    up += printfmt((*e)->str, (*e)->count, 1);
+			    nn = 1;
 			}
 			e++;
 		    }
@@ -4915,6 +4908,9 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
     int ois = instring, oib = inbackt;
     char *tmp, *p, *ns, *ol = (char *) line, sav, oaq = autoq, *qp, *qs;
 
+    swb = swe = soffs = 0;
+    ns = NULL;
+
     /* Put the string in the lexer buffer and call the lexer to *
      * get the words we have to expand.                        */
     zleparse = 1;
@@ -4930,8 +4926,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
     inpush(dupstrspace(tmp), 0, NULL);
     line = (unsigned char *) tmp;
     ll = tl - 1;
-    strinbeg();
-    stophist = 2;
+    strinbeg(0);
     noaliases = 1;
     do {
 	ctxtlex();
@@ -4979,11 +4974,21 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
     ll = oll;
     if (cur < 0 || i < 1)
 	return 1;
+    owb = offs;
+    offs = soffs;
+    if ((p = check_param(ns, 0, 1))) {
+	for (p = ns; *p; p++)
+	    if (*p == Dnull)
+		*p = '"';
+	    else if (*p == Snull)
+		*p = '\'';
+    }
+    offs = owb;
     if (*ns == Snull || *ns == Dnull) {
 	instring = (*ns == Snull ? 1 : 2);
 	inbackt = 0;
 	swb++;
-	if (ns[strlen(ns) - 1] == *ns)
+	if (ns[strlen(ns) - 1] == *ns && ns[1])
 	    swe--;
 	autoq = (*ns == Snull ? '\'' : '"');
     } else {
@@ -5028,7 +5033,8 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
 	char **ow = clwords, *os = cmdstr, *oqp = qipre, *oqs = qisuf;
 	int olws = clwsize, olwn = clwnum, olwp = clwpos;
 	int obr = brange, oer = erange, oof = offs;
-	
+	unsigned long occ = ccont;
+
 	clwsize = clwnum = countlinknodes(foo);
 	clwords = (char **) zalloc((clwnum + 1) * sizeof(char *));
 	for (n = firstnode(foo), i = 0; n; incnode(n), i++) {
@@ -5043,7 +5049,9 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
 	qipre = qp;
 	qisuf = qs;
 	offs = soffs;
+	ccont = CC_CCCONT;
 	makecomplistcmd(ns, !clwpos, CFN_FIRST);
+	ccont = occ;
 	offs = oof;
 	zsfree(cmdstr);
 	cmdstr = os;
@@ -6341,7 +6349,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	tmpbuf = (char *)zhalloc(strlen(cc->str) + 5);
 	sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */
 	inpush(tmpbuf, 0, NULL);
-	strinbeg();
+	strinbeg(0);
 	noaliases = 1;
 	do {
 	    ctxtlex();
@@ -6502,7 +6510,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	int oldn = clwnum, oldp = clwpos;
 	unsigned long occ = ccont;
 	
-	ccont = 0;
+	ccont = CC_CCCONT;
 	
 	/* So we restrict the words-array. */
 	if (brange >= clwnum)
@@ -8099,14 +8107,13 @@ doexpandhist(void)
 	lexsave();
 	/* We push ol as it will remain unchanged */
 	inpush((char *) ol, 0, NULL);
-	strinbeg();
+	strinbeg(1);
 	noaliases = 1;
 	noerrs = 1;
 	exlast = inbufct;
 	do {
 	    ctxtlex();
 	} while (tok != ENDINPUT && tok != LEXERR);
-	stophist = 2;
 	while (!lexstop)
 	    hgetc();
 	/* We have to save errflags because it's reset in lexrestore. Since  *
@@ -8178,7 +8185,7 @@ getcurcmd(void)
 	metafy_line();
 	inpush(dupstrspace((char *) line), 0, NULL);
 	unmetafy_line();
-	strinbeg();
+	strinbeg(1);
 	pushheap();
 	do {
 	    curlincmd = incmdpos;
diff --git a/Src/builtin.c b/Src/builtin.c
index 4c9b159dd..d74d9cd88 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -43,7 +43,7 @@ static struct builtin builtins[] =
     BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
     BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL),
     BUILTIN("alias", BINF_MAGICEQUALS, bin_alias, 0, -1, 0, "Lgmr", NULL),
-    BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "t", "u"),
+    BUILTIN("autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "tU", "u"),
     BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
     BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL),
     BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
@@ -64,7 +64,7 @@ static struct builtin builtins[] =
     BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
     BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL),
     BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
-    BUILTIN("functions", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "mtu", NULL),
+    BUILTIN("functions", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "mtuU", NULL),
     BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
     BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
     BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "dfmrv", NULL),
@@ -209,7 +209,7 @@ execbuiltin(LinkList args, Builtin bn)
     LinkNode n;
     char ops[MAX_OPS], *arg, *pp, *name, **argv, **oargv, *optstr;
     char *oxarg, *xarg = NULL;
-    int flags, sense, argc = 0, execop;
+    int flags, sense, argc = 0, execop, xtr = isset(XTRACE), lxarg = 0;
 
     /* initialise some static variables */
     auxdata = NULL;
@@ -250,12 +250,21 @@ execbuiltin(LinkList args, Builtin bn)
 		    break;
 	    }
 	    /* save the options in xarg, for execution tracing */
-	    if (xarg) {
-		oxarg = tricat(xarg, " ", arg);
-		zsfree(xarg);
-		xarg = oxarg;
-	    } else
-		xarg = ztrdup(arg);
+	    if (xtr) {
+		if (xarg) {
+		    int l = strlen(arg) + lxarg + 1;
+
+		    oxarg = zhalloc(l + 1);
+		    strcpy(oxarg, xarg);
+		    oxarg[lxarg] = ' ';
+		    strcpy(oxarg + lxarg + 1, arg);
+		    xarg = oxarg;
+		    lxarg = l + 1;
+		} else {
+		    xarg = dupstring(arg);
+		    lxarg = strlen(xarg);
+		}
+	    }
 	    /* handle -- or - (ops['-']), and + (ops['-'] and ops['+']) */
 	    if (arg[1] == '-')
 		arg++;
@@ -283,7 +292,6 @@ execbuiltin(LinkList args, Builtin bn)
 		if(*arg == Meta)
 		    *++arg ^= 32;
 		zerr("bad option: -%c", NULL, *arg);
-		zsfree(xarg);
 		return 1;
 	    }
 	    arg = (char *) ugetnode(args);
@@ -330,7 +338,6 @@ execbuiltin(LinkList args, Builtin bn)
 	while ((*argv++ = (char *)ugetnode(args)));
     argv = oargv;
     if (errflag) {
-	zsfree(xarg);
 	errflag = 0;
 	return 1;
     }
@@ -339,12 +346,11 @@ execbuiltin(LinkList args, Builtin bn)
     if (argc < bn->minargs || (argc > bn->maxargs && bn->maxargs != -1)) {
 	zwarnnam(name, (argc < bn->minargs)
 		? "not enough arguments" : "too many arguments", NULL, 0);
-	zsfree(xarg);
 	return 1;
     }
 
     /* display execution trace information, if required */
-    if (isset(XTRACE)) {
+    if (xtr) {
 	fprintf(stderr, "%s%s", (prompt4) ? prompt4 : "", name);
 	if (xarg)
 	    fprintf(stderr, " %s", xarg);
@@ -353,7 +359,6 @@ execbuiltin(LinkList args, Builtin bn)
 	fputc('\n', stderr);
 	fflush(stderr);
     }
-    zsfree(xarg);
     /* call the handler function, and return its return value */
     return (*(bn->handlerfunc)) (name, argv, ops, bn->funcid);
 }
@@ -1824,17 +1829,18 @@ bin_functions(char *name, char **argv, char *ops, int func)
     int on = 0, off = 0;
 
     /* Do we have any flags defined? */
-    if (ops['u'] || ops['t']) {
-	if (ops['u'] == 1)
-	    on |= PM_UNDEFINED;
-	else if (ops['u'] == 2)
-	    off |= PM_UNDEFINED;
-
-	if (ops['t'] == 1)
-	    on |= PM_TAGGED;
-	else if (ops['t'] == 2)
-	    off |= PM_TAGGED;
-    }
+    if (ops['u'] == 1)
+	on |= PM_UNDEFINED;
+    else if (ops['u'] == 2)
+	off |= PM_UNDEFINED;
+    if (ops['U'] == 1)
+	on |= PM_UNALIASED|PM_UNDEFINED;
+    else if (ops['U'] == 2)
+	off |= PM_UNALIASED;
+    if (ops['t'] == 1)
+	on |= PM_TAGGED;
+    else if (ops['t'] == 2)
+	off |= PM_TAGGED;
 
     if (off & PM_UNDEFINED) {
 	zwarnnam(name, "invalid option(s)", NULL, 0);
@@ -1845,6 +1851,8 @@ bin_functions(char *name, char **argv, char *ops, int func)
      * are given, we will print only functions containing these  *
      * flags, else we'll print them all.                         */
     if (!*argv) {
+	if (ops['U'] && !ops['u'])
+	    on &= ~PM_UNDEFINED;
 	scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, 0);
 	return 0;
     }
@@ -3078,8 +3086,7 @@ bin_eval(char *nam, char **argv, char *ops, int func)
     List list;
 
     inpush(zjoin(argv, ' '), 0, NULL);
-    strinbeg();
-    stophist = 2;
+    strinbeg(0);
     list = parse_list();
     strinend();
     inpop();
@@ -3584,7 +3591,7 @@ bin_trap(char *name, char **argv, char *ops, int func)
 		if (!sigfuncs[sig])
 		    printf("trap -- '' %s\n", sigs[sig]);
 		else {
-		    s = getpermtext((void *) dupstruct((void *) sigfuncs[sig]));
+		    s = getpermtext((void *) sigfuncs[sig]);
 		    printf("trap -- ");
 		    quotedzputs(s, stdout);
 		    printf(" %s\n", sigs[sig]);
diff --git a/Src/cond.c b/Src/cond.c
index a8387a454..98deea2bf 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -42,6 +42,7 @@ int
 evalcond(Cond c)
 {
     struct stat *st;
+    char *left, *right = NULL;
 
     switch (c->type) {
     case COND_NOT:
@@ -103,107 +104,109 @@ evalcond(Cond c)
 	    return 0;
 	}
     }
-    singsub((char **)&c->left);
-    untokenize(c->left);
+    left = dupstring((char *) c->left);
+    singsub(&left);
+    untokenize(left);
     if (c->right) {
-	singsub((char **)&c->right);
+	right = dupstring((char *) c->right);
+	singsub(&right);
 	if (c->type != COND_STREQ && c->type != COND_STRNEQ)
-	    untokenize(c->right);
+	    untokenize(right);
     }
 
     if (tracingcond) {
 	if (c->type < COND_MOD) {
-	    char *rt = (char *)c->right;
+	    char *rt = (char *)right;
 	    if (c->type == COND_STREQ || c->type == COND_STRNEQ) {
 		rt = dupstring(rt);
 		untokenize(rt);
 	    }
-	    fprintf(stderr, " %s %s %s", (char *)c->left, condstr[c->type],
+	    fprintf(stderr, " %s %s %s", (char *)left, condstr[c->type],
 		    rt);
 	} else
-	    fprintf(stderr, " -%c %s", c->type, (char *)c->left);
+	    fprintf(stderr, " -%c %s", c->type, (char *)left);
     }
 
     switch (c->type) {
     case COND_STREQ:
-	return matchpat(c->left, c->right);
+	return matchpat(left, right);
     case COND_STRNEQ:
-	return !matchpat(c->left, c->right);
+	return !matchpat(left, right);
     case COND_STRLT:
-	return strcmp(c->left, c->right) < 0;
+	return strcmp(left, right) < 0;
     case COND_STRGTR:
-	return strcmp(c->left, c->right) > 0;
+	return strcmp(left, right) > 0;
     case 'e':
     case 'a':
-	return (doaccess(c->left, F_OK));
+	return (doaccess(left, F_OK));
     case 'b':
-	return (S_ISBLK(dostat(c->left)));
+	return (S_ISBLK(dostat(left)));
     case 'c':
-	return (S_ISCHR(dostat(c->left)));
+	return (S_ISCHR(dostat(left)));
     case 'd':
-	return (S_ISDIR(dostat(c->left)));
+	return (S_ISDIR(dostat(left)));
     case 'f':
-	return (S_ISREG(dostat(c->left)));
+	return (S_ISREG(dostat(left)));
     case 'g':
-	return (!!(dostat(c->left) & S_ISGID));
+	return (!!(dostat(left) & S_ISGID));
     case 'k':
-	return (!!(dostat(c->left) & S_ISVTX));
+	return (!!(dostat(left) & S_ISVTX));
     case 'n':
-	return (!!strlen(c->left));
+	return (!!strlen(left));
     case 'o':
-	return (optison(c->left));
+	return (optison(left));
     case 'p':
-	return (S_ISFIFO(dostat(c->left)));
+	return (S_ISFIFO(dostat(left)));
     case 'r':
-	return (doaccess(c->left, R_OK));
+	return (doaccess(left, R_OK));
     case 's':
-	return ((st = getstat(c->left)) && !!(st->st_size));
+	return ((st = getstat(left)) && !!(st->st_size));
     case 'S':
-	return (S_ISSOCK(dostat(c->left)));
+	return (S_ISSOCK(dostat(left)));
     case 'u':
-	return (!!(dostat(c->left) & S_ISUID));
+	return (!!(dostat(left) & S_ISUID));
     case 'w':
-	return (doaccess(c->left, W_OK));
+	return (doaccess(left, W_OK));
     case 'x':
 	if (privasserted()) {
-	    mode_t mode = dostat(c->left);
+	    mode_t mode = dostat(left);
 	    return (mode & S_IXUGO) || S_ISDIR(mode);
 	}
-	return doaccess(c->left, X_OK);
+	return doaccess(left, X_OK);
     case 'z':
-	return (!strlen(c->left));
+	return (!strlen(left));
     case 'h':
     case 'L':
-	return (S_ISLNK(dolstat(c->left)));
+	return (S_ISLNK(dolstat(left)));
     case 'O':
-	return ((st = getstat(c->left)) && st->st_uid == geteuid());
+	return ((st = getstat(left)) && st->st_uid == geteuid());
     case 'G':
-	return ((st = getstat(c->left)) && st->st_gid == getegid());
+	return ((st = getstat(left)) && st->st_gid == getegid());
     case 'N':
-	return ((st = getstat(c->left)) && st->st_atime <= st->st_mtime);
+	return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
     case 't':
-	return isatty(matheval(c->left));
+	return isatty(matheval(left));
     case COND_EQ:
-	return matheval(c->left) == matheval(c->right);
+	return matheval(left) == matheval(right);
     case COND_NE:
-	return matheval(c->left) != matheval(c->right);
+	return matheval(left) != matheval(right);
     case COND_LT:
-	return matheval(c->left) < matheval(c->right);
+	return matheval(left) < matheval(right);
     case COND_GT:
-	return matheval(c->left) > matheval(c->right);
+	return matheval(left) > matheval(right);
     case COND_LE:
-	return matheval(c->left) <= matheval(c->right);
+	return matheval(left) <= matheval(right);
     case COND_GE:
-	return matheval(c->left) >= matheval(c->right);
+	return matheval(left) >= matheval(right);
     case COND_NT:
     case COND_OT:
 	{
 	    time_t a;
 
-	    if (!(st = getstat(c->left)))
+	    if (!(st = getstat(left)))
 		return 0;
 	    a = st->st_mtime;
-	    if (!(st = getstat(c->right)))
+	    if (!(st = getstat(right)))
 		return 0;
 	    return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
 	}
@@ -212,11 +215,11 @@ evalcond(Cond c)
 	    dev_t d;
 	    ino_t i;
 
-	    if (!(st = getstat(c->left)))
+	    if (!(st = getstat(left)))
 		return 0;
 	    d = st->st_dev;
 	    i = st->st_ino;
-	    if (!(st = getstat(c->right)))
+	    if (!(st = getstat(right)))
 		return 0;
 	    return d == st->st_dev && i == st->st_ino;
 	}
diff --git a/Src/exec.c b/Src/exec.c
index 952dfbb78..5cfe3e3ef 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -139,8 +139,7 @@ parse_string(char *s)
 
     lexsave();
     inpush(s, 0, NULL);
-    strinbeg();
-    stophist = 2;
+    strinbeg(0);
     l = parse_list();
     strinend();
     inpop();
@@ -298,12 +297,12 @@ static char list_pipe_text[JOBTEXTSIZE];
 
 /**/
 static int
-execcursh(Cmd cmd)
+execcursh(Cmd cmd, LinkList args, int flags)
 {
     if (!list_pipe)
 	deletejob(jobtab + thisjob);
-    execlist(cmd->u.list, 1, cmd->flags & CFLAG_EXEC);
-    cmd->u.list = NULL;
+    execlist(cmd->u.list, 1, flags & CFLAG_EXEC);
+
     return lastval;
 }
 
@@ -718,7 +717,6 @@ execlist(List list, int dont_change_job, int exiting)
 	/* Reset donetrap:  this ensures that a trap is only *
 	 * called once for each sublist that fails.          */
 	donetrap = 0;
-	simplifyright(list);
 	slist = list->left;
 
 	/* Loop through code followed by &&, ||, or end of sublist. */
@@ -1009,11 +1007,13 @@ execpline2(Pline pline, int how, int input, int output, int last1)
     lineno = pline->left->lineno;
 
     if (pline_level == 1)
-	strcpy(list_pipe_text, getjobtext((void *) pline->left));
-    if (pline->type == END) {
+	if (!sfcontext)
+	    strcpy(list_pipe_text, getjobtext((void *) pline->left));
+	else
+	    list_pipe_text[0] = '\0';
+    if (pline->type == END)
 	execcmd(pline->left, input, output, how, last1 ? 1 : 2);
-	pline->left = NULL;
-    } else {
+    else {
 	int old_list_pipe = list_pipe;
 
 	mpipe(pipes);
@@ -1046,11 +1046,10 @@ execpline2(Pline pline, int how, int input, int output, int last1)
 		_exit(lastval);
 	    }
 	} else {
-	/* otherwise just do the pipeline normally. */
+	    /* otherwise just do the pipeline normally. */
 	    subsh_close = pipes[0];
 	    execcmd(pline->left, input, pipes[1], how, 0);
 	}
-	pline->left = NULL;
 	zclose(pipes[1]);
 	if (pline->right) {
 	    /* if another execpline() is invoked because the command is *
@@ -1102,13 +1101,17 @@ makecline(LinkList list)
 void
 untokenize(char *s)
 {
-    for (; *s; s++)
-	if (itok(*s)) {
-	    if (*s == Nularg)
-		chuck(s--);
-	    else
-		*s = ztokens[*s - Pound];
-	}
+    if (*s) {
+	char *p = s, c;
+
+	while ((c = *s++))
+	    if (itok(c)) {
+		if (c != Nularg)
+		    *p++ = ztokens[c - Pound];
+	    } else
+		*p++ = c;
+	*p = '\0';
+    }
 }
 
 /* Open a file for writing redicection */
@@ -1152,34 +1155,34 @@ clobber_open(struct redir *f)
 static void
 closemn(struct multio **mfds, int fd)
 {
-    struct multio *mn = mfds[fd];
-    char buf[TCBUFSIZE];
-    int len, i;
+    if (fd >= 0 && mfds[fd] && mfds[fd]->ct >= 2) {
+	struct multio *mn = mfds[fd];
+	char buf[TCBUFSIZE];
+	int len, i;
 
-    if (fd < 0 || !mfds[fd] || mfds[fd]->ct < 2)
-	return;
-    if (zfork()) {
-	for (i = 0; i < mn->ct; i++)
-	    zclose(mn->fds[i]);
-	zclose(mn->pipe);
-	mn->ct = 1;
-	mn->fds[0] = fd;
-	return;
-    }
-    /* pid == 0 */
-    closeallelse(mn);
-    if (mn->rflag) {
-	/* tee process */
-	while ((len = read(mn->pipe, buf, TCBUFSIZE)) > 0)
+	if (zfork()) {
 	    for (i = 0; i < mn->ct; i++)
-		write(mn->fds[i], buf, len);
-    } else {
-	/* cat process */
-	for (i = 0; i < mn->ct; i++)
-	    while ((len = read(mn->fds[i], buf, TCBUFSIZE)) > 0)
-		write(mn->pipe, buf, len);
+		zclose(mn->fds[i]);
+	    zclose(mn->pipe);
+	    mn->ct = 1;
+	    mn->fds[0] = fd;
+	    return;
+	}
+	/* pid == 0 */
+	closeallelse(mn);
+	if (mn->rflag) {
+	    /* tee process */
+	    while ((len = read(mn->pipe, buf, TCBUFSIZE)) > 0)
+		for (i = 0; i < mn->ct; i++)
+		    write(mn->fds[i], buf, len);
+	} else {
+	    /* cat process */
+	    for (i = 0; i < mn->ct; i++)
+		while ((len = read(mn->fds[i], buf, TCBUFSIZE)) > 0)
+		    write(mn->pipe, buf, len);
+	}
+	_exit(0);
     }
-    _exit(0);
 }
 
 /* close all the mnodes (failure) */
@@ -1273,9 +1276,10 @@ static void
 addvars(LinkList l, int export)
 {
     Varasg v;
+    LinkNode n;
     LinkList vl;
     int xtr;
-    char **arr, **ptr;
+    char **arr, **ptr, *name;
 
     xtr = isset(XTRACE);
     if (xtr && nonempty(l)) {
@@ -1283,26 +1287,30 @@ addvars(LinkList l, int export)
 	doneps4 = 1;
     }
 
-    while (nonempty(l)) {
-	v = (Varasg) ugetnode(l);
-	singsub(&v->name);
+    for (n = firstnode(l); n; incnode(n)) {
+	v = (Varasg) getdata(n);
+	name = dupstring(v->name);
+	singsub(&name);
 	if (errflag)
 	    return;
-	untokenize(v->name);
+	untokenize(name);
 	if (xtr)
-	    fprintf(stderr, "%s=", v->name);
+	    fprintf(stderr, "%s=", name);
 	if (v->type == PM_SCALAR) {
 	    vl = newlinklist();
-	    addlinknode(vl, v->str);
+	    addlinknode(vl, dupstring(v->str));
 	} else
-	    vl = v->arr;
-	prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) : PF_ASSIGN);
-	if (errflag)
-	    return;
-	if (isset(GLOBASSIGN) || v->type != PM_SCALAR)
-	    globlist(vl);
-	if (errflag)
-	    return;
+	    vl = listdup(v->arr);
+	if (vl) {
+	    prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) :
+		                               PF_ASSIGN);
+	    if (errflag)
+		return;
+	    if (isset(GLOBASSIGN) || v->type != PM_SCALAR)
+		globlist(vl);
+	    if (errflag)
+		return;
+	}
 	if (v->type == PM_SCALAR && (empty(vl) || !nextnode(firstnode(vl)))) {
 	    Param pm;
 	    char *val;
@@ -1319,7 +1327,7 @@ addvars(LinkList l, int export)
 	    if (export) {
 		if (export < 0) {
 		    /* We are going to fork so do not bother freeing this */
-		    pm = (Param) paramtab->removenode(paramtab, v->name);
+		    pm = (Param) paramtab->removenode(paramtab, name);
 		    if (isset(RESTRICTED) && (pm->flags & PM_RESTRICTED)) {
 			zerr("%s: restricted", pm->nam, 0);
 			zsfree(val);
@@ -1328,18 +1336,22 @@ addvars(LinkList l, int export)
 		}
 		allexp = opts[ALLEXPORT];
 		opts[ALLEXPORT] = 1;
-		pm = setsparam(v->name, val);
+		pm = setsparam(name, val);
 		opts[ALLEXPORT] = allexp;
 	    } else
-		pm = setsparam(v->name, val);
+		pm = setsparam(name, val);
 	    if (errflag)
 		return;
 	    continue;
 	}
-	ptr = arr = (char **) zalloc(sizeof(char **) * (countlinknodes(vl) + 1));
+	if (vl) {
+	    ptr = arr = (char **) zalloc(sizeof(char **) *
+					 (countlinknodes(vl) + 1));
 
-	while (nonempty(vl))
-	    *ptr++ = ztrdup((char *) ugetnode(vl));
+	    while (nonempty(vl))
+		*ptr++ = ztrdup((char *) ugetnode(vl));
+	} else
+	    ptr = arr = (char **) zalloc(sizeof(char **));
 
 	*ptr = NULL;
 	if (xtr) {
@@ -1348,7 +1360,7 @@ addvars(LinkList l, int export)
 		fprintf(stderr, "%s ", *ptr);
 	    fprintf(stderr, ") ");
 	}
-	setaparam(v->name, arr);
+	setaparam(name, arr);
 	if (errflag)
 	    return;
     }
@@ -1364,15 +1376,19 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     struct multio *mfds[10];
     char *text;
     int save[10];
-    int fil, dfil, is_cursh, type, i;
+    int fil, dfil, is_cursh, type, flags, i;
     int nullexec = 0, assign = 0, forked = 0;
     int is_shfunc = 0, is_builtin = 0, is_exec = 0;
     /* Various flags to the command. */
     int cflags = 0, checked = 0;
+    LinkList vars, redir;
 
     doneps4 = 0;
-    args = cmd->args;
+    args = listdup(cmd->args);
     type = cmd->type;
+    flags = cmd->flags;
+    redir = dupheaplist(cmd->redir);
+    vars = cmd->vars;
 
     for (i = 0; i < 10; i++) {
 	save[i] = -2;
@@ -1381,7 +1397,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 
     /* If the command begins with `%', then assume it is a *
      * reference to a job in the job table.                */
-    if (type == SIMPLE && nonempty(args) &&
+    if (type == SIMPLE && args && nonempty(args) &&
 	*(char *)peekfirst(args) == '%') {
 	pushnode(args, dupstring((how & Z_DISOWN)
 				 ? "disown" : (how & Z_ASYNC) ? "bg" : "fg"));
@@ -1393,7 +1409,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
      * job currently in the job table.  If it does, then we treat it *
      * as a command to resume this job.                              */
     if (isset(AUTORESUME) && type == SIMPLE && (how & Z_SYNC) &&
-	nonempty(args) && empty(cmd->redir) && !input &&
+	args && nonempty(args) &&
+	(!cmd->redir || empty(cmd->redir)) && !input &&
 	!nextnode(firstnode(args))) {
 	if (unset(NOTIFY))
 	    scanjobs();
@@ -1407,7 +1424,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
      * only works in simple cases.  has_token() is called to make sure   *
      * this really is a simple case.                                     */
     if (type == SIMPLE) {
-	while (nonempty(args)) {
+	while (args && nonempty(args)) {
 	    char *cmdarg = (char *) peekfirst(args);
 	    checked = !has_token(cmdarg);
 	    if (!checked)
@@ -1444,7 +1461,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     }
 
     /* Do prefork substitutions */
-    prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0);
+    if (args)
+	prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0);
 
     if (type == SIMPLE) {
 	int unglobbed = 0;
@@ -1453,7 +1471,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    char *cmdarg;
 
 	    if (!(cflags & BINF_NOGLOB))
-		while (!checked && !errflag && nonempty(args) &&
+		while (!checked && !errflag && args && nonempty(args) &&
 		       has_token((char *) peekfirst(args)))
 		    glob(args, firstnode(args));
 	    else if (!unglobbed) {
@@ -1465,12 +1483,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    /* Current shell should not fork unless the *
 	     * exec occurs at the end of a pipeline.    */
 	    if ((cflags & BINF_EXEC) && last1 == 2)
-		cmd->flags |= CFLAG_EXEC;
+		flags |= CFLAG_EXEC;
 
 	    /* Empty command */
-	    if (empty(args)) {
-		if (nonempty(cmd->redir)) {
-		    if (cmd->flags & CFLAG_EXEC) {
+	    if (!args || empty(args)) {
+		if (redir && nonempty(redir)) {
+		    if (flags & CFLAG_EXEC) {
 			/* Was this "exec < foobar"? */
 			nullexec = 1;
 			break;
@@ -1480,17 +1498,23 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 			errflag = lastval = 1;
 			return;
 		    } else if (readnullcmd && *readnullcmd &&
-			       ((Redir) peekfirst(cmd->redir))->type == READ &&
-			       !nextnode(firstnode(cmd->redir))) {
+			       ((Redir) peekfirst(redir))->type == READ &&
+			       !nextnode(firstnode(redir))) {
+			if (!args)
+			    args = newlinklist();
 			addlinknode(args, dupstring(readnullcmd));
-		    } else
+		    } else {
+			if (!args)
+			    args = newlinklist();
 			addlinknode(args, dupstring(nullcmd));
+		    }
 		} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
 		    lastval = 0;
 		    return;
 		} else {
 		    cmdoutval = 0;
-		    addvars(cmd->vars, 0);
+		    if (vars)
+			addvars(vars, 0);
 		    if (errflag)
 			lastval = errflag;
 		    else
@@ -1502,7 +1526,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		    return;
 		}
 	    } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) &&
-		       (cmd->flags & CFLAG_EXEC)) {
+		       (flags & CFLAG_EXEC)) {
 		zerrnam("exec", "%s: restricted", (char *) getdata(firstnode(args)), 0);
 		lastval = 1;
 		return;
@@ -1548,22 +1572,32 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     }
 
     /* Get the text associated with this command. */
-    if (jobbing || (how & Z_TIMED))
+    if (!sfcontext && (jobbing || (how & Z_TIMED)))
 	text = getjobtext((void *) cmd);
     else
 	text = NULL;
 
     /* Set up special parameter $_ */
-    zsfree(underscore);
-    if (nonempty(args)
-	&& (underscore = ztrdup((char *) getdata(lastnode(args)))))
-	untokenize(underscore); 
-    else
-  	underscore = ztrdup("");
+    if (args && nonempty(args)) {
+	char *u = (char *) getdata(lastnode(args));
+
+	if (u) {
+	    int ul = strlen(u);
+
+	    if (ul >= underscorelen) {
+		zfree(underscore, underscorelen);
+		underscore = (char *) zalloc(underscorelen = ul + 32);
+	    }
+	    strcpy(underscore, u);
+	} else
+	    *underscore = '\0';
+    } else
+	*underscore = '\0';
 
     /* Warn about "rm *" */
     if (type == SIMPLE && interact && unset(RMSTARSILENT)
-	&& isset(SHINSTDIN) && nonempty(args) && nextnode(firstnode(args))
+	&& isset(SHINSTDIN) && args && nonempty(args)
+	&& nextnode(firstnode(args))
 	&& !strcmp(peekfirst(args), "rm")) {
 	LinkNode node, next;
 
@@ -1596,11 +1630,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     if (type == SIMPLE && !nullexec) {
 	char *s;
 	char trycd = (isset(AUTOCD) && isset(SHINSTDIN)
-		      && empty(cmd->redir) && !empty(args)
+		      && (!redir || empty(redir)) && args && !empty(args)
 		      && !nextnode(firstnode(args))
 		      && *(char *)peekfirst(args));
 
-	DPUTS(empty(args), "BUG: empty(args) in exec.c");
+	DPUTS((!args || empty(args)), "BUG: empty(args) in exec.c");
 	if (!hn) {
 	    /* Resolve external commands */
 	    char *cmdarg = (char *) peekfirst(args);
@@ -1652,7 +1686,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
      * current shell.                                                         *
      **************************************************************************/
 
-    if ((how & Z_ASYNC) || (!(cmd->flags & CFLAG_EXEC) &&
+    if ((how & Z_ASYNC) || (!(flags & CFLAG_EXEC) &&
        (((is_builtin || is_shfunc) && output) ||
        (!is_cursh && (last1 != 1 || sigtrapped[SIGZERR] ||
         sigtrapped[SIGEXIT] || havefiles()))))) {
@@ -1677,10 +1711,13 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 #endif
 	    if (how & Z_ASYNC) {
 		lastpid = (zlong) pid;
-	    } else if (!jobtab[thisjob].stty_in_env && nonempty(cmd->vars)) {
+	    } else if (!jobtab[thisjob].stty_in_env &&
+		       vars && nonempty(vars)) {
 		/* search for STTY=... */
-		while (nonempty(cmd->vars))
-		    if (!strcmp(((Varasg) ugetnode(cmd->vars))->name, "STTY")) {
+		LinkNode n;
+
+		for (n = firstnode(vars); n; incnode(n))
+		    if (!strcmp(((Varasg) getdata(n))->name, "STTY")) {
 			jobtab[thisjob].stty_in_env = 1;
 			break;
 		    }
@@ -1713,7 +1750,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	is_exec = 1;
     }
 
-    if (!(cflags & BINF_NOGLOB))
+    if (args && !(cflags & BINF_NOGLOB))
 	globlist(args);
     if (errflag) {
 	lastval = 1;
@@ -1727,11 +1764,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	addfd(forked, save, mfds, 1, output, 1);
 
     /* Do process substitutions */
-    spawnpipes(cmd->redir);
+    if (redir)
+	spawnpipes(redir);
 
     /* Do io redirections */
-    while (nonempty(cmd->redir)) {
-	fn = (Redir) ugetnode(cmd->redir);
+    while (redir && nonempty(redir)) {
+	fn = (Redir) ugetnode(redir);
 	DPUTS(fn->type == HEREDOC || fn->type == HEREDOCDASH,
 	      "BUG: unexpanded here document");
 	if (fn->type == INPIPE) {
@@ -1749,7 +1787,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    }
 	    addfd(forked, save, mfds, fn->fd1, fn->fd2, 1);
 	} else {
-	    if (fn->type != HERESTR && xpandredir(fn, cmd->redir))
+	    if (fn->type != HERESTR && xpandredir(fn, redir))
 		continue;
 	    if (errflag) {
 		closemnodes(mfds);
@@ -1870,15 +1908,15 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	if (is_exec)
 	    entersubsh(how, type != SUBSH ? 2 : 1, 1);
 	if (type >= CURSH) {
-	    static int (*func[]) _((Cmd)) = {
+	    static int (*func[]) _((Cmd, LinkList, int)) = {
 		execcursh, exectime, execfuncdef, execfor, execwhile,
 		execrepeat, execif, execcase, execselect, execcond,
 		execarith, execautofn
 	    };
 
 	    if (last1 == 1)
-		cmd->flags |= CFLAG_EXEC;
-	    lastval = (func[type - CURSH]) (cmd);
+		flags |= CFLAG_EXEC;
+	    lastval = (func[type - CURSH]) (cmd, args, flags);
 	} else if (is_builtin || is_shfunc) {
 	    LinkList restorelist = 0, removelist = 0;
 	    /* builtin or shell function */
@@ -1889,11 +1927,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 			     !(hn->flags & BINF_PSPECIAL))))
 		save_params(cmd, &restorelist, &removelist);
 
-	    if (cmd->vars) {
+	    if (vars) {
 		/* Export this if the command is a shell function,
 		 * but not if it's a builtin.
 		 */
-		addvars(cmd->vars, is_shfunc);
+		addvars(vars, is_shfunc);
 		if (errflag) {
 		    restore_params(restorelist, removelist);
 		    lastval = 1;
@@ -1904,6 +1942,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 
 	    if (is_shfunc) {
 		/* It's a shell function */
+
 #ifdef PATH_DEV_FD
 		int i;
 
@@ -1914,7 +1953,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		if (subsh_close >= 0)
 		    zclose(subsh_close);
 		subsh_close = -1;
-		execshfunc(cmd, (Shfunc) hn);
+		execshfunc(cmd, (Shfunc) hn, args);
 #ifdef PATH_DEV_FD
 		for (i = 10; i <= max_zsh_fd; i++)
 		    if (fdtable[i] > 1)
@@ -1943,7 +1982,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		    clearerr(stdout);
 	    }
 
-	    if (cmd->flags & CFLAG_EXEC) {
+	    if (flags & CFLAG_EXEC) {
 		if (subsh)
 		    _exit(lastval);
 
@@ -1957,7 +1996,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    restore_params(restorelist, removelist);
 
 	} else {
-	    if (cmd->flags & CFLAG_EXEC) {
+	    if (flags & CFLAG_EXEC) {
 		setiparam("SHLVL", --shlvl);
 		/* If we are exec'ing a command, and we are not *
 		 * in a subshell, then save the history file.   */
@@ -1965,8 +2004,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		    savehistfile(NULL, 1, HFILE_USE_OPTIONS);
 	    }
 	    if (type == SIMPLE) {
-		if (cmd->vars) {
-		    addvars(cmd->vars, -1);
+		if (vars) {
+		    addvars(vars, -1);
 		    if (errflag)
 			_exit(1);
 		}
@@ -1981,7 +2020,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 #endif
 		execute((Cmdnam) hn, cflags & BINF_DASH);
 	    } else {		/* ( ... ) */
-		DPUTS(cmd->vars && nonempty(cmd->vars),
+		DPUTS(vars && nonempty(vars),
 		      "BUG: assigment before complex command");
 		list_pipe = 0;
 		if (subsh_close >= 0)
@@ -2011,7 +2050,11 @@ save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p)
     char *s;
 
     MUSTUSEHEAP("save_params()");
-
+    
+    if (!cmd->vars) {
+	*restore_p = *remove_p = NULL;
+	return;
+    }
     *restore_p = newlinklist();
     *remove_p = newlinklist();
 
@@ -2283,8 +2326,9 @@ getoutput(char *cmd, int qt)
 	return NULL;
     if (list != &dummy_list && !list->right && !list->left->flags &&
 	list->left->type == END && list->left->left->type == END &&
-	(c = list->left->left->left)->type == SIMPLE && empty(c->args) &&
-	empty(c->vars) && nonempty(c->redir) &&
+	(c = list->left->left->left)->type == SIMPLE && 
+	(!c->args || empty(c->args)) &&
+	(!c->vars || empty(c->vars)) && c->redir && nonempty(c->redir) &&
 	!nextnode(firstnode(c->redir)) &&
 	(r = (Redir) getdata(firstnode(c->redir)))->fd1 == 0 &&
 	r->type == READ) {
@@ -2613,7 +2657,7 @@ extern int tracingcond;
 
 /**/
 static int
-execcond(Cmd cmd)
+execcond(Cmd cmd, LinkList args, int flags)
 {
     int stat;
     if (isset(XTRACE)) {
@@ -2633,18 +2677,19 @@ execcond(Cmd cmd)
 
 /**/
 static int
-execarith(Cmd cmd)
+execarith(Cmd cmd, LinkList args, int flags)
 {
     char *e;
     zlong val = 0;
 
     if (isset(XTRACE))
 	fprintf(stderr, "%s((", prompt4 ? prompt4 : "");
-    while ((e = (char *) ugetnode(cmd->args))) {
-	if (isset(XTRACE))
-	    fprintf(stderr, " %s", e);
-	val = matheval(e);
-    }
+    if (args)
+	while ((e = (char *) ugetnode(args))) {
+	    if (isset(XTRACE))
+		fprintf(stderr, " %s", e);
+	    val = matheval(e);
+	}
     if (isset(XTRACE)) {
 	fprintf(stderr, " ))\n");
 	fflush(stderr);
@@ -2657,7 +2702,7 @@ execarith(Cmd cmd)
 
 /**/
 static int
-exectime(Cmd cmd)
+exectime(Cmd cmd, LinkList args, int flags)
 {
     int jb;
 
@@ -2675,30 +2720,33 @@ exectime(Cmd cmd)
 
 /**/
 static int
-execfuncdef(Cmd cmd)
+execfuncdef(Cmd cmd, LinkList args, int flags)
 {
     Shfunc shf;
     char *s;
     int signum;
 
-    PERMALLOC {
-	while ((s = (char *) ugetnode(cmd->args))) {
-	    shf = (Shfunc) zalloc(sizeof *shf);
-	    shf->funcdef = (List) dupstruct(cmd->u.list);
-	    shf->flags = 0;
-
-	    /* is this shell function a signal trap? */
-	    if (!strncmp(s, "TRAP", 4) && (signum = getsignum(s + 4)) != -1) {
-		if (settrap(signum, shf->funcdef)) {
-		    freestruct(shf->funcdef);
-		    zfree(shf, sizeof *shf);
-		    LASTALLOC_RETURN 1;
-		}
-		sigtrapped[signum] |= ZSIG_FUNC;
-	    }
-	    shfunctab->addnode(shfunctab, ztrdup(s), shf);
-	}
-    } LASTALLOC;
+    if (args) {
+	PERMALLOC {
+	    while ((s = (char *) ugetnode(args))) {
+		shf = (Shfunc) zalloc(sizeof *shf);
+		shf->funcdef = (List) dupstruct(cmd->u.list);
+		shf->flags = 0;
+
+		/* is this shell function a signal trap? */
+		if (!strncmp(s, "TRAP", 4) &&
+		    (signum = getsignum(s + 4)) != -1) {
+		    if (settrap(signum, shf->funcdef)) {
+			freestruct(shf->funcdef);
+			zfree(shf, sizeof *shf);
+			LASTALLOC_RETURN 1;
+		    }
+		    sigtrapped[signum] |= ZSIG_FUNC;
+  		}
+		shfunctab->addnode(shfunctab, ztrdup(s), shf);
+  	    }
+	} LASTALLOC;
+    }
     if(isset(HISTNOFUNCTIONS))
 	remhist();
     return 0;
@@ -2708,7 +2756,7 @@ execfuncdef(Cmd cmd)
 
 /**/
 static void
-execshfunc(Cmd cmd, Shfunc shf)
+execshfunc(Cmd cmd, Shfunc shf, LinkList args)
 {
     LinkList last_file_list = NULL;
 
@@ -2726,16 +2774,17 @@ execshfunc(Cmd cmd, Shfunc shf)
     if (isset(XTRACE)) {
 	LinkNode lptr;
 	fprintf(stderr, "%s", prompt4 ? prompt4 : prompt4);
-	for (lptr = firstnode(cmd->args); lptr; incnode(lptr)) {
-	    if (lptr != firstnode(cmd->args))
-		fputc(' ', stderr);
-	    fprintf(stderr, "%s", (char *)getdata(lptr));
-	}
+	if (args)
+	    for (lptr = firstnode(args); lptr; incnode(lptr)) {
+		if (lptr != firstnode(args))
+		    fputc(' ', stderr);
+		fprintf(stderr, "%s", (char *)getdata(lptr));
+	    }
 	fputc('\n', stderr);
 	fflush(stderr);
     }
 
-    doshfunc(shf->nam, shf->funcdef, cmd->args, shf->flags, 0);
+    doshfunc(shf->nam, shf->funcdef, args, shf->flags, 0);
 
     if (!list_pipe)
 	deletefilelist(last_file_list);
@@ -2749,10 +2798,16 @@ execshfunc(Cmd cmd, Shfunc shf)
 
 /**/
 static int
-execautofn(Cmd cmd)
+execautofn(Cmd cmd, LinkList args, int flags)
 {
     Shfunc shf = cmd->u.autofn->shf;
-    List l = getfpfunc(shf->nam);
+    int noalias = noaliases;
+    List l;
+
+    noaliases = (shf->flags & PM_UNALIASED);
+    l = getfpfunc(shf->nam);
+    noaliases = noalias;
+
     if(l == &dummy_list) {
 	zerr("%s: function definition file not found", shf->nam, 0);
 	return 1;
@@ -2773,9 +2828,7 @@ execautofn(Cmd cmd)
 	} LASTALLOC;
 	shf->flags &= ~PM_UNDEFINED;
     }
-    HEAPALLOC {
-	execlist(dupstruct(shf->funcdef), 1, 0);
-    } LASTALLOC;
+    execlist(shf->funcdef, 1, 0);
     return lastval;
 }
 
@@ -2822,7 +2875,8 @@ doshfunc(char *name, List list, LinkList doshargs, int flags, int noreturnval)
 	    LinkNode node;
 
 	    node = doshargs->first;
-	    pparams = x = (char **) zcalloc(((sizeof *x) * (1 + countlinknodes(doshargs))));
+	    pparams = x = (char **) zcalloc(((sizeof *x) *
+					     (1 + countlinknodes(doshargs))));
 	    if (isset(FUNCTIONARGZERO)) {
 		oargv0 = argzero;
 		argzero = ztrdup((char *) node->dat);
@@ -2901,7 +2955,7 @@ void
 runshfunc(List list, FuncWrap wrap, char *name)
 {
     int cont;
-    char *ou;
+    VARARR(char, ou, underscorelen);
 
     while (wrap) {
 	wrap->module->wrapper++;
@@ -2917,11 +2971,9 @@ runshfunc(List list, FuncWrap wrap, char *name)
 	wrap = wrap->next;
     }
     startparamscope();
-    ou = underscore;
-    underscore = ztrdup(underscore);
-    execlist(dupstruct(list), 1, 0);
-    zsfree(underscore);
-    underscore = ou;
+    strcpy(ou, underscore);
+    execlist(list, 1, 0);
+    strcpy(underscore, ou);
     endparamscope();
 }
 
@@ -2949,20 +3001,18 @@ getfpfunc(char *s)
 	unmetafy(buf, NULL);
 	if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) {
 	    if ((len = lseek(fd, 0, 2)) != -1) {
+		d = (char *) zalloc(len + 1);
 		lseek(fd, 0, 0);
-		d = (char *) zcalloc(len + 1);
 		if (read(fd, d, len) == len) {
 		    close(fd);
+		    d[len] = '\0';
 		    d = metafy(d, len, META_REALLOC);
 		    HEAPALLOC {
 			r = parse_string(d);
 		    } LASTALLOC;
-		    zfree(d, len + 1);
 		    return r;
-		} else {
-		    zfree(d, len + 1);
+		} else
 		    close(fd);
-		}
 	    } else {
 		close(fd);
 	    }
@@ -2995,9 +3045,10 @@ stripkshdef(List l, char *name)
     if(p->right)
 	return l;
     c = p->left;
-    if(c->type != FUNCDEF || c->flags ||
-	nonempty(c->redir) || nonempty(c->vars) ||
-	empty(c->args) || lastnode(c->args) != firstnode(c->args) ||
+    if (c->type != FUNCDEF || c->flags ||
+	(c->redir && nonempty(c->redir)) || (c->vars && nonempty(c->vars)) ||
+	!c->args || empty(c->args) ||
+	lastnode(c->args) != firstnode(c->args) ||
 	strcmp(name, peekfirst(c->args)))
 	return l;
     return c->u.list;
@@ -3076,8 +3127,7 @@ execsave(void)
     es->trapreturn = trapreturn;
     es->noerrs = noerrs;
     es->subsh_close = subsh_close;
-    es->underscore = underscore;
-    underscore = ztrdup(underscore);
+    es->underscore = ztrdup(underscore);
     es->next = exstack;
     exstack = es;
     noerrs = cmdoutpid = 0;
@@ -3105,8 +3155,8 @@ execrestore(void)
     trapreturn = exstack->trapreturn;
     noerrs = exstack->noerrs;
     subsh_close = exstack->subsh_close;
-    zsfree(underscore);
-    underscore = exstack->underscore;
+    strcpy(underscore, exstack->underscore);
+    zsfree(exstack->underscore);
     en = exstack->next;
     free(exstack);
     exstack = en;
diff --git a/Src/glob.c b/Src/glob.c
index 35aa447de..93b497632 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -744,7 +744,7 @@ parsecomp(int gflag)
 		pptr++;
 	}
 
-	if (*pptr == Inpar && pptr[1] == Pound) {
+	if (*pptr == Inpar && pptr[1] == Pound && isset(EXTENDEDGLOB)) {
 	    /* Found some globbing flags */
 	    char *eptr = pptr;
 	    if (kshfunc != KF_NONE)
@@ -3432,17 +3432,17 @@ tokenize(char *s)
 void
 remnulargs(char *s)
 {
-    int nl = *s;
-    char *t = s;
-
-    while (*s)
-	if (INULL(*s))
-	    chuck(s);
-	else
-	    s++;
-    if (!*t && nl) {
-	t[0] = Nularg;
-	t[1] = '\0';
+    if (*s) {
+	char *t = s, *p = s, c;
+
+	while ((c = *s++))
+	    if (!INULL(c))
+		*p++ = c;
+	*p = '\0';
+	if (!*t) {
+	    t[0] = Nularg;
+	    t[1] = '\0';
+	}
     }
 }
 
diff --git a/Src/hashtable.c b/Src/hashtable.c
index b534d8ac1..e80461b4e 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -880,7 +880,7 @@ printshfuncnode(HashNode hn, int printflags)
 	return;
     }
  
-    t = getpermtext((void *) dupstruct((void *) f->funcdef));
+    t = getpermtext((void *) f->funcdef);
     quotedzputs(f->nam, stdout);
     printf(" () {\n\t");
     zputs(t, stdout);
@@ -1327,7 +1327,7 @@ addhistnode(HashTable ht, char *nam, void *nodeptr)
 {
     HashNode oldnode = addhashnode2(ht, nam, nodeptr);
     Histent he = (Histent)nodeptr;
-    if (oldnode && oldnode != nodeptr) {
+    if (oldnode && oldnode != (HashNode)nodeptr) {
 	if (he->flags & HIST_MAKEUNIQUE
 	 || (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
 	    he->flags |= HIST_DUP;
diff --git a/Src/hist.c b/Src/hist.c
index 4d672deab..49dac724c 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -30,6 +30,27 @@
 #include "zsh.mdh"
 #include "hist.pro"
 
+/* Functions to call for getting/ungetting a character and for history
+ * word control. */
+
+/**/
+int (*hgetc) _((void));
+
+/**/
+void (*hungetc) _((int));
+
+/**/
+void (*hwaddc) _((int));
+
+/**/
+void (*hwbegin) _((int));
+
+/**/
+void (*hwend) _((void));
+
+/**/
+void (*addtoline) _((int));
+
 /* != 0 means history substitution is turned off */
  
 /**/
@@ -159,12 +180,11 @@ int hlinesz;
 /* default event (usually curhist-1, that is, "!!") */
  
 static int defev;
- 
+
 /* add a character to the current history word */
 
-/**/
-void
-hwaddc(int c)
+static void
+ihwaddc(int c)
 {
     /* Only if history line exists and lexing has not finished. */
     if (chline && !(errflag || lexstop)) {
@@ -182,7 +202,7 @@ hwaddc(int c)
 	if (hptr - chline >= hlinesz) {
 	    int oldsiz = hlinesz;
 
-	    chline = realloc(chline, hlinesz = oldsiz + 16);
+	    chline = realloc(chline, hlinesz = oldsiz + 64);
 	    hptr = chline + oldsiz;
 	}
     }
@@ -192,12 +212,12 @@ hwaddc(int c)
  * zsh expands history (see doexpandhist() in zle_tricky.c). It also     *
  * calculates the new cursor position after the expansion. It is called  *
  * from hgetc() and from gettok() in lex.c for characters in comments.   */
- 
+
 /**/
 void
-addtoline(int c)
+iaddtoline(int c)
 {
-    if (! expanding || lexstop)
+    if (!expanding || lexstop)
 	return;
     if (qbang && c == bangchar && stophist < 2) {
 	exlast--;
@@ -216,9 +236,8 @@ addtoline(int c)
     line[cs++] = itok(c) ? ztokens[c - Pound] : c;
 }
 
-/**/
-int
-hgetc(void)
+static int
+ihgetc(void)
 {
     int c = ingetc();
 
@@ -234,7 +253,7 @@ hgetc(void)
     }
     if ((inbufflags & INP_HIST) && !stophist) {
 	/* the current character c came from a history expansion          *
-	 * (inbufflags && INP_HIST) and history is not disabled           *
+	 * (inbufflags & INP_HIST) and history is not disabled            *
 	 * (e.g. we are not inside single quotes). In that case, \!       *
 	 * should be treated as ! (since this \! came from a previous     *
 	 * history line where \ was used to escape the bang). So if       *
@@ -606,9 +625,8 @@ histsubchar(int c)
 /* unget a char and remove it from chline. It can only be used *
  * to unget a character returned by hgetc.                     */
 
-/**/
-void
-hungetc(int c)
+static void
+ihungetc(int c)
 {
     int doit = 1;
 
@@ -641,10 +659,10 @@ hungetc(int c)
 
 /**/
 void
-strinbeg(void)
+strinbeg(int dohist)
 {
     strin++;
-    hbegin();
+    hbegin(dohist);
     lexinit();
 }
 
@@ -661,17 +679,49 @@ strinend(void)
     histdone = 0;
 }
 
+/* dummy functions to use instead of hwaddc(), hwbegin(), and hwend() when
+ * they aren't needed */
+
+static void
+nohw(int c)
+{
+}
+
+static void
+nohwe(void)
+{
+}
+
 /* initialize the history mechanism */
 
 /**/
 void
-hbegin(void)
+hbegin(int dohist)
 {
     isfirstln = isfirstch = 1;
     errflag = histdone = spaceflag = 0;
-    stophist = (!interact || unset(BANGHIST) || unset(SHINSTDIN)) << 1;
-    chline = hptr = zcalloc(hlinesz = 16);
-    chwords = zalloc((chwordlen = 16)*sizeof(short));
+    stophist = (dohist ? ((!interact || unset(SHINSTDIN)) << 1) : 2);
+    if (stophist == 2 || (inbufflags & INP_ALIAS)) {
+	chline = hptr = NULL;
+	hlinesz = 0;
+	chwords = NULL;
+	chwordlen = 0;
+	hgetc = ingetc;
+	hungetc = inungetc;
+	hwaddc = nohw;
+	hwbegin = nohw;
+	hwend = nohwe;
+	addtoline = nohw;
+    } else {
+	chline = hptr = zcalloc(hlinesz = 64);
+	chwords = zalloc((chwordlen = 64) * sizeof(short));
+	hgetc = ihgetc;
+	hungetc = ihungetc;
+	hwaddc = ihwaddc;
+	hwbegin = ihwbegin;
+	hwend = ihwend;
+	addtoline = iaddtoline;
+    }
     chwordpos = 0;
 
     if (histactive & HA_JUNKED)
@@ -864,7 +914,8 @@ hend(void)
     int flag, save = 1;
     char *hf = getsparam("HISTFILE");
 
-    DPUTS(!chline, "BUG: chline is NULL in hend()");
+    DPUTS(stophist != 2 && !(inbufflags & INP_ALIAS) && !chline,
+	  "BUG: chline is NULL in hend()");
     if (histdone & HISTFLAG_SETTY)
 	settyinfo(&shttyinfo);
     if (!(histactive & HA_NOINC)) {
@@ -1005,8 +1056,10 @@ int hwgetword = -1;
 
 /**/
 void
-hwbegin(int offset)
+ihwbegin(int offset)
 {
+    if (stophist == 2 || strin)
+	return;
     if (chwordpos%2)
 	chwordpos--;	/* make sure we're on a word start, not end */
     /* If we're expanding an alias, we should overwrite the expansion
@@ -1023,15 +1076,18 @@ hwbegin(int offset)
 
 /**/
 void
-hwend(void)
+ihwend(void)
 {
+    if (stophist == 2 || strin)
+	return;
     if (chwordpos%2 && chline) {
 	/* end of word reached and we've already begun a word */
 	if (hptr > chline + chwords[chwordpos-1]) {
 	    chwords[chwordpos++] = hptr - chline;
 	    if (chwordpos >= chwordlen) {
 		chwords = (short *) realloc(chwords,
-					    (chwordlen += 16)*sizeof(short));
+					    (chwordlen += 32) * 
+					    sizeof(short));
 	    }
 	    if (hwgetword > -1) {
 		/* We want to reuse the current word position */
@@ -1606,7 +1662,7 @@ readhistfile(char *fn, int err, int readflags)
     else if (!lockhistfile(fn, 1))
 	return;
     if ((in = fopen(unmeta(fn), "r"))) {
-	nwordlist = 16;
+	nwordlist = 64;
 	wordlist = (short *)zalloc(nwordlist*sizeof(short));
 	bufsiz = 1024;
 	buf = zalloc(bufsiz);
@@ -1717,7 +1773,7 @@ readhistfile(char *fn, int err, int readflags)
 		if (*pt) {
 		    if (nwordpos >= nwordlist)
 			wordlist = (short *) realloc(wordlist,
-					(nwordlist += 16)*sizeof(short));
+					(nwordlist += 64)*sizeof(short));
 		    wordlist[nwordpos++] = pt - start;
 		    while (*pt && !inblank(*pt))
 			pt++;
diff --git a/Src/init.c b/Src/init.c
index f9e6574dd..89cbf2a8b 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -37,6 +37,14 @@
 /**/
 int noexitct = 0;
 
+/* buffer for $_ and its length */
+
+/**/
+char *underscore;
+
+/**/
+int underscorelen;
+
 /* what level of sourcing we are at */
  
 /**/
@@ -94,7 +102,7 @@ loop(int toplevel, int justonce)
 	    if (interact)
 		preprompt();
 	}
-	hbegin();		/* init history mech        */
+	hbegin(1);		/* init history mech        */
 	intr();			/* interrupts on            */
 	lexinit();              /* initialize lexical state */
 	if (!(list = parse_event())) {	/* if we couldn't parse a list */
@@ -128,6 +136,8 @@ loop(int toplevel, int justonce)
 	    if (stopmsg)	/* unset 'you have stopped jobs' flag */
 		stopmsg--;
 	    execlist(list, 0, 0);
+	    if (toplevel)
+		freestructs();
 	    tok = toksav;
 	    if (toplevel)
 		noexitct = 0;
@@ -550,8 +560,20 @@ setupvals(void)
     cdpath   = mkarray(NULL);
     manpath  = mkarray(NULL);
     fignore  = mkarray(NULL);
-#ifdef FUNCTION_DIR
-    fpath    = mkarray(ztrdup(FUNCTION_DIR));
+#ifdef FPATH_DIR
+# ifdef FPATH_SUBDIRS
+    {
+	char *fpath_subdirs[] = FPATH_SUBDIRS;
+	int len = sizeof(fpath_subdirs)/sizeof(char *), j;
+
+	fpath = zalloc((len+1)*sizeof(char *));
+	for (j = 0; j < len; j++)
+	    fpath[j] = tricat(FPATH_DIR, "/", fpath_subdirs[j]);
+	fpath[len] = NULL;
+    }
+# else
+    fpath    = mkarray(ztrdup(FPATH_DIR));
+# endif
 #else
     fpath    = mkarray(NULL);
 #endif
@@ -582,7 +604,8 @@ setupvals(void)
     ifs         = ztrdup(DEFAULT_IFS);
     wordchars   = ztrdup(DEFAULT_WORDCHARS);
     postedit    = ztrdup("");
-    underscore  = ztrdup("");
+    underscore  = (char *) zalloc(underscorelen = 32);
+    *underscore = '\0';
 
     zoptarg = ztrdup("");
     zoptind = 1;
diff --git a/Src/jobs.c b/Src/jobs.c
index 7b0eca6b6..31861e284 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -65,10 +65,6 @@ struct tms shtms;
 /**/
 int ttyfrozen;
  
-/* empty job structure for quick clearing of jobtab entries */
-
-static struct job zero;		/* static variables are initialized to zero */
-
 static struct timeval dtimeval, now;
 
 /* Diff two timevals for elapsed-time computations */
@@ -244,8 +240,11 @@ update_job(Job jn)
 		adjustwinsize(0);
 	    }
 	}
+    } else if (list_pipe && (val & 0200) && inforeground == 1) {
+	breaks = loops;
+	errflag = 1;
+	inerrflush();
     }
-
     if (somestopped && jn->stat & STAT_SUPERJOB)
 	return;
     jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
@@ -663,14 +662,16 @@ deletejob(Job jn)
 	nx = pn->next;
 	zfree(pn, sizeof(struct process));
     }
-    zsfree(jn->pwd);
-
     deletefilelist(jn->filelist);
 
     if (jn->ty)
 	zfree(jn->ty, sizeof(struct ttyinfo));
 
-    *jn = zero;
+    jn->gleader = jn->other = 0;
+    jn->stat = jn->stty_in_env = 0;
+    jn->procs = NULL;
+    jn->filelist = NULL;
+    jn->ty = NULL;
 }
 
 /* add a process to the current job */
@@ -831,7 +832,12 @@ waitjob(int job, int sig)
 void
 waitjobs(void)
 {
-    waitjob(thisjob, 0);
+    Job jn = jobtab + thisjob;
+
+    if (jn->procs)
+	waitjob(thisjob, 0);
+    else
+	deletejob(jn);
     thisjob = -1;
 }
 
@@ -843,12 +849,9 @@ clearjobtab(void)
 {
     int i;
 
-    for (i = 1; i < MAXJOB; i++) {
-	if (jobtab[i].pwd)
-	    zsfree(jobtab[i].pwd);
+    for (i = 1; i < MAXJOB; i++)
 	if (jobtab[i].ty)
 	    zfree(jobtab[i].ty, sizeof(struct ttyinfo));
-    }
 
     memset(jobtab, 0, sizeof(jobtab)); /* zero out table */
 }
@@ -864,7 +867,11 @@ initjob(void)
     for (i = 1; i < MAXJOB; i++)
 	if (!jobtab[i].stat) {
 	    jobtab[i].stat = STAT_INUSE;
-	    jobtab[i].pwd = ztrdup(pwd);
+	    if (strlen(pwd) >= PATH_MAX) {
+		memcpy(jobtab[i].pwd, pwd, PATH_MAX);
+		jobtab[i].pwd[PATH_MAX] = '\0';
+	    } else
+		strcpy(jobtab[i].pwd, pwd);
 	    jobtab[i].gleader = 0;
 	    return i;
 	}
diff --git a/Src/lex.c b/Src/lex.c
index 7371243a7..8dc836329 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -179,6 +179,12 @@ struct lexstack {
     int hwgetword;
     int lexstop;
     struct heredocs *hdocs;
+    int (*hgetc) _((void));
+    void (*hungetc) _((int));
+    void (*hwaddc) _((int));
+    void (*hwbegin) _((int));
+    void (*hwend) _((void));
+    void (*addtoline) _((int));
 
     unsigned char *cstack;
     int csp;
@@ -226,6 +232,12 @@ lexsave(void)
     ls->hwgetword = hwgetword;
     ls->lexstop = lexstop;
     ls->hdocs = hdocs;
+    ls->hgetc = hgetc;
+    ls->hungetc = hungetc;
+    ls->hwaddc = hwaddc;
+    ls->hwbegin = hwbegin;
+    ls->hwend = hwend;
+    ls->addtoline = addtoline;
     cmdsp = 0;
     inredir = 0;
     hdocs = NULL;
@@ -271,6 +283,12 @@ lexrestore(void)
     hwgetword = lstack->hwgetword;
     lexstop = lstack->lexstop;
     hdocs = lstack->hdocs;
+    hgetc = lstack->hgetc;
+    hungetc = lstack->hungetc;
+    hwaddc = lstack->hwaddc;
+    hwbegin = lstack->hwbegin;
+    hwend = lstack->hwend;
+    addtoline = lstack->addtoline;
     hlinesz = lstack->hlinesz;
     errflag = 0;
 
@@ -783,7 +801,7 @@ gettok(void)
 static int
 gettokstr(int c, int sub)
 {
-    int bct = 0, pct = 0, brct = 0;
+    int bct = 0, pct = 0, brct = 0, fdpar = 0;
     int intpos = 1, in_brace_param = 0;
     int peek, inquote;
 #ifdef DEBUG
@@ -798,8 +816,12 @@ gettokstr(int c, int sub)
     for (;;) {
 	int act;
 	int e;
+	int inbl = inblank(c);
+	
+	if (fdpar && !inbl && c != ')')
+	    fdpar = 0;
 
-	if (inblank(c) && !in_brace_param && !pct)
+	if (inbl && !in_brace_param && !pct)
 	    act = LX2_BREAK;
 	else {
 	    act = lexact2[STOUC(c)];
@@ -822,6 +844,12 @@ gettokstr(int c, int sub)
 	    add(Meta);
 	    break;
 	case LX2_OUTPAR:
+	    if (fdpar) {
+		/* this is a single word `(   )', treat as INOUTPAR */
+		add(c);
+		*bptr = '\0';
+		return INOUTPAR;
+	    }
 	    if ((sub || in_brace_param) && isset(SHGLOB))
 		break;
 	    if (!in_brace_param && !pct--) {
@@ -898,11 +926,40 @@ gettokstr(int c, int sub)
 		    e = hgetc();
 		    hungetc(e);
 		    lexstop = 0;
-		    if (e == ')' ||
-			(incmdpos && !brct && peek != ENVSTRING))
+		    /* For command words, parentheses are only
+		     * special at the start.  But now we're tokenising
+		     * the remaining string.  So I don't see what
+		     * the old incmdpos test here is for.
+		     *   pws 1999/6/8
+		     *
+		     * Oh, no.
+		     *  func1(   )
+		     * is a valid function definition in [k]sh.  The best
+		     * thing we can do, without really nasty lookahead tricks,
+		     * is break if we find a blank after a parenthesis.  At
+		     * least this can't happen inside braces or brackets.  We
+		     * only allow this with SHGLOB (set for both sh and ksh).
+		     *
+		     * Things like `print @( |foo)' should still
+		     * work, because [k]sh don't allow multiple words
+		     * in a function definition, so we only do this
+		     * in command position.
+		     *   pws 1999/6/14
+		     */
+		    if (e == ')' || (isset(SHGLOB) && inblank(e) && !bct &&
+				     !brct && !intpos && incmdpos))
 			goto brk;
 		}
-		pct++;
+		/*
+		 * This also handles the [k]sh `foo( )' function definition.
+		 * Maintain a variable fdpar, set as long as a single set of
+		 * parentheses contains only space.  Then if we get to the
+		 * closing parenthesis and it is still set, we can assume we
+		 * have a function definition.  Only do this at the start of
+		 * the word, since the (...) must be a separate token.
+		 */
+		if (!pct++ && isset(SHGLOB) && intpos && !bct && !brct)
+		    fdpar = 1;
 	    }
 	    c = Inpar;
 	    break;
@@ -1294,8 +1351,7 @@ parsestr(char *s)
 	lexsave();
 	untokenize(s);
 	inpush(dupstring(s), 0, NULL);
-	strinbeg();
-	stophist = 2;
+	strinbeg(0);
 	len = 0;
 	bptr = tokstr = s;
 	bsiz = l + 1;
@@ -1331,8 +1387,7 @@ parse_subst_string(char *s)
     lexsave();
     untokenize(s);
     inpush(dupstring(s), 0, NULL);
-    strinbeg();
-    stophist = 2;
+    strinbeg(0);
     len = 0;
     bptr = tokstr = s;
     bsiz = l + 1;
@@ -1377,8 +1432,7 @@ exalias(void)
 
     if (!tokstr) {
 	yytext = tokstrings[tok];
-	if (yytext)
-	    yytext = dupstring(yytext);
+
 	return 0;
     }
 
diff --git a/Src/linklist.c b/Src/linklist.c
index 62a962595..e3cb4d626 100644
--- a/Src/linklist.c
+++ b/Src/linklist.c
@@ -38,7 +38,7 @@ newlinklist(void)
 {
     LinkList list;
 
-    list = (LinkList) alloc(sizeof *list);
+    list = (LinkList) ncalloc(sizeof *list);
     list->first = NULL;
     list->last = (LinkNode) list;
     return list;
@@ -53,7 +53,7 @@ insertlinknode(LinkList list, LinkNode node, void *dat)
     LinkNode tmp, new;
 
     tmp = node->next;
-    node->next = new = (LinkNode) alloc(sizeof *tmp);
+    node->next = new = (LinkNode) ncalloc(sizeof *tmp);
     new->last = node;
     new->dat = dat;
     new->next = tmp;
diff --git a/Src/loop.c b/Src/loop.c
index 070173fa2..07a7a56b0 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -44,21 +44,18 @@ int contflag;
  
 /**/
 int breaks;
- 
+
 /**/
 int
-execfor(Cmd cmd)
+execfor(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     Forcmd node;
     char *str;
-    int val = 0;
-    LinkList args;
+    zlong val = 0;
 
     node = cmd->u.forcmd;
-    args = cmd->args;
     if (node->condition) {
-	str = node->name;
+	str = dupstring(node->name);
 	singsub(&str);
 	if (!errflag)
 	    matheval(str);
@@ -69,7 +66,7 @@ execfor(Cmd cmd)
 
 	args = newlinklist();
 	for (x = pparams; *x; x++)
-	    addlinknode(args, ztrdup(*x));
+	    addlinknode(args, dupstring(*x));
     }
     lastval = 0;
     loops++;
@@ -95,13 +92,12 @@ execfor(Cmd cmd)
 	    if (!val)
 		break;
 	} else {
-	    str = (char *) ugetnode(args);
-	    if (!str)
+	    if (!args || !(str = (char *) ugetnode(args)))
 		break;
 	    setsparam(node->name, ztrdup(str));
 	}
-	list = (List) dupstruct(node->list);
-	execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args));
+	execlist(node->list, 1,
+		 (flags & CFLAG_EXEC) && args && empty(args));
 	if (breaks) {
 	    breaks--;
 	    if (breaks || !contflag)
@@ -129,27 +125,24 @@ execfor(Cmd cmd)
 
 /**/
 int
-execselect(Cmd cmd)
+execselect(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     Forcmd node;
     char *str, *s;
-    LinkList args;
     LinkNode n;
     int i;
     FILE *inp;
     size_t more;
 
     node = cmd->u.forcmd;
-    args = cmd->args;
     if (!node->inflag) {
 	char **x;
 
 	args = newlinklist();
 	for (x = pparams; *x; x++)
-	    addlinknode(args, ztrdup(*x));
+	    addlinknode(args, dupstring(*x));
     }
-    if (empty(args))
+    if (!args || empty(args))
 	return 1;
     loops++;
     lastval = 0;
@@ -196,8 +189,7 @@ execselect(Cmd cmd)
 		str = "";
 	}
 	setsparam(node->name, ztrdup(str));
-	list = (List) dupstruct(node->list);
-	execlist(list, 1, 0);
+	execlist(node->list, 1, 0);
 	freeheap();
 	if (breaks) {
 	    breaks--;
@@ -278,9 +270,8 @@ selectlist(LinkList l, size_t start)
 
 /**/
 int
-execwhile(Cmd cmd)
+execwhile(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     struct whilecmd *node;
     int olderrexit, oldval;
 
@@ -290,9 +281,8 @@ execwhile(Cmd cmd)
     pushheap();
     loops++;
     for (;;) {
-	list = (List) dupstruct(node->cont);
 	noerrexit = 1;
-	execlist(list, 1, 0);
+	execlist(node->cont, 1, 0);
 	noerrexit = olderrexit;
 	if (!((lastval == 0) ^ node->cond)) {
 	    if (breaks)
@@ -300,8 +290,7 @@ execwhile(Cmd cmd)
 	    lastval = oldval;
 	    break;
 	}
-	list = (List) dupstruct(node->loop);
-	execlist(list, 1, 0);
+	execlist(node->loop, 1, 0);
 	if (breaks) {
 	    breaks--;
 	    if (breaks || !contflag)
@@ -322,22 +311,20 @@ execwhile(Cmd cmd)
 
 /**/
 int
-execrepeat(Cmd cmd)
+execrepeat(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     int count;
 
     lastval = 0;
-    if (empty(cmd->args) || nextnode(firstnode(cmd->args))) {
+    if (!args || empty(args) || nextnode(firstnode(args))) {
 	zerr("bad argument for repeat", NULL, 0);
 	return 1;
     }
-    count = atoi(peekfirst(cmd->args));
+    count = atoi(peekfirst(args));
     pushheap();
     loops++;
     while (count--) {
-	list = (List) dupstruct(cmd->u.list);
-	execlist(list, 1, 0);
+	execlist(cmd->u.list, 1, 0);
 	freeheap();
 	if (breaks) {
 	    breaks--;
@@ -357,7 +344,7 @@ execrepeat(Cmd cmd)
 
 /**/
 int
-execif(Cmd cmd)
+execif(Cmd cmd, LinkList args, int flags)
 {
     struct ifcmd *node;
     int olderrexit;
@@ -380,7 +367,7 @@ execif(Cmd cmd)
     noerrexit = olderrexit;
 
     if (*t)
-	execlist(*t, 1, cmd->flags & CFLAG_EXEC);
+	execlist(*t, 1, flags & CFLAG_EXEC);
     else
 	lastval = 0;
 
@@ -389,7 +376,7 @@ execif(Cmd cmd)
 
 /**/
 int
-execcase(Cmd cmd)
+execcase(Cmd cmd, LinkList args, int flags)
 {
     struct casecmd *node;
     char *word;
@@ -400,18 +387,18 @@ execcase(Cmd cmd)
     l = node->lists;
     p = node->pats;
 
-    word = *p++;
+    word = dupstring(*p++);
     singsub(&word);
     untokenize(word);
     lastval = 0;
 
     if (node) {
 	while (*p) {
-	    char *pat = *p + 1;
+	    char *pat = dupstring(*p + 1);
 	    singsub(&pat);
 	    if (matchpat(word, pat)) {
 		do {
-		    execlist(*l++, 1, **p == ';' && (cmd->flags & CFLAG_EXEC));
+		    execlist(*l++, 1, **p == ';' && (flags & CFLAG_EXEC));
 		} while(**p++ == '&' && *p);
 		break;
 	    }
@@ -421,4 +408,3 @@ execcase(Cmd cmd)
     }
     return lastval;
 }
-
diff --git a/Src/math.c b/Src/math.c
index efbf22e44..7e7e557ed 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -733,9 +733,9 @@ mathevall(char *s, int prek, char **ep)
     char *xptr;
     zlong xyyval;
     LV xyylval;
-    char **xlvals = 0;
+    char **xlvals = 0, *nlvals[LVCOUNT];
     int xsp;
-    struct mathvalue *xstack = 0;
+    struct mathvalue *xstack = 0, nstack[STACKSZ];
     zlong ret;
 
     xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0;
@@ -753,9 +753,10 @@ mathevall(char *s, int prek, char **ep)
 	xsp = sp;
 	xstack = stack;
     }
-    stack = (struct mathvalue *)zalloc(STACKSZ*sizeof(struct mathvalue));
+    stack = nstack;
     lastbase = -1;
-    lvals = (char **)zcalloc(LVCOUNT*sizeof(char *));
+    memset(nlvals, 0, LVCOUNT*sizeof(char *));
+    lvals = nlvals;
     lvc = 0;
     ptr = s;
     sp = -1;
@@ -769,8 +770,6 @@ mathevall(char *s, int prek, char **ep)
 
     ret = stack[0].val;
 
-    zfree(lvals, LVCOUNT*sizeof(char *));
-    zfree(stack, STACKSZ*sizeof(struct mathvalue));
     if (--mlevel) {
 	lastbase = xlastbase;
 	noeval = xnoeval;
@@ -827,7 +826,8 @@ mathevalarg(char *s, char **ss)
 static void
 mathparse(int pc)
 {
-    int q, otok, onoeval;
+    zlong q;
+    int otok, onoeval;
 
     if (errflag)
 	return;
diff --git a/Src/mem.c b/Src/mem.c
index 97ff7fdc2..7f3b4688f 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -97,7 +97,7 @@ static int h_m[1025], h_push, h_pop, h_free;
 #endif
 
 #define H_ISIZE  sizeof(zlong)
-#define HEAPSIZE (8192 - H_ISIZE)
+#define HEAPSIZE (16384 - H_ISIZE)
 #define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap))
 #define HEAPFREE (16384 - H_ISIZE)
 
@@ -133,6 +133,10 @@ global_permalloc(void)
 
 static Heap heaps;
 
+/* first heap with free space, not always correct */
+
+static Heap fheap;
+
 /* Use new heaps from now on. This returns the old heap-list. */
 
 /**/
@@ -141,7 +145,7 @@ new_heaps(void)
 {
     Heap h = heaps;
 
-    heaps = NULL;
+    fheap = heaps = NULL;
 
     return h;
 }
@@ -160,6 +164,7 @@ old_heaps(Heap old)
 	zfree(h, sizeof(*h));
     }
     heaps = old;
+    fheap = NULL;
 }
 
 /* Temporarily switch to other heaps (or back again). */
@@ -171,6 +176,7 @@ switch_heaps(Heap new)
     Heap h = heaps;
 
     heaps = new;
+    fheap = NULL;
 
     return h;
 }
@@ -208,6 +214,8 @@ freeheap(void)
 #if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
     h_free++;
 #endif
+
+    fheap = NULL;
     for (h = heaps; h; h = hn) {
 	hn = h->next;
 	if (h->sp) {
@@ -215,6 +223,8 @@ freeheap(void)
 	    memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used);
 #endif
 	    h->used = h->sp->used;
+	    if (!fheap && h->used < HEAP_ARENA_SIZE)
+		fheap = h;
 	    hl = h;
 	} else
 	    zfree(h, HEAPSIZE);
@@ -238,6 +248,7 @@ popheap(void)
     h_pop++;
 #endif
 
+    fheap = NULL;
     for (h = heaps; h; h = hn) {
 	hn = h->next;
 	if ((hs = h->sp)) {
@@ -246,6 +257,8 @@ popheap(void)
 	    memset(arena(h) + hs->used, 0xff, h->used - hs->used);
 #endif
 	    h->used = hs->used;
+	    if (!fheap && h->used < HEAP_ARENA_SIZE)
+		fheap = h;
 	    zfree(hs, sizeof(*hs));
 
 	    hl = h;
@@ -275,13 +288,12 @@ zhalloc(size_t size)
 
     /* find a heap with enough free space */
 
-    for (h = heaps; h; h = h->next) {
+    for (h = (fheap ? fheap : heaps); h; h = h->next) {
 	if (HEAP_ARENA_SIZE >= (n = size + h->used)) {
 	    h->used = n;
 	    return arena(h) + n - size;
 	}
     }
-
     {
 	Heap hp;
         /* not found, allocate new heap */
@@ -311,6 +323,7 @@ zhalloc(size_t size)
 	    hp->next = h;
 	else
 	    heaps = h;
+	fheap = NULL;
 
 	unqueue_signals();
 	return arena(h);
@@ -361,6 +374,7 @@ hrealloc(char *p, size_t old, size_t new)
 		ph->next = h->next;
 	    else
 		heaps = h->next;
+	    fheap = NULL;
 	    zfree(h, HEAPSIZE);
 	    return NULL;
 	}
@@ -593,6 +607,16 @@ struct m_hdr {
 #define M_ISIZE (sizeof(zlong))
 #define M_MIN   (2 * M_ISIZE)
 
+/* M_FREE  is the number of bytes that have to be free before memory is
+ *         given back to the system
+ * M_KEEP  is the number of bytes that will be kept when memory is given
+ *         back; note that this has to be less than M_FREE
+ * M_ALLOC is the number of extra bytes to request from the system */
+
+#define M_FREE  65536
+#define M_KEEP  32768
+#define M_ALLOC M_KEEP
+
 /* a pointer to the last free block, a pointer to the free list (the blocks
    on this list are kept in order - lowest address first) */
 
@@ -623,13 +647,13 @@ static char *m_high, *m_low;
 
 
 #define M_SIDX(S)  ((S) / M_ISIZE)
-#define M_SNUM     50
+#define M_SNUM     128
 #define M_SLEN(M)  ((M)->len / M_SNUM)
 #define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) +  \
 		    sizeof(zlong) + sizeof(struct m_hdr *))
 #define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) -  \
 		     sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
-#define M_NSMALL 8
+#define M_NSMALL   13
 
 static struct m_hdr *m_small[M_NSMALL];
 
@@ -691,9 +715,9 @@ malloc(MALLOC_ARG_T size)
 	    m->used++;
 
 	    /* if all small blocks in this block are allocated, the block is 
-	       put at the end of the list blocks wth small blocks of this
+	       put at the end of the list blocks with small blocks of this
 	       size (i.e., we try to keep blocks with free blocks at the
-	       beginning of the list, to make the search faster */
+	       beginning of the list, to make the search faster) */
 
 	    if (m->used == M_SNUM && m->next) {
 		for (mt = m; mt->next; mt = mt->next);
@@ -753,15 +777,24 @@ malloc(MALLOC_ARG_T size)
 	for (mp = NULL, m = m_free; m && m->len < size; mp = m, m = m->next);
     }
     if (!m) {
+	long nal;
 	/* no matching free block was found, we have to request new
 	   memory from the system */
-	n = (size + M_HSIZE + m_pgsz - 1) & ~(m_pgsz - 1);
+	n = (size + M_HSIZE + M_ALLOC + m_pgsz - 1) & ~(m_pgsz - 1);
 
 	if (((char *)(m = (struct m_hdr *)sbrk(n))) == ((char *)-1)) {
 	    DPUTS(1, "MEM: allocation error at sbrk.");
 	    unqueue_signals();
 	    return NULL;
 	}
+	if ((nal = ((long)(char *)m) & (M_ALIGN-1))) {
+	    if ((char *)sbrk(M_ALIGN - nal) == (char *)-1) {
+		DPUTS(1, "MEM: allocation error at sbrk.");
+		unqueue_signals();
+		return NULL;
+	    }
+	    m = (struct m_hdr *) ((char *)m + (M_ALIGN - nal));
+	}
 	/* set m_low, for the check in free() */
 	if (!m_low)
 	    m_low = (char *)m;
@@ -1034,8 +1067,8 @@ zfree(void *p, int sz)
        and now there is more than one page size of memory, we can give
        it back to the system (and we do it ;-) */
     if ((((char *)m_lfree) + M_ISIZE + m_lfree->len) == m_high &&
-	m_lfree->len >= m_pgsz + M_MIN) {
-	long n = (m_lfree->len - M_MIN) & ~(m_pgsz - 1);
+	m_lfree->len >= m_pgsz + M_MIN + M_FREE) {
+	long n = (m_lfree->len - M_MIN - M_KEEP) & ~(m_pgsz - 1);
 
 	m_lfree->len -= n;
 	if (brk(m_high -= n) == -1) {
diff --git a/Src/params.c b/Src/params.c
index 75910c6fd..b9f3d33a0 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -52,7 +52,6 @@ char **pparams,		/* $argv        */
  
 /**/
 char *argzero,		/* $0           */
-     *underscore,	/* $_           */
      *home,		/* $HOME        */
      *hostnam,		/* $HOST        */
      *ifs,		/* $IFS         */
@@ -232,11 +231,6 @@ IPDEF9("manpath", &manpath, "MANPATH"),
 IPDEF9("psvar", &psvar, "PSVAR"),
 IPDEF9("watch", &watch, "WATCH"),
 
-/*TEST BEGIN*/
-#define IPDEF10(A) {NULL,A,PM_HASHED|PM_SPECIAL|PM_DONTIMPORT,BR((void *)0),SFN(hashsetfn),GFN(hashgetfn),stdunsetfn,0,NULL,NULL,NULL,0}
-IPDEF10("testhash"),
-/*TEST END*/
-
 #ifdef DYNAMIC
 IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
 #endif
@@ -723,16 +717,13 @@ isident(char *s)
 #endif
 }
 
-static char **garr;
-
 /**/
 static zlong
 getarg(char **str, int *inv, Value v, int a2, zlong *w)
 {
-    int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash;
-    int beg = 0, hasbeg = 0;
+    int hasbeg = 0, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash;
     char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt;
-    zlong r = 0;
+    zlong num = 1, beg = 0, r = 0;
     Comp c;
 
     ishash = (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED);
@@ -1147,7 +1138,6 @@ fetchvalue(char **pptr, int bracks, int flags)
     int ppar = 0;
 
     s = t = *pptr;
-    garr = NULL;
 
     if (idigit(*s)) {
 	if (bracks >= 0)
@@ -1638,7 +1628,7 @@ setaparam(char *s, char **val)
 	if (!(v = getvalue(&s, 1)))
 	    createparam(t, PM_ARRAY);
 	*ss = '[';
-	if (PM_TYPE(v->pm->flags) == PM_HASHED) {
+	if (v && PM_TYPE(v->pm->flags) == PM_HASHED) {
 	    zerr("attempt to set slice of associative array", NULL, 0);
 	    freearray(val);
 	    errflag = 1;
@@ -2466,7 +2456,10 @@ wordcharssetfn(Param pm, char *x)
 char *
 underscoregetfn(Param pm)
 {
-    return underscore;
+    char *u = dupstring(underscore);
+
+    untokenize(u);
+    return u;
 }
 
 /* Function to get value for special parameter `TERM' */
diff --git a/Src/parse.c b/Src/parse.c
index 043aa0f0d..520181750 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -298,6 +298,8 @@ par_pline(void)
 	rdr->type = MERGEOUT;
 	rdr->fd1 = 2;
 	rdr->name = dupstring("1");
+	if (!c->redir)
+	    c->redir = newlinklist();
 	addlinknode(c->redir, rdr);
 
 	cmdpush(CS_ERRPIPE);
@@ -330,11 +332,14 @@ par_cmd(void)
 
     c = (Cmd) make_cmd();
     c->lineno = lineno;
-    c->args = newlinklist();
-    c->redir = newlinklist();
-    c->vars = newlinklist();
-    while (IS_REDIROP(tok))
-	par_redir(c->redir);
+    c->args = NULL;
+    c->vars = NULL;
+    if (IS_REDIROP(tok)) {
+	c->redir = newlinklist();
+	while (IS_REDIROP(tok))
+	    par_redir(c->redir);
+    } else
+	c->redir = NULL;
     switch (tok) {
     case FOR:
 	cmdpush(CS_FOR);
@@ -399,6 +404,8 @@ par_cmd(void)
 	break;
     case DINPAR:
 	c->type = CARITH;
+	if (!c->args)
+	    c->args = newlinklist();
 	addlinknode(c->args, tokstr);
 	yylex();
 	break;
@@ -407,8 +414,12 @@ par_cmd(void)
 	    return NULL;
 	break;
     }
-    while (IS_REDIROP(tok))
-	par_redir(c->redir);
+    if (IS_REDIROP(tok)) {
+	if (!c->redir)
+	    c->redir = newlinklist();
+	while (IS_REDIROP(tok))
+	    par_redir(c->redir);
+    }
     incmdpos = 1;
     incasepat = 0;
     incond = 0;
@@ -460,6 +471,8 @@ par_for(Cmd c)
 	    f->inflag = 1;
 	    incmdpos = 0;
 	    yylex();
+	    if (!c->args)
+		c->args = newlinklist();
 	    c->args = par_wordlist();
 	    if (tok != SEPER)
 		YYERRORV;
@@ -467,6 +480,8 @@ par_for(Cmd c)
 	    f->inflag = 1;
 	    incmdpos = 0;
 	    yylex();
+	    if (!c->args)
+		c->args = newlinklist();
 	    c->args = par_nl_wordlist();
 	    if (tok != OUTPAR)
 		YYERRORV;
@@ -819,6 +834,8 @@ par_repeat(Cmd c)
     yylex();
     if (tok != STRING)
 	YYERRORV;
+    if (!c->args)
+	c->args = newlinklist();
     addlinknode(c->args, tokstr);
     incmdpos = 1;
     yylex();
@@ -966,6 +983,8 @@ par_simple(Cmd c)
 		v->str = p + 1;
 	    } else
 		equalsplit(tokstr, &v->str);
+	    if (!c->vars)
+		c->vars = newlinklist();
 	    addlinknode(c->vars, v);
 	    isnull = 0;
 	} else if (tok == ENVARRAY) {
@@ -982,6 +1001,8 @@ par_simple(Cmd c)
 	    if (tok != OUTPAR)
 		YYERROR;
 	    incmdpos = oldcmdpos;
+	    if (!c->vars)
+		c->vars = newlinklist();
 	    addlinknode(c->vars, v);
 	    isnull = 0;
 	} else
@@ -993,9 +1014,13 @@ par_simple(Cmd c)
     for (;;) {
 	if (tok == STRING) {
 	    incmdpos = 0;
+	    if (!c->args)
+		c->args = newlinklist();
 	    addlinknode(c->args, tokstr);
 	    yylex();
 	} else if (IS_REDIROP(tok)) {
+	    if (!c->redir)
+		c->redir = newlinklist();
 	    par_redir(c->redir);
 	} else if (tok == INOUTPAR) {
 	    incmdpos = 1;
@@ -1011,15 +1036,26 @@ par_simple(Cmd c)
 		    YYERROR;
 		}
 		yylex();
-	    } else
-		c->u.list = (List) expandstruct((struct node *) par_cmd(), N_LIST);
+	    } else {
+		List l;
+		Sublist sl;
+		Pline pl;
+
+		l = (List) allocnode(N_LIST);
+		l->type = Z_SYNC;
+		l->left = sl = (Sublist) allocnode(N_SUBLIST);
+		sl->type = END;
+		sl->left = pl = (Pline) allocnode(N_PLINE);
+		pl->type = END;
+		pl->left = par_cmd();
+	    }
 	    cmdpop();
 	    c->type = FUNCDEF;
 	} else
 	    break;
 	isnull = 0;
     }
-    if (isnull && empty(c->redir))
+    if (isnull && (!c->redir || empty(c->redir)))
 	return NULL;
     incmdpos = 1;
     return c;
diff --git a/Src/signals.c b/Src/signals.c
index 3e655cbfd..f69da0140 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -719,7 +719,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
 	freelinklist(args, (FreeFunc) NULL);
 	zsfree(name);
     } else HEAPALLOC {
-	execlist(dupstruct(sigfn), 1, 0);
+	execlist(sigfn, 1, 0);
     } LASTALLOC;
     if (trapreturn > 0)
 	trapret = trapreturn;
diff --git a/Src/subst.c b/Src/subst.c
index 0017b205e..d85d73f58 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -53,9 +53,9 @@ prefork(LinkList list, int flags)
 
     MUSTUSEHEAP("prefork");
     for (node = firstnode(list); node; incnode(node)) {
-	char *str, *str3;
+	char *str;
 
-	str = str3 = (char *)getdata(node);
+	str = (char *)getdata(node);
 	if ((*str == Inang || *str == Outang || *str == Equals) &&
 	    str[1] == Inpar) {
 	    if (*str == Inang || *str == Outang)
diff --git a/Src/text.c b/Src/text.c
index d3eafaf9f..73b9088f2 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -169,7 +169,6 @@ gettext2(struct node *n)
 	    if (_List(n)->type & Z_DISOWN)
 		taddstr("|");
 	}
-	simplifyright(_List(n));
 	if (_List(n)->right) {
 	    if (tnewlins)
 		taddnl();
@@ -460,22 +459,23 @@ getsimptext(Cmd cmd)
 {
     LinkNode n;
 
-    for (n = firstnode(cmd->vars); n; incnode(n)) {
-	struct varasg *v = (struct varasg *)getdata(n);
-
-	taddstr(v->name);
-	taddchr('=');
-	if (PM_TYPE(v->type) == PM_ARRAY) {
-	    taddchr('(');
-	    taddlist(v->arr);
-	    taddstr(") ");
-	} else if (PM_TYPE(v->type) == PM_HASHED) {
-	    /* XXX */
-	} else {
-	    taddstr(v->str);
-	    taddchr(' ');
+    if (cmd->vars)
+	for (n = firstnode(cmd->vars); n; incnode(n)) {
+	    struct varasg *v = (struct varasg *)getdata(n);
+
+	    taddstr(v->name);
+	    taddchr('=');
+	    if (PM_TYPE(v->type) == PM_ARRAY) {
+		taddchr('(');
+		taddlist(v->arr);
+		taddstr(") ");
+	    } else if (PM_TYPE(v->type) == PM_HASHED) {
+		/* XXX */
+	    } else {
+		taddstr(v->str);
+		taddchr(' ');
+	    }
 	}
-    }
     taddlist(cmd->args);
 }
 
@@ -490,6 +490,8 @@ getredirs(Cmd cmd)
 	"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
     };
 
+    if (!cmd->redir)
+	return;
     taddchr(' ');
     for (n = firstnode(cmd->redir); n; incnode(n)) {
 	struct redir *f = (struct redir *)getdata(n);
@@ -537,7 +539,7 @@ taddlist(LinkList l)
 {
     LinkNode n;
 
-    if (!(n = firstnode(l)))
+    if (!l || !(n = firstnode(l)))
 	return;
     for (; n; incnode(n)) {
 	taddstr(getdata(n));
diff --git a/Src/utils.c b/Src/utils.c
index 32588b4c3..ba4f3dc9d 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -853,61 +853,131 @@ int resetneeded;
 int winchanged;
 #endif
 
-/* check the size of the window and adjust if necessary. *
- * The value of from:					 *
- *   0: called from update_job or setupvals		 *
- *   1: called from the SIGWINCH handler		 *
- *   2: the user have just changed LINES manually	 *
- *   3: the user have just changed COLUMNS manually      */
-
-/**/
-void
-adjustwinsize(int from)
+static int
+adjustlines(int signalled)
 {
-    int oldcols = columns, oldrows = lines;
+    int oldlines = lines;
 
 #ifdef TIOCGWINSZ
-    static int userlines, usercols;
-
-    if (SHTTY == -1)
-	return;
-
-    if (from == 2)
-	userlines = lines > 0;
-    if (from == 3)
-	usercols = columns > 0;
-
-    if (!ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize)) {
-	if (!userlines || from == 1)
-	    lines = shttyinfo.winsize.ws_row;
-	if (!usercols || from == 1)
-	    columns = shttyinfo.winsize.ws_col;
+    if (signalled || lines <= 0)
+	lines = shttyinfo.winsize.ws_row;
+    else
+	shttyinfo.winsize.ws_row = lines;
+#endif /* TIOCGWINSZ */
+    if (lines <= 0) {
+	DPUTS(signalled, "BUG: Impossible TIOCGWINSZ rows");
+	lines = tclines > 0 ? tclines : 24;
     }
-#endif   /* TIOCGWINSZ */
 
-    if (lines <= 0)
-	lines = tclines > 0 ? tclines : 24;
-    if (columns <= 0)
-	columns = tccolumns > 0 ? tccolumns : 80;
     if (lines > 2)
 	termflags &= ~TERM_SHORT;
     else
 	termflags |= TERM_SHORT;
+
+    return (lines != oldlines);
+}
+
+static int
+adjustcolumns(int signalled)
+{
+    int oldcolumns = columns;
+
+#ifdef TIOCGWINSZ
+    if (signalled || columns <= 0)
+	columns = shttyinfo.winsize.ws_col;
+    else
+	shttyinfo.winsize.ws_col = columns;
+#endif /* TIOCGWINSZ */
+    if (columns <= 0) {
+	DPUTS(signalled, "BUG: Impossible TIOCGWINSZ cols");
+	columns = tccolumns > 0 ? tccolumns : 80;
+    }
+
     if (columns > 2)
 	termflags &= ~TERM_NARROW;
     else
 	termflags |= TERM_NARROW;
 
+    return (columns != oldcolumns);
+}
+
+/* check the size of the window and adjust if necessary. *
+ * The value of from:					 *
+ *   0: called from update_job or setupvals		 *
+ *   1: called from the SIGWINCH handler		 *
+ *   2: called from the LINES parameter callback	 *
+ *   3: called from the COLUMNS parameter callback	 */
+
+/**/
+void
+adjustwinsize(int from)
+{
+    static int getwinsz = 1;
+    int ttyrows = shttyinfo.winsize.ws_row;
+    int ttycols = shttyinfo.winsize.ws_col;
+    int resetzle = 0;
+
+    if (getwinsz || from == 1) {
 #ifdef TIOCGWINSZ
-    if (interact && from >= 2) {
-	shttyinfo.winsize.ws_row = lines;
-	shttyinfo.winsize.ws_col = columns;
+	if (SHTTY == -1)
+	    return;
+	if (ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize) == 0) {
+	    resetzle = (ttyrows != shttyinfo.winsize.ws_row ||
+			ttycols != shttyinfo.winsize.ws_col);
+	    if (from == 0 && resetzle && ttyrows && ttycols)
+		from = 1; /* Signal missed while a job owned the tty? */
+	    ttyrows = shttyinfo.winsize.ws_row;
+	    ttycols = shttyinfo.winsize.ws_col;
+	} else {
+	    /* Set to unknown on failure */
+	    shttyinfo.winsize.ws_row = 0;
+	    shttyinfo.winsize.ws_col = 0;
+	    resetzle = 1;
+	}
+#else
+	resetzle = from == 1;
+#endif /* TIOCGWINSZ */
+    } /* else
+	 return; */
+
+    switch (from) {
+    case 0:
+    case 1:
+	getwinsz = 0;
+	/* Calling setiparam() here calls this function recursively, but  *
+	 * because we've already called adjustlines() and adjustcolumns() *
+	 * here, recursive calls are no-ops unless a signal intervenes.   *
+	 * The commented "else return;" above might be a safe shortcut,   *
+	 * but I'm concerned about what happens on race conditions; e.g., *
+	 * suppose the user resizes his xterm during `eval $(resize)'?    */
+	if (adjustlines(from) && zgetenv("LINES"))
+	    setiparam("LINES", lines);
+	if (adjustcolumns(from) && zgetenv("COLUMNS"))
+	    setiparam("COLUMNS", columns);
+	getwinsz = 1;
+	break;
+    case 2:
+	resetzle = adjustlines(0);
+	break;
+    case 3:
+	resetzle = adjustcolumns(0);
+	break;
+    }
+
+#ifdef TIOCGWINSZ
+    if (interact && from >= 2 &&
+	(shttyinfo.winsize.ws_row != ttyrows ||
+	 shttyinfo.winsize.ws_col != ttycols)) {
+	/* shttyinfo.winsize is already set up correctly */
 	ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize);
     }
-#endif
+#endif /* TIOCGWINSZ */
 
-    if (zleactive && (from >= 2 || oldcols != columns || oldrows != lines)) {
-	resetneeded = winchanged = 1;
+    if (zleactive && resetzle) {
+#ifdef TIOCGWINSZ
+	winchanged =
+#endif /* TIOCGWINSZ */
+	    resetneeded = 1;
 	zrefresh();
     }
 }
@@ -1733,13 +1803,12 @@ char *
 sepjoin(char **s, char *sep)
 {
     char *r, *p, **t;
-    int l, sl, elide = 0;
+    int l, sl;
     char sepbuf[3];
 
     if (!*s)
 	return "";
     if (!sep) {
-	elide = 1;
 	sep = sepbuf;
 	sepbuf[0] = *ifs;
 	sepbuf[1] = *ifs == Meta ? ifs[1] ^ 32 : '\0';
@@ -1853,329 +1922,21 @@ allocnode(int type)
 {
     struct node *n;
 
-    n = (struct node *) alloc(sizetab[type]);
+    n = (struct node *) ncalloc(sizetab[type]);
     memset((void *) n, 0, sizetab[type]);
     n->ntype = flagtab[type];
-    if (useheap)
-	n->ntype |= NT_HEAP;
 
     return (void *) n;
 }
+ 
+/* duplicate a syntax tree */
 
 /**/
 void *
 dupstruct(void *a)
 {
-    struct node *n, *r;
-
-    n = (struct node *) a;
-    if (!a || ((List) a) == &dummy_list)
-	return (void *) a;
-
-    if ((n->ntype & NT_HEAP) && !useheap) {
-	HEAPALLOC {
-	    n = (struct node *) dupstruct2((void *) n);
-	} LASTALLOC;
-	n = simplifystruct(n);
-    }
-    r = (struct node *)dupstruct2((void *) n);
-
-    if (!(n->ntype & NT_HEAP) && useheap)
-	r = expandstruct(r, N_LIST);
-
-    return (void *) r;
-}
-
-/**/
-static struct node *
-simplifystruct(struct node *n)
-{
-    if (!n || ((List) n) == &dummy_list)
-	return n;
-
-    switch (NT_TYPE(n->ntype)) {
-    case N_LIST:
-	{
-	    List l = (List) n;
-
-	    l->left = (Sublist) simplifystruct((struct node *)l->left);
-	    if ((l->type & Z_SYNC) && !l->right)
-		return (struct node *)l->left;
-	}
-	break;
-    case N_SUBLIST:
-	{
-	    Sublist sl = (Sublist) n;
-
-	    sl->left = (Pline) simplifystruct((struct node *)sl->left);
-	    if (sl->type == END && !sl->flags && !sl->right)
-		return (struct node *)sl->left;
-	}
-	break;
-    case N_PLINE:
-	{
-	    Pline pl = (Pline) n;
-
-	    pl->left = (Cmd) simplifystruct((struct node *)pl->left);
-	    if (pl->type == END && !pl->right)
-		return (struct node *)pl->left;
-	}
-	break;
-    case N_CMD:
-	{
-	    Cmd c = (Cmd) n;
-	    int i = 0;
-
-	    if (empty(c->args))
-		c->args = NULL, i++;
-	    if (empty(c->redir))
-		c->redir = NULL, i++;
-	    if (empty(c->vars))
-		c->vars = NULL, i++;
-
-	    c->u.list = (List) simplifystruct((struct node *)c->u.list);
-	    if (i == 3 && !c->flags &&
-		(c->type == CWHILE || c->type == CIF ||
-		 c->type == COND))
-		return (struct node *)c->u.list;
-	}
-	break;
-    case N_FOR:
-	{
-	    Forcmd f = (Forcmd) n;
-
-	    f->list = (List) simplifystruct((struct node *)f->list);
-	}
-	break;
-    case N_CASE:
-	{
-	    struct casecmd *c = (struct casecmd *)n;
-	    List *l;
-
-	    for (l = c->lists; *l; l++)
-		*l = (List) simplifystruct((struct node *)*l);
-	}
-	break;
-    case N_IF:
-	{
-	    struct ifcmd *i = (struct ifcmd *)n;
-	    List *l;
-
-	    for (l = i->ifls; *l; l++)
-		*l = (List) simplifystruct((struct node *)*l);
-	    for (l = i->thenls; *l; l++)
-		*l = (List) simplifystruct((struct node *)*l);
-	}
-	break;
-    case N_WHILE:
-	{
-	    struct whilecmd *w = (struct whilecmd *)n;
-
-	    w->cont = (List) simplifystruct((struct node *)w->cont);
-	    w->loop = (List) simplifystruct((struct node *)w->loop);
-	}
-    }
-
-    return n;
-}
-
-/**/
-struct node *
-expandstruct(struct node *n, int exp)
-{
-    struct node *m;
-
-    if (!n || ((List) n) == &dummy_list)
-	return n;
-
-    if (exp != N_COUNT && exp != NT_TYPE(n->ntype)) {
-	switch (exp) {
-	case N_LIST:
-	    {
-		List l;
-
-		m = (struct node *) allocnode(N_LIST);
-		l = (List) m;
-		l->type = Z_SYNC;
-		l->left = (Sublist) expandstruct(n, N_SUBLIST);
-
-		return (struct node *)l;
-	    }
-	case N_SUBLIST:
-	    {
-		Sublist sl;
-
-		m = (struct node *) allocnode(N_SUBLIST);
-		sl = (Sublist) m;
-		sl->type = END;
-		sl->left = (Pline) expandstruct(n, N_PLINE);
-
-		return (struct node *)sl;
-	    }
-	case N_PLINE:
-	    {
-		Pline pl;
-
-		m = (struct node *) allocnode(N_PLINE);
-		pl = (Pline) m;
-		pl->type = END;
-		pl->left = (Cmd) expandstruct(n, N_CMD);
-
-		return (struct node *)pl;
-	    }
-	case N_CMD:
-	    {
-		Cmd c;
-
-		m = (struct node *) allocnode(N_CMD);
-		c = (Cmd) m;
-		switch (NT_TYPE(n->ntype)) {
-		case N_WHILE:
-		    c->type = CWHILE;
-		    break;
-		case N_IF:
-		    c->type = CIF;
-		    break;
-		case N_COND:
-		    c->type = COND;
-		}
-		c->u.list = (List) expandstruct(n, NT_TYPE(n->ntype));
-		c->args = newlinklist();
-		c->vars = newlinklist();
-		c->redir = newlinklist();
-
-		return (struct node *)c;
-	    }
-	}
-    } else
-	switch (NT_TYPE(n->ntype)) {
-	case N_LIST:
-	    {
-		List l = (List) n;
-
-		l->left = (Sublist) expandstruct((struct node *)l->left,
-						 N_SUBLIST);
-		l->right = (List) expandstruct((struct node *)l->right,
-					       N_LIST);
-	    }
-	    break;
-	case N_SUBLIST:
-	    {
-		Sublist sl = (Sublist) n;
-
-		sl->left = (Pline) expandstruct((struct node *)sl->left,
-						N_PLINE);
-		sl->right = (Sublist) expandstruct((struct node *)sl->right,
-						   N_SUBLIST);
-	    }
-	    break;
-	case N_PLINE:
-	    {
-		Pline pl = (Pline) n;
-
-		pl->left = (Cmd) expandstruct((struct node *)pl->left,
-					      N_CMD);
-		pl->right = (Pline) expandstruct((struct node *)pl->right,
-						 N_PLINE);
-	    }
-	    break;
-	case N_CMD:
-	    {
-		Cmd c = (Cmd) n;
-
-		if (!c->args)
-		    c->args = newlinklist();
-		if (!c->vars)
-		    c->vars = newlinklist();
-		if (!c->redir)
-		    c->redir = newlinklist();
-
-		switch (c->type) {
-		case CFOR:
-		case CSELECT:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_FOR);
-		    break;
-		case CWHILE:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_WHILE);
-		    break;
-		case CIF:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_IF);
-		    break;
-		case CCASE:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_CASE);
-		    break;
-		case COND:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_COND);
-		    break;
-		case ZCTIME:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_SUBLIST);
-		    break;
-		case AUTOFN:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_AUTOFN);
-		    break;
-		default:
-		    c->u.list = (List) expandstruct((struct node *)c->u.list,
-						    N_LIST);
-		}
-	    }
-	    break;
-	case N_FOR:
-	    {
-		Forcmd f = (Forcmd) n;
-
-		f->list = (List) expandstruct((struct node *)f->list,
-					      N_LIST);
-	    }
-	    break;
-	case N_CASE:
-	    {
-		struct casecmd *c = (struct casecmd *)n;
-		List *l;
-
-		for (l = c->lists; *l; l++)
-		    *l = (List) expandstruct((struct node *)*l, N_LIST);
-	    }
-	    break;
-	case N_IF:
-	    {
-		struct ifcmd *i = (struct ifcmd *)n;
-		List *l;
-
-		for (l = i->ifls; *l; l++)
-		    *l = (List) expandstruct((struct node *)*l, N_LIST);
-		for (l = i->thenls; *l; l++)
-		    *l = (List) expandstruct((struct node *)*l, N_LIST);
-	    }
-	    break;
-	case N_WHILE:
-	    {
-		struct whilecmd *w = (struct whilecmd *)n;
-
-		w->cont = (List) expandstruct((struct node *)w->cont,
-					      N_LIST);
-		w->loop = (List) expandstruct((struct node *)w->loop,
-					      N_LIST);
-	    }
-	}
-
-    return n;
-}
-
-/* duplicate a syntax tree */
-
-/**/
-static void *
-dupstruct2(void *a)
-{
     void **onodes, **nnodes, *ret, *n, *on;
-    int type, heap;
+    int type;
     size_t nodeoffs;
 
     if (!a || ((List) a) == &dummy_list)
@@ -2183,53 +1944,33 @@ dupstruct2(void *a)
     type = *(int *)a;
     ret = alloc(sizetab[NT_TYPE(type)]);
     memcpy(ret, a, nodeoffs = offstab[NT_TYPE(type)]);
-    *(int*)ret = (type & ~NT_HEAP) | (useheap ? NT_HEAP : 0);
     onodes = (void **) ((char *)a + nodeoffs);
     nnodes = (void **) ((char *)ret + nodeoffs);
-    heap = type & NT_HEAP;
     for (type = (type & 0xffff00) >> 4; (type >>= 4); *nnodes++ = n) {
 	if (!(on = *onodes++))
 	    n = NULL;
 	else {
 	    switch (type & 0xf) {
 	    case NT_NODE:
-		n = dupstruct2(on);
+		n = dupstruct(on);
 		break;
 	    case NT_STR:
 		n = dupstring(on);
 		break;
 	    case NT_LIST | NT_NODE:
-		if (heap) {
-		    if (useheap)
-			n =  duplist(on, (VFunc) dupstruct2);
-		    else
-			n = list2arr(on, (VFunc) dupstruct2);
-		}
-		else if (useheap)
-		    n = arr2list(on, (VFunc) dupstruct2);
-		else
-		    n = duparray(on, (VFunc) dupstruct2);
+		n = duplist(on, (VFunc) dupstruct);
 		break;
 	    case NT_LIST | NT_STR:
-		if (heap) {
-		    if (useheap)
-			n = duplist(on, (VFunc) dupstring);
-		    else
-			n = list2arr(on, (VFunc) ztrdup);
-		}
-		else if (useheap)
-		    n = arr2list(on, (VFunc) dupstring);
-		else
-		    n = duparray(on, (VFunc) ztrdup);
+		n = duplist(on, (VFunc) (useheap ? dupstring : ztrdup));
 		break;
 	    case NT_NODE | NT_ARR:
-		n = duparray(on, (VFunc) dupstruct2);
+		n = duparray(on, (VFunc) dupstruct);
 		break;
 	    case NT_STR | NT_ARR:
 		n = duparray(on, (VFunc) (useheap ? dupstring : ztrdup));
 		break;
 	    default:
-		DPUTS(1, "BUG: bad node type in dupstruct2()");
+		DPUTS(1, "BUG: bad node type in dupstruct()");
 		abort();
 	    }
 	}
@@ -2237,19 +1978,46 @@ dupstruct2(void *a)
     return ret;
 }
 
-/* free a syntax tree */
+/* Free a syntax tree. Now, freestruct() only registers everything that
+ * has to be freed. Later, freestructs() will be called to do the real
+ * work. This is to avoid having functions that are currently executed
+ * free themselves by re-defining themselves. */
+
+static LinkList freeslist = NULL;
 
 /**/
 void
 freestruct(void *a)
 {
-    void **nodes, *n;
-    int type, size;
-
     if (!a || ((List) a) == &dummy_list)
 	return;
 
-    type = * (int *) a;
+    PERMALLOC {
+	if (!freeslist)
+	    freeslist = newlinklist();
+	addlinknode(freeslist, a);
+    } LASTALLOC;
+}
+
+/**/
+void
+freestructs(void)
+{
+    void *a;
+
+    if (freeslist)
+	while ((a = getlinknode(freeslist)))
+	    ifreestruct(a);
+}
+
+/**/
+static void
+ifreestruct(void *a)
+{
+    void **nodes, *n;
+    int type, size;
+
+    type = *(int *) a;
     nodes = (void **) ((char *)a + offstab[NT_TYPE(type)]);
     size = sizetab[NT_TYPE(type)];
     for (type = (type & 0xffff00) >> 4; (type >>= 4);) {
@@ -2262,6 +2030,8 @@ freestruct(void *a)
 		zsfree((char *) n);
 		break;
 	    case NT_LIST | NT_NODE:
+		freelinklist((LinkList) n, (FreeFunc) freestruct);
+		break;
 	    case NT_NODE | NT_ARR:
 	    {
 		void **p = (void **) n;
@@ -2272,6 +2042,8 @@ freestruct(void *a)
 		break;
 	    }
 	    case NT_LIST | NT_STR:
+		freelinklist((LinkList) n, (FreeFunc) zsfree);
+		break;
 	    case NT_STR | NT_ARR:
 		freearray((char **) n);
 		break;
@@ -2287,58 +2059,46 @@ freestruct(void *a)
 }
 
 /**/
-static LinkList
-duplist(LinkList l, VFunc func)
+LinkList
+dupheaplist(LinkList l)
 {
-    LinkList ret;
-    LinkNode node;
-
-    ret = newlinklist();
-    for (node = firstnode(l); node; incnode(node))
-	addlinknode(ret, func(getdata(node)));
-    return ret;
-}
-
-/**/
-char **
-duparray(char **arr, VFunc func)
-{
-    char **ret, **rr;
-
-    ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *));
-    for (rr = ret; *arr;)
-	*rr++ = (char *)func(*arr++);
-    *rr = NULL;
+    if (!l)
+	return NULL;
 
-    return ret;
+    return duplist(l, (VFunc) dupstruct);
 }
 
 /**/
-static char **
-list2arr(LinkList l, VFunc func)
+static LinkList
+duplist(LinkList l, VFunc func)
 {
-    char **arr, **r;
-    LinkNode n;
-
-    arr = r = (char **) alloc((countlinknodes(l) + 1) * sizeof(char *));
+    if (l && nonempty(l)) {
+	LinkList ret;
+	LinkNode node;
 
-    for (n = firstnode(l); n; incnode(n))
-	*r++ = (char *)func(getdata(n));
-    *r = NULL;
-
-    return arr;
+	ret = newlinklist();
+	for (node = firstnode(l); node; incnode(node))
+	    addlinknode(ret, func(getdata(node)));
+	return ret;
+    }
+    return NULL;
 }
 
 /**/
-static LinkList
-arr2list(char **arr, VFunc func)
+char **
+duparray(char **arr, VFunc func)
 {
-    LinkList l = newlinklist();
+    if (arr && *arr) {
+	char **ret, **rr, *p;
 
-    while (*arr)
-	addlinknode(l, func(*arr++));
+	ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *));
+	for (rr = ret; (p = *arr++);)
+	    *rr++ = (char *)func(p);
+	*rr = NULL;
 
-    return l;
+	return ret;
+    }
+    return NULL;
 }
 
 /**/
@@ -2384,28 +2144,6 @@ equalsplit(char *s, char **t)
     return 0;
 }
 
-/* see if the right side of a list is trivial */
-
-/**/
-void
-simplifyright(List l)
-{
-    Cmd c;
-
-    if (l == &dummy_list || !l->right)
-	return;
-    if (l->right->right || l->right->left->right ||
-	l->right->left->flags || l->right->left->left->right ||
-	l->left->flags)
-	return;
-    c = l->left->left->left;
-    if (c->type != SIMPLE || nonempty(c->args) || nonempty(c->redir)
-	|| nonempty(c->vars))
-	return;
-    l->right = NULL;
-    return;
-}
-
 /* the ztypes table */
 
 /**/
@@ -2470,6 +2208,25 @@ arrdup(char **s)
     return y;
 }
 
+/* Duplicate a list of strings. */
+
+/**/
+LinkList
+listdup(LinkList l)
+{
+    if (!l)
+	return NULL;
+    else {
+	LinkList r = newlinklist();
+	LinkNode n;
+
+	for (n = firstnode(l); n; incnode(n))
+	    addlinknode(r, dupstring((char *) getdata(n)));
+
+	return r;
+    }
+}
+
 /**/
 char **
 listarr(LinkList l)
diff --git a/Src/zsh.export b/Src/zsh.export
index ef9fca8c6..72779e24a 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -75,6 +75,7 @@ findcmd
 firsthist
 freearray
 freeheap
+freelinklist
 freestruct
 getaparam
 gethashnode
@@ -113,6 +114,7 @@ hist_skip_flags
 holdintr
 hptr
 hrealloc
+ifs
 inbufct
 incmdpos
 incond
@@ -179,7 +181,6 @@ path
 pathchecked
 popheap
 postedit
-pparams
 ppid
 prefork
 prepromptfns
diff --git a/Src/zsh.h b/Src/zsh.h
index 4d46beada..e7b6e5ae0 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -47,7 +47,11 @@
  */
 #ifdef ZSH_64_BIT_TYPE
 typedef ZSH_64_BIT_TYPE zlong;
-typedef unsigned ZSH_64_BIT_TYPE zulong;
+#ifdef ZSH_64_BIT_UTYPE
+typedef ZSH_64_BIT_UTYPE zulong;
+#else
+typedef unsigned zlong zulong;
+#endif
 #else
 typedef long zlong;
 typedef unsigned long zulong;
@@ -352,7 +356,6 @@ struct node {
 #define NT_N(T, N) (((T) >> (8 + (N) * 4)) & 0xf)
 #define NT_SET(T0, T1, T2, T3, T4) \
     ((T0) | ((T1) << 8) | ((T2) << 12) | ((T3) << 16) | ((T4) << 20))
-#define NT_HEAP   (1 << 30)
 
 /* tree element for lists */
 
@@ -605,7 +608,7 @@ struct job {
     pid_t gleader;		/* process group leader of this job  */
     pid_t other;		/* subjob id or subshell pid         */
     int stat;                   /* see STATs below                   */
-    char *pwd;			/* current working dir of shell when *
+    char pwd[PATH_MAX + 1];	/* current working dir of shell when *
 				 * this job was spawned              */
     struct process *procs;	/* list of processes                 */
     LinkList filelist;		/* list of files to delete when done */
@@ -948,7 +951,12 @@ struct param {
 #define PM_READONLY	(1<<8)	/* readonly                                   */
 #define PM_TAGGED	(1<<9)	/* tagged                                     */
 #define PM_EXPORTED	(1<<10)	/* exported                                   */
+
+/* The following are the same since they *
+ * both represent -U option to typeset   */
 #define PM_UNIQUE	(1<<11)	/* remove duplicates                          */
+#define PM_UNALIASED	(1<<11)	/* do not expand aliases when autoloading     */
+
 #define PM_TIED 	(1<<12)	/* array tied to colon-path or v.v. */
 #define PM_SPECIAL	(1<<13) /* special builtin parameter                  */
 #define PM_DONTIMPORT	(1<<14)	/* do not import this variable                */
diff --git a/Src/zsh.mdd b/Src/zsh.mdd
index bd9aabc2e..ef04658b1 100644
--- a/Src/zsh.mdd
+++ b/Src/zsh.mdd
@@ -31,7 +31,16 @@ version.h: $(sdir_top)/Config/version.mk
 zshpaths.h: FORCE Makemod
 	@echo '#define MODULE_DIR "'$(MODDIR)'"' > zshpaths.h.tmp
 	@if test x$(fndir) != xno; then \
-	  echo '#define FUNCTION_DIR "'$(fndir)'"' >> zshpaths.h.tmp; \
+	  echo '#define FPATH_DIR "'$(fndir)'"' >> zshpaths.h.tmp; \
+	  if test x$(FUNCTIONS_SUBDIRS) != x -a \
+	  x$(FUNCTIONS_SUBDIRS) != xno; then \
+	    fpath_tmp="`for f in $$FUNCTIONS_INSTALL; do \
+	      echo $$f | sed s%/.*%%; \
+	    done | sort | uniq`"; \
+	    fpath_tmp="`echo $$fpath_tmp | sed 's/ /\", \"/g'`"; \
+	    echo "#define FPATH_SUBDIRS { \"$$fpath_tmp\" }" \
+	    >>zshpaths.h.tmp; \
+	  fi; \
 	fi
 	@if cmp -s zshpaths.h zshpaths.h.tmp; then \
 	    rm -f zshpaths.h.tmp; \
diff --git a/Util/zsh-development-guide b/Util/zsh-development-guide
index a37abfe32..f8e331f54 100644
--- a/Util/zsh-development-guide
+++ b/Util/zsh-development-guide
@@ -504,3 +504,21 @@ Documentation
   ocurring in the main text, "plugh" is a normal word that is being quoted
   (it's the user that says `plugh', not the documentation), and "xyzzy"
   is some text to be typed literally that is being quoted.
+
+* For multiple-line pieces of text that should not be filled, there are
+  various models.
+  - If the text is pure example, i.e. with no metasyntactic variables etc.,
+    it should be included within `example(...)'.  The text will be
+    indented, will not be filled and will be put into a fixed width font.
+  - If the text includes mixed fonts, it should be included within
+    `indent(...)'.  As with `example()', the text is not filled, but now
+    explicit font-changing commands are required inside.
+  - If the text appears inside some other format, such as for example the
+    `item()' list structure, then the instruction `nofill(...)', which
+    simply turns off filling should be used; as with `indent(...)',
+    explicit font changing commands are required.  This is also an
+    alternative to `indent()' when no identation is required, e.g. if the
+    accumulated indentation would otherwise be too long.
+  All the above should appear on their own, separated by newlines from the
+  surrounding text.  No extra newlines after the opening or before the
+  closing parenthesis are required.
diff --git a/acconfig.h b/acconfig.h
index 822393c6b..94e6113f8 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -248,9 +248,12 @@
 /* Define to 1 if long is 64 bits */
 #undef LONG_IS_64_BIT
 
-/* Define to a 64 bit type if there is one, but long is shorter */
+/* Define to a 64 bit integer type if there is one, but long is shorter */
 #undef ZSH_64_BIT_TYPE
 
+/* Define to an unsigned variant of ZSH_64_BIT_TYPE if that is defined */
+#undef ZSH_64_BIT_UTYPE
+
 /* Define to 1 if off_t is 64 bit (for large file support) */
 #undef OFF_T_IS_64_BIT
 
diff --git a/aczsh.m4 b/aczsh.m4
index 9a01e2603..cdbd607a8 100644
--- a/aczsh.m4
+++ b/aczsh.m4
@@ -41,11 +41,13 @@ for ac_shellvar in $ac_shellvars; do
   CPPFLAGS) ac_lfsvar=LFS_CFLAGS ;;
   *) ac_lfsvar=LFS_$ac_shellvar ;;
   esac
-  eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar
   (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; }
   ac_getconf=`getconf $ac_lfsvar`
-  ac_getconfs=$ac_getconfs$ac_getconf
-  eval ac_test_$ac_shellvar="\$ac_getconf"
+  if test -n "$ac_getconf"; then
+    eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar
+    ac_getconfs=$ac_getconfs$ac_getconf
+    eval ac_test_$ac_shellvar="\$ac_getconf"
+  fi
 done
 case "$ac_result$ac_getconfs" in
 yes) ac_result=no ;;
@@ -74,12 +76,12 @@ esac
 dnl
 dnl zsh_64_BIT_TYPE
 dnl   Check whether the first argument works as a 64-bit type.
-dnl   If there is a non-zero second argument, we just assume it works
+dnl   If there is a non-zero third argument, we just assume it works
 dnl   when we're cross compiling.  This is to allow a type to be
 dnl   specified directly as --enable-lfs="long long".
-dnl   Sets zsh_cv_64_bit_type to the first argument if the test worked,
-dnl   `no' otherwise.  Be careful testing this, as it may produce
-dnl   two words `long long' on an unquoted substitution.
+dnl   Sets the variable given in the second argument to the first argument
+dnl   if the test worked, `no' otherwise.  Be careful testing this, as it
+dnl   may produce two words `long long' on an unquoted substitution.
 dnl   This macro does not produce messages as it may be run several times
 dnl   before finding the right type.
 dnl
@@ -95,11 +97,11 @@ main()
   $1 foo = 0; 
   return sizeof($1) != 8;
 }
-], zsh_cv_64_bit_type="$1", zsh_cv_64_bit_type=no,
-  [if test x$2 != x ; then
-    zsh_cv_64_bit_type="$1"
+], $2="$1", $2=no,
+  [if test x$3 != x ; then
+    $2="$1"
   else
-    zsh_cv_64_bit_type=no
+    $2=no
   fi])
 ])
 
diff --git a/configure.in b/configure.in
index 02abcc67b..59dcdb991 100644
--- a/configure.in
+++ b/configure.in
@@ -97,8 +97,7 @@ AC_ARG_ENABLE(zsh-hash-debug,
   AC_DEFINE(ZSH_HASH_DEBUG)
 fi])
 
-dnl Do you want large file support, if available (mostly Solaris)?
-dnl Currently this is only partially implemented.
+dnl Do you want large file support, if available?
 undefine([lfs])dnl
 AC_ARG_ENABLE(lfs,
 [  --enable-lfs               turn on support for large files])
@@ -203,18 +202,35 @@ AC_DEFINE(RESTRICTED_R)
 
 undefine([fndir])dnl
 AC_ARG_ENABLE(fndir,
-[  --enable-fndir=DIR        where functions go (default DATADIR/zsh-fns)],
-[fndir="$enableval"], [fndir=${datadir}/zsh/functions])
+[  --enable-fndir=DIR        where functions go (default DATADIR/zsh/functions)],
+[if test $enableval = yes; then
+  fndir=${datadir}/zsh/functions
+else
+  fndir="$enableval"
+fi], [fndir=${datadir}/zsh/functions])
+
+undefine([function_subdirs])
+AC_ARG_ENABLE(function-subdirs,
+[  --enable-function-subdirs  install functions in subdirectories])
 
-if test x${FUNCTIONS_INSTALL+set} != xset; then
+if test "x${FUNCTIONS_INSTALL+set}" != xset; then
   FUNCTIONS_INSTALL="Core/* Base/* Builtins/* User/* Commands/*"
   if test $dynamic != no; then
     FUNCTIONS_INSTALL="${FUNCTIONS_INSTALL} Zftp/*"
   fi
 fi
 
+if test "x${enable_function_subdirs}" != x -a \
+  "x${enable_function_subdirs}" != xno -a \
+  "x$FUNCTIONS_INSTALL" != x; then
+  FUNCTIONS_SUBDIRS=yes
+else
+  FUNCTIONS_SUBDIRS=no
+fi
+
 AC_SUBST(fndir)dnl
 AC_SUBST(FUNCTIONS_INSTALL)dnl
+AC_SUBST(FUNCTIONS_SUBDIRS)dnl
 
 dnl ------------------
 dnl CHECK THE COMPILER
@@ -225,7 +241,7 @@ test -z "${LDFLAGS+set}" && LDFLAGS= auto_ldflags=1
 
 AC_PROG_CC
 
-dnl Check for large file support (Solaris).
+dnl Check for large file support.
 dnl This needs to be done early to get the stuff into the flags.
 if test "x$enable_lfs" != x; then
 zsh_LARGE_FILE_SUPPORT
@@ -552,44 +568,69 @@ zsh_cv_long_is_64_bit=no)])
 
 if test $zsh_cv_long_is_64_bit = yes; then
   AC_DEFINE(LONG_IS_64_BIT)
-elif test "x$enable_lfs" != x; then
-  AC_CACHE_CHECK(if compiler has a 64 bit type, zsh_cv_64_bit_type,
-  [if test "x$enable_lfs" != xyes; then
-     zsh_64_BIT_TYPE(${enable_lfs})
-   else
-     zsh_64_BIT_TYPE(long long)
-     if test "$zsh_cv_64_bit_type" = no; then
-       zsh_64_BIT_TYPE(quad_t)
-     fi
-   fi
-])
-  if test "$zsh_cv_64_bit_type" != no; then
-    AC_DEFINE_UNQUOTED(ZSH_64_BIT_TYPE, $zsh_cv_64_bit_type)
-
-    AC_CACHE_CHECK(if off_t is 64 bit, zsh_cv_off_t_is_64_bit,
-    [AC_TRY_RUN([
+else
+  AC_CACHE_CHECK(if off_t is 64 bit, zsh_cv_off_t_is_64_bit,
+  [AC_TRY_RUN([
 #include <sys/types.h>
 
 main() { return sizeof(off_t) < 8; }
 ],
-    zsh_cv_off_t_is_64_bit=yes,
-    zsh_cv_off_t_is_64_bit=no,
-    zsh_cv_off_t_is_64_bit=no)])
-    if test $zsh_cv_off_t_is_64_bit = yes; then
-      AC_DEFINE(OFF_T_IS_64_BIT)
-    fi
+  zsh_cv_off_t_is_64_bit=yes,
+  zsh_cv_off_t_is_64_bit=no,
+  zsh_cv_off_t_is_64_bit=no)])
+  if test $zsh_cv_off_t_is_64_bit = yes; then
+    AC_DEFINE(OFF_T_IS_64_BIT)
+  fi
 
-    AC_CACHE_CHECK(if ino_t is 64 bit, zsh_cv_ino_t_is_64_bit,
-    [AC_TRY_RUN([
+  AC_CACHE_CHECK(if ino_t is 64 bit, zsh_cv_ino_t_is_64_bit,
+  [AC_TRY_RUN([
 #include <sys/types.h>
 
 main() { return sizeof(ino_t) < 8; }
 ],
-    zsh_cv_ino_t_is_64_bit=yes,
-    zsh_cv_ino_t_is_64_bit=no,
-    zsh_cv_ino_t_is_64_bit=no)])
-    if test $zsh_cv_ino_t_is_64_bit = yes; then
-      AC_DEFINE(INO_T_IS_64_BIT)
+  zsh_cv_ino_t_is_64_bit=yes,
+  zsh_cv_ino_t_is_64_bit=no,
+  zsh_cv_ino_t_is_64_bit=no)])
+  if test $zsh_cv_ino_t_is_64_bit = yes; then
+    AC_DEFINE(INO_T_IS_64_BIT)
+  fi
+
+  if test "x$enable_lfs" != xno -o $zsh_cv_off_t_is_64_bit = yes \
+  -o $zsh_cv_ino_t_is_64_bit = yes; then
+    AC_CACHE_CHECK(if compiler has a 64 bit type, zsh_cv_64_bit_type,
+    [if test "x$enable_lfs" != xyes -a "x$enable_lfs" != xno; then
+      zsh_64_BIT_TYPE(${enable_lfs}, zsh_cv_64_bit_type, force)
+     else
+       zsh_64_BIT_TYPE(long long, zsh_cv_64_bit_type)
+       if test "$zsh_cv_64_bit_type" = no; then
+         zsh_64_BIT_TYPE(quad_t, zsh_cv_64_bit_type)
+       fi
+       if test "$zsh_cv_64_bit_type" = no; then
+         zsh_64_BIT_TYPE(__int64_t, zsh_cv_64_bit_type)
+       fi
+       dnl As a last resort, if we know off_t has 64 bits, use that as
+       dnl the 64-bit integer type.  I don't dare try ino_t since there's
+       dnl probably nothing to stop that being unsigned.
+       if test "$zsh_cv_64_bit_type" = no -a \
+       "$zsh_cv_off_t_is_64_bit" = yes; then
+         zsh_64_BIT_TYPE(off_t, zsh_cv_64_bit_type)
+       fi
+     fi])
+    if test "$zsh_cv_64_bit_type" != no; then
+      AC_DEFINE_UNQUOTED(ZSH_64_BIT_TYPE, $zsh_cv_64_bit_type)
+
+      dnl Handle cases where unsigned type cannot be simply
+      dnl `unsigned ZSH_64_BIT_TYPE'.  More tests may be required.
+      AC_CACHE_CHECK(for a corresponding unsigned 64 bit type,
+      zsh_cv_64_bit_utype,
+      [zsh_64_BIT_TYPE(unsigned $zsh_cv_64_bit_type, zsh_cv_64_bit_utype,
+       force)
+       if test "$zsh_cv_64_bit_utype" = no; then
+         zsh_64_BIT_TYPE(__uint64_t, zsh_cv_64_bit_utype)
+       fi])
+      if test "$zsh_cv_64_bit_utype" != no; then
+        AC_DEFINE_UNQUOTED(ZSH_64_BIT_UTYPE, $zsh_cv_64_bit_utype)
+      fi
     fi
   fi
 fi
@@ -1326,6 +1367,7 @@ eval "zshbin1=${bindir}"
 eval "zshbin2=${zshbin1}"
 eval "zshman=${mandir}"
 eval "zshinfo=${infodir}"
+eval "zshfndir=${fndir}"
 
 echo "
 zsh configuration
@@ -1350,5 +1392,9 @@ echo "\
 library flags             : ${LIBS}
 binary install path       : ${zshbin2}
 man page install path     : ${zshman}
-info install path         : ${zshinfo}
+info install path         : ${zshinfo}"
+if test "$zshfndir" != no; then
+echo "functions install path    : ${zshfndir}
+installed functions       : ${FUNCTIONS_INSTALL}
 "
+fi