1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-08-13 15:41:01 +02:00

zsh-3.1.5-pws-22

This commit is contained in:
Tanaka Akira 1999-06-18 10:55:45 +00:00
parent 805381040d
commit a2159285e8
77 changed files with 1651 additions and 1236 deletions

179
ChangeLog
View file

@ -1,5 +1,182 @@
1999-06-15 Peter Stephenson <pws@ibmth.difi.unipi.it>
* Oliver: 6636: Completion/Builtins/_limits: wasn't working
* Bart: 6617 + minor changes: Src/utils.c: Be more careful keeping
$COLUMNS and $LINES correct, particularly if exported.
* Sven: zsh-users/2388: Src/jobs.c: while loops etc. in shells
running without MONITOR were hard to kill.
* Bart: 6628: Src/params.c: setting slices of unset array
caused a crash.
1999-06-14 Peter Stephenson <pws@ibmth.difi.unipi.it>
* pws: 6626: Src/mem.c: in zsh's malloc, try to make sure when
sbrk'ing that it's sufficiently well aligned.
* Oliver: 6624: Completion/Builtins/_kill,
Completion/Builtins/_wait: more widely functioning process
handling
* pws: 6623: Completion/Makefile.in, Config/defs.mk.in,
Functions/Makefile.in, INSTALL, Src/init.c, Src/zsh.mdd,
configure.in: --enable-function-subdirs allows installation
into subdirectories of the function directory and sets the
initial $fpath appropriately.
* Oliver: 6620: Completion/Builtins/_jobs: handle disown, too.
* pws: 6618: Doc/Zsh/func.yo, Doc/Zsh/grammar.yo, Src/lex.c:
with SH_GLOB set, function definition parentheses after the
first word on the line allow spaces inside.
* Sven: 6614: Src/Zle/zle_tricky.c, Completion/Brace/_brace_parameter:
completion after quotes in parameters
* pws: 6610: Src/glob.c: globbing flags shouldn't be active
without extendedglob.
* Bart: 6608: Doc/Zsh files compctl.yo, compsys.yo, compwid.yo,
expn.yo, files.yo, mod_mapfile.yo, mod_zftp.yo, params.yo,
zftpsys.yo, zle.yo: spelling corrections
1999-06-12 Peter Stephenson <pws@ibmth.difi.unipi.it>
* pws: 6601: Src/Makefile.in: don't remake Makemod just
to clean up files
* pws: 6600: Doc/Zsh/arith.yo, Doc/Zsh/compctl.yo,
Doc/Zsh/compsys.yo, Doc/Zsh/compwid.yo, Doc/Zsh/expn.yo,
Doc/Zsh/guide.yo, Doc/Zsh/jobs.yo, Doc/Zsh/metafaq.yo,
Doc/Zsh/mod_compctl.yo, Doc/Zsh/mod_zftp.yo, Doc/Zsh/params.yo,
Doc/Zsh/redirect.yo, Doc/Zsh/zftpsys.yo, Doc/Zsh/zle.yo,
Doc/zman.yo, Doc/ztexi.yo, Util/zsh-development-guide:
Formatting of unfilled text now handled by three distinct
macros example(), indent(), nofill(); compctl description node
is now called `Programmable Completion Using compctl' to
distinguish it from widget completion; don't put chapters on
separate pages because many are too short.
* Wayne: 6599: Src/Zle/zle_tricky.c: unitialised variable warnings
from gcc
1999-06-11 Peter Stephenson <pws@ibmth.difi.unipi.it>
* pws: 6598: Doc/Zsh/zftpsys.yo, Functions/Zftp/zfinit,
Functions/Zftp/zfgoto, Functions/Zftp/zfmark,
Functions/Zftp/zftp_chpwd, Completion/Builtins/_zftp:
add zfmark and zfgoto implementing bookmarks (including use
ncftp bookmarks) for zftp function suite; autoload functions
from zfinit; patcomps -> _patcomps.
* pws: 6596: Doc/Zsh/arith.yo: update on size of integers and
increase in clarity of presentation
* Sven: 6589: Completion/Core/_path_files: use :h and :t instead
of pattern matching
* Sven: 6587, 6588: Src/Zle/zle_misc.c, Doc/Zsh/options.yo: < and
> shouldn't remove a suffix, but | does
* Sven: 6586: Src/exec.c, Src/lex.c, Src/loop.c: don't modify
struct cmd to insert cmd args and flags, always pass those
separately
1999-06-10 Peter Stephenson <pws@ibmth.difi.unipi.it>
* Andrej: 6581: Doc/Makefile: dependencies for manuals
* Sven: 6579: Src/exec.c: old hack of storing shell function
args in struct cmd doesn't work any more
* Sven: 6577: Src/exec.c, Src/text.c, Src/utils.c: expunge
simplifyright(), which appears no longer to have an effect
* pws: 6575: Doc/Zsh/mod_mapfile.yo: avoid mapping long files
* pws: 6571: Src/Builtins/rlimits.c: use appropriate printf()
routine in printulimit() instead of just casting to long
* pws: 6570: configure.in, INSTALL: some systems have
sizeof(off_t) or sizeof(ino_t) == 8 and sizeof(long) == 4 even
without explicit enabling, so check and if so use the
--enable-lfs code.
* pws/Sven: 6567, 6568: Completion/Base/_vars: complete assoc
array keys
* pws: 6566: Src/params.c: junk testhash assoc array
* pws: 6563: sporadic: minor changes affecting casts, sizes
of integers, unused variables; add index for subscripts in
manual
* Bart: email: Src/zsh.h: alternative definition for zulong
* Bart: 6558: Src/builtins.c: printing functions with the
UNALIASED flag
* Sven: 6557: Doc/zsh/compsys.yo: a few typos
1999-06-09 Peter Stephenson <pws@ibmth.difi.unipi.it>
* Andrej: 6556: aczsh.m4: don't disable setting variables
for --enable-lfs just because some other variables were set
* Sven: 6554: Src/Zle/zle_tricky.c: display bugs with compadd -X:
newline missing and display unnecessarily altered
* pws: 6552: configure.in, aczsh.m4, acconfig.h, Src/zsh.h:
define separate unsigned 64-bit integer; try __int64_t and
__uint64_t.
* Sven: 6548: Src/Zle/zle_tricky.c: fix `compctl -l'
* Andrej: 6544: configure displays info on function installation
* Sven: 6542: Src/builtin.c, Src/exec.c, Src/hist.c, Src/init.c,
Src/lex.c: when not using interactive history, don't allocate
history at all
* Andrej: 6541: configure.in: add missing `test'
* Sven: 6535: Completion/core/_normal: an eval was unnecessary
* Bart: 6534: Completion/Core/compdump, Completion/Core/compinit,
Doc/Zsh/builtins.yo, Src/builtin.c, Src/exec.c, Src/zsh.h:
autoload -U defines functions which don't use expand aliases
during loading; used in new completion code to protect
functions.
* Sven: 6527: Src/builtin.c, Src/cond.c, Src/exec.c, Src/glob.c,
Src/hashtable.c, Src/init.c, Src/jobs.c, Src/lex.c,
Src/linklist.c, Src/loop.c, Src/math.c, Src/mem.c, Src/params.c,
Src/parse.c, Src/signals.c, Src/text.c, Src/utils.c, Src/zsh.h:
various sets of patches:
- make zhalloc() use a pointer to the first free heap
- make zsh-mem allocators keep some memory back when freeing
- reduce the amount of allocation work done in the exec.c
execution hierarchy
- don't duplicate execution trees any more than necessary, e.g.
execute functions from stored tree
* pws: Etc/MACHINES: Danek Duvall reports --enable-dynamic OK
on Solaris 2.7, despite previous reports; Sven says on Digital
UNIX 4.0, you need special DLLD and LDFLAGS.
1999-06-08 Peter Stephenson <pws@ibmth.difi.unipi.it> 1999-06-08 Peter Stephenson <pws@ibmth.difi.unipi.it>
* pws: 6525: Src/lex.c (gettokstr): allow parentheses after
first character in command word
* Tanaka Akira: 6522: configure.in: help string for --enable-fndir
had wrong default directory
* pws: 6520: configure.in: --enable-fndir might be yes,
so turn it into ${datadir}/zsh/functions
* 3.1.5-pws-21 made available * 3.1.5-pws-21 made available
* Sven: 6515: Src/Zle/zle_tricky.c: fix memory problems with 6492 * 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; `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, 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, 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. the bits which will now be ignored.
* pws: 6490: Completion/Core/compinit: nounset workaround * pws: 6490: Completion/Core/compinit: nounset workaround

View file

