From a2159285e80508bb682d90a71270fbddada8bd05 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Fri, 18 Jun 1999 10:55:45 +0000 Subject: zsh-3.1.5-pws-22 --- ChangeLog | 179 ++++++++++- Completion/Base/_brace_parameter | 2 + Completion/Base/_vars | 19 +- Completion/Builtins/_jobs | 2 +- Completion/Builtins/_kill | 3 +- Completion/Builtins/_limits | 2 +- Completion/Builtins/_wait | 2 +- Completion/Builtins/_zftp | 13 + Completion/Core/_normal | 2 +- Completion/Core/_path_files | 4 +- Completion/Core/compdump | 2 +- Completion/Core/compinit | 4 +- Completion/Makefile.in | 16 +- Config/defs.mk.in | 1 + Config/version.mk | 4 +- Doc/Makefile.in | 6 +- Doc/Zsh/arith.yo | 53 +++- Doc/Zsh/builtins.yo | 13 +- Doc/Zsh/compctl.yo | 110 +++---- Doc/Zsh/compsys.yo | 49 ++- Doc/Zsh/compwid.yo | 45 +-- Doc/Zsh/expn.yo | 25 +- Doc/Zsh/files.yo | 2 +- Doc/Zsh/func.yo | 3 +- Doc/Zsh/grammar.yo | 5 + Doc/Zsh/guide.yo | 4 +- Doc/Zsh/jobs.yo | 2 +- Doc/Zsh/metafaq.yo | 2 +- Doc/Zsh/mod_compctl.yo | 2 +- Doc/Zsh/mod_mapfile.yo | 8 +- Doc/Zsh/mod_zftp.yo | 16 +- Doc/Zsh/params.yo | 18 +- Doc/Zsh/redirect.yo | 20 +- Doc/Zsh/zftpsys.yo | 104 ++++--- Doc/Zsh/zle.yo | 6 +- Doc/zman.yo | 10 +- Doc/zsh.yo | 2 +- Doc/ztexi.yo | 10 +- Etc/MACHINES | 10 +- Functions/Makefile.in | 16 +- Functions/Zftp/.distfiles | 2 +- Functions/Zftp/zfgoto | 0 Functions/Zftp/zfinit | 14 +- Functions/Zftp/zfmark | 0 Functions/Zftp/zftp_chpwd | 1 + INSTALL | 24 +- Src/Builtins/rlimits.c | 17 +- Src/Makefile.in | 8 +- Src/Modules/zftp.c | 11 +- Src/Zle/zle_misc.c | 5 +- Src/Zle/zle_tricky.c | 91 +++--- Src/builtin.c | 63 ++-- Src/cond.c | 91 +++--- Src/exec.c | 396 +++++++++++++----------- Src/glob.c | 24 +- Src/hashtable.c | 4 +- Src/hist.c | 110 +++++-- Src/init.c | 31 +- Src/jobs.c | 35 ++- Src/lex.c | 76 ++++- Src/linklist.c | 4 +- Src/loop.c | 64 ++-- Src/math.c | 14 +- Src/mem.c | 55 +++- Src/params.c | 21 +- Src/parse.c | 56 +++- Src/signals.c | 2 +- Src/subst.c | 4 +- Src/text.c | 36 +-- Src/utils.c | 641 ++++++++++++--------------------------- Src/zsh.export | 3 +- Src/zsh.h | 14 +- Src/zsh.mdd | 11 +- Util/zsh-development-guide | 18 ++ acconfig.h | 5 +- aczsh.m4 | 24 +- configure.in | 118 ++++--- 77 files changed, 1652 insertions(+), 1237 deletions(-) create mode 100644 Functions/Zftp/zfgoto create mode 100644 Functions/Zftp/zfmark diff --git a/ChangeLog b/ChangeLog index 48818fe3d..8daf08449 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,182 @@ +1999-06-15 Peter Stephenson + + * 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: 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: 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: 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 + + * 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 + + * 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: 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['. 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() -) +indent(var()) 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())var(process1)tt(RPAR() >LPAR())var(process2)tt(RPAR() >/dev/null)) +nofill(tt(paste 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(). Zsh is now maintained by the members of the zsh-workers mailing list tt(). The development is currently -coordinated by Andrew Main (Zefram) tt(). The coordinator +coordinated by Peter Stephenson tt(). The coordinator can be contacted at tt(), 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 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 ' ./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 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 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 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 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 -- cgit 1.4.1