@ -16,4 +16,6 @@ ls="$RBUFFER[${#SUFFIX}+1,-1]"
n=${(M)#ls##\"#} n=${(M)#ls##\"#}
q=${(M)lp%%\"#} q=${(M)lp%%\"#}
[[ n -gt 0 ]] && suf=''
_parameters -s "${q[1,-n-1]}" -S "$suf" -r '-:?#%+=[/' _parameters -s "${q[1,-n-1]}" -S "$suf" -r '-:?#%+=[/'

View file

@ -1,3 +1,20 @@
#compdef getopts read unset vared #compdef getopts read unset vared
compgen -v # This will handle completion of keys of associative arrays, e.g. at
# `vared compconfig[<TAB>'. However, in this version the [ must be
# added by hand.
if [[ $PREFIX = *\[* ]]; then
local var=${PREFIX%%\[*}
local elt="${PREFIX#*\]}${SUFFIX%\]}"
local addclose
compset -p $(( ${#var} + 1 ))
if ! compset -S \]; then
addclose=(-S ']')
fi
if [[ ${(tP)var} = assoc* ]]; then
compadd $addclose - ${(kP)var}
fi
else
compgen -v
fi

View file

@ -1,3 +1,3 @@
#compdef fg jobs #compdef disown fg jobs
compgen -j -P '%' compgen -j -P '%'

View file

@ -9,7 +9,8 @@ else
compgen -P '%' -j && ret=0 compgen -P '%' -j && ret=0
list=("$(ps 2>/dev/null)") 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 return ret
fi fi

View file

@ -1,3 +1,3 @@
#compdef limit unlimit #compdef limit unlimit
compgen -k "(${(j: :)${(f)$(limit)}%% *})" compgen -s '${${(f)"$(limit)"}%% *}'

View file

@ -4,6 +4,6 @@ local list ret=1
compgen -P '%' -j && ret=0 compgen -P '%' -j && ret=0
list=("$(ps 2>/dev/null)") 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 return ret

View file

@ -43,6 +43,19 @@ case $subcom in
compgen -k hosts 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. # dunno... try ordinary completion after all.
unset _compskip unset _compskip

View file

@ -20,7 +20,7 @@ elif [[ "$command" == */* ]]; then
cmd2="${command:t}" cmd2="${command:t}"
else else
cmd1="$command" cmd1="$command"
eval cmd2=$(whence -p $command) cmd2=$(whence -p $command)
fi fi
# See if there are any matching pattern completions. # See if there are any matching pattern completions.

View file

@ -231,7 +231,7 @@ for prepath in "$prepaths[@]"; do
# See which of them match what's on the line. # See which of them match what's on the line.
tmp2=("$tmp1[@]") tmp2=("$tmp1[@]")
compadd -D tmp1 "$ignore[@]" - "${(@)tmp1##*/}" compadd -D tmp1 "$ignore[@]" - "${(@)tmp1:t}"
# If no file matches, save the expanded path and continue with # If no file matches, save the expanded path and continue with
# the outer loop. # the outer loop.
@ -240,7 +240,7 @@ for prepath in "$prepaths[@]"; do
if [[ "$tmp2[1]" = */* ]]; then if [[ "$tmp2[1]" = */* ]]; then
tmp2=( "${(@)tmp2#${prepath}${realpath}}" ) tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
if [[ "$tmp2[1]" = */* ]]; then if [[ "$tmp2[1]" = */* ]]; then
exppaths=( "$exppaths[@]" ${^tmp2%/*}/${tpre}${tsuf} ) exppaths=( "$exppaths[@]" ${^tmp2:h}/${tpre}${tsuf} )
else else
exppaths=( "$exppaths[@]" ${tpre}${tsuf} ) exppaths=( "$exppaths[@]" ${tpre}${tsuf} )
fi fi

View file

@ -74,7 +74,7 @@ done))
# print them out: about five to a line looks neat # print them out: about five to a line looks neat
while (( $#_d_als )); do while (( $#_d_als )); do
print -n autoload print -n autoload -U
for (( _i = 0; _i < 5; _i++ )); do for (( _i = 0; _i < 5; _i++ )); do
if (( $#_d_als )); then if (( $#_d_als )); then
print -n " $_d_als[1]" print -n " $_d_als[1]"

View file

@ -194,7 +194,7 @@ compdef() {
# and probably do autoloading. # and probably do autoloading.
func="$1" func="$1"
[[ -n "$autol" ]] && autoload "$func" [[ -n "$autol" ]] && autoload -U "$func"
shift shift
case "$type" in case "$type" in
@ -363,7 +363,7 @@ if [[ -z "$_i_done" ]]; then
fi fi
;; ;;
(\#autoload) (\#autoload)
autoload ${_i_file:t} autoload -U ${_i_file:t}
;; ;;
esac esac
done done

View file

@ -55,7 +55,14 @@ install.fns:
$(sdir_top)/mkinstalldirs $(fndir) || exit 1; \ $(sdir_top)/mkinstalldirs $(fndir) || exit 1; \
for file in $(FUNCTIONS_INSTALL); do \ for file in $(FUNCTIONS_INSTALL); do \
if test -f $$file; then \ 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; \ fi; \
done; \ done; \
fi; \ fi; \
@ -65,7 +72,12 @@ uninstall.fns:
if test x$(fndir) != x && test x$(fndir) != xno; then \ if test x$(fndir) != x && test x$(fndir) != xno; then \
for file in $(FUNCTIONS_INSTALL); do \ for file in $(FUNCTIONS_INSTALL); do \
if test -f $$file; then \ 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; \ fi; \
done; \ done; \
fi; \ fi; \

View file

@ -68,6 +68,7 @@ INSTALL_DATA = @INSTALL_DATA@
# variables used in determining what to install # variables used in determining what to install
FUNCTIONS_INSTALL = @FUNCTIONS_INSTALL@ FUNCTIONS_INSTALL = @FUNCTIONS_INSTALL@
FUNCTIONS_SUBDIRS = @FUNCTIONS_SUBDIRS@
# flags passed to recursive makes in subdirectories # flags passed to recursive makes in subdirectories
MAKEDEFS = \ MAKEDEFS = \

View file

@ -27,5 +27,5 @@
# This must also serve as a shell script, so do not add spaces around the # This must also serve as a shell script, so do not add spaces around the
# `=' signs. # `=' signs.
VERSION=3.1.5-pws-21 VERSION=3.1.5-pws-22
VERSION_DATE='June 6, 1999' VERSION_DATE='June 13, 1999'

View file

@ -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/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/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_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/mod_zle.yo Zsh/options.yo \
Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo Zsh/restricted.yo \ Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo Zsh/restricted.yo \
Zsh/seealso.yo Zsh/zftpsys.yo Zsh/zle.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 \ 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_comp1.yo Zsh/mod_compctl.yo Zsh/mod_deltochar.yo \
Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_sched.yo \ Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_mapfile.yo \
Zsh/mod_stat.yo Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_sched.yo Zsh/mod_stat.yo Zsh/mod_zftp.yo Zsh/mod_zle.yo
zshoptions.1: Zsh/options.yo zshoptions.1: Zsh/options.yo

View file

@ -5,16 +5,42 @@ sect(Arithmetic Evaluation)
)\ )\
cindex(arithmetic evaluation) cindex(arithmetic evaluation)
cindex(evaluation, arithmetic) cindex(evaluation, arithmetic)
An ability to perform integer arithmetic is provided with the builtin tt(let).
findex(let, use of) 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. 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 where var(base) is a decimal number between two and thirty-six
representing the arithmetic base and var(n) representing the arithmetic base and var(n)
is a number in that base (for example, `tt(16#ff)' is 255 in hexadecimal). is a number in that base (for example, `tt(16#ff)' is 255 in hexadecimal).
If var(base) is omitted The var(base)tt(#) may also be omitted, in which case
then base 10 is used. For backwards compatibility the form base 10 is used. For backwards compatibility the form
`tt([)var(base)tt(])var(n)' is also accepted. `tt([)var(base)tt(])var(n)' is also accepted.
cindex(arithmetic operators) cindex(arithmetic operators)
@ -50,10 +76,17 @@ and XOR operators.
An expression of the form `tt(#\)var(x)' where var(x) is any character 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 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 `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). of the parameter var(foo).
Named parameters and subscripted arrays can be referenced by name within an 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 An internal integer representation of a named parameter
can be specified with the tt(integer) builtin. 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 Arithmetic evaluation is performed on the value of each
assignment to a named parameter declared integer assignment to a named parameter declared integer
in this manner. 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(")'.

View file

@ -981,12 +981,13 @@ shown.
) )
item(tt(-f))( item(tt(-f))(
The names refer to functions rather than parameters. No assignments The names refer to functions rather than parameters. No assignments
can be made, and the only other valid flags are tt(-t) can be made, and the only other valid flags are tt(-t), tt(-u) and
and tt(-u). The flag tt(-t) turns on execution tracing for this tt(-U). The flag tt(-t) turns on execution tracing for this
function. The flag tt(-u) causes this function to be marked function. The tt(-u) and tt(-U) flags cause the function to be
for autoloading. The tt(fpath) parameter will be searched to find the marked for autoloading; tt(-U) also causes alias expansion to be
function definition when the function is first referenced; see suppressed when the function is loaded. The tt(fpath) parameter
noderef(Functions). will be searched to find the function definition when the function
is first referenced; see noderef(Functions).
) )
item(tt(-i))( item(tt(-i))(
Use an internal integer representation. If var(n) is nonzero it Use an internal integer representation. If var(n) is nonzero it

View file

@ -1,5 +1,5 @@
texinode(Programmable Completion)(Completion Widgets)(Zsh Line Editor)(Top) texinode(Programmable Completion Using compctl)(Completion Widgets)(Zsh Line Editor)(Top)
chapter(Programmable Completion) chapter(Programmable Completion Using compctl)
cindex(completion, programmable) cindex(completion, programmable)
cindex(completion, controlling) cindex(completion, controlling)
findex(compctl) findex(compctl)
@ -33,7 +33,7 @@ menu(Matching Control)
menu(Example) menu(Example)
endmenu() endmenu()
texinode(Command Flags)(Option Flags)()(Programmable Completion) texinode(Command Flags)(Option Flags)()(Programmable Completion Using compctl)
sect(Command Flags) sect(Command Flags)
Completion of the arguments of a command may be different for each Completion of the arguments of a command may be different for each
command or may use the default. The behavior when completing the 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 arranges for completion of the words of any command beginning with
tt(foo). When completion is attempted, all pattern completions are tt(foo). When completion is attempted, all pattern completions are
tried in the reverse order of their definition until one matches. By 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 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 can be overridden by including tt(-tn) in the flags for the pattern
completion. 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 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 that completion after `tt(~)' is too slow to be usable), you can use
indent( example(compctl -T -x 's[~] C[0,[^/]#]' -k friends -S/ -tn)
tt(compctl -T -x 's[~] C[0,[^/]#]' -k friends -S/ -tn)
)
to complete the strings in the array tt(friends) after a `tt(~)'. 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 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 The form with tt(-M) as the first and only option defines global
matching specifications, as described below in noderef(Matching Control). 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) sect(Option Flags)
startlist() startlist()
list([ tt(-fcFBdeaRGovNAIOPZEnbjrzu/) ]) 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 delimiter may be escaped with a backslash; in this case the argument
should be quoted. For example, should be quoted. For example,
indent( example(compctl -k "(cputime filesize datasize stacksize
nofill(tt(compctl -k "(cputime filesize datasize stacksize coredumpsize resident descriptors)" limit)
coredumpsize resident descriptors)" limit))
)
) )
item(tt(-g) var(globstring))( item(tt(-g) var(globstring))(
The var(globstring) is expanded using filename globbing; it should be 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))( item(tt(-K) var(function))(
Call the given function to get the completions. Unless the name 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 passed two arguments: the prefix and the suffix of the word on which
completion is to be attempted, in other words those characters before completion is to be attempted, in other words those characters before
the cursor position, and those from the cursor position onwards. The 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 command line can be accessed with the tt(-c) and tt(-l) flags to
the tt(read) builtin. For example, the tt(read) builtin. For example,
indent( example(function whoson { reply=(`users`); }
nofill(tt(function whoson { reply=(`users`); } compctl -K whoson talk)
compctl -K whoson talk))
)
completes only logged-on users after `tt(talk)'. Note that `tt(whoson)' must completes only logged-on users after `tt(talk)'. Note that `tt(whoson)' must
return an array, so `tt(reply=`users`)' would be incorrect. 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 the empty string all words are taken (as with `tt(*)'). A typical
use is use is
indent( example(compctl -D -f PLUS() -H 0 '')
tt(compctl -D -f PLUS() -H 0 '')
)
which forces completion to look back in the history list for a word if which forces completion to look back in the history list for a word if
no filename matches. 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) initial part already typed will be completed and the whole var(prefix)
ignored for completion purposes. For example, ignored for completion purposes. For example,
indent( example(compctl -j -P "%" kill)
tt(compctl -j -P "%" kill)
)
inserts a `%' after the kill command and then completes job names. 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 globbing completion (options tt(-c), tt(-f), tt(-/), tt(-g)), the file
prefix is implicitly added in front of the completion. For example, prefix is implicitly added in front of the completion. For example,
indent( example(compctl -/ -W ~/Mail maildirs)
tt(compctl -/ -W ~/Mail maildirs)
)
completes any subdirectories to any depth beneath the directory completes any subdirectories to any depth beneath the directory
tt(~/Mail), although that prefix does not appear on the command line. 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 is instead taken as the command name, and command name completion
performed on the first word in the range. For example, performed on the first word in the range. For example,
indent( example(compctl -x 'r[-exec,;]' -l '' -- find)
tt(compctl -x 'r[-exec,;]' -l '' -- find)
)
completes arguments between `tt(-exec)' and the following `tt(;)' (or the end 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 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 use its own criteria to decide what matches. If there is no
completion, the original word is retained. Since the produced completion, the original word is retained. Since the produced
possible completions seldom seldom have interesting common prefixes 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. set and this flag is used.
) )
item(tt(-y) var(func-or-var))( 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 This can be useful with non-exclusive alternative completions. For
example, in example, in
indent( example(compctl -f -J files -t+ + -v -J variables foo)
tt(compctl -f -J files -t+ + -v -J variables foo)
)
both files and variables are possible completions, as the tt(-t+) forces 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 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() enditem()
texinode(Alternative Completion)(Extended Completion)(Option Flags)(Programmable Completion) texinode(Alternative Completion)(Extended Completion)(Option Flags)(Programmable Completion Using compctl)
sect(Alternative Completion) sect(Alternative Completion)
startlist() startlist()
list(tt(compctl) [ tt(-CDT) ] var(options) tt(PLUS()) var(options) [ tt(PLUS()) ... ] \ 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 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. 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) sect(Extended Completion)
startlist() startlist()
list(nofill(tt(compctl) [ tt(-CDT) ] var(options) \ 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 be negative to count from the end: in most cases, var(index) will be
1 or -1. For example, 1 or -1. For example,
indent( example(compctl -s '`users`' -x 'n[1,@]' -k hosts -- talk)
tt(compctl -s '`users`' -x 'n[1,@]' -k hosts -- talk)
)
will usually complete usernames, but if you insert an tt(@) after the will usually complete usernames, but if you insert an tt(@) after the
name, names from the array var(hosts) (assumed to contain hostnames, 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() enditem()
texinode(Matching Control)(Example)(Extended Completion)(Programmable Completion) texinode(Matching Control)(Example)(Extended Completion)(Programmable Completion Using compctl)
sect(Matching Control) sect(Matching Control)
It is possible by use of the tt(-M) var(spec) flag to specify how the 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 underscore are ignored when trying to match the trial completions
generated and uppercase letters on the line match the corresponding generated and uppercase letters on the line match the corresponding
lowercase letters in the words: lowercase letters in the words:
indent(
nofill(tt(compctl -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ example(compctl -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
-o setopt unsetopt)) -o setopt unsetopt)
)
The first part says that the pattern `tt([nN][oO])' at the beginning 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 (the empty anchor before the pipe symbol) of the string on the
line matches the empty string in the list of words generated by 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 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 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: 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. This makes lowercase letters match their uppercase counterparts.
To make uppercase letters match the lowercase forms as well: 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 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) 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 tt(source) and tt(unix) in this example, is to be completed separately
is a different problem to be solved by extended completion. The is a different problem to be solved by extended completion. The
example can be handled by: example can be handled by:
indent(
nofill(tt(compctl -M 'r:|.=* r:|=*' \ example(compctl -M 'r:|.=* r:|=*' \
-k '(comp.sources.unix comp.sources.misc ...)' ngroups)) -k '(comp.sources.unix comp.sources.misc ...)' ngroups)
)
The first specification says that tt(lpat) is the empty string, while 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 tt(anchor) is a dot; tt(tpat) is tt(*), so this can match anything
except for the `tt(.)' from the anchor in 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. at the end of the trial completion.
More generally, the specification 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 allows one to complete words with abbreviations before any of the
characters in the square brackets in any completion. For example, to characters in the square brackets in any completion. For example, to
complete tt(veryverylongfile.c) rather than tt(veryverylongheader.h) 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, 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 we arrange for it to be tried only if the matchers described above don't
produce any matches: 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) 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 first tries matching tt(foo)var(anything)tt(.bar)var(anything), as
with the previous example. If that fails, the two descriptions in the 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 characters at the beginning or end of the trial completion, so it will
look for var(anything)tt(foo.bar)var(anything). 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) sect(Example)
indent(
nofill( example(compctl -u -x 's[tt(PLUS())] c[-1,-f],s[-f+PLUS()]' \
tt(compctl -u -x 's[tt(PLUS())] c[-1,-f],s[-f+PLUS()]' \ -g '~/Mail/*(:t)' - 's[-f],c[-1,-f]' -f -- mail)
-g '~/Mail/*(:t)' - 's[-f],c[-1,-f]' -f -- mail))
)
This is to be interpreted as follows: This is to be interpreted as follows:
If the current command is tt(mail), then If the current command is tt(mail), then

View file

@ -51,7 +51,7 @@ sect(Initialisation)
The script tt(compinstall) can be run by a user to set up the completion 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 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 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 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. 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 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. 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, 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 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 (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 be given following the tt(-d). On the next call to tt(compinit -d), the
dumped file will be read instead. 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 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 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 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 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 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 change, it is easiest to delete the dump file by hand so that the next time
tt(compinit) will re-create it. 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. var(pattern) may be given.
) )
item(tt(#compdef -k) var(style key-sequences...))( 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(key-sequences). It creates a widget behaving like the builtin widget
var(style), which must be one of those that perform completion, namely var(style), which must be one of those that perform completion, namely
tt(complete-word), tt(delete-char-or-list), tt(expand-or-complete), 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 configuration key tt(completer). For example, to use normal
completion and correction if that doesn't generate any matches: completion and correction if that doesn't generate any matches:
indent( example(compconf completer=_complete:_correct)
nofill(tt(compconf completer=_complete:_correct))
)
after sourcing tt(compinit). The default value for this configuration key after sourcing tt(compinit). The default value for this configuration key
set up in tt(compinit) is `tt(_complete)', i.e. normally only ordinary 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 presented to the user. The intended use of this completer function is to
try after the normal tt(_complete) completer by setting: try after the normal tt(_complete) completer by setting:
indent( example(compconf completer=_complete:_approximate)
nofill(tt(compconf completer=_complete:_approximate))
)
This will give correcting completion if and only if This will give correcting completion if and only if
normal completion doesn't yield any possible completions. When 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 completer function will take any numeric argument as the
maximum number of errors allowed. For example, with maximum number of errors allowed. For example, with
indent( example(compconf approximate_accept=2n)
nofill(tt(compconf approximate_accept=2n))
)
two errors will be allowed if no numeric argument is given. However, 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 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: For example, with:
indent(tt( example(compconf completer=_complete:_correct:_approximate
nofill(compconf completer=_complete:_correct:_approximate) compconf correct_accept='2n!' approximate_accept=3n)
nofill(compconf correct_accept='2n!' approximate_accept=3n))
)
correction will accept up to two errors. If a numeric argument is correction will accept up to two errors. If a numeric argument is
given, correction will not be performed, but correcting completion will be, 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))( item(tt(_match))(
This completer is intended to be used after the tt(_complete) This completer is intended to be used after the tt(_complete)
completer. It allows one to give patterns on the command line and 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 completions for the context the cursor is in, without having to set
the tt(GLOB_COMPLETE) option. 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 arithmetical expression. In this case, expansion of substitutions will
be done if the expression evaluates to `tt(1)'. For example, with be done if the expression evaluates to `tt(1)'. For example, with
indent( example(compconf expand_substitute='NUMERIC != 1')
nofill(tt(compconf expand_substitute='NUMERIC != 1'))
)
substitution will be performed only if given an explicit numeric substitution will be performed only if given an explicit numeric
argument other than `tt(1)', as by typing `tt(ESC 2 TAB)'. 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 arithmetical expression. In this case, delaying will be done if the
expression evaluates to `tt(1)'. For example, with expression evaluates to `tt(1)'. For example, with
indent( example(compconf list_condition='NUMERIC != 1')
nofill(tt(compconf list_condition='NUMERIC != 1'))
)
delaying will be done only if given an explicit numeric argument delaying will be done only if given an explicit numeric argument
other than `tt(1)'. 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 tt(never), however, a new completion is started if the old list was
generated by a different completion command (the behaviour without the generated by a different completion command (the behaviour without the
tt(_oldlist) completer). tt(_oldlist) completer).
For example, suppose you type tt(^Xc) to generate a list of corrections, 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 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 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. parameter in normal completion.
The function tt(_files) calls tt(_path_files) with all the arguments 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. without any tt(-g) or tt(-/) option, thus generating all filenames.
These functions also accept the `tt(-J)', `tt(-V)', `tt(-X)', `tt(-P)', 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 command (probably with arguments) that should be invoked to complete
after the equal sign. Example: after the equal sign. Example:
indent( example(_long_options '*\*' '(yes no)' \
nofill(tt(_long_options '*\*' '(yes no)' \)) '*=FILE*' '_files' \
nofill(tt( '*=FILE*' '_files' \)) '*=DIR*' '_files -/')
nofill(tt( '*=DIR*' '_files -/'))
)
Here, `tt(yes)' and `tt(no)' will be completed as the argument of 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 options whose description ends in a star, file names for options that

View file

@ -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) chapter(Completion Widgets)
cindex(completion, widgets) cindex(completion, widgets)
cindex(completion, programmable) cindex(completion, programmable)
@ -10,9 +10,7 @@ ifzman(zmanref(zshzle))\
ifnzman(noderef(The zle Module))\ ifnzman(noderef(The zle Module))\
). For example, ). For example,
indent( example(zle -C complete expand-or-complete completer)
nofill(tt(zle -C complete expand-or-complete completer))
)
defines a widget named tt(complete). When this widget is bound to a key 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 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 transferred from the beginning of tt(PREFIX) to the end of tt(IPREFIX), for
example: example:
tt(indent( example(IPREFIX=${PREFIX%%\=*}=
nofill(IPREFIX=${PREFIX%%\=*}=) PREFIX=${PREFIX#*=})
nofill(PREFIX=${PREFIX#*=})
))
causes the part of the prefix up to and including the first equal sign not causes the part of the prefix up to and including the first equal sign not
to be treated as part of a matched string. 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 When completion is performed with a global match specification as defined
by by
indent( indent(tt(compctl -M) var(spec1 ... specN ...))
nofill(tt(compctl -M) var(spec1 ... specN ...))
)
this gives the number of the specification string currently in use. this gives the number of the specification string currently in use.
In this case, matching is performed with each specification in turn. In this case, matching is performed with each specification in turn.
@ -229,7 +223,7 @@ the tt(ALWAYS_LAST_PROMPT) option.
) )
item(tt(insert))( item(tt(insert))(
This controls the manner in which a match is inserted into the command 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 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 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, 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 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 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 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 valid list and it is also currently shown on the screen, the value of this
key is tt(shown). 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 normal option flags (not those for extended completion) supported by
the tt(compctl) builtin command (see the tt(compctl) builtin command (see
ifzman(zmanref(zshcompctl))\ 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) ) 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 flag, the function given as argument to it cannot access the command
line with the tt(read) builtin 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 generated them directly from a tt(compctl)-definition with the same
flags. The completion code will consider only those matches as flags. The completion code will consider only those matches as
possible completions that match the prefix and suffix from the special 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 generated matches using the normal matching rules and any matching
specifications given with the tt(-M) flag to tt(compgen) and the specifications given with the tt(-M) flag to tt(compgen) and the
global matching specifications given via the tt(compctl -M )var(spec1 ...) 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 completion code breaks the string to complete into seven fields in
the order: the order:
indent( indent(var(<ipre><apre><hpre><word><hsuf><asuf><isuf>))
var(<ipre><apre><hpre><word><hsuf><asuf><isuf>)
)
The first field The first field
is an ignored prefix taken from the command line, the contents of the 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))( item(tt(-q))(
If the cursor is currently inside single or double quotes, the word 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), resulting words are stored in the tt(words) array, and tt(PREFIX),
tt(SUFFIX), tt(QIPREFIX), and tt(QISUFFIX) are modified to reflect the tt(SUFFIX), tt(QIPREFIX), and tt(QISUFFIX) are modified to reflect the
word part that is completed. word part that is completed.
) )
enditem() 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 and the parameters were modified and non-zero otherwise. This allows
one to use this builtin in tests such as: one to use this builtin in tests such as:
indent( example(if compset -P '*\='; then ...)
tt(if compset -P '*\='; then ...)
)
This forces anything up to and including the last equal sign to be This forces anything up to and including the last equal sign to be
ignored by the completion code. ignored by the completion code.
@ -685,21 +675,18 @@ sect(Examples)
The first step is to define the widget: The first step is to define the widget:
indent(nofill( example(zle -C complete complete-word complete-history)
tt(zle -C complete complete-word complete-history)))
Then the widget can be bound to a key using the tt(bindkey) builtin Then the widget can be bound to a key using the tt(bindkey) builtin
command: command:
indent(nofill( example(bindkey '^X\t' complete)
tt(bindkey '^X\t' complete)))
After that the shell function tt(complete-history) will be invoked After that the shell function tt(complete-history) will be invoked
after typing control-X and TAB. The function should then generate the after typing control-X and TAB. The function should then generate the
matches, e.g.: matches, e.g.:
indent(nofill( example(complete-history LPAR()RPAR() { compgen -H 0 '' })
tt(complete-history LPAR()RPAR() { compgen -H 0 '' })))
This function will complete words from the history matching the This function will complete words from the history matching the
current word. current word.

View file

@ -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. be a named pipe connected to the output of the var(list) process.
For example, For example,
nofill(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() | tee >LPAR())var(process1)tt(RPAR() >LPAR())var(process2)tt(RPAR() >/dev/null)) nofill(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() |
tee >LPAR())var(process1)tt(RPAR() >LPAR())var(process2)tt(RPAR() >/dev/null))
cuts fields 1 and 3 from the files var(file1) and var(file2) respectively, cuts fields 1 and 3 from the files var(file1) and var(file2) respectively,
pastes the results together, and sends it to the processes 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, For example,
nofill(tt(foo="twinkle twinkle little star" sub="t*e" rep="spy") example(foo="twinkle twinkle little star" sub="t*e" rep="spy"
tt(print ${foo//${~sub}/$rep}) print ${foo//${~sub}/$rep}
tt(print ${(S)foo//${~sub}/$rep})) print ${(S)foo//${~sub}/$rep})
Here, the `tt(~)' ensures that the text of tt($sub) is treated as a 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 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 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 current level of substitution, just as if the nested substitution were the
outermost. The flags are not propagated up to enclosing 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 array as determined by the flags, possibly adjusted for quoting. All the
following steps take place where applicable at all levels of substitution. 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 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((*/)#)'. As a shorthand, `tt(**/)' is equivalent to `tt((*/)#)'.
Thus: Thus:
nofill(tt(ls (*/)#bar)) example(ls (*/)#bar)
or or
nofill(tt(ls **/bar)) example(ls **/bar)
does a recursive directory search for files named `tt(bar)', not following does a recursive directory search for files named `tt(bar)', not following
symbolic links. To follow links, use `tt(***/)'. 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. `tt((:..))' even if no actual filename generation is performed.
Thus: Thus:
nofill(tt(ls *(-/))) example(ls *(-/))
lists all directories and symbolic links that point to directories, lists all directories and symbolic links that point to directories,
and and
nofill(tt(ls *(%W))) example(ls *(%W))
lists all world-writable device files in the current directory, and 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 lists all files in the current directory that are
world-writable or world-executable, and 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 outputs the basename of all root-owned files beginning with the string
`tt(foo)' in tt(/tmp), ignoring symlinks, and `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 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 (but not those starting with a dot, since tt(GLOB_DOTS) is explicitly

View file

@ -26,7 +26,7 @@ tt($ZDOTDIR/.zlogin) are read.
When a login shell exits, the files tt($ZDOTDIR/.zlogout) and then When a login shell exits, the files tt($ZDOTDIR/.zlogout) and then
tt(/etc/zlogout) are read. This happens with either an explicit exit 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 end-of-file from the terminal. However, if the shell terminates due
to tt(exec)'ing another process, the logout files are not read. 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. These are also affected by the tt(RCS) and tt(GLOBAL_RCS) options.

View file

@ -5,7 +5,8 @@ sect(Functions)
)\ )\
cindex(functions) cindex(functions)
findex(function) 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. Shell functions are read in and stored internally.
Alias names are resolved when the function is read. Alias names are resolved when the function is read.
Functions are executed like commands with the arguments Functions are executed like commands with the arguments

View file

@ -203,6 +203,11 @@ Normally, only one var(word) is provided; multiple var(word)s
are usually only useful for setting traps. are usually only useful for setting traps.
The body of the function is the var(list) between The body of the function is the var(list) between
the tt({) and tt(}). See noderef(Functions). 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) cindex(timing)
item(tt(time) [ var(pipeline) ])( item(tt(time) [ var(pipeline) ])(

View file

@ -28,7 +28,7 @@ menu(Parameters)
menu(Options) menu(Options)
menu(Shell Builtin Commands) menu(Shell Builtin Commands)
menu(Zsh Line Editor) menu(Zsh Line Editor)
menu(Programmable Completion) menu(Programmable Completion Using compctl)
menu(Completion Widgets) menu(Completion Widgets)
menu(Zsh Modules) menu(Zsh Modules)
menu(Completion System) menu(Completion System)
@ -98,7 +98,7 @@ menu(Arguments)
menu(Completion) menu(Completion)
menu(Miscellaneous) menu(Miscellaneous)
Programmable Completion Programmable Completion Using compctl
menu(Command Flags) menu(Command Flags)
menu(Option Flags) menu(Option Flags)

View file

@ -9,7 +9,7 @@ command, and assigns them small integer numbers.
When a job is started asynchronously with `tt(&)', When a job is started asynchronously with `tt(&)',
the shell prints a line which looks like: 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 indicating that the job which was started asynchronously was job number
1 and had one (top-level) process, whose process ID was 1234. 1 and had one (top-level) process, whose process ID was 1234.

View file

@ -12,7 +12,7 @@ cindex(author)
Zsh was originally written by Paul Falstad tt(<pf@zsh.org>). Zsh was originally written by Paul Falstad tt(<pf@zsh.org>).
Zsh is now maintained by the members of the zsh-workers mailing Zsh is now maintained by the members of the zsh-workers mailing
list tt(<zsh-workers@sunsite.auc.dk>). The development is currently list tt(<zsh-workers@sunsite.auc.dk>). The development is currently
coordinated by Andrew Main (Zefram) tt(<zefram@zsh.org>). The coordinator coordinated by Peter Stephenson tt(<pws@zsh.org>). The coordinator
can be contacted at tt(<coordinator@zsh.org>), but matters relating to can be contacted at tt(<coordinator@zsh.org>), but matters relating to
the code should generally go to the mailing list. the code should generally go to the mailing list.
texinode(Availability)(Mailing Lists)(Author)(Introduction) texinode(Availability)(Mailing Lists)(Author)(Introduction)

View file

@ -3,7 +3,7 @@ sect(The compctl Module)
The tt(compctl) module makes available several builtin commands. tt(compctl), The tt(compctl) module makes available several builtin commands. tt(compctl),
is the standard way to control completions for ZLE. See is the standard way to control completions for ZLE. See
ifzman(zmanref(zshcompctl))\ 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, The other builtin commands can be used in user-defined completion widgets,
see see

View file

@ -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 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 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 the whole contents of the file will always reside physically in memory when
accessed (possibly multiple times, due to standard parameter subsitution accessed (possibly multiple times, due to standard parameter substitution
operations). 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 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. execution hierarchy to make this convenient.
It is unfortunate that the mechanism for loading modules does not yet allow It is unfortunate that the mechanism for loading modules does not yet allow

View file

@ -80,7 +80,7 @@ will be deleted if the tt(zftp) module is unloaded.
For example, 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 will store the host tt(ftp.elsewhere.xx) and the user tt(juser) and
then prompt the user for the corresponding password. 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 place completely in the background, freeing tt(zftp) for concurrent
foreground use. For example, foreground use. For example,
nofill(tt(zftp params ftp.soreeyes.ca bubble squeak)) example(zftp params ftp.soreeyes.ca bubble squeak
nofill(tt(LPAR()zftp open; zftp get foo >bar; zftp close)tt(RPAR() &)) (zftp open; zftp get foo >bar; zftp close) &)
--- here, the connection is restricted to a background subshell and --- here, the connection is restricted to a background subshell and
you are free to open a simultaneous connection in the foreground. 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 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 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 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. Create a new directory var(directory) on the server.
) )
item(tt(rmdir) var(directory))( 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))( item(tt(rename) var(old-name) var(new-name))(
Rename file var(old-name) to var(new-name) on the server. 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...))( item(tt(quote) var(args...))(
Send the raw FTP command sequence to the server. You should be Send the raw FTP command sequence to the server. You should be
familiar with the FTP command set as defined in RFC959 before doing 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 the mechanism for returning messages as described for the variable
tt(ZFTP_VERBOSE) below, in particular that all messages from the tt(ZFTP_VERBOSE) below, in particular that all messages from the
control connection are sent to standard error. control connection are sent to standard error.
@ -335,7 +335,7 @@ digit reply code is defined by RFC959 to correspond to:
startitem() startitem()
item(1.)( item(1.)(
A positive prelimnary reply. A positive preliminary reply.
) )
item(2.)( item(2.)(
A positive completion reply. 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 will not be reflected by changes to the variables (but should
be otherwise harmless). 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 fork(), so that operations in subshells or on the left hand side of a
pipeline are not possible. pipeline are not possible.

View file

@ -16,7 +16,7 @@ To assign an array value, use `tt(set -A) var(name) var(value) ...'.
findex(set, use of) findex(set, use of)
The value of a parameter may also be assigned by writing: 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) If the integer attribute, tt(-i), is set for var(name), the var(value)
is subject to arithmetic evaluation. See noderef(Array Parameters) is subject to arithmetic evaluation. See noderef(Array Parameters)
@ -38,19 +38,19 @@ texinode(Array Parameters)(Positional Parameters)()(Parameters)
sect(Array Parameters) sect(Array Parameters)
The value of an array parameter may be assigned by writing: 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. If no parameter var(name) exists, an ordinary array parameter is created.
Associative arrays must be declared first, by `tt(typeset -A) var(name)'. Associative arrays must be declared first, by `tt(typeset -A) var(name)'.
When var(name) refers to an associative array, the parenthesized list is When var(name) refers to an associative array, the parenthesized list is
interpreted as alternating keys and values: 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 Every var(key) must have a var(value) in this case. To create an empty
array or associative array, use: 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 Individual elements of an array may be selected using a
subscript. A subscript of the form `tt([)var(exp)tt(])' 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())'. expansion as if it were surrounded by `tt($LPAR()LPAR())...tt(RPAR()RPAR())'.
The elements are numbered beginning with 1 unless the The elements are numbered beginning with 1 unless the
tt(KSH_ARRAYS) option is set when they are numbered from zero. tt(KSH_ARRAYS) option is set when they are numbered from zero.
cindex(subscripts)
pindex(KSH_ARRAYS, use of) pindex(KSH_ARRAYS, use of)
The same subscripting syntax is used for associative arrays, 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(])' A subscript of the form `tt([)var(exp1)tt(,)var(exp2)tt(])'
selects all elements in the range var(exp1) to var(exp2), selects all elements in the range var(exp1) to var(exp2),
inclusive. inclusive. (Associative arrays are unordered, and so do not support
(Associative arrays are unordered, and so do not support ranges.) ranges.) If one of the subscripts evaluates to a negative number,
If one of the subscripts evaluates to a negative number,
say tt(-)var(n), then the var(n)th element from the end 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 of the array is used. Thus `tt($foo[-3])' is the third element
from the end of the array tt(foo), and 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 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 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 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.) is not supported for associative arrays.)
To delete an element of an ordinary array, assign `tt(LPAR()RPAR())' to 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 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 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 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) texinode(Local Parameters)(Parameters Set By The Shell)(Positional Parameters)(Parameters)
sect(Local Parameters) sect(Local Parameters)

View file

@ -107,7 +107,7 @@ The shell evaluates each redirection in terms of the
association at the time of evaluation. association at the time of evaluation.
For example: 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). first associates file descriptor 1 with file var(fname).
It then associates file descriptor 2 with the file associated with file 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), its input to all the specified outputs, similar to bf(tee),
provided the tt(MULTIOS) option is set. Thus: 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)'. writes the date to two files, named `tt(foo)' and `tt(bar)'.
Note that a pipe is an implicit redirection; thus 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. 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 option is set, the word after a redirection operator is also subjected
to filename generation (globbing). Thus to filename generation (globbing). Thus
nofill(tt(: > *)) example(: > *)
will truncate all files in the current directory, will truncate all files in the current directory,
assuming there's at least one. (Without the tt(MULTIOS) assuming there's at least one. (Without the tt(MULTIOS)
option, it would create an empty file called `tt(*)'.) option, it would create an empty file called `tt(*)'.)
Similarly, you can do 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, 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 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), specified, similar to bf(cat),
provided the tt(MULTIOS) option is set. Thus provided the tt(MULTIOS) option is set. Thus
nofill(tt(sort <foo <fubar)) example(sort <foo <fubar)
or even or even
nofill(tt(sort <f{oo,ubar})) example(sort <f{oo,ubar})
is equivalent to `tt(cat foo fubar | sort)'. is equivalent to `tt(cat foo fubar | sort)'.
Note that a pipe is an implicit redirection; thus Note that a pipe is an implicit redirection; thus
nofill(tt(cat bar | sort <foo)) example(cat bar | sort <foo)
is equivalent to `tt(cat bar foo | sort)' (note the order of the inputs). is equivalent to `tt(cat bar foo | sort)' (note the order of the inputs).
@ -169,7 +169,7 @@ If the tt(MULTIOS) option is em(un)set,
each redirection replaces the previous redirection for that file descriptor. each redirection replaces the previous redirection for that file descriptor.
However, all files redirected to are actually opened, so However, all files redirected to are actually opened, so
nofill(tt(echo foo > bar > baz)) example(echo foo > bar > baz)
when tt(MULTIOS) is unset will truncate bar, and write `tt(foo)' into baz. 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. the command named in the shell variable tt(READNULLCMD) is assumed.
(If tt(READNULLCMD) is empty or not set, `tt(cat)' is used.) Thus (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. copies the contents of tt(file) to the standard output.

View file

@ -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 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 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 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 and so on, are present, and macros are particularly simple to write as they
are just ordinary shell functions. 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 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; 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 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 appear as one of the elements of the tt($fpath) array (this should already
should be autoloaded. Finally, to initialise the use of the system you be the case if they were installed), and at least the function tt(zfinit)
need to call the tt(zfinit) function. The following code in your should be autoloaded; it will autoload the rest. Finally, to initialise
tt(.zshrc) will arrange for this; assume the functions are stored in the the use of the system you need to call the tt(zfinit) function. The
directory tt(~/myfns): following code in your tt(.zshrc) will arrange for this; assume the
functions are stored in the directory tt(~/myfns):
tt(indent( example(fpath=(~/myfns $fpath)
nofill(fpath=(~/myfns $fpath)) autoload zfinit
nofill(autoload ~/myfns/zf*(:t)) zfinit)
nofill(zfinit)
))
Note that tt(zfinit) assumes you are using the tt(zmodload) method to 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 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) texinode(Zftp Functions)(Miscellaneous Features)(Installation)(Zftp Function System)
sect(Functions) 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). 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 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 ~)'. is omitted, has the effect of `tt(zfcd ~)'.
The second form changes to the directory previously current. The second form changes to the directory previously current.
@ -274,13 +275,48 @@ then tt(zfpcp) will retry using the second form.
) )
enditem() enditem()
subsect(Closing the connectino) subsect(Closing the connection)
startitem() startitem()
item(tt(zfclose))( item(tt(zfclose))(
Close the connection. Close the connection.
) )
enditem() 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) subsect(Other functions)
Mostly, these functions will not be called directly (apart from Mostly, these functions will not be called directly (apart from
tt(zfinit)), but are described here for completeness. You may wish to 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() startitem()
item(tt(zfinit [ -n ]))( 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 tt(-n) option should be used if the zftp command is already built into
the shell. the shell.
) )
@ -320,7 +356,7 @@ var(prefix) and var(suffix) set appropriately.
item(tt(zfrglob var(varname)))( item(tt(zfrglob var(varname)))(
Perform remote globbing, as describes in more detail below. 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 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. filenames on return.
) )
item(tt(zfrtime var(lfile) var(rfile) [ var(time) ]))( 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 hostnames and current directories. It works best when combined with the
function tt(chpwd). In particular, a function of the form function tt(chpwd). In particular, a function of the form
tt(indent( example(chpwd() {
nofill(chpwd() {) if [[ -n $ZFTP_USER ]]; then
nofill( if [[ -n $ZFTP_USER ]]; then) zftp_chpwd
nofill( zftp_chpwd) else
nofill( else) # usual chpwd e.g put host:directory in title bar
nofill( # usual chpwd e.g put host:directory in title bar) fi
nofill( fi) })
nofill(})
))
fits in well. 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 handling is problematic and it is recommended that globbing only be used
within the current directory. The list of files in the current directory, within the current directory. The list of files in the current directory,
if retrieved, will be cached, so that subsequent globs in the same 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 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 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) Information about the previous connection is given by the tt(zfstat)
function. So, for example, if that reports: function. So, for example, if that reports:
tt(indent( example(Not connected.
nofill(Not connected.) Last session: ftp.bar.com:/pub/textfiles)
nofill(Last session: ftp.bar.com:/pub/textfiles)
))
then the command tt(zfget file.txt) will attempt to reopen a connection to 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 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) subsect(Completion)
Completion of remote files and directories is supported. The older, Completion of remote files, directories and bookmarks is supported. The
tt(compctl)-style completion is defined when tt(zfinit) is called; support older, tt(compctl)-style completion is defined when tt(zfinit) is called;
for the new widget-based completion system is provided in the function support for the new widget-based completion system is provided in the
tt(Completion/Builtins/_zftp), which should be installed with the other function tt(Completion/Builtins/_zftp), which should be installed with the
functions of the completion system and hence should automatically be other functions of the completion system and hence should automatically be
available. available.

View file

@ -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) chapter(Zsh Line Editor)
cindex(line editor) cindex(line editor)
cindex(editor, line) 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 in keymaps are bound to are in fact widgets. Widgets can be user-defined
or built in. 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 Other built-in widgets can be defined by other modules (see
ifzman(zmanref(zshmodules))\ ifzman(zmanref(zshmodules))\
ifnzman(noderef(Zsh Modules))\ ifnzman(noderef(Zsh Modules))\
@ -157,7 +157,7 @@ vindex(keys)
item(tt(keys) (array))( item(tt(keys) (array))(
The keys typed to invoke this widget, one element per The keys typed to invoke this widget, one element per
key. Control-keys are reported with a leading `tt(^)', as in `tt(^A)', 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)'. `tt(M-^A)'.
) )
vindex(NUMERIC) vindex(NUMERIC)

View file

@ -162,6 +162,12 @@ def(itemiz)(1)(\
COMMENT(--- special effects ---) 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)(\ def(nofill)(1)(\
NOTRANS(.nf)NL()\ NOTRANS(.nf)NL()\
ARG1\ ARG1\
@ -169,9 +175,9 @@ def(nofill)(1)(\
) )
def(indent)(1)(\ def(indent)(1)(\
NOTRANS(.RS)\ NOTRANS(.RS)NL()NOTRANS(.nf)NL()\
ARG1\ ARG1\
NOTRANS(.RE)\ NL()NOTRANS(.fi)NL()NOTRANS(.RE)\
) )
COMMENT(--- hyperlink menus ---) COMMENT(--- hyperlink menus ---)

View file

@ -17,7 +17,7 @@ def(ifzshall)(1)()\
)\ )\
ifztexi(\ ifztexi(\
texinfo(zsh.info)(zsh) texinfo(zsh.info)(zsh)
NOTRANS(@setchapternewpage odd NOTRANS(@setchapternewpage off
@iftex @iftex
@finalout @finalout
@afourpaper @afourpaper

View file

@ -11,7 +11,7 @@ def(CMT)(0)(NOTRANS(@c))
ATEXIT(\ ATEXIT(\
NL()\ NL()\
NOTRANS(@setchapternewpage odd)NL()\ NOTRANS(@setchapternewpage off)NL()\
NOTRANS(@contents)NL()\ NOTRANS(@contents)NL()\
NOTRANS(@bye)NL()\ NOTRANS(@bye)NL()\
) )
@ -207,8 +207,16 @@ def(nofill)(1)(\
USECHARTABLE(standard)\ USECHARTABLE(standard)\
) )
def(indent)(1)(\ def(example)(1)(\
NOTRANS(@example)NL()\
ARG1\ ARG1\
NL()NOTRANS(@end example)\
)
def(indent)(1)(\
NOTRANS(@display)NL()\
ARG1\
NL()NOTRANS(@end display)\
) )
COMMENT(--- hyperlink menus ---) COMMENT(--- hyperlink menus ---)

View file

@ -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, This problem is not related to zsh. If you have such problems,
remove the bogus strip and use /bin/strip instead. remove the bogus strip and use /bin/strip instead.
On Digital UNIX 4.0, compilation with gcc and with --enable-dynamic
apparently needs configuring with explicit flags:
DLLD=gcc LDFLAGS='-g -rpath <path-to-.so-files>' ./configure ...
FreeBSD: FreeBSD 2.2.7 [3.1.4] FreeBSD: FreeBSD 2.2.7 [3.1.4]
Should build `out-of-the-box'. 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 to /usr/ucblib in your LD_LIBRARY_PATH. You can easily do this
by just unsetting LD_LIBRARY_PATH before building zsh. by just unsetting LD_LIBRARY_PATH before building zsh.
Under Solaris 2.7, dynamically loaded library support with Under Solaris 2.7, problems have been reported with dynamically
--enable-dynamic currently does not work. 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.

View file

@ -55,7 +55,14 @@ install.fns:
$(sdir_top)/mkinstalldirs $(fndir) || exit 1; \ $(sdir_top)/mkinstalldirs $(fndir) || exit 1; \
for file in $(FUNCTIONS_INSTALL); do \ for file in $(FUNCTIONS_INSTALL); do \
if test -f $$file; then \ 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; \ fi; \
done; \ done; \
fi; \ fi; \
@ -65,7 +72,12 @@ uninstall.fns:
if test x$(fndir) != x && test x$(fndir) != xno; then \ if test x$(fndir) != x && test x$(fndir) != xno; then \
for file in $(FUNCTIONS_INSTALL); do \ for file in $(FUNCTIONS_INSTALL); do \
if test -f $$file; then \ 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; \ fi; \
done; \ done; \
fi; \ fi; \

View file

@ -1,7 +1,7 @@
DISTFILES_SRC=' DISTFILES_SRC='
.distfiles .distfiles
zfanon zfautocheck zfcd zfcd_match zfcget zfclose zfcput zfdir 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 zfpcp zfput zfrglob zfrtime zfstat zftp_chpwd zftp_progress
zftype zfuget zfuput zftype zfuget zfuput
' '

0
Functions/Zftp/zfgoto Normal file
View file

View file

@ -1,3 +1,5 @@
emulate -L zsh
[[ $1 = -n ]] || zmodload -ia zftp [[ $1 = -n ]] || zmodload -ia zftp
alias zfcd='noglob zfcd' alias zfcd='noglob zfcd'
@ -6,6 +8,11 @@ alias zfls='noglob zfls'
alias zfdir='noglob zfdir' alias zfdir='noglob zfdir'
alias zfuget='noglob zfuget' 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 # only way of getting that noglob out of the way: this is unnecessary with
# widget-based completion and can be commented out. # widget-based completion and can be commented out.
setopt completealiases setopt completealiases
@ -14,7 +21,7 @@ setopt completealiases
# zftp completions: only use these if new-style completion is not # zftp completions: only use these if new-style completion is not
# active. # 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]' \ compctl -f -x 'p[1]' \
-k '(open params user login type ascii binary mode put putat -k '(open params user login type ascii binary mode put putat
get getat append appendat ls dir local remote mkdir rmdir delete 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 zfcd_match -S/ -q zfcd zfdir zfls
compctl -K zfget_match zfget zfgcp zfuget zfcget compctl -K zfget_match zfget zfgcp zfuget zfcget
compctl -k hosts zfanon zfopen zfparams 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 fi

0
Functions/Zftp/zfmark Normal file
View file

View file

@ -24,6 +24,7 @@ if [[ -z $ZFTP_USER ]]; then
else else
[[ -n $ZFTP_PWD ]] && zflastdir=$ZFTP_PWD [[ -n $ZFTP_PWD ]] && zflastdir=$ZFTP_PWD
zflastsession="$ZFTP_HOST:$ZFTP_PWD" zflastsession="$ZFTP_HOST:$ZFTP_PWD"
zflastuser="$ZFTP_USER"
local args local args
if [[ -t 1 && -t 2 ]]; then if [[ -t 1 && -t 2 ]]; then
local str=$zflastsession local str=$zflastsession

24
INSTALL
View file

@ -220,11 +220,12 @@ turn off both installation of functions and the setting of a default value
for $fpath/$FPATH. for $fpath/$FPATH.
You can control the functions which get installed by setting You can control the functions which get installed by setting
FUNCTIONS_INSTALL, either when running configure or when running `make FUNCTIONS_INSTALL, either when running configure (e.g.
install' or `make install.fns'. It includes a list of files relative to `FUNCTIONS_INSTALL="..." configure ...') or when running `make install' or
either the Completion or Functions subdirectories. By default, all the `make install.fns'. It includes a list of files relative to either the
functions for the Completion system will be installed (see the zshcompsys Completion or Functions subdirectories. By default, all the functions for
manual page), i.e. the Completion system will be installed (see the zshcompsys manual page),
i.e.
FUNCTIONS_INSTALL='Core/* Base/* Builtins/* User/* Commands/*' FUNCTIONS_INSTALL='Core/* Base/* Builtins/* User/* Commands/*'
and if the --enable-dynamic option was given, the functions in and if the --enable-dynamic option was given, the functions in
Functions/Zftp, which require the zftp module to be available (see the 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 of functions can be installed with
FUNCTIONS_INSTALL='Core/* Base/* Builtins/* User/* Commands/* Misc/* Zftp/*' 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 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 enabled. Hence you might consider using --enable-lfs on any 32-bit system
with a suitable compiler such as gcc. 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 None of this is relevant for 64-bit systems; zsh should compile and run
without problems if (sizeof(long) == 8). without problems if (sizeof(long) == 8).
@ -300,6 +311,7 @@ Features:
zlogin=pathname # the full pathname of the global zlogin script zlogin=pathname # the full pathname of the global zlogin script
zprofile=pathname # the full pathname of the global zprofile script zprofile=pathname # the full pathname of the global zprofile script
zlogout=pathname # the full pathname of the global zlogout 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 dynamic # allow dynamically loaded binary modules
lfs # allow configure check for large files lfs # allow configure check for large files

View file

@ -222,8 +222,21 @@ printulimit(int lim, int hard, int head)
/* display the limit */ /* display the limit */
if (limit == RLIM_INFINITY) if (limit == RLIM_INFINITY)
printf("unlimited\n"); printf("unlimited\n");
else else {
printf("%ld\n", (long)limit); # 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 * /* limit: set or show resource limits. The variable hard indicates *

View file

@ -205,8 +205,12 @@ clean: clean-modules
distclean: distclean-modules distclean: distclean-modules
realclean: realclean-modules realclean: realclean-modules
mostlyclean-modules clean-modules distclean-modules realclean-modules: Makemod # Don't remake Makemod just to delete things, even if it doesn't exist.
@$(MAKE) -f Makemod $(MAKEDEFS) `echo $@ | sed 's/-modules//'` 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@ @CLEAN_MK@

View file

@ -230,7 +230,7 @@ static char *lastmsg, lastcodestr[4];
static int lastcode; static int lastcode;
/* flag for remote system is UNIX --- useful to know as things are simpler */ /* 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 */ /* remote system has size, mdtm commands */
enum { enum {
@ -1786,7 +1786,6 @@ zftp_open(char *name, char **args, int flags)
return 1; return 1;
} }
zfis_unix = 0;
zfhas_size = zfhas_mdtm = ZFCP_UNKN; zfhas_size = zfhas_mdtm = ZFCP_UNKN;
zdfd = -1; zdfd = -1;
/* initial status: open, ASCII data, stream mode 'n' stuff */ /* 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 * Use binary for transfers. This simple test saves much
* hassle for all concerned, particularly me. * 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; 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); zfsetparam("ZFTP_SYSTEM", systype, ZFPM_READONLY);
} }
zfstatus |= ZFST_SYST; zfstatus |= ZFST_SYST;

View file

@ -788,9 +788,8 @@ static char *suffixfunc;
void void
makesuffix(int n) makesuffix(int n)
{ {
suffixlen[256] = suffixlen[' '] = suffixlen['\t'] = suffixlen['\n'] = suffixlen[256] = suffixlen[' '] = suffixlen['\t'] = suffixlen['\n'] =
suffixlen[';'] = suffixlen['|'] = suffixlen['&'] = suffixlen[';'] = suffixlen['&'] = suffixlen['|'] = n;
suffixlen['<'] = suffixlen['>'] = n;
} }
/* Set up suffix for parameter names: the last n characters are a suffix * /* Set up suffix for parameter names: the last n characters are a suffix *

View file

@ -681,12 +681,11 @@ cmphaswilds(char *str)
/* Check if we have to complete a parameter name. */ /* Check if we have to complete a parameter name. */
static char * static char *
check_param(char *s, int set, char **ep) check_param(char *s, int set, int test)
{ {
char *p; char *p;
int bq = 0, eq = 0, i;
if (!ep) if (!test)
ispar = parq = eparq = 0; ispar = parq = eparq = 0;
/* Try to find a `$'. */ /* Try to find a `$'. */
for (p = s + offs; p > s && *p != String && *p != Qstring; p--); 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; e = b;
if (br) { if (br) {
while (*e == (ep ? Dnull : '"')) while (*e == (test ? Dnull : '"'))
e++, parq++, bq++; e++, parq++;
if (!ep) if (!test)
b = e; b = e;
} }
/* Find the end of the name. */ /* 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 (offs <= e - s && offs >= b - s && n <= 0) {
if (br) { if (br) {
p = e; p = e;
while (*p == (ep ? Dnull : '"')) while (*p == (test ? Dnull : '"'))
p++, parq--, eparq++, eq++; p++, parq--, eparq++;
} }
/* It is. */ /* It is. */
if (ep) { if (test)
*ep = e;
return b; return b;
}
/* If we were called from makecomplistflags(), we have to set the /* If we were called from makecomplistflags(), we have to set the
* global variables. */ * global variables. */
@ -765,21 +762,12 @@ check_param(char *s, int set, char **ep)
mflags |= CMF_PARBR; mflags |= CMF_PARBR;
/* Get the prefix (anything up to the character before the name). */ /* Get the prefix (anything up to the character before the name). */
for (i = eq, p = e; i; i--, p++) isuf = dupstring(e);
*p = '.'; untokenize(isuf);
isuf = quotename(e, NULL);
for (i = eq, p = isuf; i; i--, p++)
*p = '"';
*e = '\0'; *e = '\0';
ripre = dupstring(s); ripre = dupstring(s);
ripre[b - s] = '\0'; ripre[b - s] = '\0';
for (i = bq, p = ripre + (b - s) - 1; i; i--, p--) ipre = dupstring(ripre);
*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 = '"';
untokenize(ipre); untokenize(ipre);
} }
else else
@ -1231,8 +1219,7 @@ get_comp_string(void)
clwpos = -1; clwpos = -1;
lexsave(); lexsave();
inpush(dupstrspace((char *) linptr), 0, NULL); inpush(dupstrspace((char *) linptr), 0, NULL);
strinbeg(); strinbeg(0);
stophist = 2;
i = tt0 = cp = rd = ins = oins = linarr = parct = ia = 0; i = tt0 = cp = rd = ins = oins = linarr = parct = ia = 0;
/* This loop is possibly the wrong way to do this. It goes through * /* 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. */ /* This variable will hold the current word in quoted form. */
qword = ztrdup(s); qword = ztrdup(s);
offs = cs - wb; offs = cs - wb;
if ((p = check_param(s, 0, &tt))) { if ((p = check_param(s, 0, 1))) {
for (; *p == Dnull; p++) for (p = s; *p; p++)
*p = '"'; if (*p == Dnull)
for (; *tt == Dnull; tt++) *p = '"';
*tt = '"'; else if (*p == Snull)
*p = '\'';
} }
if (*s == Snull || *s == Dnull) { if (*s == Snull || *s == Dnull) {
char *q = (*s == Snull ? "'" : "\""), *n = tricat(qipre, q, ""); 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); Aminfo ai = (alt ? fainfo : ainfo);
int palen, salen, qipl, ipl, pl, ppl, qisl, isl, psl; 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"); DPUTS(!line, "BUG: add_match_data() without cline");
@ -4369,10 +4357,10 @@ docompletion(char *s, int lst, int incmd)
invalidatelist(); invalidatelist();
/* Print the explanation strings if needed. */ /* Print the explanation strings if needed. */
if (!showinglist && validlist && nmatches != 1) { if (!showinglist && validlist && usemenu != 2 && nmatches != 1) {
Cmgroup g = amatches; Cmgroup g = amatches;
Cexpl *e; Cexpl *e;
int up = 0, tr = 1; int up = 0, tr = 1, nn = 0;
if (!nmatches) if (!nmatches)
feep(); feep();
@ -4385,7 +4373,12 @@ docompletion(char *s, int lst, int incmd)
trashzle(); trashzle();
tr = 0; tr = 0;
} }
if (nn) {
up++;
putc('\n', shout);
}
up += printfmt((*e)->str, (*e)->count, 1); up += printfmt((*e)->str, (*e)->count, 1);
nn = 1;
} }
e++; e++;
} }
@ -4915,6 +4908,9 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
int ois = instring, oib = inbackt; int ois = instring, oib = inbackt;
char *tmp, *p, *ns, *ol = (char *) line, sav, oaq = autoq, *qp, *qs; 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 * /* Put the string in the lexer buffer and call the lexer to *
* get the words we have to expand. */ * get the words we have to expand. */
zleparse = 1; zleparse = 1;
@ -4930,8 +4926,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
inpush(dupstrspace(tmp), 0, NULL); inpush(dupstrspace(tmp), 0, NULL);
line = (unsigned char *) tmp; line = (unsigned char *) tmp;
ll = tl - 1; ll = tl - 1;
strinbeg(); strinbeg(0);
stophist = 2;
noaliases = 1; noaliases = 1;
do { do {
ctxtlex(); ctxtlex();
@ -4979,11 +4974,21 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
ll = oll; ll = oll;
if (cur < 0 || i < 1) if (cur < 0 || i < 1)
return 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) { if (*ns == Snull || *ns == Dnull) {
instring = (*ns == Snull ? 1 : 2); instring = (*ns == Snull ? 1 : 2);
inbackt = 0; inbackt = 0;
swb++; swb++;
if (ns[strlen(ns) - 1] == *ns) if (ns[strlen(ns) - 1] == *ns && ns[1])
swe--; swe--;
autoq = (*ns == Snull ? '\'' : '"'); autoq = (*ns == Snull ? '\'' : '"');
} else { } 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; char **ow = clwords, *os = cmdstr, *oqp = qipre, *oqs = qisuf;
int olws = clwsize, olwn = clwnum, olwp = clwpos; int olws = clwsize, olwn = clwnum, olwp = clwpos;
int obr = brange, oer = erange, oof = offs; int obr = brange, oer = erange, oof = offs;
unsigned long occ = ccont;
clwsize = clwnum = countlinknodes(foo); clwsize = clwnum = countlinknodes(foo);
clwords = (char **) zalloc((clwnum + 1) * sizeof(char *)); clwords = (char **) zalloc((clwnum + 1) * sizeof(char *));
for (n = firstnode(foo), i = 0; n; incnode(n), i++) { 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; qipre = qp;
qisuf = qs; qisuf = qs;
offs = soffs; offs = soffs;
ccont = CC_CCCONT;
makecomplistcmd(ns, !clwpos, CFN_FIRST); makecomplistcmd(ns, !clwpos, CFN_FIRST);
ccont = occ;
offs = oof; offs = oof;
zsfree(cmdstr); zsfree(cmdstr);
cmdstr = os; cmdstr = os;
@ -6341,7 +6349,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
tmpbuf = (char *)zhalloc(strlen(cc->str) + 5); tmpbuf = (char *)zhalloc(strlen(cc->str) + 5);
sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */ sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */
inpush(tmpbuf, 0, NULL); inpush(tmpbuf, 0, NULL);
strinbeg(); strinbeg(0);
noaliases = 1; noaliases = 1;
do { do {
ctxtlex(); ctxtlex();
@ -6502,7 +6510,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
int oldn = clwnum, oldp = clwpos; int oldn = clwnum, oldp = clwpos;
unsigned long occ = ccont; unsigned long occ = ccont;
ccont = 0; ccont = CC_CCCONT;
/* So we restrict the words-array. */ /* So we restrict the words-array. */
if (brange >= clwnum) if (brange >= clwnum)
@ -8099,14 +8107,13 @@ doexpandhist(void)
lexsave(); lexsave();
/* We push ol as it will remain unchanged */ /* We push ol as it will remain unchanged */
inpush((char *) ol, 0, NULL); inpush((char *) ol, 0, NULL);
strinbeg(); strinbeg(1);
noaliases = 1; noaliases = 1;
noerrs = 1; noerrs = 1;
exlast = inbufct; exlast = inbufct;
do { do {
ctxtlex(); ctxtlex();
} while (tok != ENDINPUT && tok != LEXERR); } while (tok != ENDINPUT && tok != LEXERR);
stophist = 2;
while (!lexstop) while (!lexstop)
hgetc(); hgetc();
/* We have to save errflags because it's reset in lexrestore. Since * /* We have to save errflags because it's reset in lexrestore. Since *
@ -8178,7 +8185,7 @@ getcurcmd(void)
metafy_line(); metafy_line();
inpush(dupstrspace((char *) line), 0, NULL); inpush(dupstrspace((char *) line), 0, NULL);
unmetafy_line(); unmetafy_line();
strinbeg(); strinbeg(1);
pushheap(); pushheap();
do { do {
curlincmd = incmdpos; curlincmd = incmdpos;

View file

@ -43,7 +43,7 @@ static struct builtin builtins[] =
BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL), BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -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("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("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, 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), 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("false", 0, bin_false, 0, -1, 0, NULL, NULL),
BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", 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("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("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL), BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "dfmrv", NULL), BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "dfmrv", NULL),
@ -209,7 +209,7 @@ execbuiltin(LinkList args, Builtin bn)
LinkNode n; LinkNode n;
char ops[MAX_OPS], *arg, *pp, *name, **argv, **oargv, *optstr; char ops[MAX_OPS], *arg, *pp, *name, **argv, **oargv, *optstr;
char *oxarg, *xarg = NULL; 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 */ /* initialise some static variables */
auxdata = NULL; auxdata = NULL;
@ -250,12 +250,21 @@ execbuiltin(LinkList args, Builtin bn)
break; break;
} }
/* save the options in xarg, for execution tracing */ /* save the options in xarg, for execution tracing */
if (xarg) { if (xtr) {
oxarg = tricat(xarg, " ", arg); if (xarg) {
zsfree(xarg); int l = strlen(arg) + lxarg + 1;
xarg = oxarg;
} else oxarg = zhalloc(l + 1);
xarg = ztrdup(arg); 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['+']) */ /* handle -- or - (ops['-']), and + (ops['-'] and ops['+']) */
if (arg[1] == '-') if (arg[1] == '-')
arg++; arg++;
@ -283,7 +292,6 @@ execbuiltin(LinkList args, Builtin bn)
if(*arg == Meta) if(*arg == Meta)
*++arg ^= 32; *++arg ^= 32;
zerr("bad option: -%c", NULL, *arg); zerr("bad option: -%c", NULL, *arg);
zsfree(xarg);
return 1; return 1;
} }
arg = (char *) ugetnode(args); arg = (char *) ugetnode(args);
@ -330,7 +338,6 @@ execbuiltin(LinkList args, Builtin bn)
while ((*argv++ = (char *)ugetnode(args))); while ((*argv++ = (char *)ugetnode(args)));
argv = oargv; argv = oargv;
if (errflag) { if (errflag) {
zsfree(xarg);
errflag = 0; errflag = 0;
return 1; return 1;
} }
@ -339,12 +346,11 @@ execbuiltin(LinkList args, Builtin bn)
if (argc < bn->minargs || (argc > bn->maxargs && bn->maxargs != -1)) { if (argc < bn->minargs || (argc > bn->maxargs && bn->maxargs != -1)) {
zwarnnam(name, (argc < bn->minargs) zwarnnam(name, (argc < bn->minargs)
? "not enough arguments" : "too many arguments", NULL, 0); ? "not enough arguments" : "too many arguments", NULL, 0);
zsfree(xarg);
return 1; return 1;
} }
/* display execution trace information, if required */ /* display execution trace information, if required */
if (isset(XTRACE)) { if (xtr) {
fprintf(stderr, "%s%s", (prompt4) ? prompt4 : "", name); fprintf(stderr, "%s%s", (prompt4) ? prompt4 : "", name);
if (xarg) if (xarg)
fprintf(stderr, " %s", xarg); fprintf(stderr, " %s", xarg);
@ -353,7 +359,6 @@ execbuiltin(LinkList args, Builtin bn)
fputc('\n', stderr); fputc('\n', stderr);
fflush(stderr); fflush(stderr);
} }
zsfree(xarg);
/* call the handler function, and return its return value */ /* call the handler function, and return its return value */
return (*(bn->handlerfunc)) (name, argv, ops, bn->funcid); 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; int on = 0, off = 0;
/* Do we have any flags defined? */ /* Do we have any flags defined? */
if (ops['u'] || ops['t']) { if (ops['u'] == 1)
if (ops['u'] == 1) on |= PM_UNDEFINED;
on |= PM_UNDEFINED; else if (ops['u'] == 2)
else if (ops['u'] == 2) off |= PM_UNDEFINED;
off |= PM_UNDEFINED; if (ops['U'] == 1)
on |= PM_UNALIASED|PM_UNDEFINED;
if (ops['t'] == 1) else if (ops['U'] == 2)
on |= PM_TAGGED; off |= PM_UNALIASED;
else if (ops['t'] == 2) if (ops['t'] == 1)
off |= PM_TAGGED; on |= PM_TAGGED;
} else if (ops['t'] == 2)
off |= PM_TAGGED;
if (off & PM_UNDEFINED) { if (off & PM_UNDEFINED) {
zwarnnam(name, "invalid option(s)", NULL, 0); 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 * * are given, we will print only functions containing these *
* flags, else we'll print them all. */ * flags, else we'll print them all. */
if (!*argv) { if (!*argv) {
if (ops['U'] && !ops['u'])
on &= ~PM_UNDEFINED;
scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, 0); scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, 0);
return 0; return 0;
} }
@ -3078,8 +3086,7 @@ bin_eval(char *nam, char **argv, char *ops, int func)
List list; List list;
inpush(zjoin(argv, ' '), 0, NULL); inpush(zjoin(argv, ' '), 0, NULL);
strinbeg(); strinbeg(0);
stophist = 2;
list = parse_list(); list = parse_list();
strinend(); strinend();
inpop(); inpop();
@ -3584,7 +3591,7 @@ bin_trap(char *name, char **argv, char *ops, int func)
if (!sigfuncs[sig]) if (!sigfuncs[sig])
printf("trap -- '' %s\n", sigs[sig]); printf("trap -- '' %s\n", sigs[sig]);
else { else {
s = getpermtext((void *) dupstruct((void *) sigfuncs[sig])); s = getpermtext((void *) sigfuncs[sig]);
printf("trap -- "); printf("trap -- ");
quotedzputs(s, stdout); quotedzputs(s, stdout);
printf(" %s\n", sigs[sig]); printf(" %s\n", sigs[sig]);

View file

@ -42,6 +42,7 @@ int
evalcond(Cond c) evalcond(Cond c)
{ {
struct stat *st; struct stat *st;
char *left, *right = NULL;
switch (c->type) { switch (c->type) {
case COND_NOT: case COND_NOT:
@ -103,107 +104,109 @@ evalcond(Cond c)
return 0; return 0;
} }
} }
singsub((char **)&c->left); left = dupstring((char *) c->left);
untokenize(c->left); singsub(&left);
untokenize(left);
if (c->right) { if (c->right) {
singsub((char **)&c->right); right = dupstring((char *) c->right);
singsub(&right);
if (c->type != COND_STREQ && c->type != COND_STRNEQ) if (c->type != COND_STREQ && c->type != COND_STRNEQ)
untokenize(c->right); untokenize(right);
} }
if (tracingcond) { if (tracingcond) {
if (c->type < COND_MOD) { if (c->type < COND_MOD) {
char *rt = (char *)c->right; char *rt = (char *)right;
if (c->type == COND_STREQ || c->type == COND_STRNEQ) { if (c->type == COND_STREQ || c->type == COND_STRNEQ) {
rt = dupstring(rt); rt = dupstring(rt);
untokenize(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); rt);
} else } else
fprintf(stderr, " -%c %s", c->type, (char *)c->left); fprintf(stderr, " -%c %s", c->type, (char *)left);
} }
switch (c->type) { switch (c->type) {
case COND_STREQ: case COND_STREQ:
return matchpat(c->left, c->right); return matchpat(left, right);
case COND_STRNEQ: case COND_STRNEQ:
return !matchpat(c->left, c->right); return !matchpat(left, right);
case COND_STRLT: case COND_STRLT:
return strcmp(c->left, c->right) < 0; return strcmp(left, right) < 0;
case COND_STRGTR: case COND_STRGTR:
return strcmp(c->left, c->right) > 0; return strcmp(left, right) > 0;
case 'e': case 'e':
case 'a': case 'a':
return (doaccess(c->left, F_OK)); return (doaccess(left, F_OK));
case 'b': case 'b':
return (S_ISBLK(dostat(c->left))); return (S_ISBLK(dostat(left)));
case 'c': case 'c':
return (S_ISCHR(dostat(c->left))); return (S_ISCHR(dostat(left)));
case 'd': case 'd':
return (S_ISDIR(dostat(c->left))); return (S_ISDIR(dostat(left)));
case 'f': case 'f':
return (S_ISREG(dostat(c->left))); return (S_ISREG(dostat(left)));
case 'g': case 'g':
return (!!(dostat(c->left) & S_ISGID)); return (!!(dostat(left) & S_ISGID));
case 'k': case 'k':
return (!!(dostat(c->left) & S_ISVTX)); return (!!(dostat(left) & S_ISVTX));
case 'n': case 'n':
return (!!strlen(c->left)); return (!!strlen(left));
case 'o': case 'o':
return (optison(c->left)); return (optison(left));
case 'p': case 'p':
return (S_ISFIFO(dostat(c->left))); return (S_ISFIFO(dostat(left)));
case 'r': case 'r':
return (doaccess(c->left, R_OK)); return (doaccess(left, R_OK));
case 's': case 's':
return ((st = getstat(c->left)) && !!(st->st_size)); return ((st = getstat(left)) && !!(st->st_size));
case 'S': case 'S':
return (S_ISSOCK(dostat(c->left))); return (S_ISSOCK(dostat(left)));
case 'u': case 'u':
return (!!(dostat(c->left) & S_ISUID)); return (!!(dostat(left) & S_ISUID));
case 'w': case 'w':
return (doaccess(c->left, W_OK)); return (doaccess(left, W_OK));
case 'x': case 'x':
if (privasserted()) { if (privasserted()) {
mode_t mode = dostat(c->left); mode_t mode = dostat(left);
return (mode & S_IXUGO) || S_ISDIR(mode); return (mode & S_IXUGO) || S_ISDIR(mode);
} }
return doaccess(c->left, X_OK); return doaccess(left, X_OK);
case 'z': case 'z':
return (!strlen(c->left)); return (!strlen(left));
case 'h': case 'h':
case 'L': case 'L':
return (S_ISLNK(dolstat(c->left))); return (S_ISLNK(dolstat(left)));
case 'O': case 'O':
return ((st = getstat(c->left)) && st->st_uid == geteuid()); return ((st = getstat(left)) && st->st_uid == geteuid());
case 'G': case 'G':
return ((st = getstat(c->left)) && st->st_gid == getegid()); return ((st = getstat(left)) && st->st_gid == getegid());
case 'N': 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': case 't':
return isatty(matheval(c->left)); return isatty(matheval(left));
case COND_EQ: case COND_EQ:
return matheval(c->left) == matheval(c->right); return matheval(left) == matheval(right);
case COND_NE: case COND_NE:
return matheval(c->left) != matheval(c->right); return matheval(left) != matheval(right);
case COND_LT: case COND_LT:
return matheval(c->left) < matheval(c->right); return matheval(left) < matheval(right);
case COND_GT: case COND_GT:
return matheval(c->left) > matheval(c->right); return matheval(left) > matheval(right);
case COND_LE: case COND_LE:
return matheval(c->left) <= matheval(c->right); return matheval(left) <= matheval(right);
case COND_GE: case COND_GE:
return matheval(c->left) >= matheval(c->right); return matheval(left) >= matheval(right);
case COND_NT: case COND_NT:
case COND_OT: case COND_OT:
{ {
time_t a; time_t a;
if (!(st = getstat(c->left))) if (!(st = getstat(left)))
return 0; return 0;
a = st->st_mtime; a = st->st_mtime;
if (!(st = getstat(c->right))) if (!(st = getstat(right)))
return 0; return 0;
return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime; return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
} }
@ -212,11 +215,11 @@ evalcond(Cond c)
dev_t d; dev_t d;
ino_t i; ino_t i;
if (!(st = getstat(c->left))) if (!(st = getstat(left)))
return 0; return 0;
d = st->st_dev; d = st->st_dev;
i = st->st_ino; i = st->st_ino;
if (!(st = getstat(c->right))) if (!(st = getstat(right)))
return 0; return 0;
return d == st->st_dev && i == st->st_ino; return d == st->st_dev && i == st->st_ino;
} }

View file

@ -139,8 +139,7 @@ parse_string(char *s)
lexsave(); lexsave();
inpush(s, 0, NULL); inpush(s, 0, NULL);
strinbeg(); strinbeg(0);
stophist = 2;
l = parse_list(); l = parse_list();
strinend(); strinend();
inpop(); inpop();
@ -298,12 +297,12 @@ static char list_pipe_text[JOBTEXTSIZE];
/**/ /**/
static int static int
execcursh(Cmd cmd) execcursh(Cmd cmd, LinkList args, int flags)
{ {
if (!list_pipe) if (!list_pipe)
deletejob(jobtab + thisjob); deletejob(jobtab + thisjob);
execlist(cmd->u.list, 1, cmd->flags & CFLAG_EXEC); execlist(cmd->u.list, 1, flags & CFLAG_EXEC);
cmd->u.list = NULL;
return lastval; return lastval;
} }
@ -718,7 +717,6 @@ execlist(List list, int dont_change_job, int exiting)
/* Reset donetrap: this ensures that a trap is only * /* Reset donetrap: this ensures that a trap is only *
* called once for each sublist that fails. */ * called once for each sublist that fails. */
donetrap = 0; donetrap = 0;
simplifyright(list);
slist = list->left; slist = list->left;
/* Loop through code followed by &&, ||, or end of sublist. */ /* 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; lineno = pline->left->lineno;
if (pline_level == 1) if (pline_level == 1)
strcpy(list_pipe_text, getjobtext((void *) pline->left)); if (!sfcontext)
if (pline->type == END) { 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); execcmd(pline->left, input, output, how, last1 ? 1 : 2);
pline->left = NULL; else {
} else {
int old_list_pipe = list_pipe; int old_list_pipe = list_pipe;
mpipe(pipes); mpipe(pipes);
@ -1046,11 +1046,10 @@ execpline2(Pline pline, int how, int input, int output, int last1)
_exit(lastval); _exit(lastval);
} }
} else { } else {
/* otherwise just do the pipeline normally. */ /* otherwise just do the pipeline normally. */
subsh_close = pipes[0]; subsh_close = pipes[0];
execcmd(pline->left, input, pipes[1], how, 0); execcmd(pline->left, input, pipes[1], how, 0);
} }
pline->left = NULL;
zclose(pipes[1]); zclose(pipes[1]);
if (pline->right) { if (pline->right) {
/* if another execpline() is invoked because the command is * /* if another execpline() is invoked because the command is *
@ -1102,13 +1101,17 @@ makecline(LinkList list)
void void
untokenize(char *s) untokenize(char *s)
{ {
for (; *s; s++) if (*s) {
if (itok(*s)) { char *p = s, c;
if (*s == Nularg)
chuck(s--); while ((c = *s++))
else if (itok(c)) {
*s = ztokens[*s - Pound]; if (c != Nularg)
} *p++ = ztokens[c - Pound];
} else
*p++ = c;
*p = '\0';
}
} }
/* Open a file for writing redicection */ /* Open a file for writing redicection */
@ -1152,34 +1155,34 @@ clobber_open(struct redir *f)
static void static void
closemn(struct multio **mfds, int fd) closemn(struct multio **mfds, int fd)
{ {
struct multio *mn = mfds[fd]; if (fd >= 0 && mfds[fd] && mfds[fd]->ct >= 2) {
char buf[TCBUFSIZE]; struct multio *mn = mfds[fd];
int len, i; char buf[TCBUFSIZE];
int len, i;
if (fd < 0 || !mfds[fd] || mfds[fd]->ct < 2) if (zfork()) {
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)
for (i = 0; i < mn->ct; i++) for (i = 0; i < mn->ct; i++)
write(mn->fds[i], buf, len); zclose(mn->fds[i]);
} else { zclose(mn->pipe);
/* cat process */ mn->ct = 1;
for (i = 0; i < mn->ct; i++) mn->fds[0] = fd;
while ((len = read(mn->fds[i], buf, TCBUFSIZE)) > 0) return;
write(mn->pipe, buf, len); }
/* 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) */ /* close all the mnodes (failure) */
@ -1273,9 +1276,10 @@ static void
addvars(LinkList l, int export) addvars(LinkList l, int export)
{ {
Varasg v; Varasg v;
LinkNode n;
LinkList vl; LinkList vl;
int xtr; int xtr;
char **arr, **ptr; char **arr, **ptr, *name;
xtr = isset(XTRACE); xtr = isset(XTRACE);
if (xtr && nonempty(l)) { if (xtr && nonempty(l)) {
@ -1283,26 +1287,30 @@ addvars(LinkList l, int export)
doneps4 = 1; doneps4 = 1;
} }
while (nonempty(l)) { for (n = firstnode(l); n; incnode(n)) {
v = (Varasg) ugetnode(l); v = (Varasg) getdata(n);
singsub(&v->name); name = dupstring(v->name);
singsub(&name);
if (errflag) if (errflag)
return; return;
untokenize(v->name); untokenize(name);
if (xtr) if (xtr)
fprintf(stderr, "%s=", v->name); fprintf(stderr, "%s=", name);
if (v->type == PM_SCALAR) { if (v->type == PM_SCALAR) {
vl = newlinklist(); vl = newlinklist();
addlinknode(vl, v->str); addlinknode(vl, dupstring(v->str));
} else } else
vl = v->arr; vl = listdup(v->arr);
prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) : PF_ASSIGN); if (vl) {
if (errflag) prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) :
return; PF_ASSIGN);
if (isset(GLOBASSIGN) || v->type != PM_SCALAR) if (errflag)
globlist(vl); return;
if (errflag) if (isset(GLOBASSIGN) || v->type != PM_SCALAR)
return; globlist(vl);
if (errflag)
return;
}
if (v->type == PM_SCALAR && (empty(vl) || !nextnode(firstnode(vl)))) { if (v->type == PM_SCALAR && (empty(vl) || !nextnode(firstnode(vl)))) {
Param pm; Param pm;
char *val; char *val;
@ -1319,7 +1327,7 @@ addvars(LinkList l, int export)
if (export) { if (export) {
if (export < 0) { if (export < 0) {
/* We are going to fork so do not bother freeing this */ /* 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)) { if (isset(RESTRICTED) && (pm->flags & PM_RESTRICTED)) {
zerr("%s: restricted", pm->nam, 0); zerr("%s: restricted", pm->nam, 0);
zsfree(val); zsfree(val);
@ -1328,18 +1336,22 @@ addvars(LinkList l, int export)
} }
allexp = opts[ALLEXPORT]; allexp = opts[ALLEXPORT];
opts[ALLEXPORT] = 1; opts[ALLEXPORT] = 1;
pm = setsparam(v->name, val); pm = setsparam(name, val);
opts[ALLEXPORT] = allexp; opts[ALLEXPORT] = allexp;
} else } else
pm = setsparam(v->name, val); pm = setsparam(name, val);
if (errflag) if (errflag)
return; return;
continue; continue;
} }
ptr = arr = (char **) zalloc(sizeof(char **) * (countlinknodes(vl) + 1)); if (vl) {
ptr = arr = (char **) zalloc(sizeof(char **) *
(countlinknodes(vl) + 1));
while (nonempty(vl)) while (nonempty(vl))
*ptr++ = ztrdup((char *) ugetnode(vl)); *ptr++ = ztrdup((char *) ugetnode(vl));
} else
ptr = arr = (char **) zalloc(sizeof(char **));
*ptr = NULL; *ptr = NULL;
if (xtr) { if (xtr) {
@ -1348,7 +1360,7 @@ addvars(LinkList l, int export)
fprintf(stderr, "%s ", *ptr); fprintf(stderr, "%s ", *ptr);
fprintf(stderr, ") "); fprintf(stderr, ") ");
} }
setaparam(v->name, arr); setaparam(name, arr);
if (errflag) if (errflag)
return; return;
} }
@ -1364,15 +1376,19 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
struct multio *mfds[10]; struct multio *mfds[10];
char *text; char *text;
int save[10]; 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 nullexec = 0, assign = 0, forked = 0;
int is_shfunc = 0, is_builtin = 0, is_exec = 0; int is_shfunc = 0, is_builtin = 0, is_exec = 0;
/* Various flags to the command. */ /* Various flags to the command. */
int cflags = 0, checked = 0; int cflags = 0, checked = 0;
LinkList vars, redir;
doneps4 = 0; doneps4 = 0;
args = cmd->args; args = listdup(cmd->args);
type = cmd->type; type = cmd->type;
flags = cmd->flags;
redir = dupheaplist(cmd->redir);
vars = cmd->vars;
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
save[i] = -2; 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 * /* If the command begins with `%', then assume it is a *
* reference to a job in the job table. */ * reference to a job in the job table. */
if (type == SIMPLE && nonempty(args) && if (type == SIMPLE && args && nonempty(args) &&
*(char *)peekfirst(args) == '%') { *(char *)peekfirst(args) == '%') {
pushnode(args, dupstring((how & Z_DISOWN) pushnode(args, dupstring((how & Z_DISOWN)
? "disown" : (how & Z_ASYNC) ? "bg" : "fg")); ? "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 * * job currently in the job table. If it does, then we treat it *
* as a command to resume this job. */ * as a command to resume this job. */
if (isset(AUTORESUME) && type == SIMPLE && (how & Z_SYNC) && 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))) { !nextnode(firstnode(args))) {
if (unset(NOTIFY)) if (unset(NOTIFY))
scanjobs(); 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 * * only works in simple cases. has_token() is called to make sure *
* this really is a simple case. */ * this really is a simple case. */
if (type == SIMPLE) { if (type == SIMPLE) {
while (nonempty(args)) { while (args && nonempty(args)) {
char *cmdarg = (char *) peekfirst(args); char *cmdarg = (char *) peekfirst(args);
checked = !has_token(cmdarg); checked = !has_token(cmdarg);
if (!checked) if (!checked)
@ -1444,7 +1461,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
} }
/* Do prefork substitutions */ /* Do prefork substitutions */
prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0); if (args)
prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0);
if (type == SIMPLE) { if (type == SIMPLE) {
int unglobbed = 0; int unglobbed = 0;
@ -1453,7 +1471,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
char *cmdarg; char *cmdarg;
if (!(cflags & BINF_NOGLOB)) if (!(cflags & BINF_NOGLOB))
while (!checked && !errflag && nonempty(args) && while (!checked && !errflag && args && nonempty(args) &&
has_token((char *) peekfirst(args))) has_token((char *) peekfirst(args)))
glob(args, firstnode(args)); glob(args, firstnode(args));
else if (!unglobbed) { 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 * /* Current shell should not fork unless the *
* exec occurs at the end of a pipeline. */ * exec occurs at the end of a pipeline. */
if ((cflags & BINF_EXEC) && last1 == 2) if ((cflags & BINF_EXEC) && last1 == 2)
cmd->flags |= CFLAG_EXEC; flags |= CFLAG_EXEC;
/* Empty command */ /* Empty command */
if (empty(args)) { if (!args || empty(args)) {
if (nonempty(cmd->redir)) { if (redir && nonempty(redir)) {
if (cmd->flags & CFLAG_EXEC) { if (flags & CFLAG_EXEC) {
/* Was this "exec < foobar"? */ /* Was this "exec < foobar"? */
nullexec = 1; nullexec = 1;
break; break;
@ -1480,17 +1498,23 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
errflag = lastval = 1; errflag = lastval = 1;
return; return;
} else if (readnullcmd && *readnullcmd && } else if (readnullcmd && *readnullcmd &&
((Redir) peekfirst(cmd->redir))->type == READ && ((Redir) peekfirst(redir))->type == READ &&
!nextnode(firstnode(cmd->redir))) { !nextnode(firstnode(redir))) {
if (!args)
args = newlinklist();
addlinknode(args, dupstring(readnullcmd)); addlinknode(args, dupstring(readnullcmd));
} else } else {
if (!args)
args = newlinklist();
addlinknode(args, dupstring(nullcmd)); addlinknode(args, dupstring(nullcmd));
}
} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) { } else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
lastval = 0; lastval = 0;
return; return;
} else { } else {
cmdoutval = 0; cmdoutval = 0;
addvars(cmd->vars, 0); if (vars)
addvars(vars, 0);
if (errflag) if (errflag)
lastval = errflag; lastval = errflag;
else else
@ -1502,7 +1526,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
return; return;
} }
} else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) &&
(cmd->flags & CFLAG_EXEC)) { (flags & CFLAG_EXEC)) {
zerrnam("exec", "%s: restricted", (char *) getdata(firstnode(args)), 0); zerrnam("exec", "%s: restricted", (char *) getdata(firstnode(args)), 0);
lastval = 1; lastval = 1;
return; return;
@ -1548,22 +1572,32 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
} }
/* Get the text associated with this command. */ /* Get the text associated with this command. */
if (jobbing || (how & Z_TIMED)) if (!sfcontext && (jobbing || (how & Z_TIMED)))
text = getjobtext((void *) cmd); text = getjobtext((void *) cmd);
else else
text = NULL; text = NULL;
/* Set up special parameter $_ */ /* Set up special parameter $_ */
zsfree(underscore); if (args && nonempty(args)) {
if (nonempty(args) char *u = (char *) getdata(lastnode(args));
&& (underscore = ztrdup((char *) getdata(lastnode(args)))))
untokenize(underscore); if (u) {
else int ul = strlen(u);
underscore = ztrdup("");
if (ul >= underscorelen) {
zfree(underscore, underscorelen);
underscore = (char *) zalloc(underscorelen = ul + 32);
}
strcpy(underscore, u);
} else
*underscore = '\0';
} else
*underscore = '\0';
/* Warn about "rm *" */ /* Warn about "rm *" */
if (type == SIMPLE && interact && unset(RMSTARSILENT) 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")) { && !strcmp(peekfirst(args), "rm")) {
LinkNode node, next; LinkNode node, next;
@ -1596,11 +1630,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
if (type == SIMPLE && !nullexec) { if (type == SIMPLE && !nullexec) {
char *s; char *s;
char trycd = (isset(AUTOCD) && isset(SHINSTDIN) char trycd = (isset(AUTOCD) && isset(SHINSTDIN)
&& empty(cmd->redir) && !empty(args) && (!redir || empty(redir)) && args && !empty(args)
&& !nextnode(firstnode(args)) && !nextnode(firstnode(args))
&& *(char *)peekfirst(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) { if (!hn) {
/* Resolve external commands */ /* Resolve external commands */
char *cmdarg = (char *) peekfirst(args); char *cmdarg = (char *) peekfirst(args);
@ -1652,7 +1686,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
* current shell. * * current shell. *
**************************************************************************/ **************************************************************************/
if ((how & Z_ASYNC) || (!(cmd->flags & CFLAG_EXEC) && if ((how & Z_ASYNC) || (!(flags & CFLAG_EXEC) &&
(((is_builtin || is_shfunc) && output) || (((is_builtin || is_shfunc) && output) ||
(!is_cursh && (last1 != 1 || sigtrapped[SIGZERR] || (!is_cursh && (last1 != 1 || sigtrapped[SIGZERR] ||
sigtrapped[SIGEXIT] || havefiles()))))) { sigtrapped[SIGEXIT] || havefiles()))))) {
@ -1677,10 +1711,13 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
#endif #endif
if (how & Z_ASYNC) { if (how & Z_ASYNC) {
lastpid = (zlong) pid; 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=... */ /* search for STTY=... */
while (nonempty(cmd->vars)) LinkNode n;
if (!strcmp(((Varasg) ugetnode(cmd->vars))->name, "STTY")) {
for (n = firstnode(vars); n; incnode(n))
if (!strcmp(((Varasg) getdata(n))->name, "STTY")) {
jobtab[thisjob].stty_in_env = 1; jobtab[thisjob].stty_in_env = 1;
break; break;
} }
@ -1713,7 +1750,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
is_exec = 1; is_exec = 1;
} }
if (!(cflags & BINF_NOGLOB)) if (args && !(cflags & BINF_NOGLOB))
globlist(args); globlist(args);
if (errflag) { if (errflag) {
lastval = 1; lastval = 1;
@ -1727,11 +1764,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
addfd(forked, save, mfds, 1, output, 1); addfd(forked, save, mfds, 1, output, 1);
/* Do process substitutions */ /* Do process substitutions */
spawnpipes(cmd->redir); if (redir)
spawnpipes(redir);
/* Do io redirections */ /* Do io redirections */
while (nonempty(cmd->redir)) { while (redir && nonempty(redir)) {
fn = (Redir) ugetnode(cmd->redir); fn = (Redir) ugetnode(redir);
DPUTS(fn->type == HEREDOC || fn->type == HEREDOCDASH, DPUTS(fn->type == HEREDOC || fn->type == HEREDOCDASH,
"BUG: unexpanded here document"); "BUG: unexpanded here document");
if (fn->type == INPIPE) { 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); addfd(forked, save, mfds, fn->fd1, fn->fd2, 1);
} else { } else {
if (fn->type != HERESTR && xpandredir(fn, cmd->redir)) if (fn->type != HERESTR && xpandredir(fn, redir))
continue; continue;
if (errflag) { if (errflag) {
closemnodes(mfds); closemnodes(mfds);
@ -1870,15 +1908,15 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
if (is_exec) if (is_exec)
entersubsh(how, type != SUBSH ? 2 : 1, 1); entersubsh(how, type != SUBSH ? 2 : 1, 1);
if (type >= CURSH) { if (type >= CURSH) {
static int (*func[]) _((Cmd)) = { static int (*func[]) _((Cmd, LinkList, int)) = {
execcursh, exectime, execfuncdef, execfor, execwhile, execcursh, exectime, execfuncdef, execfor, execwhile,
execrepeat, execif, execcase, execselect, execcond, execrepeat, execif, execcase, execselect, execcond,
execarith, execautofn execarith, execautofn
}; };
if (last1 == 1) if (last1 == 1)
cmd->flags |= CFLAG_EXEC; flags |= CFLAG_EXEC;
lastval = (func[type - CURSH]) (cmd); lastval = (func[type - CURSH]) (cmd, args, flags);
} else if (is_builtin || is_shfunc) { } else if (is_builtin || is_shfunc) {
LinkList restorelist = 0, removelist = 0; LinkList restorelist = 0, removelist = 0;
/* builtin or shell function */ /* builtin or shell function */
@ -1889,11 +1927,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
!(hn->flags & BINF_PSPECIAL)))) !(hn->flags & BINF_PSPECIAL))))
save_params(cmd, &restorelist, &removelist); save_params(cmd, &restorelist, &removelist);
if (cmd->vars) { if (vars) {
/* Export this if the command is a shell function, /* Export this if the command is a shell function,
* but not if it's a builtin. * but not if it's a builtin.
*/ */
addvars(cmd->vars, is_shfunc); addvars(vars, is_shfunc);
if (errflag) { if (errflag) {
restore_params(restorelist, removelist); restore_params(restorelist, removelist);
lastval = 1; lastval = 1;
@ -1904,6 +1942,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
if (is_shfunc) { if (is_shfunc) {
/* It's a shell function */ /* It's a shell function */
#ifdef PATH_DEV_FD #ifdef PATH_DEV_FD
int i; int i;
@ -1914,7 +1953,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
if (subsh_close >= 0) if (subsh_close >= 0)
zclose(subsh_close); zclose(subsh_close);
subsh_close = -1; subsh_close = -1;
execshfunc(cmd, (Shfunc) hn); execshfunc(cmd, (Shfunc) hn, args);
#ifdef PATH_DEV_FD #ifdef PATH_DEV_FD
for (i = 10; i <= max_zsh_fd; i++) for (i = 10; i <= max_zsh_fd; i++)
if (fdtable[i] > 1) if (fdtable[i] > 1)
@ -1943,7 +1982,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
clearerr(stdout); clearerr(stdout);
} }
if (cmd->flags & CFLAG_EXEC) { if (flags & CFLAG_EXEC) {
if (subsh) if (subsh)
_exit(lastval); _exit(lastval);
@ -1957,7 +1996,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
restore_params(restorelist, removelist); restore_params(restorelist, removelist);
} else { } else {
if (cmd->flags & CFLAG_EXEC) { if (flags & CFLAG_EXEC) {
setiparam("SHLVL", --shlvl); setiparam("SHLVL", --shlvl);
/* If we are exec'ing a command, and we are not * /* If we are exec'ing a command, and we are not *
* in a subshell, then save the history file. */ * 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); savehistfile(NULL, 1, HFILE_USE_OPTIONS);
} }
if (type == SIMPLE) { if (type == SIMPLE) {
if (cmd->vars) { if (vars) {
addvars(cmd->vars, -1); addvars(vars, -1);
if (errflag) if (errflag)
_exit(1); _exit(1);
} }
@ -1981,7 +2020,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
#endif #endif
execute((Cmdnam) hn, cflags & BINF_DASH); execute((Cmdnam) hn, cflags & BINF_DASH);
} else { /* ( ... ) */ } else { /* ( ... ) */
DPUTS(cmd->vars && nonempty(cmd->vars), DPUTS(vars && nonempty(vars),
"BUG: assigment before complex command"); "BUG: assigment before complex command");
list_pipe = 0; list_pipe = 0;
if (subsh_close >= 0) if (subsh_close >= 0)
@ -2011,7 +2050,11 @@ save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p)
char *s; char *s;
MUSTUSEHEAP("save_params()"); MUSTUSEHEAP("save_params()");
if (!cmd->vars) {
*restore_p = *remove_p = NULL;
return;
}
*restore_p = newlinklist(); *restore_p = newlinklist();
*remove_p = newlinklist(); *remove_p = newlinklist();
@ -2283,8 +2326,9 @@ getoutput(char *cmd, int qt)
return NULL; return NULL;
if (list != &dummy_list && !list->right && !list->left->flags && if (list != &dummy_list && !list->right && !list->left->flags &&
list->left->type == END && list->left->left->type == END && list->left->type == END && list->left->left->type == END &&
(c = list->left->left->left)->type == SIMPLE && empty(c->args) && (c = list->left->left->left)->type == SIMPLE &&
empty(c->vars) && nonempty(c->redir) && (!c->args || empty(c->args)) &&
(!c->vars || empty(c->vars)) && c->redir && nonempty(c->redir) &&
!nextnode(firstnode(c->redir)) && !nextnode(firstnode(c->redir)) &&
(r = (Redir) getdata(firstnode(c->redir)))->fd1 == 0 && (r = (Redir) getdata(firstnode(c->redir)))->fd1 == 0 &&
r->type == READ) { r->type == READ) {
@ -2613,7 +2657,7 @@ extern int tracingcond;
/**/ /**/
static int static int
execcond(Cmd cmd) execcond(Cmd cmd, LinkList args, int flags)
{ {
int stat; int stat;
if (isset(XTRACE)) { if (isset(XTRACE)) {
@ -2633,18 +2677,19 @@ execcond(Cmd cmd)
/**/ /**/
static int static int
execarith(Cmd cmd) execarith(Cmd cmd, LinkList args, int flags)
{ {
char *e; char *e;
zlong val = 0; zlong val = 0;
if (isset(XTRACE)) if (isset(XTRACE))
fprintf(stderr, "%s((", prompt4 ? prompt4 : ""); fprintf(stderr, "%s((", prompt4 ? prompt4 : "");
while ((e = (char *) ugetnode(cmd->args))) { if (args)
if (isset(XTRACE)) while ((e = (char *) ugetnode(args))) {
fprintf(stderr, " %s", e); if (isset(XTRACE))
val = matheval(e); fprintf(stderr, " %s", e);
} val = matheval(e);
}
if (isset(XTRACE)) { if (isset(XTRACE)) {
fprintf(stderr, " ))\n"); fprintf(stderr, " ))\n");
fflush(stderr); fflush(stderr);
@ -2657,7 +2702,7 @@ execarith(Cmd cmd)
/**/ /**/
static int static int
exectime(Cmd cmd) exectime(Cmd cmd, LinkList args, int flags)
{ {
int jb; int jb;
@ -2675,30 +2720,33 @@ exectime(Cmd cmd)
/**/ /**/
static int static int
execfuncdef(Cmd cmd) execfuncdef(Cmd cmd, LinkList args, int flags)
{ {
Shfunc shf; Shfunc shf;
char *s; char *s;
int signum; int signum;
PERMALLOC { if (args) {
while ((s = (char *) ugetnode(cmd->args))) { PERMALLOC {
shf = (Shfunc) zalloc(sizeof *shf); while ((s = (char *) ugetnode(args))) {
shf->funcdef = (List) dupstruct(cmd->u.list); shf = (Shfunc) zalloc(sizeof *shf);
shf->flags = 0; shf->funcdef = (List) dupstruct(cmd->u.list);
shf->flags = 0;
/* is this shell function a signal trap? */ /* is this shell function a signal trap? */
if (!strncmp(s, "TRAP", 4) && (signum = getsignum(s + 4)) != -1) { if (!strncmp(s, "TRAP", 4) &&
if (settrap(signum, shf->funcdef)) { (signum = getsignum(s + 4)) != -1) {
freestruct(shf->funcdef); if (settrap(signum, shf->funcdef)) {
zfree(shf, sizeof *shf); freestruct(shf->funcdef);
LASTALLOC_RETURN 1; zfree(shf, sizeof *shf);
} LASTALLOC_RETURN 1;
sigtrapped[signum] |= ZSIG_FUNC; }
} sigtrapped[signum] |= ZSIG_FUNC;
shfunctab->addnode(shfunctab, ztrdup(s), shf); }
} shfunctab->addnode(shfunctab, ztrdup(s), shf);
} LASTALLOC; }
} LASTALLOC;
}
if(isset(HISTNOFUNCTIONS)) if(isset(HISTNOFUNCTIONS))
remhist(); remhist();
return 0; return 0;
@ -2708,7 +2756,7 @@ execfuncdef(Cmd cmd)
/**/ /**/
static void static void
execshfunc(Cmd cmd, Shfunc shf) execshfunc(Cmd cmd, Shfunc shf, LinkList args)
{ {
LinkList last_file_list = NULL; LinkList last_file_list = NULL;
@ -2726,16 +2774,17 @@ execshfunc(Cmd cmd, Shfunc shf)
if (isset(XTRACE)) { if (isset(XTRACE)) {
LinkNode lptr; LinkNode lptr;
fprintf(stderr, "%s", prompt4 ? prompt4 : prompt4); fprintf(stderr, "%s", prompt4 ? prompt4 : prompt4);
for (lptr = firstnode(cmd->args); lptr; incnode(lptr)) { if (args)
if (lptr != firstnode(cmd->args)) for (lptr = firstnode(args); lptr; incnode(lptr)) {
fputc(' ', stderr); if (lptr != firstnode(args))
fprintf(stderr, "%s", (char *)getdata(lptr)); fputc(' ', stderr);
} fprintf(stderr, "%s", (char *)getdata(lptr));
}
fputc('\n', stderr); fputc('\n', stderr);
fflush(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) if (!list_pipe)
deletefilelist(last_file_list); deletefilelist(last_file_list);
@ -2749,10 +2798,16 @@ execshfunc(Cmd cmd, Shfunc shf)
/**/ /**/
static int static int
execautofn(Cmd cmd) execautofn(Cmd cmd, LinkList args, int flags)
{ {
Shfunc shf = cmd->u.autofn->shf; 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) { if(l == &dummy_list) {
zerr("%s: function definition file not found", shf->nam, 0); zerr("%s: function definition file not found", shf->nam, 0);
return 1; return 1;
@ -2773,9 +2828,7 @@ execautofn(Cmd cmd)
} LASTALLOC; } LASTALLOC;
shf->flags &= ~PM_UNDEFINED; shf->flags &= ~PM_UNDEFINED;
} }
HEAPALLOC { execlist(shf->funcdef, 1, 0);
execlist(dupstruct(shf->funcdef), 1, 0);
} LASTALLOC;
return lastval; return lastval;
} }
@ -2822,7 +2875,8 @@ doshfunc(char *name, List list, LinkList doshargs, int flags, int noreturnval)
LinkNode node; LinkNode node;
node = doshargs->first; node = doshargs->first;
pparams = x = (char **) zcalloc(((sizeof *x) * (1 + countlinknodes(doshargs)))); pparams = x = (char **) zcalloc(((sizeof *x) *
(1 + countlinknodes(doshargs))));
if (isset(FUNCTIONARGZERO)) { if (isset(FUNCTIONARGZERO)) {
oargv0 = argzero; oargv0 = argzero;
argzero = ztrdup((char *) node->dat); argzero = ztrdup((char *) node->dat);
@ -2901,7 +2955,7 @@ void
runshfunc(List list, FuncWrap wrap, char *name) runshfunc(List list, FuncWrap wrap, char *name)
{ {
int cont; int cont;
char *ou; VARARR(char, ou, underscorelen);
while (wrap) { while (wrap) {
wrap->module->wrapper++; wrap->module->wrapper++;
@ -2917,11 +2971,9 @@ runshfunc(List list, FuncWrap wrap, char *name)
wrap = wrap->next; wrap = wrap->next;
} }
startparamscope(); startparamscope();
ou = underscore; strcpy(ou, underscore);
underscore = ztrdup(underscore); execlist(list, 1, 0);
execlist(dupstruct(list), 1, 0); strcpy(underscore, ou);
zsfree(underscore);
underscore = ou;
endparamscope(); endparamscope();
} }
@ -2949,20 +3001,18 @@ getfpfunc(char *s)
unmetafy(buf, NULL); unmetafy(buf, NULL);
if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) { if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) {
if ((len = lseek(fd, 0, 2)) != -1) { if ((len = lseek(fd, 0, 2)) != -1) {
d = (char *) zalloc(len + 1);
lseek(fd, 0, 0); lseek(fd, 0, 0);
d = (char *) zcalloc(len + 1);
if (read(fd, d, len) == len) { if (read(fd, d, len) == len) {
close(fd); close(fd);
d[len] = '\0';
d = metafy(d, len, META_REALLOC); d = metafy(d, len, META_REALLOC);
HEAPALLOC { HEAPALLOC {
r = parse_string(d); r = parse_string(d);
} LASTALLOC; } LASTALLOC;
zfree(d, len + 1);
return r; return r;
} else { } else
zfree(d, len + 1);
close(fd); close(fd);
}
} else { } else {
close(fd); close(fd);
} }
@ -2995,9 +3045,10 @@ stripkshdef(List l, char *name)
if(p->right) if(p->right)
return l; return l;
c = p->left; c = p->left;
if(c->type != FUNCDEF || c->flags || if (c->type != FUNCDEF || c->flags ||
nonempty(c->redir) || nonempty(c->vars) || (c->redir && nonempty(c->redir)) || (c->vars && nonempty(c->vars)) ||
empty(c->args) || lastnode(c->args) != firstnode(c->args) || !c->args || empty(c->args) ||
lastnode(c->args) != firstnode(c->args) ||
strcmp(name, peekfirst(c->args))) strcmp(name, peekfirst(c->args)))
return l; return l;
return c->u.list; return c->u.list;
@ -3076,8 +3127,7 @@ execsave(void)
es->trapreturn = trapreturn; es->trapreturn = trapreturn;
es->noerrs = noerrs; es->noerrs = noerrs;
es->subsh_close = subsh_close; es->subsh_close = subsh_close;
es->underscore = underscore; es->underscore = ztrdup(underscore);
underscore = ztrdup(underscore);
es->next = exstack; es->next = exstack;
exstack = es; exstack = es;
noerrs = cmdoutpid = 0; noerrs = cmdoutpid = 0;
@ -3105,8 +3155,8 @@ execrestore(void)
trapreturn = exstack->trapreturn; trapreturn = exstack->trapreturn;
noerrs = exstack->noerrs; noerrs = exstack->noerrs;
subsh_close = exstack->subsh_close; subsh_close = exstack->subsh_close;
zsfree(underscore); strcpy(underscore, exstack->underscore);
underscore = exstack->underscore; zsfree(exstack->underscore);
en = exstack->next; en = exstack->next;
free(exstack); free(exstack);
exstack = en; exstack = en;

View file

@ -744,7 +744,7 @@ parsecomp(int gflag)
pptr++; pptr++;
} }
if (*pptr == Inpar && pptr[1] == Pound) { if (*pptr == Inpar && pptr[1] == Pound && isset(EXTENDEDGLOB)) {
/* Found some globbing flags */ /* Found some globbing flags */
char *eptr = pptr; char *eptr = pptr;
if (kshfunc != KF_NONE) if (kshfunc != KF_NONE)
@ -3432,17 +3432,17 @@ tokenize(char *s)
void void
remnulargs(char *s) remnulargs(char *s)
{ {
int nl = *s; if (*s) {
char *t = s; char *t = s, *p = s, c;
while (*s) while ((c = *s++))
if (INULL(*s)) if (!INULL(c))
chuck(s); *p++ = c;
else *p = '\0';
s++; if (!*t) {
if (!*t && nl) { t[0] = Nularg;
t[0] = Nularg; t[1] = '\0';
t[1] = '\0'; }
} }
} }

View file

@ -880,7 +880,7 @@ printshfuncnode(HashNode hn, int printflags)
return; return;
} }
t = getpermtext((void *) dupstruct((void *) f->funcdef)); t = getpermtext((void *) f->funcdef);
quotedzputs(f->nam, stdout); quotedzputs(f->nam, stdout);
printf(" () {\n\t"); printf(" () {\n\t");
zputs(t, stdout); zputs(t, stdout);
@ -1327,7 +1327,7 @@ addhistnode(HashTable ht, char *nam, void *nodeptr)
{ {
HashNode oldnode = addhashnode2(ht, nam, nodeptr); HashNode oldnode = addhashnode2(ht, nam, nodeptr);
Histent he = (Histent)nodeptr; Histent he = (Histent)nodeptr;
if (oldnode && oldnode != nodeptr) { if (oldnode && oldnode != (HashNode)nodeptr) {
if (he->flags & HIST_MAKEUNIQUE if (he->flags & HIST_MAKEUNIQUE
|| (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) { || (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
he->flags |= HIST_DUP; he->flags |= HIST_DUP;

View file

@ -30,6 +30,27 @@
#include "zsh.mdh" #include "zsh.mdh"
#include "hist.pro" #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 */ /* != 0 means history substitution is turned off */
/**/ /**/
@ -159,12 +180,11 @@ int hlinesz;
/* default event (usually curhist-1, that is, "!!") */ /* default event (usually curhist-1, that is, "!!") */
static int defev; static int defev;
/* add a character to the current history word */ /* add a character to the current history word */
/**/ static void
void ihwaddc(int c)
hwaddc(int c)
{ {
/* Only if history line exists and lexing has not finished. */ /* Only if history line exists and lexing has not finished. */
if (chline && !(errflag || lexstop)) { if (chline && !(errflag || lexstop)) {
@ -182,7 +202,7 @@ hwaddc(int c)
if (hptr - chline >= hlinesz) { if (hptr - chline >= hlinesz) {
int oldsiz = hlinesz; int oldsiz = hlinesz;
chline = realloc(chline, hlinesz = oldsiz + 16); chline = realloc(chline, hlinesz = oldsiz + 64);
hptr = chline + oldsiz; hptr = chline + oldsiz;
} }
} }
@ -192,12 +212,12 @@ hwaddc(int c)
* zsh expands history (see doexpandhist() in zle_tricky.c). It also * * zsh expands history (see doexpandhist() in zle_tricky.c). It also *
* calculates the new cursor position after the expansion. It is called * * calculates the new cursor position after the expansion. It is called *
* from hgetc() and from gettok() in lex.c for characters in comments. */ * from hgetc() and from gettok() in lex.c for characters in comments. */
/**/ /**/
void void
addtoline(int c) iaddtoline(int c)
{ {
if (! expanding || lexstop) if (!expanding || lexstop)
return; return;
if (qbang && c == bangchar && stophist < 2) { if (qbang && c == bangchar && stophist < 2) {
exlast--; exlast--;
@ -216,9 +236,8 @@ addtoline(int c)
line[cs++] = itok(c) ? ztokens[c - Pound] : c; line[cs++] = itok(c) ? ztokens[c - Pound] : c;
} }
/**/ static int
int ihgetc(void)
hgetc(void)
{ {
int c = ingetc(); int c = ingetc();
@ -234,7 +253,7 @@ hgetc(void)
} }
if ((inbufflags & INP_HIST) && !stophist) { if ((inbufflags & INP_HIST) && !stophist) {
/* the current character c came from a history expansion * /* 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, \! * * (e.g. we are not inside single quotes). In that case, \! *
* should be treated as ! (since this \! came from a previous * * should be treated as ! (since this \! came from a previous *
* history line where \ was used to escape the bang). So if * * 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 * /* unget a char and remove it from chline. It can only be used *
* to unget a character returned by hgetc. */ * to unget a character returned by hgetc. */
/**/ static void
void ihungetc(int c)
hungetc(int c)
{ {
int doit = 1; int doit = 1;
@ -641,10 +659,10 @@ hungetc(int c)
/**/ /**/
void void
strinbeg(void) strinbeg(int dohist)
{ {
strin++; strin++;
hbegin(); hbegin(dohist);
lexinit(); lexinit();
} }
@ -661,17 +679,49 @@ strinend(void)
histdone = 0; 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 */ /* initialize the history mechanism */
/**/ /**/
void void
hbegin(void) hbegin(int dohist)
{ {
isfirstln = isfirstch = 1; isfirstln = isfirstch = 1;
errflag = histdone = spaceflag = 0; errflag = histdone = spaceflag = 0;
stophist = (!interact || unset(BANGHIST) || unset(SHINSTDIN)) << 1; stophist = (dohist ? ((!interact || unset(SHINSTDIN)) << 1) : 2);
chline = hptr = zcalloc(hlinesz = 16); if (stophist == 2 || (inbufflags & INP_ALIAS)) {
chwords = zalloc((chwordlen = 16)*sizeof(short)); 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; chwordpos = 0;
if (histactive & HA_JUNKED) if (histactive & HA_JUNKED)
@ -864,7 +914,8 @@ hend(void)
int flag, save = 1; int flag, save = 1;
char *hf = getsparam("HISTFILE"); 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) if (histdone & HISTFLAG_SETTY)
settyinfo(&shttyinfo); settyinfo(&shttyinfo);
if (!(histactive & HA_NOINC)) { if (!(histactive & HA_NOINC)) {
@ -1005,8 +1056,10 @@ int hwgetword = -1;
/**/ /**/
void void
hwbegin(int offset) ihwbegin(int offset)
{ {
if (stophist == 2 || strin)
return;
if (chwordpos%2) if (chwordpos%2)
chwordpos--; /* make sure we're on a word start, not end */ chwordpos--; /* make sure we're on a word start, not end */
/* If we're expanding an alias, we should overwrite the expansion /* If we're expanding an alias, we should overwrite the expansion
@ -1023,15 +1076,18 @@ hwbegin(int offset)
/**/ /**/
void void
hwend(void) ihwend(void)
{ {
if (stophist == 2 || strin)
return;
if (chwordpos%2 && chline) { if (chwordpos%2 && chline) {
/* end of word reached and we've already begun a word */ /* end of word reached and we've already begun a word */
if (hptr > chline + chwords[chwordpos-1]) { if (hptr > chline + chwords[chwordpos-1]) {
chwords[chwordpos++] = hptr - chline; chwords[chwordpos++] = hptr - chline;
if (chwordpos >= chwordlen) { if (chwordpos >= chwordlen) {
chwords = (short *) realloc(chwords, chwords = (short *) realloc(chwords,
(chwordlen += 16)*sizeof(short)); (chwordlen += 32) *
sizeof(short));
} }
if (hwgetword > -1) { if (hwgetword > -1) {
/* We want to reuse the current word position */ /* We want to reuse the current word position */
@ -1606,7 +1662,7 @@ readhistfile(char *fn, int err, int readflags)
else if (!lockhistfile(fn, 1)) else if (!lockhistfile(fn, 1))
return; return;
if ((in = fopen(unmeta(fn), "r"))) { if ((in = fopen(unmeta(fn), "r"))) {
nwordlist = 16; nwordlist = 64;
wordlist = (short *)zalloc(nwordlist*sizeof(short)); wordlist = (short *)zalloc(nwordlist*sizeof(short));
bufsiz = 1024; bufsiz = 1024;
buf = zalloc(bufsiz); buf = zalloc(bufsiz);
@ -1717,7 +1773,7 @@ readhistfile(char *fn, int err, int readflags)
if (*pt) { if (*pt) {
if (nwordpos >= nwordlist) if (nwordpos >= nwordlist)
wordlist = (short *) realloc(wordlist, wordlist = (short *) realloc(wordlist,
(nwordlist += 16)*sizeof(short)); (nwordlist += 64)*sizeof(short));
wordlist[nwordpos++] = pt - start; wordlist[nwordpos++] = pt - start;
while (*pt && !inblank(*pt)) while (*pt && !inblank(*pt))
pt++; pt++;

View file

@ -37,6 +37,14 @@
/**/ /**/
int noexitct = 0; int noexitct = 0;
/* buffer for $_ and its length */
/**/
char *underscore;
/**/
int underscorelen;
/* what level of sourcing we are at */ /* what level of sourcing we are at */
/**/ /**/
@ -94,7 +102,7 @@ loop(int toplevel, int justonce)
if (interact) if (interact)
preprompt(); preprompt();
} }
hbegin(); /* init history mech */ hbegin(1); /* init history mech */
intr(); /* interrupts on */ intr(); /* interrupts on */
lexinit(); /* initialize lexical state */ lexinit(); /* initialize lexical state */
if (!(list = parse_event())) { /* if we couldn't parse a list */ 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 */ if (stopmsg) /* unset 'you have stopped jobs' flag */
stopmsg--; stopmsg--;
execlist(list, 0, 0); execlist(list, 0, 0);
if (toplevel)
freestructs();
tok = toksav; tok = toksav;
if (toplevel) if (toplevel)
noexitct = 0; noexitct = 0;
@ -550,8 +560,20 @@ setupvals(void)
cdpath = mkarray(NULL); cdpath = mkarray(NULL);
manpath = mkarray(NULL); manpath = mkarray(NULL);
fignore = mkarray(NULL); fignore = mkarray(NULL);
#ifdef FUNCTION_DIR #ifdef FPATH_DIR
fpath = mkarray(ztrdup(FUNCTION_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 #else
fpath = mkarray(NULL); fpath = mkarray(NULL);
#endif #endif
@ -582,7 +604,8 @@ setupvals(void)
ifs = ztrdup(DEFAULT_IFS); ifs = ztrdup(DEFAULT_IFS);
wordchars = ztrdup(DEFAULT_WORDCHARS); wordchars = ztrdup(DEFAULT_WORDCHARS);
postedit = ztrdup(""); postedit = ztrdup("");
underscore = ztrdup(""); underscore = (char *) zalloc(underscorelen = 32);
*underscore = '\0';
zoptarg = ztrdup(""); zoptarg = ztrdup("");
zoptind = 1; zoptind = 1;

View file

@ -65,10 +65,6 @@ struct tms shtms;
/**/ /**/
int ttyfrozen; 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; static struct timeval dtimeval, now;
/* Diff two timevals for elapsed-time computations */ /* Diff two timevals for elapsed-time computations */
@ -244,8 +240,11 @@ update_job(Job jn)
adjustwinsize(0); adjustwinsize(0);
} }
} }
} else if (list_pipe && (val & 0200) && inforeground == 1) {
breaks = loops;
errflag = 1;
inerrflush();
} }
if (somestopped && jn->stat & STAT_SUPERJOB) if (somestopped && jn->stat & STAT_SUPERJOB)
return; return;
jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED : jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
@ -663,14 +662,16 @@ deletejob(Job jn)
nx = pn->next; nx = pn->next;
zfree(pn, sizeof(struct process)); zfree(pn, sizeof(struct process));
} }
zsfree(jn->pwd);
deletefilelist(jn->filelist); deletefilelist(jn->filelist);
if (jn->ty) if (jn->ty)
zfree(jn->ty, sizeof(struct ttyinfo)); 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 */ /* add a process to the current job */
@ -831,7 +832,12 @@ waitjob(int job, int sig)
void void
waitjobs(void) waitjobs(void)
{ {
waitjob(thisjob, 0); Job jn = jobtab + thisjob;
if (jn->procs)
waitjob(thisjob, 0);
else
deletejob(jn);
thisjob = -1; thisjob = -1;
} }
@ -843,12 +849,9 @@ clearjobtab(void)
{ {
int i; int i;
for (i = 1; i < MAXJOB; i++) { for (i = 1; i < MAXJOB; i++)
if (jobtab[i].pwd)
zsfree(jobtab[i].pwd);
if (jobtab[i].ty) if (jobtab[i].ty)
zfree(jobtab[i].ty, sizeof(struct ttyinfo)); zfree(jobtab[i].ty, sizeof(struct ttyinfo));
}
memset(jobtab, 0, sizeof(jobtab)); /* zero out table */ memset(jobtab, 0, sizeof(jobtab)); /* zero out table */
} }
@ -864,7 +867,11 @@ initjob(void)
for (i = 1; i < MAXJOB; i++) for (i = 1; i < MAXJOB; i++)
if (!jobtab[i].stat) { if (!jobtab[i].stat) {
jobtab[i].stat = STAT_INUSE; 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; jobtab[i].gleader = 0;
return i; return i;
} }

View file

@ -179,6 +179,12 @@ struct lexstack {
int hwgetword; int hwgetword;
int lexstop; int lexstop;
struct heredocs *hdocs; struct heredocs *hdocs;
int (*hgetc) _((void));
void (*hungetc) _((int));
void (*hwaddc) _((int));
void (*hwbegin) _((int));
void (*hwend) _((void));
void (*addtoline) _((int));
unsigned char *cstack; unsigned char *cstack;
int csp; int csp;
@ -226,6 +232,12 @@ lexsave(void)
ls->hwgetword = hwgetword; ls->hwgetword = hwgetword;
ls->lexstop = lexstop; ls->lexstop = lexstop;
ls->hdocs = hdocs; ls->hdocs = hdocs;
ls->hgetc = hgetc;
ls->hungetc = hungetc;
ls->hwaddc = hwaddc;
ls->hwbegin = hwbegin;
ls->hwend = hwend;
ls->addtoline = addtoline;
cmdsp = 0; cmdsp = 0;
inredir = 0; inredir = 0;
hdocs = NULL; hdocs = NULL;
@ -271,6 +283,12 @@ lexrestore(void)
hwgetword = lstack->hwgetword; hwgetword = lstack->hwgetword;
lexstop = lstack->lexstop; lexstop = lstack->lexstop;
hdocs = lstack->hdocs; hdocs = lstack->hdocs;
hgetc = lstack->hgetc;
hungetc = lstack->hungetc;
hwaddc = lstack->hwaddc;
hwbegin = lstack->hwbegin;
hwend = lstack->hwend;
addtoline = lstack->addtoline;
hlinesz = lstack->hlinesz; hlinesz = lstack->hlinesz;
errflag = 0; errflag = 0;
@ -783,7 +801,7 @@ gettok(void)
static int static int
gettokstr(int c, int sub) 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 intpos = 1, in_brace_param = 0;
int peek, inquote; int peek, inquote;
#ifdef DEBUG #ifdef DEBUG
@ -798,8 +816,12 @@ gettokstr(int c, int sub)
for (;;) { for (;;) {
int act; int act;
int e; 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; act = LX2_BREAK;
else { else {
act = lexact2[STOUC(c)]; act = lexact2[STOUC(c)];
@ -822,6 +844,12 @@ gettokstr(int c, int sub)
add(Meta); add(Meta);
break; break;
case LX2_OUTPAR: 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)) if ((sub || in_brace_param) && isset(SHGLOB))
break; break;
if (!in_brace_param && !pct--) { if (!in_brace_param && !pct--) {
@ -898,11 +926,40 @@ gettokstr(int c, int sub)
e = hgetc(); e = hgetc();
hungetc(e); hungetc(e);
lexstop = 0; lexstop = 0;
if (e == ')' || /* For command words, parentheses are only
(incmdpos && !brct && peek != ENVSTRING)) * 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; 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; c = Inpar;
break; break;
@ -1294,8 +1351,7 @@ parsestr(char *s)
lexsave(); lexsave();
untokenize(s); untokenize(s);
inpush(dupstring(s), 0, NULL); inpush(dupstring(s), 0, NULL);
strinbeg(); strinbeg(0);
stophist = 2;
len = 0; len = 0;
bptr = tokstr = s; bptr = tokstr = s;
bsiz = l + 1; bsiz = l + 1;
@ -1331,8 +1387,7 @@ parse_subst_string(char *s)
lexsave(); lexsave();
untokenize(s); untokenize(s);
inpush(dupstring(s), 0, NULL); inpush(dupstring(s), 0, NULL);
strinbeg(); strinbeg(0);
stophist = 2;
len = 0; len = 0;
bptr = tokstr = s; bptr = tokstr = s;
bsiz = l + 1; bsiz = l + 1;
@ -1377,8 +1432,7 @@ exalias(void)
if (!tokstr) { if (!tokstr) {
yytext = tokstrings[tok]; yytext = tokstrings[tok];
if (yytext)
yytext = dupstring(yytext);
return 0; return 0;
} }

View file

@ -38,7 +38,7 @@ newlinklist(void)
{ {
LinkList list; LinkList list;
list = (LinkList) alloc(sizeof *list); list = (LinkList) ncalloc(sizeof *list);
list->first = NULL; list->first = NULL;
list->last = (LinkNode) list; list->last = (LinkNode) list;
return list; return list;
@ -53,7 +53,7 @@ insertlinknode(LinkList list, LinkNode node, void *dat)
LinkNode tmp, new; LinkNode tmp, new;
tmp = node->next; tmp = node->next;
node->next = new = (LinkNode) alloc(sizeof *tmp); node->next = new = (LinkNode) ncalloc(sizeof *tmp);
new->last = node; new->last = node;
new->dat = dat; new->dat = dat;
new->next = tmp; new->next = tmp;

View file

@ -44,21 +44,18 @@ int contflag;
/**/ /**/
int breaks; int breaks;
/**/ /**/
int int
execfor(Cmd cmd) execfor(Cmd cmd, LinkList args, int flags)
{ {
List list;
Forcmd node; Forcmd node;
char *str; char *str;
int val = 0; zlong val = 0;
LinkList args;
node = cmd->u.forcmd; node = cmd->u.forcmd;
args = cmd->args;
if (node->condition) { if (node->condition) {
str = node->name; str = dupstring(node->name);
singsub(&str); singsub(&str);
if (!errflag) if (!errflag)
matheval(str); matheval(str);
@ -69,7 +66,7 @@ execfor(Cmd cmd)
args = newlinklist(); args = newlinklist();
for (x = pparams; *x; x++) for (x = pparams; *x; x++)
addlinknode(args, ztrdup(*x)); addlinknode(args, dupstring(*x));
} }
lastval = 0; lastval = 0;
loops++; loops++;
@ -95,13 +92,12 @@ execfor(Cmd cmd)
if (!val) if (!val)
break; break;
} else { } else {
str = (char *) ugetnode(args); if (!args || !(str = (char *) ugetnode(args)))
if (!str)
break; break;
setsparam(node->name, ztrdup(str)); setsparam(node->name, ztrdup(str));
} }
list = (List) dupstruct(node->list); execlist(node->list, 1,
execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args)); (flags & CFLAG_EXEC) && args && empty(args));
if (breaks) { if (breaks) {
breaks--; breaks--;
if (breaks || !contflag) if (breaks || !contflag)
@ -129,27 +125,24 @@ execfor(Cmd cmd)
/**/ /**/
int int
execselect(Cmd cmd) execselect(Cmd cmd, LinkList args, int flags)
{ {
List list;
Forcmd node; Forcmd node;
char *str, *s; char *str, *s;
LinkList args;
LinkNode n; LinkNode n;
int i; int i;
FILE *inp; FILE *inp;
size_t more; size_t more;
node = cmd->u.forcmd; node = cmd->u.forcmd;
args = cmd->args;
if (!node->inflag) { if (!node->inflag) {
char **x; char **x;
args = newlinklist(); args = newlinklist();
for (x = pparams; *x; x++) for (x = pparams; *x; x++)
addlinknode(args, ztrdup(*x)); addlinknode(args, dupstring(*x));
} }
if (empty(args)) if (!args || empty(args))
return 1; return 1;
loops++; loops++;
lastval = 0; lastval = 0;
@ -196,8 +189,7 @@ execselect(Cmd cmd)
str = ""; str = "";
} }
setsparam(node->name, ztrdup(str)); setsparam(node->name, ztrdup(str));
list = (List) dupstruct(node->list); execlist(node->list, 1, 0);
execlist(list, 1, 0);
freeheap(); freeheap();
if (breaks) { if (breaks) {
breaks--; breaks--;
@ -278,9 +270,8 @@ selectlist(LinkList l, size_t start)
/**/ /**/
int int
execwhile(Cmd cmd) execwhile(Cmd cmd, LinkList args, int flags)
{ {
List list;
struct whilecmd *node; struct whilecmd *node;
int olderrexit, oldval; int olderrexit, oldval;
@ -290,9 +281,8 @@ execwhile(Cmd cmd)
pushheap(); pushheap();
loops++; loops++;
for (;;) { for (;;) {
list = (List) dupstruct(node->cont);
noerrexit = 1; noerrexit = 1;
execlist(list, 1, 0); execlist(node->cont, 1, 0);
noerrexit = olderrexit; noerrexit = olderrexit;
if (!((lastval == 0) ^ node->cond)) { if (!((lastval == 0) ^ node->cond)) {
if (breaks) if (breaks)
@ -300,8 +290,7 @@ execwhile(Cmd cmd)
lastval = oldval; lastval = oldval;
break; break;
} }
list = (List) dupstruct(node->loop); execlist(node->loop, 1, 0);
execlist(list, 1, 0);
if (breaks) { if (breaks) {
breaks--; breaks--;
if (breaks || !contflag) if (breaks || !contflag)
@ -322,22 +311,20 @@ execwhile(Cmd cmd)
/**/ /**/
int int
execrepeat(Cmd cmd) execrepeat(Cmd cmd, LinkList args, int flags)
{ {
List list;
int count; int count;
lastval = 0; lastval = 0;
if (empty(cmd->args) || nextnode(firstnode(cmd->args))) { if (!args || empty(args) || nextnode(firstnode(args))) {
zerr("bad argument for repeat", NULL, 0); zerr("bad argument for repeat", NULL, 0);
return 1; return 1;
} }
count = atoi(peekfirst(cmd->args)); count = atoi(peekfirst(args));
pushheap(); pushheap();
loops++; loops++;
while (count--) { while (count--) {
list = (List) dupstruct(cmd->u.list); execlist(cmd->u.list, 1, 0);
execlist(list, 1, 0);
freeheap(); freeheap();
if (breaks) { if (breaks) {
breaks--; breaks--;
@ -357,7 +344,7 @@ execrepeat(Cmd cmd)
/**/ /**/
int int
execif(Cmd cmd) execif(Cmd cmd, LinkList args, int flags)
{ {
struct ifcmd *node; struct ifcmd *node;
int olderrexit; int olderrexit;
@ -380,7 +367,7 @@ execif(Cmd cmd)
noerrexit = olderrexit; noerrexit = olderrexit;
if (*t) if (*t)
execlist(*t, 1, cmd->flags & CFLAG_EXEC); execlist(*t, 1, flags & CFLAG_EXEC);
else else
lastval = 0; lastval = 0;
@ -389,7 +376,7 @@ execif(Cmd cmd)
/**/ /**/
int int
execcase(Cmd cmd) execcase(Cmd cmd, LinkList args, int flags)
{ {
struct casecmd *node; struct casecmd *node;
char *word; char *word;
@ -400,18 +387,18 @@ execcase(Cmd cmd)
l = node->lists; l = node->lists;
p = node->pats; p = node->pats;
word = *p++; word = dupstring(*p++);
singsub(&word); singsub(&word);
untokenize(word); untokenize(word);
lastval = 0; lastval = 0;
if (node) { if (node) {
while (*p) { while (*p) {
char *pat = *p + 1; char *pat = dupstring(*p + 1);
singsub(&pat); singsub(&pat);
if (matchpat(word, pat)) { if (matchpat(word, pat)) {
do { do {
execlist(*l++, 1, **p == ';' && (cmd->flags & CFLAG_EXEC)); execlist(*l++, 1, **p == ';' && (flags & CFLAG_EXEC));
} while(**p++ == '&' && *p); } while(**p++ == '&' && *p);
break; break;
} }
@ -421,4 +408,3 @@ execcase(Cmd cmd)
} }
return lastval; return lastval;
} }

View file

@ -733,9 +733,9 @@ mathevall(char *s, int prek, char **ep)
char *xptr; char *xptr;
zlong xyyval; zlong xyyval;
LV xyylval; LV xyylval;
char **xlvals = 0; char **xlvals = 0, *nlvals[LVCOUNT];
int xsp; int xsp;
struct mathvalue *xstack = 0; struct mathvalue *xstack = 0, nstack[STACKSZ];
zlong ret; zlong ret;
xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0; xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0;
@ -753,9 +753,10 @@ mathevall(char *s, int prek, char **ep)
xsp = sp; xsp = sp;
xstack = stack; xstack = stack;
} }
stack = (struct mathvalue *)zalloc(STACKSZ*sizeof(struct mathvalue)); stack = nstack;
lastbase = -1; lastbase = -1;
lvals = (char **)zcalloc(LVCOUNT*sizeof(char *)); memset(nlvals, 0, LVCOUNT*sizeof(char *));
lvals = nlvals;
lvc = 0; lvc = 0;
ptr = s; ptr = s;
sp = -1; sp = -1;
@ -769,8 +770,6 @@ mathevall(char *s, int prek, char **ep)
ret = stack[0].val; ret = stack[0].val;
zfree(lvals, LVCOUNT*sizeof(char *));
zfree(stack, STACKSZ*sizeof(struct mathvalue));
if (--mlevel) { if (--mlevel) {
lastbase = xlastbase; lastbase = xlastbase;
noeval = xnoeval; noeval = xnoeval;
@ -827,7 +826,8 @@ mathevalarg(char *s, char **ss)
static void static void
mathparse(int pc) mathparse(int pc)
{ {
int q, otok, onoeval; zlong q;
int otok, onoeval;
if (errflag) if (errflag)
return; return;

View file

@ -97,7 +97,7 @@ static int h_m[1025], h_push, h_pop, h_free;
#endif #endif
#define H_ISIZE sizeof(zlong) #define H_ISIZE sizeof(zlong)
#define HEAPSIZE (8192 - H_ISIZE) #define HEAPSIZE (16384 - H_ISIZE)
#define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap)) #define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap))
#define HEAPFREE (16384 - H_ISIZE) #define HEAPFREE (16384 - H_ISIZE)
@ -133,6 +133,10 @@ global_permalloc(void)
static Heap heaps; 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. */ /* Use new heaps from now on. This returns the old heap-list. */
/**/ /**/
@ -141,7 +145,7 @@ new_heaps(void)
{ {
Heap h = heaps; Heap h = heaps;
heaps = NULL; fheap = heaps = NULL;
return h; return h;
} }
@ -160,6 +164,7 @@ old_heaps(Heap old)
zfree(h, sizeof(*h)); zfree(h, sizeof(*h));
} }
heaps = old; heaps = old;
fheap = NULL;
} }
/* Temporarily switch to other heaps (or back again). */ /* Temporarily switch to other heaps (or back again). */
@ -171,6 +176,7 @@ switch_heaps(Heap new)
Heap h = heaps; Heap h = heaps;
heaps = new; heaps = new;
fheap = NULL;
return h; return h;
} }
@ -208,6 +214,8 @@ freeheap(void)
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG) #if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
h_free++; h_free++;
#endif #endif
fheap = NULL;
for (h = heaps; h; h = hn) { for (h = heaps; h; h = hn) {
hn = h->next; hn = h->next;
if (h->sp) { if (h->sp) {
@ -215,6 +223,8 @@ freeheap(void)
memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used); memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used);
#endif #endif
h->used = h->sp->used; h->used = h->sp->used;
if (!fheap && h->used < HEAP_ARENA_SIZE)
fheap = h;
hl = h; hl = h;
} else } else
zfree(h, HEAPSIZE); zfree(h, HEAPSIZE);
@ -238,6 +248,7 @@ popheap(void)
h_pop++; h_pop++;
#endif #endif
fheap = NULL;
for (h = heaps; h; h = hn) { for (h = heaps; h; h = hn) {
hn = h->next; hn = h->next;
if ((hs = h->sp)) { if ((hs = h->sp)) {
@ -246,6 +257,8 @@ popheap(void)
memset(arena(h) + hs->used, 0xff, h->used - hs->used); memset(arena(h) + hs->used, 0xff, h->used - hs->used);
#endif #endif
h->used = hs->used; h->used = hs->used;
if (!fheap && h->used < HEAP_ARENA_SIZE)
fheap = h;
zfree(hs, sizeof(*hs)); zfree(hs, sizeof(*hs));
hl = h; hl = h;
@ -275,13 +288,12 @@ zhalloc(size_t size)
/* find a heap with enough free space */ /* 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)) { if (HEAP_ARENA_SIZE >= (n = size + h->used)) {
h->used = n; h->used = n;
return arena(h) + n - size; return arena(h) + n - size;
} }
} }
{ {
Heap hp; Heap hp;
/* not found, allocate new heap */ /* not found, allocate new heap */
@ -311,6 +323,7 @@ zhalloc(size_t size)
hp->next = h; hp->next = h;
else else
heaps = h; heaps = h;
fheap = NULL;
unqueue_signals(); unqueue_signals();
return arena(h); return arena(h);
@ -361,6 +374,7 @@ hrealloc(char *p, size_t old, size_t new)
ph->next = h->next; ph->next = h->next;
else else
heaps = h->next; heaps = h->next;
fheap = NULL;
zfree(h, HEAPSIZE); zfree(h, HEAPSIZE);
return NULL; return NULL;
} }
@ -593,6 +607,16 @@ struct m_hdr {
#define M_ISIZE (sizeof(zlong)) #define M_ISIZE (sizeof(zlong))
#define M_MIN (2 * M_ISIZE) #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 /* 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) */ 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_SIDX(S) ((S) / M_ISIZE)
#define M_SNUM 50 #define M_SNUM 128
#define M_SLEN(M) ((M)->len / M_SNUM) #define M_SLEN(M) ((M)->len / M_SNUM)
#define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \ #define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \
sizeof(zlong) + sizeof(struct m_hdr *)) sizeof(zlong) + sizeof(struct m_hdr *))
#define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \ #define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \
sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM) sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
#define M_NSMALL 8 #define M_NSMALL 13
static struct m_hdr *m_small[M_NSMALL]; static struct m_hdr *m_small[M_NSMALL];
@ -691,9 +715,9 @@ malloc(MALLOC_ARG_T size)
m->used++; m->used++;
/* if all small blocks in this block are allocated, the block is /* 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 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) { if (m->used == M_SNUM && m->next) {
for (mt = m; mt->next; mt = mt->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); for (mp = NULL, m = m_free; m && m->len < size; mp = m, m = m->next);
} }
if (!m) { if (!m) {
long nal;
/* no matching free block was found, we have to request new /* no matching free block was found, we have to request new
memory from the system */ 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)) { if (((char *)(m = (struct m_hdr *)sbrk(n))) == ((char *)-1)) {
DPUTS(1, "MEM: allocation error at sbrk."); DPUTS(1, "MEM: allocation error at sbrk.");
unqueue_signals(); unqueue_signals();
return NULL; 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() */ /* set m_low, for the check in free() */
if (!m_low) if (!m_low)
m_low = (char *)m; 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 and now there is more than one page size of memory, we can give
it back to the system (and we do it ;-) */ it back to the system (and we do it ;-) */
if ((((char *)m_lfree) + M_ISIZE + m_lfree->len) == m_high && if ((((char *)m_lfree) + M_ISIZE + m_lfree->len) == m_high &&
m_lfree->len >= m_pgsz + M_MIN) { m_lfree->len >= m_pgsz + M_MIN + M_FREE) {
long n = (m_lfree->len - M_MIN) & ~(m_pgsz - 1); long n = (m_lfree->len - M_MIN - M_KEEP) & ~(m_pgsz - 1);
m_lfree->len -= n; m_lfree->len -= n;
if (brk(m_high -= n) == -1) { if (brk(m_high -= n) == -1) {

View file

@ -52,7 +52,6 @@ char **pparams, /* $argv */
/**/ /**/
char *argzero, /* $0 */ char *argzero, /* $0 */
*underscore, /* $_ */
*home, /* $HOME */ *home, /* $HOME */
*hostnam, /* $HOST */ *hostnam, /* $HOST */
*ifs, /* $IFS */ *ifs, /* $IFS */
@ -232,11 +231,6 @@ IPDEF9("manpath", &manpath, "MANPATH"),
IPDEF9("psvar", &psvar, "PSVAR"), IPDEF9("psvar", &psvar, "PSVAR"),
IPDEF9("watch", &watch, "WATCH"), 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 #ifdef DYNAMIC
IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED), IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
#endif #endif
@ -723,16 +717,13 @@ isident(char *s)
#endif #endif
} }
static char **garr;
/**/ /**/
static zlong static zlong
getarg(char **str, int *inv, Value v, int a2, zlong *w) 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 hasbeg = 0, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash;
int beg = 0, hasbeg = 0;
char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt; char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt;
zlong r = 0; zlong num = 1, beg = 0, r = 0;
Comp c; Comp c;
ishash = (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED); ishash = (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED);
@ -1147,7 +1138,6 @@ fetchvalue(char **pptr, int bracks, int flags)
int ppar = 0; int ppar = 0;
s = t = *pptr; s = t = *pptr;
garr = NULL;
if (idigit(*s)) { if (idigit(*s)) {
if (bracks >= 0) if (bracks >= 0)
@ -1638,7 +1628,7 @@ setaparam(char *s, char **val)
if (!(v = getvalue(&s, 1))) if (!(v = getvalue(&s, 1)))
createparam(t, PM_ARRAY); createparam(t, PM_ARRAY);
*ss = '['; *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); zerr("attempt to set slice of associative array", NULL, 0);
freearray(val); freearray(val);
errflag = 1; errflag = 1;
@ -2466,7 +2456,10 @@ wordcharssetfn(Param pm, char *x)
char * char *
underscoregetfn(Param pm) underscoregetfn(Param pm)
{ {
return underscore; char *u = dupstring(underscore);
untokenize(u);
return u;
} }
/* Function to get value for special parameter `TERM' */ /* Function to get value for special parameter `TERM' */

View file

@ -298,6 +298,8 @@ par_pline(void)
rdr->type = MERGEOUT; rdr->type = MERGEOUT;
rdr->fd1 = 2; rdr->fd1 = 2;
rdr->name = dupstring("1"); rdr->name = dupstring("1");
if (!c->redir)
c->redir = newlinklist();
addlinknode(c->redir, rdr); addlinknode(c->redir, rdr);
cmdpush(CS_ERRPIPE); cmdpush(CS_ERRPIPE);
@ -330,11 +332,14 @@ par_cmd(void)
c = (Cmd) make_cmd(); c = (Cmd) make_cmd();
c->lineno = lineno; c->lineno = lineno;
c->args = newlinklist(); c->args = NULL;
c->redir = newlinklist(); c->vars = NULL;
c->vars = newlinklist(); if (IS_REDIROP(tok)) {
while (IS_REDIROP(tok)) c->redir = newlinklist();
par_redir(c->redir); while (IS_REDIROP(tok))
par_redir(c->redir);
} else
c->redir = NULL;
switch (tok) { switch (tok) {
case FOR: case FOR:
cmdpush(CS_FOR); cmdpush(CS_FOR);
@ -399,6 +404,8 @@ par_cmd(void)
break; break;
case DINPAR: case DINPAR:
c->type = CARITH; c->type = CARITH;
if (!c->args)
c->args = newlinklist();
addlinknode(c->args, tokstr); addlinknode(c->args, tokstr);
yylex(); yylex();
break; break;
@ -407,8 +414,12 @@ par_cmd(void)
return NULL; return NULL;
break; break;
} }
while (IS_REDIROP(tok)) if (IS_REDIROP(tok)) {
par_redir(c->redir); if (!c->redir)
c->redir = newlinklist();
while (IS_REDIROP(tok))
par_redir(c->redir);
}
incmdpos = 1; incmdpos = 1;
incasepat = 0; incasepat = 0;
incond = 0; incond = 0;
@ -460,6 +471,8 @@ par_for(Cmd c)
f->inflag = 1; f->inflag = 1;
incmdpos = 0; incmdpos = 0;
yylex(); yylex();
if (!c->args)
c->args = newlinklist();
c->args = par_wordlist(); c->args = par_wordlist();
if (tok != SEPER) if (tok != SEPER)
YYERRORV; YYERRORV;
@ -467,6 +480,8 @@ par_for(Cmd c)
f->inflag = 1; f->inflag = 1;
incmdpos = 0; incmdpos = 0;
yylex(); yylex();
if (!c->args)
c->args = newlinklist();
c->args = par_nl_wordlist(); c->args = par_nl_wordlist();
if (tok != OUTPAR) if (tok != OUTPAR)
YYERRORV; YYERRORV;
@ -819,6 +834,8 @@ par_repeat(Cmd c)
yylex(); yylex();
if (tok != STRING) if (tok != STRING)
YYERRORV; YYERRORV;
if (!c->args)
c->args = newlinklist();
addlinknode(c->args, tokstr); addlinknode(c->args, tokstr);
incmdpos = 1; incmdpos = 1;
yylex(); yylex();
@ -966,6 +983,8 @@ par_simple(Cmd c)
v->str = p + 1; v->str = p + 1;
} else } else
equalsplit(tokstr, &v->str); equalsplit(tokstr, &v->str);
if (!c->vars)
c->vars = newlinklist();
addlinknode(c->vars, v); addlinknode(c->vars, v);
isnull = 0; isnull = 0;
} else if (tok == ENVARRAY) { } else if (tok == ENVARRAY) {
@ -982,6 +1001,8 @@ par_simple(Cmd c)
if (tok != OUTPAR) if (tok != OUTPAR)
YYERROR; YYERROR;
incmdpos = oldcmdpos; incmdpos = oldcmdpos;
if (!c->vars)
c->vars = newlinklist();
addlinknode(c->vars, v); addlinknode(c->vars, v);
isnull = 0; isnull = 0;
} else } else
@ -993,9 +1014,13 @@ par_simple(Cmd c)
for (;;) { for (;;) {
if (tok == STRING) { if (tok == STRING) {
incmdpos = 0; incmdpos = 0;
if (!c->args)
c->args = newlinklist();
addlinknode(c->args, tokstr); addlinknode(c->args, tokstr);
yylex(); yylex();
} else if (IS_REDIROP(tok)) { } else if (IS_REDIROP(tok)) {
if (!c->redir)
c->redir = newlinklist();
par_redir(c->redir); par_redir(c->redir);
} else if (tok == INOUTPAR) { } else if (tok == INOUTPAR) {
incmdpos = 1; incmdpos = 1;
@ -1011,15 +1036,26 @@ par_simple(Cmd c)
YYERROR; YYERROR;
} }
yylex(); yylex();
} else } else {
c->u.list = (List) expandstruct((struct node *) par_cmd(), N_LIST); 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(); cmdpop();
c->type = FUNCDEF; c->type = FUNCDEF;
} else } else
break; break;
isnull = 0; isnull = 0;
} }
if (isnull && empty(c->redir)) if (isnull && (!c->redir || empty(c->redir)))
return NULL; return NULL;
incmdpos = 1; incmdpos = 1;
return c; return c;

View file

@ -719,7 +719,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
freelinklist(args, (FreeFunc) NULL); freelinklist(args, (FreeFunc) NULL);
zsfree(name); zsfree(name);
} else HEAPALLOC { } else HEAPALLOC {
execlist(dupstruct(sigfn), 1, 0); execlist(sigfn, 1, 0);
} LASTALLOC; } LASTALLOC;
if (trapreturn > 0) if (trapreturn > 0)
trapret = trapreturn; trapret = trapreturn;

View file

@ -53,9 +53,9 @@ prefork(LinkList list, int flags)
MUSTUSEHEAP("prefork"); MUSTUSEHEAP("prefork");
for (node = firstnode(list); node; incnode(node)) { 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) && if ((*str == Inang || *str == Outang || *str == Equals) &&
str[1] == Inpar) { str[1] == Inpar) {
if (*str == Inang || *str == Outang) if (*str == Inang || *str == Outang)

View file

@ -169,7 +169,6 @@ gettext2(struct node *n)
if (_List(n)->type & Z_DISOWN) if (_List(n)->type & Z_DISOWN)
taddstr("|"); taddstr("|");
} }
simplifyright(_List(n));
if (_List(n)->right) { if (_List(n)->right) {
if (tnewlins) if (tnewlins)
taddnl(); taddnl();
@ -460,22 +459,23 @@ getsimptext(Cmd cmd)
{ {
LinkNode n; LinkNode n;
for (n = firstnode(cmd->vars); n; incnode(n)) { if (cmd->vars)
struct varasg *v = (struct varasg *)getdata(n); for (n = firstnode(cmd->vars); n; incnode(n)) {
struct varasg *v = (struct varasg *)getdata(n);
taddstr(v->name); taddstr(v->name);
taddchr('='); taddchr('=');
if (PM_TYPE(v->type) == PM_ARRAY) { if (PM_TYPE(v->type) == PM_ARRAY) {
taddchr('('); taddchr('(');
taddlist(v->arr); taddlist(v->arr);
taddstr(") "); taddstr(") ");
} else if (PM_TYPE(v->type) == PM_HASHED) { } else if (PM_TYPE(v->type) == PM_HASHED) {
/* XXX */ /* XXX */
} else { } else {
taddstr(v->str); taddstr(v->str);
taddchr(' '); taddchr(' ');
}
} }
}
taddlist(cmd->args); taddlist(cmd->args);
} }
@ -490,6 +490,8 @@ getredirs(Cmd cmd)
"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">" "<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
}; };
if (!cmd->redir)
return;
taddchr(' '); taddchr(' ');
for (n = firstnode(cmd->redir); n; incnode(n)) { for (n = firstnode(cmd->redir); n; incnode(n)) {
struct redir *f = (struct redir *)getdata(n); struct redir *f = (struct redir *)getdata(n);
@ -537,7 +539,7 @@ taddlist(LinkList l)
{ {
LinkNode n; LinkNode n;
if (!(n = firstnode(l))) if (!l || !(n = firstnode(l)))
return; return;
for (; n; incnode(n)) { for (; n; incnode(n)) {
taddstr(getdata(n)); taddstr(getdata(n));

View file

@ -853,61 +853,131 @@ int resetneeded;
int winchanged; int winchanged;
#endif #endif
/* check the size of the window and adjust if necessary. * static int
* The value of from: * adjustlines(int signalled)
* 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)
{ {
int oldcols = columns, oldrows = lines; int oldlines = lines;
#ifdef TIOCGWINSZ #ifdef TIOCGWINSZ
static int userlines, usercols; if (signalled || lines <= 0)
lines = shttyinfo.winsize.ws_row;
if (SHTTY == -1) else
return; shttyinfo.winsize.ws_row = lines;
#endif /* TIOCGWINSZ */
if (from == 2) if (lines <= 0) {
userlines = lines > 0; DPUTS(signalled, "BUG: Impossible TIOCGWINSZ rows");
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;
}
#endif /* TIOCGWINSZ */
if (lines <= 0)
lines = tclines > 0 ? tclines : 24; lines = tclines > 0 ? tclines : 24;
if (columns <= 0) }
columns = tccolumns > 0 ? tccolumns : 80;
if (lines > 2) if (lines > 2)
termflags &= ~TERM_SHORT; termflags &= ~TERM_SHORT;
else else
termflags |= TERM_SHORT; 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) if (columns > 2)
termflags &= ~TERM_NARROW; termflags &= ~TERM_NARROW;
else else
termflags |= TERM_NARROW; 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 #ifdef TIOCGWINSZ
if (interact && from >= 2) { if (SHTTY == -1)
shttyinfo.winsize.ws_row = lines; return;
shttyinfo.winsize.ws_col = columns; 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); ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize);
} }
#endif #endif /* TIOCGWINSZ */
if (zleactive && (from >= 2 || oldcols != columns || oldrows != lines)) { if (zleactive && resetzle) {
resetneeded = winchanged = 1; #ifdef TIOCGWINSZ
winchanged =
#endif /* TIOCGWINSZ */
resetneeded = 1;
zrefresh(); zrefresh();
} }
} }
@ -1733,13 +1803,12 @@ char *
sepjoin(char **s, char *sep) sepjoin(char **s, char *sep)
{ {
char *r, *p, **t; char *r, *p, **t;
int l, sl, elide = 0; int l, sl;
char sepbuf[3]; char sepbuf[3];
if (!*s) if (!*s)
return ""; return "";
if (!sep) { if (!sep) {
elide = 1;
sep = sepbuf; sep = sepbuf;
sepbuf[0] = *ifs; sepbuf[0] = *ifs;
sepbuf[1] = *ifs == Meta ? ifs[1] ^ 32 : '\0'; sepbuf[1] = *ifs == Meta ? ifs[1] ^ 32 : '\0';
@ -1853,329 +1922,21 @@ allocnode(int type)
{ {
struct node *n; struct node *n;
n = (struct node *) alloc(sizetab[type]); n = (struct node *) ncalloc(sizetab[type]);
memset((void *) n, 0, sizetab[type]); memset((void *) n, 0, sizetab[type]);
n->ntype = flagtab[type]; n->ntype = flagtab[type];
if (useheap)
n->ntype |= NT_HEAP;
return (void *) n; return (void *) n;
} }
/* duplicate a syntax tree */
/**/ /**/
void * void *
dupstruct(void *a) 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; void **onodes, **nnodes, *ret, *n, *on;
int type, heap; int type;
size_t nodeoffs; size_t nodeoffs;
if (!a || ((List) a) == &dummy_list) if (!a || ((List) a) == &dummy_list)
@ -2183,53 +1944,33 @@ dupstruct2(void *a)
type = *(int *)a; type = *(int *)a;
ret = alloc(sizetab[NT_TYPE(type)]); ret = alloc(sizetab[NT_TYPE(type)]);
memcpy(ret, a, nodeoffs = offstab[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); onodes = (void **) ((char *)a + nodeoffs);
nnodes = (void **) ((char *)ret + nodeoffs); nnodes = (void **) ((char *)ret + nodeoffs);
heap = type & NT_HEAP;
for (type = (type & 0xffff00) >> 4; (type >>= 4); *nnodes++ = n) { for (type = (type & 0xffff00) >> 4; (type >>= 4); *nnodes++ = n) {
if (!(on = *onodes++)) if (!(on = *onodes++))
n = NULL; n = NULL;
else { else {
switch (type & 0xf) { switch (type & 0xf) {
case NT_NODE: case NT_NODE:
n = dupstruct2(on); n = dupstruct(on);
break; break;
case NT_STR: case NT_STR:
n = dupstring(on); n = dupstring(on);
break; break;
case NT_LIST | NT_NODE: case NT_LIST | NT_NODE:
if (heap) { n = duplist(on, (VFunc) dupstruct);
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);
break; break;
case NT_LIST | NT_STR: case NT_LIST | NT_STR:
if (heap) { n = duplist(on, (VFunc) (useheap ? dupstring : ztrdup));
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);
break; break;
case NT_NODE | NT_ARR: case NT_NODE | NT_ARR:
n = duparray(on, (VFunc) dupstruct2); n = duparray(on, (VFunc) dupstruct);
break; break;
case NT_STR | NT_ARR: case NT_STR | NT_ARR:
n = duparray(on, (VFunc) (useheap ? dupstring : ztrdup)); n = duparray(on, (VFunc) (useheap ? dupstring : ztrdup));
break; break;
default: default:
DPUTS(1, "BUG: bad node type in dupstruct2()"); DPUTS(1, "BUG: bad node type in dupstruct()");
abort(); abort();
} }
} }
@ -2237,19 +1978,46 @@ dupstruct2(void *a)
return ret; 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 void
freestruct(void *a) freestruct(void *a)
{ {
void **nodes, *n;
int type, size;
if (!a || ((List) a) == &dummy_list) if (!a || ((List) a) == &dummy_list)
return; 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)]); nodes = (void **) ((char *)a + offstab[NT_TYPE(type)]);
size = sizetab[NT_TYPE(type)]; size = sizetab[NT_TYPE(type)];
for (type = (type & 0xffff00) >> 4; (type >>= 4);) { for (type = (type & 0xffff00) >> 4; (type >>= 4);) {
@ -2262,6 +2030,8 @@ freestruct(void *a)
zsfree((char *) n); zsfree((char *) n);
break; break;
case NT_LIST | NT_NODE: case NT_LIST | NT_NODE:
freelinklist((LinkList) n, (FreeFunc) freestruct);
break;
case NT_NODE | NT_ARR: case NT_NODE | NT_ARR:
{ {
void **p = (void **) n; void **p = (void **) n;
@ -2272,6 +2042,8 @@ freestruct(void *a)
break; break;
} }
case NT_LIST | NT_STR: case NT_LIST | NT_STR:
freelinklist((LinkList) n, (FreeFunc) zsfree);
break;
case NT_STR | NT_ARR: case NT_STR | NT_ARR:
freearray((char **) n); freearray((char **) n);
break; break;
@ -2286,59 +2058,47 @@ freestruct(void *a)
zfree(a, size); zfree(a, size);
} }
/**/
LinkList
dupheaplist(LinkList l)
{
if (!l)
return NULL;
return duplist(l, (VFunc) dupstruct);
}
/**/ /**/
static LinkList static LinkList
duplist(LinkList l, VFunc func) duplist(LinkList l, VFunc func)
{ {
LinkList ret; if (l && nonempty(l)) {
LinkNode node; LinkList ret;
LinkNode node;
ret = newlinklist(); ret = newlinklist();
for (node = firstnode(l); node; incnode(node)) for (node = firstnode(l); node; incnode(node))
addlinknode(ret, func(getdata(node))); addlinknode(ret, func(getdata(node)));
return ret; return ret;
}
return NULL;
} }
/**/ /**/
char ** char **
duparray(char **arr, VFunc func) duparray(char **arr, VFunc func)
{ {
char **ret, **rr; if (arr && *arr) {
char **ret, **rr, *p;
ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *)); ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *));
for (rr = ret; *arr;) for (rr = ret; (p = *arr++);)
*rr++ = (char *)func(*arr++); *rr++ = (char *)func(p);
*rr = NULL; *rr = NULL;
return ret; return ret;
} }
return NULL;
/**/
static char **
list2arr(LinkList l, VFunc func)
{
char **arr, **r;
LinkNode n;
arr = r = (char **) alloc((countlinknodes(l) + 1) * sizeof(char *));
for (n = firstnode(l); n; incnode(n))
*r++ = (char *)func(getdata(n));
*r = NULL;
return arr;
}
/**/
static LinkList
arr2list(char **arr, VFunc func)
{
LinkList l = newlinklist();
while (*arr)
addlinknode(l, func(*arr++));
return l;
} }
/**/ /**/
@ -2384,28 +2144,6 @@ equalsplit(char *s, char **t)
return 0; 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 */ /* the ztypes table */
/**/ /**/
@ -2470,6 +2208,25 @@ arrdup(char **s)
return y; 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 ** char **
listarr(LinkList l) listarr(LinkList l)

View file

@ -75,6 +75,7 @@ findcmd
firsthist firsthist
freearray freearray
freeheap freeheap
freelinklist
freestruct freestruct
getaparam getaparam
gethashnode gethashnode
@ -113,6 +114,7 @@ hist_skip_flags
holdintr holdintr
hptr hptr
hrealloc hrealloc
ifs
inbufct inbufct
incmdpos incmdpos
incond incond
@ -179,7 +181,6 @@ path
pathchecked pathchecked
popheap popheap
postedit postedit
pparams
ppid ppid
prefork prefork
prepromptfns prepromptfns

View file

@ -47,7 +47,11 @@
*/ */
#ifdef ZSH_64_BIT_TYPE #ifdef ZSH_64_BIT_TYPE
typedef ZSH_64_BIT_TYPE zlong; 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 #else
typedef long zlong; typedef long zlong;
typedef unsigned long zulong; typedef unsigned long zulong;
@ -352,7 +356,6 @@ struct node {
#define NT_N(T, N) (((T) >> (8 + (N) * 4)) & 0xf) #define NT_N(T, N) (((T) >> (8 + (N) * 4)) & 0xf)
#define NT_SET(T0, T1, T2, T3, T4) \ #define NT_SET(T0, T1, T2, T3, T4) \
((T0) | ((T1) << 8) | ((T2) << 12) | ((T3) << 16) | ((T4) << 20)) ((T0) | ((T1) << 8) | ((T2) << 12) | ((T3) << 16) | ((T4) << 20))
#define NT_HEAP (1 << 30)
/* tree element for lists */ /* tree element for lists */
@ -605,7 +608,7 @@ struct job {
pid_t gleader; /* process group leader of this job */ pid_t gleader; /* process group leader of this job */
pid_t other; /* subjob id or subshell pid */ pid_t other; /* subjob id or subshell pid */
int stat; /* see STATs below */ 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 */ * this job was spawned */
struct process *procs; /* list of processes */ struct process *procs; /* list of processes */
LinkList filelist; /* list of files to delete when done */ LinkList filelist; /* list of files to delete when done */
@ -948,7 +951,12 @@ struct param {
#define PM_READONLY (1<<8) /* readonly */ #define PM_READONLY (1<<8) /* readonly */
#define PM_TAGGED (1<<9) /* tagged */ #define PM_TAGGED (1<<9) /* tagged */
#define PM_EXPORTED (1<<10) /* exported */ #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_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_TIED (1<<12) /* array tied to colon-path or v.v. */
#define PM_SPECIAL (1<<13) /* special builtin parameter */ #define PM_SPECIAL (1<<13) /* special builtin parameter */
#define PM_DONTIMPORT (1<<14) /* do not import this variable */ #define PM_DONTIMPORT (1<<14) /* do not import this variable */

View file

@ -31,7 +31,16 @@ version.h: $(sdir_top)/Config/version.mk
zshpaths.h: FORCE Makemod zshpaths.h: FORCE Makemod
@echo '#define MODULE_DIR "'$(MODDIR)'"' > zshpaths.h.tmp @echo '#define MODULE_DIR "'$(MODDIR)'"' > zshpaths.h.tmp
@if test x$(fndir) != xno; then \ @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 fi
@if cmp -s zshpaths.h zshpaths.h.tmp; then \ @if cmp -s zshpaths.h zshpaths.h.tmp; then \
rm -f zshpaths.h.tmp; \ rm -f zshpaths.h.tmp; \

View file

@ -504,3 +504,21 @@ Documentation
ocurring in the main text, "plugh" is a normal word that is being quoted 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" (it's the user that says `plugh', not the documentation), and "xyzzy"
is some text to be typed literally that is being quoted. 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.

View file

@ -248,9 +248,12 @@
/* Define to 1 if long is 64 bits */ /* Define to 1 if long is 64 bits */
#undef LONG_IS_64_BIT #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 #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) */ /* Define to 1 if off_t is 64 bit (for large file support) */
#undef OFF_T_IS_64_BIT #undef OFF_T_IS_64_BIT

View file

@ -41,11 +41,13 @@ for ac_shellvar in $ac_shellvars; do
CPPFLAGS) ac_lfsvar=LFS_CFLAGS ;; CPPFLAGS) ac_lfsvar=LFS_CFLAGS ;;
*) ac_lfsvar=LFS_$ac_shellvar ;; *) ac_lfsvar=LFS_$ac_shellvar ;;
esac esac
eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar
(getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; } (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; }
ac_getconf=`getconf $ac_lfsvar` ac_getconf=`getconf $ac_lfsvar`
ac_getconfs=$ac_getconfs$ac_getconf if test -n "$ac_getconf"; then
eval ac_test_$ac_shellvar="\$ac_getconf" 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 done
case "$ac_result$ac_getconfs" in case "$ac_result$ac_getconfs" in
yes) ac_result=no ;; yes) ac_result=no ;;
@ -74,12 +76,12 @@ esac
dnl dnl
dnl zsh_64_BIT_TYPE dnl zsh_64_BIT_TYPE
dnl Check whether the first argument works as a 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 when we're cross compiling. This is to allow a type to be
dnl specified directly as --enable-lfs="long long". dnl specified directly as --enable-lfs="long long".
dnl Sets zsh_cv_64_bit_type to the first argument if the test worked, dnl Sets the variable given in the second argument to the first argument
dnl `no' otherwise. Be careful testing this, as it may produce dnl if the test worked, `no' otherwise. Be careful testing this, as it
dnl two words `long long' on an unquoted substitution. 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 This macro does not produce messages as it may be run several times
dnl before finding the right type. dnl before finding the right type.
dnl dnl
@ -95,11 +97,11 @@ main()
$1 foo = 0; $1 foo = 0;
return sizeof($1) != 8; return sizeof($1) != 8;
} }
], zsh_cv_64_bit_type="$1", zsh_cv_64_bit_type=no, ], $2="$1", $2=no,
[if test x$2 != x ; then [if test x$3 != x ; then
zsh_cv_64_bit_type="$1" $2="$1"
else else
zsh_cv_64_bit_type=no $2=no
fi]) fi])
]) ])

View file

@ -97,8 +97,7 @@ AC_ARG_ENABLE(zsh-hash-debug,
AC_DEFINE(ZSH_HASH_DEBUG) AC_DEFINE(ZSH_HASH_DEBUG)
fi]) fi])
dnl Do you want large file support, if available (mostly Solaris)? dnl Do you want large file support, if available?
dnl Currently this is only partially implemented.
undefine([lfs])dnl undefine([lfs])dnl
AC_ARG_ENABLE(lfs, AC_ARG_ENABLE(lfs,
[ --enable-lfs turn on support for large files]) [ --enable-lfs turn on support for large files])
@ -203,18 +202,35 @@ AC_DEFINE(RESTRICTED_R)
undefine([fndir])dnl undefine([fndir])dnl
AC_ARG_ENABLE(fndir, AC_ARG_ENABLE(fndir,
[ --enable-fndir=DIR where functions go (default DATADIR/zsh-fns)], [ --enable-fndir=DIR where functions go (default DATADIR/zsh/functions)],
[fndir="$enableval"], [fndir=${datadir}/zsh/functions]) [if test $enableval = yes; then
fndir=${datadir}/zsh/functions
else
fndir="$enableval"
fi], [fndir=${datadir}/zsh/functions])
if test x${FUNCTIONS_INSTALL+set} != xset; then undefine([function_subdirs])
AC_ARG_ENABLE(function-subdirs,
[ --enable-function-subdirs install functions in subdirectories])
if test "x${FUNCTIONS_INSTALL+set}" != xset; then
FUNCTIONS_INSTALL="Core/* Base/* Builtins/* User/* Commands/*" FUNCTIONS_INSTALL="Core/* Base/* Builtins/* User/* Commands/*"
if test $dynamic != no; then if test $dynamic != no; then
FUNCTIONS_INSTALL="${FUNCTIONS_INSTALL} Zftp/*" FUNCTIONS_INSTALL="${FUNCTIONS_INSTALL} Zftp/*"
fi fi
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(fndir)dnl
AC_SUBST(FUNCTIONS_INSTALL)dnl AC_SUBST(FUNCTIONS_INSTALL)dnl
AC_SUBST(FUNCTIONS_SUBDIRS)dnl
dnl ------------------ dnl ------------------
dnl CHECK THE COMPILER dnl CHECK THE COMPILER
@ -225,7 +241,7 @@ test -z "${LDFLAGS+set}" && LDFLAGS= auto_ldflags=1
AC_PROG_CC 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. dnl This needs to be done early to get the stuff into the flags.
if test "x$enable_lfs" != x; then if test "x$enable_lfs" != x; then
zsh_LARGE_FILE_SUPPORT 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 if test $zsh_cv_long_is_64_bit = yes; then
AC_DEFINE(LONG_IS_64_BIT) AC_DEFINE(LONG_IS_64_BIT)
elif test "x$enable_lfs" != x; then else
AC_CACHE_CHECK(if compiler has a 64 bit type, zsh_cv_64_bit_type, AC_CACHE_CHECK(if off_t is 64 bit, zsh_cv_off_t_is_64_bit,
[if test "x$enable_lfs" != xyes; then [AC_TRY_RUN([
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([
#include <sys/types.h> #include <sys/types.h>
main() { return sizeof(off_t) < 8; } main() { return sizeof(off_t) < 8; }
], ],
zsh_cv_off_t_is_64_bit=yes, zsh_cv_off_t_is_64_bit=yes,
zsh_cv_off_t_is_64_bit=no, zsh_cv_off_t_is_64_bit=no,
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 if test $zsh_cv_off_t_is_64_bit = yes; then
AC_DEFINE(OFF_T_IS_64_BIT) AC_DEFINE(OFF_T_IS_64_BIT)
fi fi
AC_CACHE_CHECK(if ino_t is 64 bit, zsh_cv_ino_t_is_64_bit, AC_CACHE_CHECK(if ino_t is 64 bit, zsh_cv_ino_t_is_64_bit,
[AC_TRY_RUN([ [AC_TRY_RUN([
#include <sys/types.h> #include <sys/types.h>
main() { return sizeof(ino_t) < 8; } main() { return sizeof(ino_t) < 8; }
], ],
zsh_cv_ino_t_is_64_bit=yes, zsh_cv_ino_t_is_64_bit=yes,
zsh_cv_ino_t_is_64_bit=no, zsh_cv_ino_t_is_64_bit=no,
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 if test $zsh_cv_ino_t_is_64_bit = yes; then
AC_DEFINE(INO_T_IS_64_BIT) 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 fi
fi fi
@ -1326,6 +1367,7 @@ eval "zshbin1=${bindir}"
eval "zshbin2=${zshbin1}" eval "zshbin2=${zshbin1}"
eval "zshman=${mandir}" eval "zshman=${mandir}"
eval "zshinfo=${infodir}" eval "zshinfo=${infodir}"
eval "zshfndir=${fndir}"
echo " echo "
zsh configuration zsh configuration
@ -1350,5 +1392,9 @@ echo "\
library flags : ${LIBS} library flags : ${LIBS}
binary install path : ${zshbin2} binary install path : ${zshbin2}
man page install path : ${zshman} 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