1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-02 22:11:54 +02:00

zsh-3.1.5-pws-2

This commit is contained in:
Tanaka Akira 1999-04-15 18:07:38 +00:00
parent a61dc2074a
commit f13624e0f8
27 changed files with 852 additions and 375 deletions

View file

@ -139,9 +139,13 @@ install.info: zsh.info
elif test -f $(sdir)/$$file; then \ elif test -f $(sdir)/$$file; then \
$(INSTALL_DATA) $(sdir)/$$file $(infodir); \ $(INSTALL_DATA) $(sdir)/$$file $(infodir); \
else :; \ else :; \
fi || exit 1; \ fi || exit 1; \
done done
install.html: zsh_toc.html
$(sdir_top)/mkinstalldirs $(htmldir)
$(INSTALL_DATA) *.html $(htmldir)
# uninstall man pages # uninstall man pages
uninstall.man: uninstall.man:
for file in $(MAN); do \ for file in $(MAN); do \

View file

@ -98,12 +98,13 @@ Change the current directory. In the first form, change the
current directory to var(arg), or to the value of tt($HOME) if current directory to var(arg), or to the value of tt($HOME) if
var(arg) is not specified. If var(arg) is `tt(-)', change to the var(arg) is not specified. If var(arg) is `tt(-)', change to the
value of tt($OLDPWD), the previous directory. value of tt($OLDPWD), the previous directory.
If a directory named var(arg) is not found in the current directory Otherwise, if a directory named var(arg) is not found in the current
and var(arg) does not begin with a slash, directory and var(arg) does not begin with a slash, search each
search each component of the shell parameter tt(cdpath). component of the shell parameter tt(cdpath). If no directory is found
If the option tt(CDABLE_VARS) is set, and a parameter named var(arg) and the option tt(CDABLE_VARS) is set, and a parameter named var(arg)
exists whose value begins with a slash, treat its value as exists whose value begins with a slash, treat its value as the
the directory. directory. In that case, the parameter is added to the named
directory hash table.
The second form of tt(cd) substitutes the string var(new) The second form of tt(cd) substitutes the string var(new)
for the string var(old) in the name of the current directory, for the string var(old) in the name of the current directory,
@ -357,11 +358,20 @@ is stored in tt(OPTARG).
vindex(OPTIND, use of) vindex(OPTIND, use of)
vindex(OPTARG, use of) vindex(OPTARG, use of)
The first option to be examined may be changed by explicitly assigning
to tt(OPTIND). tt(OPTIND) has an initial value of tt(1), and is
normally reset to tt(1) upon exit from a shell function. tt(OPTARG)
is not reset and retains its value from the most recent call to
tt(getopts). If either of tt(OPTIND) or tt(OPTARG) is explicitly
unset, it remains unset, and the index or option argument is not
stored. The option itself is still stored in var(name) in this case.
A leading `tt(:)' in var(optstring) causes tt(getopts) to store the A leading `tt(:)' in var(optstring) causes tt(getopts) to store the
letter of the invalid option in tt(OPTARG), and to set var(name) letter of any invalid option in tt(OPTARG), and to set var(name) to
to `tt(?)' for an unknown option and to `tt(:)' when a required option `tt(?)' for an unknown option and to `tt(:)' when a required option is
is missing. Otherwise, tt(getopts) prints an error missing. Otherwise, tt(getopts) sets var(name) to `tt(?)' and prints
message. The exit status is nonzero when there are no more options. an error message when an option is invalid. The exit status is
nonzero when there are no more options.
) )
findex(hash) findex(hash)
item(tt(hash) [ tt(-dfmrv) ] [ var(name)[tt(=)var(value)] ] ...)( item(tt(hash) [ tt(-dfmrv) ] [ var(name)[tt(=)var(value)] ] ...)(
@ -521,8 +531,8 @@ Same as tt(exit), except that it only works in a login shell.
prefix(noglob) prefix(noglob)
findex(popd) findex(popd)
item(tt(popd) [ {tt(PLUS())|tt(-)}var(n) ])( item(tt(popd) [ {tt(PLUS())|tt(-)}var(n) ])(
Removes a entry from the directory stack, and perform a tt(cd) to Remove an entry from the directory stack, and perform a tt(cd) to
the new top directory. With no argument, the current top entry is the new top directory. With no argument, the current top entry is
removed. An argument of the form `tt(PLUS())var(n)' identifies a stack removed. An argument of the form `tt(PLUS())var(n)' identifies a stack
entry by counting from the left of the list shown by the tt(dirs) command, entry by counting from the left of the list shown by the tt(dirs) command,
starting with zero. An argument of the form tt(-n) counts from the right. starting with zero. An argument of the form tt(-n) counts from the right.
@ -615,21 +625,9 @@ If var(arg) is not specified, change to the second directory
on the stack (that is, exchange the top two entries), or on the stack (that is, exchange the top two entries), or
change to tt($HOME) if the tt(PUSHD_TO_HOME) change to tt($HOME) if the tt(PUSHD_TO_HOME)
option is set or if there is only one entry on the stack. option is set or if there is only one entry on the stack.
Otherwise, var(arg) is interpreted as it would be by tt(cd).
If var(arg) is `tt(-)', change to tt($OLDPWD), the previous directory. The meaning of var(old) and var(new) in the second form is also
If a directory named var(arg) is not found in the current directory the same as for tt(cd).
and var(arg) does not contain a slash,
search each component of the shell parameter tt(cdpath).
If the option tt(CDABLE_VARS) is set, and a parameter named var(arg)
exists whose value begins with a slash, treat its value as
the directory.
If the option tt(PUSHD_SILENT) is not set, the directory
stack will be printed after a tt(pushd) is performed.
The second form of tt(pushd) substitutes the string var(new)
for the string var(old) in the name of the current directory,
and tries to change to this new directory.
The third form of tt(pushd) changes directory by rotating the The third form of tt(pushd) changes directory by rotating the
directory list. An argument of the form `tt(PLUS())var(n)' identifies a stack directory list. An argument of the form `tt(PLUS())var(n)' identifies a stack
@ -637,6 +635,9 @@ entry by counting from the left of the list shown by the tt(dirs)
command, starting with zero. An argument of the form `tt(-)var(n)' counts command, starting with zero. An argument of the form `tt(-)var(n)' counts
from the right. If the tt(PUSHD_MINUS) option is set, the meanings from the right. If the tt(PUSHD_MINUS) option is set, the meanings
of `tt(PLUS())' and `tt(-)' in this context are swapped. of `tt(PLUS())' and `tt(-)' in this context are swapped.
If the option tt(PUSHD_SILENT) is not set, the directory
stack will be printed after a tt(pushd) is performed.
) )
findex(pushln) findex(pushln)
item(tt(pushln) [ var(arg) ... ])( item(tt(pushln) [ var(arg) ... ])(
@ -727,7 +728,8 @@ is interactive.
The value (exit status) of tt(read) is 1 when an end-of-file is The value (exit status) of tt(read) is 1 when an end-of-file is
encountered, or when tt(-c) or tt(-l) is present and the command is encountered, or when tt(-c) or tt(-l) is present and the command is
not called from a tt(compctl) function. Otherwise the value is 0. not called from a tt(compctl) function, or as described for tt(-q).
Otherwise the value is 0.
The behavior of some combinations of the tt(-k), tt(-p), tt(-q), tt(-u) The behavior of some combinations of the tt(-k), tt(-p), tt(-q), tt(-u)
and tt(-z) flags is undefined. Presently tt(-q) cancels all the others, and tt(-z) flags is undefined. Presently tt(-q) cancels all the others,
@ -835,7 +837,7 @@ var(arg) is a command to be read and executed when the shell
receives var(sig). Each var(sig) can be given as a number receives var(sig). Each var(sig) can be given as a number
or as the name of a signal. or as the name of a signal.
If var(arg) is `tt(-)', then all traps var(sig) are reset to their If var(arg) is `tt(-)', then all traps var(sig) are reset to their
default values. If var(arg) is the null string, then this signal default values. If var(arg) is the empty string, then this signal
is ignored by the shell and by the commands it invokes. is ignored by the shell and by the commands it invokes.
If var(sig) is tt(ZERR) then var(arg) will be executed If var(sig) is tt(ZERR) then var(arg) will be executed
@ -958,7 +960,7 @@ or functions (with the tt(-f) flag) with matching names are printed.
findex(ulimit) findex(ulimit)
cindex(resource limits) cindex(resource limits)
cindex(limits, resource) cindex(limits, resource)
item(tt(ulimit) [ tt(-SHacdflmnpstv) [ tt(limit) ] ... ])( item(tt(ulimit) [ tt(-SHacdflmnpstv) [ var(limit) ] ... ])(
Set or display resource limits of the shell and the processes started by Set or display resource limits of the shell and the processes started by
the shell. The value of var(limit) can be a number in the unit specified the shell. The value of var(limit) can be a number in the unit specified
below or the value `tt(unlimited)'. If the tt(-H) flag is given use below or the value `tt(unlimited)'. If the tt(-H) flag is given use

View file

@ -573,11 +573,11 @@ enditem()
subsect(Example) subsect(Example)
The flag tt(f) is useful to split a double-quoted substitution line by The flag tt(f) is useful to split a double-quoted substitution line by
line. For example, `tt("${(f)$LPAR()<)var(file)tt(RPAR()}")' line. For example, `tt("${(f)$LPAR()<)var(file)tt(RPAR()}")'
will substitue the contents of var(file) divided so that one line is substitutes the contents of var(file) divided so that each line is
supplied per argument to var(cmd). Compare this with the effect of an element of the resulting array. Compare this with the effect of
`tt($)tt(LPAR()<)var(file)tt(RPAR())' alone, which divides the file `tt($)tt(LPAR()<)var(file)tt(RPAR())' alone, which divides the file
up by words, or the same inside double quotes, where the entire up by words, or the same inside double quotes, which makes the entire
contents of the file are passed as a single argument. content of the file a single string.
texinode(Command Substitution)(Arithmetic Expansion)(Parameter Expansion)(Expansion) texinode(Command Substitution)(Arithmetic Expansion)(Parameter Expansion)(Expansion)
sect(Command Substitution) sect(Command Substitution)
cindex(command substitution) cindex(command substitution)

View file

@ -614,7 +614,7 @@ Thus if `tt(/usr/local/bin)' is in the user's path, and he types
Commands explicitly beginning with `tt(/)', `tt(./)' or `tt(../)' Commands explicitly beginning with `tt(/)', `tt(./)' or `tt(../)'
are not subject to the path search. are not subject to the path search.
This also applies to the tt(.) builtin, This also applies to the tt(.) builtin,
and searches for modules performed by the tt(zmodload) builtin. and to searches for modules performed by the tt(zmodload) builtin.
) )
pindex(POSIX_BUILTINS) pindex(POSIX_BUILTINS)
item(tt(POSIX_BUILTINS))( item(tt(POSIX_BUILTINS))(

View file

@ -175,6 +175,8 @@ sitem(tt(w))(True if the day of the week is equal to var(n) (Sunday = 0).)
sitem(tt(?))(True if the exit status of the last command was var(n).) sitem(tt(?))(True if the exit status of the last command was var(n).)
sitem(tt(#))(True if the effective uid of the current process is var(n).) sitem(tt(#))(True if the effective uid of the current process is var(n).)
sitem(tt(g))(True if the effective gid of the current process is var(n).) sitem(tt(g))(True if the effective gid of the current process is var(n).)
sitem(tt(l))(True if at least var(n) characters have already been
printed on the current line.)
sitem(tt(L))(True if the tt(SHLVL) parameter is at least var(n).) sitem(tt(L))(True if the tt(SHLVL) parameter is at least var(n).)
sitem(tt(S))(True if the tt(SECONDS) parameter is at least var(n).) sitem(tt(S))(True if the tt(SECONDS) parameter is at least var(n).)
sitem(tt(v))(True if the array tt(psvar) has at least var(n) elements.) sitem(tt(v))(True if the array tt(psvar) has at least var(n) elements.)
@ -185,25 +187,40 @@ endsitem()
xitem(tt(%<)var(string)tt(<)) xitem(tt(%<)var(string)tt(<))
xitem(tt(%>)var(string)tt(>)) xitem(tt(%>)var(string)tt(>))
item(tt(%[)var(xstring)tt(]))( item(tt(%[)var(xstring)tt(]))(
Specifies truncation behaviour. Specifies truncation behaviour for the remainder of the prompt string.
The third, deprecated, form is equivalent to `tt(%)var(xstringx)', The third, deprecated, form is equivalent to `tt(%)var(xstringx)',
i.e. var(x) may be `tt(<)' or `tt(>)'. i.e. var(x) may be `tt(<)' or `tt(>)'.
The numeric argument, which in the third form may appear immediately The numeric argument, which in the third form may appear immediately
after the `tt([)', specifies the maximum permitted length of after the `tt([)', specifies the maximum permitted length of
the various strings that can be displayed in the prompt. If this the various strings that can be displayed in the prompt.
integer is zero, or missing, truncation is disabled. Truncation is
initially disabled.
The var(string) will be displayed in The var(string) will be displayed in
place of the truncated portion of any string. place of the truncated portion of any string; note this does not
undergo prompt expansion.
The forms with `tt(<)' truncate at the left of the string, The forms with `tt(<)' truncate at the left of the string,
and the forms with `tt(>)' truncate at the right of the string. and the forms with `tt(>)' truncate at the right of the string.
For example, if the current directory is `tt(/home/pike)', For example, if the current directory is `tt(/home/pike)',
the prompt `tt(%8<..<%/)' will expand to `tt(..e/pike)'. the prompt `tt(%8<..<%/)' will expand to `tt(..e/pike)'.
In this string, the terminating character (`tt(<)', `tt(>)' or `tt(])'), In this string, the terminating character (`tt(<)', `tt(>)' or `tt(])'),
or in fact any character, may be quoted by a preceding `tt(\)'. or in fact any character, may be quoted by a preceding `tt(\)'; note
% escapes are em(not) recognised. when using tt(print -P), however, that this must be doubled as the
string is also subject to standard tt(print) processing, in addition
to any backslashes removed by a double quoted string: the worst case
is therefore `tt(print -P "%<\\\\<<...")'.
If the var(string) is longer than the specified truncation length, If the var(string) is longer than the specified truncation length,
it will appear in full, completely replacing the truncated string. it will appear in full, completely replacing the truncated string.
The part of the prompt string to be truncated runs to the end of the
string, or to the end of the next enclosing group of the `tt(%LPAR())'
construct, or to the next truncation encountered at the same grouping
level (i.e. truncations inside a `tt(%LPAR())' are separate), which
ever comes first. In particular, a truncation with argument zero
(e.g. `tt(%<<)') marks the end of the range of the string to be
truncated while turning off truncation from there on. For example, the
prompt '%10<...<%~%<<%# ' will print a truncated representation of the
current directory, followed by a `tt(%)' or `tt(#)', followed by a
space. Without the `tt(%<<)', those two characters would be included
in the string to be truncated.
) )
enditem() enditem()

View file

@ -5,8 +5,6 @@
# Usage: e.g. # Usage: e.g.
# compctl -D -f + -U -Q -S '' -K multicomp # compctl -D -f + -U -Q -S '' -K multicomp
# #
# Note that exactly matched directories are not expanded, e.g.
# s/zsh-2.4/s<TAB> will not expand to src/zsh-2.4old/src.
# Will expand glob patterns already in the word, but use complete-word, # Will expand glob patterns already in the word, but use complete-word,
# not TAB (expand-or-complete), or you will get ordinary glob expansion. # not TAB (expand-or-complete), or you will get ordinary glob expansion.
# Requires the -U option to compctl. # Requires the -U option to compctl.
@ -42,32 +40,32 @@ while [[ -n "$pref" ]]; do
[[ "$pref" = /* ]] && sofar=(${sofar}/) && pref="${pref#/}" [[ "$pref" = /* ]] && sofar=(${sofar}/) && pref="${pref#/}"
head="${pref%%/*}" head="${pref%%/*}"
pref="${pref#$head}" pref="${pref#$head}"
if [[ -n "$pref" && -z $sofar[2] && -d "${sofar}$head" ]]; then [[ -z "$pref" ]] && globdir=
# Exactly matched directory: don't try to glob # if path segment contains wildcards, don't add another.
reply=("${sofar}$head") if [[ "$head" = *[\[\(\*\?\$\~]* ]]; then
wild=$head
else else
[[ -z "$pref" ]] && globdir= [[ -z "$pref" ]] && globdir=
# if path segment contains wildcards, don't add another. # if path segment contains wildcards, don't add another.
if [[ "$head" = *[\[\(\*\?\$\~]* || -z "$head" ]]; then if [[ "$head" = *[\[\(\*\?\$\~]* || -z "$head" ]]; then
wild=$head wild=$head
else else
# Simulate case-insensitive globbing for ASCII characters # Simulate case-insensitive globbing for ASCII characters
wild="[${(j(][))${(s())head:l}}]*" # :gs/a/[a]/ etc. wild="[${(j(][))${(s())head:l}}]*" # :gs/a/[a]/ etc.
# The following could all be one expansion, but for readability: # The following could all be one expansion, but for readability:
wild=$wild:gs/a/aA/:gs/b/bB/:gs/c/cC/:gs/d/dD/:gs/e/eE/:gs/f/fF/ wild=$wild:gs/a/aA/:gs/b/bB/:gs/c/cC/:gs/d/dD/:gs/e/eE/:gs/f/fF/
wild=$wild:gs/g/gG/:gs/h/hH/:gs/i/iI/:gs/j/jJ/:gs/k/kK/:gs/l/lL/ wild=$wild:gs/g/gG/:gs/h/hH/:gs/i/iI/:gs/j/jJ/:gs/k/kK/:gs/l/lL/
wild=$wild:gs/m/mM/:gs/n/nN/:gs/o/oO/:gs/p/pP/:gs/q/qQ/:gs/r/rR/ wild=$wild:gs/m/mM/:gs/n/nN/:gs/o/oO/:gs/p/pP/:gs/q/qQ/:gs/r/rR/
wild=$wild:gs/s/sS/:gs/t/tT/:gs/u/uU/:gs/v/vV/:gs/w/wW/:gs/x/xX/ wild=$wild:gs/s/sS/:gs/t/tT/:gs/u/uU/:gs/v/vV/:gs/w/wW/:gs/x/xX/
wild=$wild:gs/y/yY/:gs/z/zZ/:gs/-/_/:gs/_/-_/:gs/[]// wild=$wild:gs/y/yY/:gs/z/zZ/:gs/-/_/:gs/_/-_/:gs/[]//
# Expand on both sides of '.' (except when leading) as for '/' # Expand on both sides of '.' (except when leading) as for '/'
wild="${${wild:gs/[.]/*.*/}#\*}" wild="${${wild:gs/[.]/*.*/}#\*}"
fi
reply=(${sofar}"${wild}${globdir}")
reply=(${~reply})
fi fi
reply=(${sofar}"${wild}${globdir}")
reply=(${~reply})
[[ -z $reply[1] ]] && reply=() && break [[ -z $reply[1] ]] && reply=() && break
[[ -n $pref ]] && sofar=($reply) [[ -n $pref ]] && sofar=($reply)
done done
@ -77,4 +75,3 @@ done
[[ -n "$origtop" ]] && reply=("$origtop"${reply#$newtop}) [[ -n "$origtop" ]] && reply=("$origtop"${reply#$newtop})
# } # }

View file

@ -1,3 +1,3 @@
# get a random line from a file # get a random line from a file
integer z=$(wc -l <$1) integer z="$(wc -l <$1)"
sed -n $[RANDOM%z+1]p $1 sed -n $[RANDOM%z+1]p $1

View file

@ -51,6 +51,10 @@ META-FAQ: FORCE
# ========== DEPENDENCIES FOR INSTALLING ========== # ========== DEPENDENCIES FOR INSTALLING ==========
# install stripped
install-strip:
$(MAKE) install STRIPFLAGS="-s"
# install/uninstall everything # install/uninstall everything
install: install.bin install.modules install.man install.info install: install.bin install.modules install.man install.info
uninstall: uninstall.bin uninstall.modules uninstall.man uninstall.info uninstall: uninstall.bin uninstall.modules uninstall.man uninstall.info
@ -71,6 +75,10 @@ install.man uninstall.man:
install.info uninstall.info: install.info uninstall.info:
@cd Doc && $(MAKE) $(MAKEDEFS) $@ @cd Doc && $(MAKE) $(MAKEDEFS) $@
# install/uninstall just the html pages
install.html uninstall.html:
@cd Doc && $(MAKE) $(MAKEDEFS) $@
# ========== DEPENDENCIES FOR CLEANUP ========== # ========== DEPENDENCIES FOR CLEANUP ==========
@@clean.mk@@ @@clean.mk@@

View file

@ -3,6 +3,7 @@
# c2z - environment conversion tool # c2z - environment conversion tool
# Contributed by Bart Schaefer # Contributed by Bart Schaefer
# (Tweaked a bit by Paul Falstad) # (Tweaked a bit by Paul Falstad)
# (Tweaked again by Bart Schaefer)
# #
# This is a quick script to convert csh aliases to zsh aliases/functions. # This is a quick script to convert csh aliases to zsh aliases/functions.
# It also converts the csh environment and local variables to zsh. c2z # It also converts the csh environment and local variables to zsh. c2z
@ -81,7 +82,13 @@ grep -v ! /tmp/cz$$.1 >/tmp/cz$$.3
sed -e "s/'/'"\\\\"''"/g \ sed -e "s/'/'"\\\\"''"/g \
-e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/alias -- \1='"'\2'/" \ -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/alias -- \1='"'\2'/" \
/tmp/cz$$.3 /tmp/cz$$.3
sed -e 's/![:#]*/$/g' \ sed -e 's/>\(&*\)!/>\1|/g' \
-e 's/!\*:q/"$@"/g' \
-e 's/\(![:#]*[^'"$T"']*\):q/"\1"/g' \
-e 's/!\([-0-9][0-9]*\)\(:x\)*/$\2(fc -nl \1)/g' \
-e 's/\$:x(fc/$=(fc/g' \
-e 's/![:#]*\([^'"$T"']\)/$==\1/g' \
-e 's/\$=\(=[^'"$T"']*\):x/$\1/g' \
-e 's/\$cwd/$PWD/' \ -e 's/\$cwd/$PWD/' \
-e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/\1 () { \2 }/' \ -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/\1 () { \2 }/' \
/tmp/cz$$.2 /tmp/cz$$.2
@ -92,6 +99,7 @@ exec < /tmp/cz$$.e
# Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ... # Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ...
sed -e '/^SHLVL/d' \ sed -e '/^SHLVL/d' \
-e '/^PWD/d' \ -e '/^PWD/d' \
-e '/^_=/d' \
-e "s/'/'"\\\\"''"/g \ -e "s/'/'"\\\\"''"/g \
-e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \ -e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \
-e "s/$/'/" -e "s/$/'/"

View file

@ -149,7 +149,7 @@ uninstall.bin: uninstall.bin-here
# install binary, creating install directory if necessary # install binary, creating install directory if necessary
install.bin-here: zsh install.bin-@L@ install.bin-here: zsh install.bin-@L@
$(sdir_top)/mkinstalldirs $(bindir) $(sdir_top)/mkinstalldirs $(bindir)
$(INSTALL_PROGRAM) zsh $(bindir)/zsh-$(VERSION) $(INSTALL_PROGRAM) $(STRIPFLAGS) zsh $(bindir)/zsh-$(VERSION)
if test -f $(bindir)/zsh; then \ if test -f $(bindir)/zsh; then \
rm -f $(bindir)/zsh.old; \ rm -f $(bindir)/zsh.old; \
ln $(bindir)/zsh $(bindir)/zsh.old; \ ln $(bindir)/zsh $(bindir)/zsh.old; \

View file

@ -119,8 +119,9 @@ uninstall.modules: uninstall.modules-here
install.bin-here uninstall.bin-here: install.bin-here uninstall.bin-here:
install.modules-here: install.modules-here:
$(sdir_top)/mkinstalldirs $(MODDIR) modules='$(MODULES)'; \
modules='$(MODULES)'; for mod in $$modules; do \ if test -n "$$modules"; then $(sdir_top)/mkinstalldirs $(MODDIR); fi; \
for mod in $$modules; do \
$(INSTALL_PROGRAM) $$mod $(MODDIR)/$$mod; \ $(INSTALL_PROGRAM) $$mod $(MODDIR)/$$mod; \
done done

View file

@ -2945,7 +2945,7 @@ docompletion(char *s, int lst, int incmd)
ainfo = fainfo = NULL; ainfo = fainfo = NULL;
/* Make sure we have the completion list and compctl. */ /* Make sure we have the completion list and compctl. */
if (makecomplist(s, incmd)) { if (makecomplist(s, incmd, lst)) {
/* Error condition: feeeeeeeeeeeeep(). */ /* Error condition: feeeeeeeeeeeeep(). */
feep(); feep();
goto compend; goto compend;
@ -3029,7 +3029,7 @@ static unsigned long ccont;
/**/ /**/
static int static int
makecomplist(char *s, int incmd) makecomplist(char *s, int incmd, int lst)
{ {
struct cmlist ms; struct cmlist ms;
Cmlist m = cmatcher; Cmlist m = cmatcher;
@ -3062,7 +3062,7 @@ makecomplist(char *s, int incmd)
ccused = newlinklist(); ccused = newlinklist();
ccstack = newlinklist(); ccstack = newlinklist();
makecomplistglobal(s, incmd); makecomplistglobal(s, incmd, lst);
endcmgroup(NULL); endcmgroup(NULL);
@ -3098,12 +3098,14 @@ makecomplist(char *s, int incmd)
/**/ /**/
static void static void
makecomplistglobal(char *os, int incmd) makecomplistglobal(char *os, int incmd, int lst)
{ {
Compctl cc; Compctl cc;
char *s; char *s;
if (inwhat == IN_ENV) if (lst == COMP_WIDGET) {
cc = compwidget->u.cc;
} else if (inwhat == IN_ENV)
/* Default completion for parameter values. */ /* Default completion for parameter values. */
cc = &cc_default; cc = &cc_default;
else if (inwhat == IN_MATH) { else if (inwhat == IN_MATH) {
@ -4413,7 +4415,8 @@ get_user_var(char *nam)
} else { } else {
/* Otherwise it should be a parameter name. */ /* Otherwise it should be a parameter name. */
char **arr = NULL, *val; char **arr = NULL, *val;
if (!(arr = getaparam(nam)) && (val = getsparam(nam))) { if (!(arr = getaparam(nam)) && !(arr = gethparam(nam)) &&
(val = getsparam(nam))) {
arr = (char **)ncalloc(2*sizeof(char *)); arr = (char **)ncalloc(2*sizeof(char *));
arr[0] = val; arr[0] = val;
arr[1] = NULL; arr[1] = NULL;
@ -5026,6 +5029,7 @@ do_single(Cmatch m)
else { else {
p = (char *) ncalloc(strlen(ppre) + strlen(str) + p = (char *) ncalloc(strlen(ppre) + strlen(str) +
strlen(psuf) + 1); strlen(psuf) + 1);
sprintf(p, "%s%s%s", ppre, str, psuf);
} }
parsestr(p); parsestr(p);
if (ic) if (ic)

View file

@ -50,7 +50,7 @@ static struct builtin builtins[] =
BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL), BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL),
BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtux", NULL), BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtux", NULL),
BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL), BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL),
BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL), BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL),
BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
@ -60,7 +60,7 @@ static struct builtin builtins[] =
BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL), BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL),
BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL), BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL), BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZfilrtu", "x"), BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZafilrtu", "x"),
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),
@ -78,7 +78,7 @@ static struct builtin builtins[] =
BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL), BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL),
BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL), BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL),
BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL), BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZilrtu", NULL), BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZailrtu", NULL),
BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL), BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL), BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
@ -93,7 +93,7 @@ static struct builtin builtins[] =
BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL),
BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL), BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL),
BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL), BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL),
BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfiltux", "r"), BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafiltux", "r"),
BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"), BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"),
BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL),
BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL), BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL),
@ -107,7 +107,7 @@ static struct builtin builtins[] =
BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL), BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL),
BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL), BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL),
BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"), BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"),
BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtuxm", NULL), BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtuxm", NULL),
BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"), BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"),
BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"), BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"),
@ -618,6 +618,8 @@ set_pwd_env(void)
{ {
Param pm; Param pm;
/* update the PWD and OLDPWD shell parameters */
pm = (Param) paramtab->getnode(paramtab, "PWD"); pm = (Param) paramtab->getnode(paramtab, "PWD");
if (pm && PM_TYPE(pm->flags) != PM_SCALAR) { if (pm && PM_TYPE(pm->flags) != PM_SCALAR) {
pm->flags &= ~PM_READONLY; pm->flags &= ~PM_READONLY;
@ -704,7 +706,6 @@ bin_cd(char *nam, char **argv, char *ops, int func)
chdir(unmeta(pwd)); chdir(unmeta(pwd));
} }
} }
set_pwd_env();
return 0; return 0;
} }
@ -946,7 +947,6 @@ cd_try_chdir(char *pfix, char *dest, int hard)
static void static void
cd_new_pwd(int func, LinkNode dir, int chaselinks) cd_new_pwd(int func, LinkNode dir, int chaselinks)
{ {
Param pm;
List l; List l;
char *new_pwd, *s; char *new_pwd, *s;
int dirstacksize; int dirstacksize;
@ -981,13 +981,8 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks)
zsfree(oldpwd); zsfree(oldpwd);
oldpwd = pwd; oldpwd = pwd;
pwd = new_pwd; pwd = new_pwd;
/* update the PWD and OLDPWD shell parameters */ set_pwd_env();
if ((pm = (Param) paramtab->getnode(paramtab, "PWD")) &&
(pm->flags & PM_EXPORTED) && pm->env)
pm->env = replenv(pm->env, pwd);
if ((pm = (Param) paramtab->getnode(paramtab, "OLDPWD")) &&
(pm->flags & PM_EXPORTED) && pm->env)
pm->env = replenv(pm->env, oldpwd);
if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE)) if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
printdirstack(); printdirstack();
else if (doprintdir) { else if (doprintdir) {
@ -1474,8 +1469,8 @@ bin_typeset(char *name, char **argv, char *ops, int func)
Param pm; Param pm;
Asgment asg; Asgment asg;
Comp com; Comp com;
char *optstr = "iLRZlurtxU"; char *optstr = "aiLRZlurtxU----A";
int on = 0, off = 0, roff, bit = PM_INTEGER; int on = 0, off = 0, roff, bit = PM_ARRAY;
int initon, initoff, of, i; int initon, initoff, of, i;
int returnval = 0, printflags = 0; int returnval = 0, printflags = 0;
@ -1506,6 +1501,8 @@ bin_typeset(char *name, char **argv, char *ops, int func)
off |= PM_LOWER; off |= PM_LOWER;
if (on & PM_LOWER) if (on & PM_LOWER)
off |= PM_UPPER; off |= PM_UPPER;
if (on & PM_HASHED)
off |= PM_ARRAY;
on &= ~off; on &= ~off;
/* Given no arguments, list whatever the options specify. */ /* Given no arguments, list whatever the options specify. */
@ -1548,8 +1545,15 @@ bin_typeset(char *name, char **argv, char *ops, int func)
if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) && if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
!(pm->flags & PM_READONLY & ~off)) !(pm->flags & PM_READONLY & ~off))
uniqarray((*pm->gets.afn) (pm)); uniqarray((*pm->gets.afn) (pm));
if ((on & ~pm->flags) & PM_HASHED) {
char *nam = ztrdup(pm->nam);
unsetparam(nam);
pm = createparam(nam, on & ~PM_READONLY);
DPUTS(!pm, "BUG: parameter not created");
}
pm->flags = (pm->flags | on) & ~off; pm->flags = (pm->flags | on) & ~off;
if (PM_TYPE(pm->flags) != PM_ARRAY) { if (PM_TYPE(pm->flags) != PM_ARRAY &&
PM_TYPE(pm->flags) != PM_HASHED) {
if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen) if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen)
pm->ct = auxlen; pm->ct = auxlen;
/* did we just export this? */ /* did we just export this? */
@ -1598,7 +1602,8 @@ bin_typeset(char *name, char **argv, char *ops, int func)
(((pm->flags & PM_SPECIAL) && pm->level == locallevel) || (((pm->flags & PM_SPECIAL) && pm->level == locallevel) ||
(!(pm->flags & PM_UNSET) && (!(pm->flags & PM_UNSET) &&
((locallevel == pm->level) || func == BIN_EXPORT) && ((locallevel == pm->level) || func == BIN_EXPORT) &&
!(bit = ((off & pm->flags) | (on & ~pm->flags)) & PM_INTEGER)))) { !(bit = (((off & pm->flags) | (on & ~pm->flags)) &
(PM_INTEGER|PM_HASHED)))))) {
/* if no flags or values are given, just print this parameter */ /* if no flags or values are given, just print this parameter */
if (!on && !roff && !asg->value) { if (!on && !roff && !asg->value) {
paramtab->printnode((HashNode) pm, 0); paramtab->printnode((HashNode) pm, 0);
@ -1623,7 +1628,8 @@ bin_typeset(char *name, char **argv, char *ops, int func)
if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
auxlen) auxlen)
pm->ct = auxlen; pm->ct = auxlen;
if (PM_TYPE(pm->flags) != PM_ARRAY) { if (PM_TYPE(pm->flags) != PM_ARRAY &&
PM_TYPE(pm->flags) != PM_HASHED) {
if (pm->flags & PM_EXPORTED) { if (pm->flags & PM_EXPORTED) {
if (!(pm->flags & PM_UNSET) && !pm->env && !asg->value) if (!(pm->flags & PM_UNSET) && !pm->env && !asg->value)
pm->env = addenv(asg->name, getsparam(asg->name)); pm->env = addenv(asg->name, getsparam(asg->name));

View file

@ -1004,11 +1004,12 @@ void
untokenize(char *s) untokenize(char *s)
{ {
for (; *s; s++) for (; *s; s++)
if (itok(*s)) if (itok(*s)) {
if (*s == Nularg) if (*s == Nularg)
chuck(s--); chuck(s--);
else else
*s = ztokens[*s - Pound]; *s = ztokens[*s - Pound];
}
} }
/* Open a file for writing redicection */ /* Open a file for writing redicection */
@ -1923,22 +1924,8 @@ save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p)
} else if (!(pm->flags & PM_READONLY) && } else if (!(pm->flags & PM_READONLY) &&
(unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) { (unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) {
Param tpm = (Param) alloc(sizeof *tpm); Param tpm = (Param) alloc(sizeof *tpm);
tpm->nam = s; tpm->nam = s;
tpm->flags = pm->flags; copyparam(tpm, pm, 1);
switch (PM_TYPE(pm->flags)) {
case PM_SCALAR:
tpm->u.str = ztrdup(pm->gets.cfn(pm));
break;
case PM_INTEGER:
tpm->u.val = pm->gets.ifn(pm);
break;
case PM_ARRAY:
PERMALLOC {
tpm->u.arr = arrdup(pm->gets.afn(pm));
} LASTALLOC;
break;
}
pm = tpm; pm = tpm;
} }
addlinknode(*remove_p, s); addlinknode(*remove_p, s);
@ -1989,6 +1976,9 @@ restore_params(LinkList restorelist, LinkList removelist)
case PM_ARRAY: case PM_ARRAY:
tpm->sets.afn(tpm, pm->u.arr); tpm->sets.afn(tpm, pm->u.arr);
break; break;
case PM_HASHED:
tpm->sets.hfn(tpm, pm->u.hash);
break;
} }
} else } else
paramtab->addnode(paramtab, pm->nam, pm); paramtab->addnode(paramtab, pm->nam, pm);

View file

@ -355,21 +355,12 @@ scanner(Complist q)
insert(c->str, 0); insert(c->str, 0);
} else { } else {
/* Do pattern matching on current path section. */ /* Do pattern matching on current path section. */
char *fn; char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : ".";
int dirs = !!q->next; int dirs = !!q->next;
DIR *lock; DIR *lock = opendir(fn);
char *subdirs = NULL; char *subdirs = NULL;
int subdirlen = 0; int subdirlen = 0;
fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : ".";
if (dirs) {
struct stat st;
stat(fn, &st);
/* a directory with subdirectories has link count greater than 2 */
if (!S_ISDIR(st.st_mode) || st.st_nlink == 2)
return;
}
lock = opendir(fn);
if (lock == NULL) if (lock == NULL)
return; return;
while ((fn = zreaddir(lock, 1)) && !errflag) { while ((fn = zreaddir(lock, 1)) && !errflag) {
@ -594,7 +585,8 @@ parsecomp(int gflag)
pptr[1] && pptr[1] != Outpar && pptr[1] != Bar) || pptr[1] && pptr[1] != Outpar && pptr[1] != Bar) ||
*pptr == Outpar) { *pptr == Outpar) {
if (*pptr == '/' || !*pptr || if (*pptr == '/' || !*pptr ||
(isset(EXTENDEDGLOB) && *pptr == Tilde && ((*pptr == Bar ||
(isset(EXTENDEDGLOB) && *pptr == Tilde)) &&
(gflag & GF_TOPLEV))) (gflag & GF_TOPLEV)))
c->stat |= C_LAST; c->stat |= C_LAST;
return c; return c;
@ -746,7 +738,8 @@ parsecomp(int gflag)
} }
/* mark if last pattern component in path component or pattern */ /* mark if last pattern component in path component or pattern */
if (*pptr == '/' || !*pptr || if (*pptr == '/' || !*pptr ||
(isset(EXTENDEDGLOB) && *pptr == Tilde && (gflag & GF_TOPLEV))) ((*pptr == Bar ||
(isset(EXTENDEDGLOB) && *pptr == Tilde)) && (gflag & GF_TOPLEV)))
c->stat |= C_LAST; c->stat |= C_LAST;
c->str = dupstrpfx(cstr, pptr - cstr); c->str = dupstrpfx(cstr, pptr - cstr);
return c; return c;

View file

@ -1061,93 +1061,6 @@ printaliasnode(HashNode hn, int printflags)
putchar('\n'); putchar('\n');
} }
/**********************************/
/* Parameter Hash Table Functions */
/**********************************/
/**/
void
freeparamnode(HashNode hn)
{
Param pm = (Param) hn;
zsfree(pm->nam);
zfree(pm, sizeof(struct param));
}
/* Print a parameter */
/**/
void
printparamnode(HashNode hn, int printflags)
{
Param p = (Param) hn;
char *t, **u;
if (p->flags & PM_UNSET)
return;
/* Print the attributes of the parameter */
if (printflags & PRINT_TYPE) {
if (p->flags & PM_INTEGER)
printf("integer ");
if (p->flags & PM_ARRAY)
printf("array ");
if (p->flags & PM_LEFT)
printf("left justified %d ", p->ct);
if (p->flags & PM_RIGHT_B)
printf("right justified %d ", p->ct);
if (p->flags & PM_RIGHT_Z)
printf("zero filled %d ", p->ct);
if (p->flags & PM_LOWER)
printf("lowercase ");
if (p->flags & PM_UPPER)
printf("uppercase ");
if (p->flags & PM_READONLY)
printf("readonly ");
if (p->flags & PM_TAGGED)
printf("tagged ");
if (p->flags & PM_EXPORTED)
printf("exported ");
}
if (printflags & PRINT_NAMEONLY) {
zputs(p->nam, stdout);
putchar('\n');
return;
}
/* How the value is displayed depends *
* on the type of the parameter */
quotedzputs(p->nam, stdout);
putchar('=');
switch (PM_TYPE(p->flags)) {
case PM_SCALAR:
/* string: simple output */
if (p->gets.cfn && (t = p->gets.cfn(p)))
quotedzputs(t, stdout);
putchar('\n');
break;
case PM_INTEGER:
/* integer */
printf("%ld\n", p->gets.ifn(p));
break;
case PM_ARRAY:
/* array */
putchar('(');
u = p->gets.afn(p);
if(*u) {
quotedzputs(*u++, stdout);
while (*u) {
putchar(' ');
quotedzputs(*u++, stdout);
}
}
printf(")\n");
break;
}
}
/****************************************/ /****************************************/
/* Named Directory Hash Table Functions */ /* Named Directory Hash Table Functions */
/****************************************/ /****************************************/

View file

@ -176,7 +176,7 @@ shingetline(void)
int int
ingetc(void) ingetc(void)
{ {
char lastc; int lastc;
if (lexstop) if (lexstop)
return ' '; return ' ';

View file

@ -232,6 +232,11 @@ 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
@ -247,7 +252,137 @@ static Param argvparam;
/**/ /**/
HashTable paramtab; HashTable paramtab;
/**/
HashTable
newparamtable(int size, char const *name)
{
HashTable ht = newhashtable(size, name, NULL);
ht->hash = hasher;
ht->emptytable = emptyhashtable;
ht->filltable = NULL;
ht->addnode = addhashnode;
ht->getnode = gethashnode2;
ht->getnode2 = gethashnode2;
ht->removenode = removehashnode;
ht->disablenode = NULL;
ht->enablenode = NULL;
ht->freenode = freeparamnode;
ht->printnode = printparamnode;
return ht;
}
/* Copy a parameter hash table */
static HashTable outtable;
/**/
static void
scancopyparams(HashNode hn, int flags)
{
/* Going into a real parameter, so always use permanent storage */
Param pm = (Param)hn;
Param tpm = (Param) zcalloc(sizeof *tpm);
tpm->nam = ztrdup(pm->nam);
copyparam(tpm, pm, 0);
addhashnode(outtable, tpm->nam, tpm);
}
/**/
HashTable
copyparamtable(HashTable ht, char *name)
{
HashTable nht = newparamtable(ht->hsize, name);
outtable = nht;
scanhashtable(ht, 0, 0, 0, scancopyparams, 0);
outtable = NULL;
return nht;
}
#define SCANPM_WANTVALS (1<<0)
#define SCANPM_WANTKEYS (1<<1)
#define SCANPM_WANTINDEX (1<<2)
static unsigned numparamvals;
/**/
static void
scancountparams(HashNode hn, int flags)
{
if (!(((Param)hn)->flags & PM_UNSET)) {
++numparamvals;
if ((flags & SCANPM_WANTKEYS) && (flags & SCANPM_WANTVALS))
++numparamvals;
}
}
static char **paramvals;
/**/
static void
scanparamvals(HashNode hn, int flags)
{
struct value v;
v.pm = (Param)hn;
if (!(v.pm->flags & PM_UNSET)) {
if (flags & SCANPM_WANTKEYS) {
paramvals[numparamvals++] = v.pm->nam;
if (!(flags & SCANPM_WANTVALS))
return;
}
v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED));
v.inv = (flags & SCANPM_WANTINDEX);
v.a = 0;
v.b = -1;
paramvals[numparamvals++] = getstrvalue(&v);
}
}
/**/
char **
paramvalarr(HashTable ht, unsigned flags)
{
MUSTUSEHEAP("paramvalarr");
numparamvals = 0;
if (ht)
scanhashtable(ht, 0, 0, 0, scancountparams, flags);
paramvals = (char **) alloc((numparamvals + 1) * sizeof(char *));
if (ht) {
numparamvals = 0;
scanhashtable(ht, 0, 0, 0, scanparamvals, flags);
}
paramvals[numparamvals] = 0;
return paramvals;
}
/* Return the full array (no indexing) referred to by a Value. *
* The array value is cached for the lifetime of the Value. */
/**/
static char **
getvaluearr(Value v)
{
if (v->arr)
return v->arr;
else if (PM_TYPE(v->pm->flags) == PM_ARRAY)
return v->arr = v->pm->gets.afn(v->pm);
else if (PM_TYPE(v->pm->flags) == PM_HASHED) {
unsigned flags = 0;
if (v->a)
flags |= SCANPM_WANTKEYS;
if (v->b > v->a)
flags |= SCANPM_WANTVALS;
v->arr = paramvalarr(v->pm->gets.hfn(v->pm), flags);
/* Can't take numeric slices of associative arrays */
v->a = 0;
v->b = -1;
return v->arr;
} else
return NULL;
}
/* Set up parameter hash table. This will add predefined * /* Set up parameter hash table. This will add predefined *
* parameter entries as well as setting up parameter table * * parameter entries as well as setting up parameter table *
* entries for environment variables we inherit. */ * entries for environment variables we inherit. */
@ -261,19 +396,7 @@ createparamtable(void)
char buf[50], *str, *iname; char buf[50], *str, *iname;
int num_env; int num_env;
paramtab = newhashtable(151, "paramtab", NULL); paramtab = newparamtable(151, "paramtab");
paramtab->hash = hasher;
paramtab->emptytable = NULL;
paramtab->filltable = NULL;
paramtab->addnode = addhashnode;
paramtab->getnode = gethashnode2;
paramtab->getnode2 = gethashnode2;
paramtab->removenode = removehashnode;
paramtab->disablenode = NULL;
paramtab->enablenode = NULL;
paramtab->freenode = freeparamnode;
paramtab->printnode = printparamnode;
/* Add the special parameters to the hash table */ /* Add the special parameters to the hash table */
for (ip = special_params; ip->nam; ip++) for (ip = special_params; ip->nam; ip++)
@ -368,6 +491,36 @@ createparamtable(void)
noerrs = 0; noerrs = 0;
} }
/* assign various functions used for non-special parameters */
/**/
static void
assigngetset(Param pm)
{
switch (PM_TYPE(pm->flags)) {
case PM_SCALAR:
pm->sets.cfn = strsetfn;
pm->gets.cfn = strgetfn;
break;
case PM_INTEGER:
pm->sets.ifn = intsetfn;
pm->gets.ifn = intgetfn;
break;
case PM_ARRAY:
pm->sets.afn = arrsetfn;
pm->gets.afn = arrgetfn;
break;
case PM_HASHED:
pm->sets.hfn = hashsetfn;
pm->gets.hfn = hashgetfn;
break;
default:
DPUTS(1, "BUG: tried to create param node without valid flag");
break;
}
pm->unsetfn = stdunsetfn;
}
/* Create a parameter, so that it can be assigned to. Returns NULL if the * /* Create a parameter, so that it can be assigned to. Returns NULL if the *
* parameter already exists or can't be created, otherwise returns the * * parameter already exists or can't be created, otherwise returns the *
* parameter node. If a parameter of the same name exists in an outer * * parameter node. If a parameter of the same name exists in an outer *
@ -413,27 +566,51 @@ createparam(char *name, int flags)
pm = (Param) alloc(sizeof *pm); pm = (Param) alloc(sizeof *pm);
pm->flags = flags; pm->flags = flags;
if(!(pm->flags & PM_SPECIAL)) { if(!(pm->flags & PM_SPECIAL))
switch (PM_TYPE(flags)) { assigngetset(pm);
return pm;
}
/* Copy a parameter */
/**/
void
copyparam(Param tpm, Param pm, int toplevel)
{
/*
* Note that tpm, into which we're copying, may not be in permanent
* storage. However, the values themselves are later used directly
* to set the parameter, so must be permanently allocated (in accordance
* with sets.?fn() usage).
*/
PERMALLOC {
tpm->flags = pm->flags;
if (!toplevel)
tpm->flags &= ~PM_SPECIAL;
switch (PM_TYPE(pm->flags)) {
case PM_SCALAR: case PM_SCALAR:
pm->sets.cfn = strsetfn; tpm->u.str = ztrdup(pm->gets.cfn(pm));
pm->gets.cfn = strgetfn;
break; break;
case PM_INTEGER: case PM_INTEGER:
pm->sets.ifn = intsetfn; tpm->u.val = pm->gets.ifn(pm);
pm->gets.ifn = intgetfn;
break; break;
case PM_ARRAY: case PM_ARRAY:
pm->sets.afn = arrsetfn; tpm->u.arr = arrdup(pm->gets.afn(pm));
pm->gets.afn = arrgetfn;
break; break;
default: case PM_HASHED:
DPUTS(1, "BUG: tried to create param node without valid flag"); tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam);
break; break;
} }
pm->unsetfn = stdunsetfn; } LASTALLOC;
} /*
return pm; * If called from inside an associative array, that array is later going
* to be passed as a real parameter, so we need the gets and sets
* functions to be useful. However, the saved associated array is
* not itself special, so we just use the standard ones.
* This is also why we switch off PM_SPECIAL.
*/
if (!toplevel)
assigngetset(tpm);
} }
/* Return 1 if the string s is a valid identifier, else return 0. */ /* Return 1 if the string s is a valid identifier, else return 0. */
@ -577,6 +754,23 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
singsub(&s); singsub(&s);
if (!rev) { if (!rev) {
if (PM_TYPE(v->pm->flags) == PM_HASHED) {
HashTable ht = v->pm->gets.hfn(v->pm);
if (!ht) {
ht = newparamtable(17, v->pm->nam);
v->pm->sets.hfn(v->pm, ht);
}
if (!(v->pm = (Param) ht->getnode(ht, s))) {
HashTable tht = paramtab;
paramtab = ht;
v->pm = createparam(s, PM_SCALAR|PM_UNSET);
paramtab = tht;
}
v->isarr = 0;
v->a = 0;
*w = v->b = -1;
r = isset(KSHARRAYS) ? 1 : 0;
} else
if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0)) if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0))
r++; r++;
if (word && !v->isarr) { if (word && !v->isarr) {
@ -799,11 +993,12 @@ getvalue(char **pptr, int bracks)
s = t = *pptr; s = t = *pptr;
garr = NULL; garr = NULL;
if (idigit(*s)) if (idigit(*s)) {
if (bracks >= 0) if (bracks >= 0)
ppar = zstrtol(s, &s, 10); ppar = zstrtol(s, &s, 10);
else else
ppar = *s++ - '0'; ppar = *s++ - '0';
}
else if (iident(*s)) else if (iident(*s))
while (iident(*s)) while (iident(*s))
s++; s++;
@ -844,7 +1039,7 @@ getvalue(char **pptr, int bracks)
if (!pm || (pm->flags & PM_UNSET)) if (!pm || (pm->flags & PM_UNSET))
return NULL; return NULL;
v = (Value) hcalloc(sizeof *v); v = (Value) hcalloc(sizeof *v);
if (PM_TYPE(pm->flags) == PM_ARRAY) if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))
v->isarr = isvarat ? -1 : 1; v->isarr = isvarat ? -1 : 1;
v->pm = pm; v->pm = pm;
v->inv = 0; v->inv = 0;
@ -863,12 +1058,12 @@ getvalue(char **pptr, int bracks)
*pptr = s; *pptr = s;
if (v->a > MAX_ARRLEN || if (v->a > MAX_ARRLEN ||
v->a < -MAX_ARRLEN) { v->a < -MAX_ARRLEN) {
zerr("subscript to %s: %d", (v->a < 0) ? "small" : "big", v->a); zerr("subscript too %s: %d", (v->a < 0) ? "small" : "big", v->a);
return NULL; return NULL;
} }
if (v->b > MAX_ARRLEN || if (v->b > MAX_ARRLEN ||
v->b < -MAX_ARRLEN) { v->b < -MAX_ARRLEN) {
zerr("subscript to %s: %d", (v->b < 0) ? "small" : "big", v->b); zerr("subscript too %s: %d", (v->b < 0) ? "small" : "big", v->b);
return NULL; return NULL;
} }
return v; return v;
@ -891,11 +1086,12 @@ getstrvalue(Value v)
} }
switch(PM_TYPE(v->pm->flags)) { switch(PM_TYPE(v->pm->flags)) {
case PM_HASHED:
case PM_ARRAY: case PM_ARRAY:
ss = getvaluearr(v);
if (v->isarr) if (v->isarr)
s = sepjoin(v->pm->gets.afn(v->pm), NULL); s = sepjoin(ss, NULL);
else { else {
ss = v->pm->gets.afn(v->pm);
if (v->a < 0) if (v->a < 0)
v->a += arrlen(ss); v->a += arrlen(ss);
s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a]; s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a];
@ -913,8 +1109,9 @@ getstrvalue(Value v)
break; break;
} }
if (v->a == 0 && v->b == -1) if (v->a == 0 && v->b == -1) {
LASTALLOC_RETURN s; LASTALLOC_RETURN s;
}
if (v->a < 0) if (v->a < 0)
v->a += strlen(s); v->a += strlen(s);
if (v->b < 0) if (v->b < 0)
@ -946,7 +1143,7 @@ getarrvalue(Value v)
s[0] = dupstring(buf); s[0] = dupstring(buf);
return s; return s;
} }
s = v->pm->gets.afn(v->pm); s = getvaluearr(v);
if (v->a == 0 && v->b == -1) if (v->a == 0 && v->b == -1)
return s; return s;
if (v->a < 0) if (v->a < 0)
@ -993,6 +1190,7 @@ setstrvalue(Value v, char *val)
zsfree(val); zsfree(val);
return; return;
} }
v->pm->flags &= ~PM_UNSET;
switch (PM_TYPE(v->pm->flags)) { switch (PM_TYPE(v->pm->flags)) {
case PM_SCALAR: case PM_SCALAR:
MUSTUSEHEAP("setstrvalue"); MUSTUSEHEAP("setstrvalue");
@ -1103,17 +1301,25 @@ setarrvalue(Value v, char **val)
freearray(val); freearray(val);
return; return;
} }
if (PM_TYPE(v->pm->flags) != PM_ARRAY) { if (PM_TYPE(v->pm->flags) & ~(PM_ARRAY|PM_HASHED)) {
freearray(val); freearray(val);
zerr("attempt to assign array value to non-array", NULL, 0); zerr("attempt to assign array value to non-array", NULL, 0);
return; return;
} }
if (v->a == 0 && v->b == -1) if (v->a == 0 && v->b == -1) {
(v->pm->sets.afn) (v->pm, val); if (PM_TYPE(v->pm->flags) == PM_HASHED)
else { arrhashsetfn(v->pm, val);
else
(v->pm->sets.afn) (v->pm, val);
} else {
char **old, **new, **p, **q, **r; char **old, **new, **p, **q, **r;
int n, ll, i; int n, ll, i;
if ((PM_TYPE(v->pm->flags) == PM_HASHED)) {
freearray(val);
zerr("attempt to set slice of associative array", NULL, 0);
return;
}
if (v->inv && unset(KSHARRAYS)) if (v->inv && unset(KSHARRAYS))
v->a--, v->b--; v->a--, v->b--;
q = old = v->pm->gets.afn(v->pm); q = old = v->pm->gets.afn(v->pm);
@ -1187,6 +1393,20 @@ getaparam(char *s)
return NULL; return NULL;
} }
/* Retrieve an assoc array parameter as an array */
/**/
char **
gethparam(char *s)
{
Value v;
if (!idigit(*s) && (v = getvalue(&s, 0)) &&
PM_TYPE(v->pm->flags) == PM_HASHED)
return paramvalarr(v->pm->gets.hfn(v->pm), SCANPM_WANTVALS);
return NULL;
}
/**/ /**/
Param Param
setsparam(char *s, char *val) setsparam(char *s, char *val)
@ -1248,7 +1468,7 @@ setaparam(char *s, char **val)
} else { } else {
if (!(v = getvalue(&s, 1))) if (!(v = getvalue(&s, 1)))
createparam(t, PM_ARRAY); createparam(t, PM_ARRAY);
else if (PM_TYPE(v->pm->flags) != PM_ARRAY && else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
!(v->pm->flags & PM_SPECIAL)) { !(v->pm->flags & PM_SPECIAL)) {
int uniq = v->pm->flags & PM_UNIQUE; int uniq = v->pm->flags & PM_UNIQUE;
unsetparam(t); unsetparam(t);
@ -1338,7 +1558,7 @@ unsetparam_pm(Param pm, int altflag, int exp)
* is called. Beyond that, there is an ambiguity: should * * is called. Beyond that, there is an ambiguity: should *
* foo() { local bar; unset bar; } make the global bar * * foo() { local bar; unset bar; } make the global bar *
* available or not? The following makes the answer "no". */ * available or not? The following makes the answer "no". */
if (locallevel >= pm->level) if ((locallevel && locallevel >= pm->level) || (pm->flags & PM_SPECIAL))
return; return;
paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */ paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */
@ -1363,6 +1583,7 @@ stdunsetfn(Param pm, int exp)
switch (PM_TYPE(pm->flags)) { switch (PM_TYPE(pm->flags)) {
case PM_SCALAR: pm->sets.cfn(pm, NULL); break; case PM_SCALAR: pm->sets.cfn(pm, NULL); break;
case PM_ARRAY: pm->sets.afn(pm, NULL); break; case PM_ARRAY: pm->sets.afn(pm, NULL); break;
case PM_HASHED: pm->sets.hfn(pm, NULL); break;
} }
pm->flags |= PM_UNSET; pm->flags |= PM_UNSET;
} }
@ -1429,6 +1650,70 @@ arrsetfn(Param pm, char **x)
pm->u.arr = x; pm->u.arr = x;
} }
/* Function to get value of an association parameter */
/**/
static HashTable
hashgetfn(Param pm)
{
return pm->u.hash;
}
/* Flag to freeparamnode to unset the struct */
static int delunset;
/* Function to set value of an association parameter */
/**/
static void
hashsetfn(Param pm, HashTable x)
{
if (pm->u.hash && pm->u.hash != x) {
/* The parameters in the hash table need to be unset *
* before being deleted. */
int odelunset = delunset;
delunset = 1;
deletehashtable(pm->u.hash);
delunset = odelunset;
}
pm->u.hash = x;
}
/* Function to set value of an association parameter using key/value pairs */
/**/
static void
arrhashsetfn(Param pm, char **val)
{
/* Best not to shortcut this by using the existing hash table, *
* since that could cause trouble for special hashes. This way, *
* it's up to pm->sets.hfn() what to do. */
int alen = arrlen(val);
HashTable opmtab = paramtab, ht;
char **aptr = val;
Value v = (Value) hcalloc(sizeof *v);
v->b = -1;
if (alen % 2) {
freearray(val);
zerr("bad set of key/value pairs for associative array\n",
NULL, 0);
return;
}
ht = paramtab = newparamtable(17, pm->nam);
while (*aptr) {
/* The parameter name is ztrdup'd... */
v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
zsfree(*aptr++);
/* ...but we can use the value without copying. */
setstrvalue(v, *aptr++);
}
paramtab = opmtab;
pm->sets.hfn(pm, ht);
free(val); /* not freearray() */
}
/* This function is used as the set function for * /* This function is used as the set function for *
* special parameters that cannot be set by the user. */ * special parameters that cannot be set by the user. */
@ -2189,3 +2474,107 @@ scanendscope(HashNode hn, int flags)
if(pm->level > locallevel) if(pm->level > locallevel)
unsetparam_pm(pm, 0, 0); unsetparam_pm(pm, 0, 0);
} }
/**********************************/
/* Parameter Hash Table Functions */
/**********************************/
/**/
void
freeparamnode(HashNode hn)
{
Param pm = (Param) hn;
/* Since the second flag to unsetfn isn't used, I don't *
* know what its value should be. */
if (delunset)
pm->unsetfn(pm, 1);
zsfree(pm->nam);
zfree(pm, sizeof(struct param));
}
/* Print a parameter */
/**/
void
printparamnode(HashNode hn, int printflags)
{
Param p = (Param) hn;
char *t, **u;
if (p->flags & PM_UNSET)
return;
/* Print the attributes of the parameter */
if (printflags & PRINT_TYPE) {
if (p->flags & PM_INTEGER)
printf("integer ");
else if (p->flags & PM_ARRAY)
printf("array ");
else if (p->flags & PM_HASHED)
printf("association ");
if (p->flags & PM_LEFT)
printf("left justified %d ", p->ct);
if (p->flags & PM_RIGHT_B)
printf("right justified %d ", p->ct);
if (p->flags & PM_RIGHT_Z)
printf("zero filled %d ", p->ct);
if (p->flags & PM_LOWER)
printf("lowercase ");
if (p->flags & PM_UPPER)
printf("uppercase ");
if (p->flags & PM_READONLY)
printf("readonly ");
if (p->flags & PM_TAGGED)
printf("tagged ");
if (p->flags & PM_EXPORTED)
printf("exported ");
}
if (printflags & PRINT_NAMEONLY) {
zputs(p->nam, stdout);
putchar('\n');
return;
}
/* How the value is displayed depends *
* on the type of the parameter */
quotedzputs(p->nam, stdout);
putchar('=');
switch (PM_TYPE(p->flags)) {
case PM_SCALAR:
/* string: simple output */
if (p->gets.cfn && (t = p->gets.cfn(p)))
quotedzputs(t, stdout);
putchar('\n');
break;
case PM_INTEGER:
/* integer */
printf("%ld\n", p->gets.ifn(p));
break;
case PM_ARRAY:
/* array */
putchar('(');
u = p->gets.afn(p);
if(*u) {
quotedzputs(*u++, stdout);
while (*u) {
putchar(' ');
quotedzputs(*u++, stdout);
}
}
printf(")\n");
break;
case PM_HASHED:
/* association */
putchar('(');
{
HashTable ht = p->gets.hfn(p);
if (ht)
scanhashtable(ht, 0, 0, 0, ht->printnode, 0);
}
printf(")\n");
break;
}
}

View file

@ -71,6 +71,10 @@ static int bufspc;
static char *bp; static char *bp;
/* Position of the start of the current line in the buffer */
static char *bufline;
/* bp1 is an auxilliary pointer into the buffer, which when non-NULL is * /* bp1 is an auxilliary pointer into the buffer, which when non-NULL is *
* moved whenever the buffer is reallocated. It is used when data is * * moved whenever the buffer is reallocated. It is used when data is *
* being temporarily held in the buffer. */ * being temporarily held in the buffer. */
@ -81,11 +85,9 @@ static char *bp1;
static char *fm; static char *fm;
/* Current truncation string (metafied), the length at which truncation * /* Non-zero if truncating the current segment of the buffer. */
* occurs, and the direction in which it occurs. */
static char *truncstr; static int trunclen;
static int trunclen, truncatleft;
/* Current level of nesting of %{ / %} sequences. */ /* Current level of nesting of %{ / %} sequences. */
@ -95,10 +97,6 @@ static int dontcount;
static char *rstring, *Rstring; static char *rstring, *Rstring;
/* If non-zero, Inpar, Outpar and Nularg can be added to the buffer. */
static int nonsp;
/* Perform prompt expansion on a string, putting the result in a * /* Perform prompt expansion on a string, putting the result in a *
* permanently-allocated string. If ns is non-zero, this string * * permanently-allocated string. If ns is non-zero, this string *
* may have embedded Inpar and Outpar, which indicate a toggling * * may have embedded Inpar and Outpar, which indicate a toggling *
@ -130,9 +128,8 @@ promptexpand(char *s, int ns, char *rs, char *Rs)
rstring = rs; rstring = rs;
Rstring = Rs; Rstring = Rs;
nonsp = ns;
fm = s; fm = s;
bp = buf = zalloc(bufspc = 256); bp = bufline = buf = zalloc(bufspc = 256);
bp1 = NULL; bp1 = NULL;
trunclen = 0; trunclen = 0;
putpromptchar(1, '\0'); putpromptchar(1, '\0');
@ -140,6 +137,15 @@ promptexpand(char *s, int ns, char *rs, char *Rs)
if(dontcount) if(dontcount)
*bp++ = Outpar; *bp++ = Outpar;
*bp = 0; *bp = 0;
if (!ns) {
/* If zero, Inpar, Outpar and Nularg should be removed. */
for (bp = buf; *bp; bp++) {
if (*bp == Meta)
bp++;
else if (*bp == Inpar || *bp == Outpar || *bp == Nularg)
chuck(bp);
}
}
return buf; return buf;
} }
@ -164,7 +170,7 @@ putpromptchar(int doprint, int endchar)
arg = zstrtol(fm, &fm, 10); arg = zstrtol(fm, &fm, 10);
} }
if (*fm == '(') { if (*fm == '(') {
int tc; int tc, otrunclen;
if (idigit(*++fm)) { if (idigit(*++fm)) {
arg = zstrtol(fm, &fm, 10); arg = zstrtol(fm, &fm, 10);
@ -224,6 +230,12 @@ putpromptchar(int doprint, int endchar)
if (getegid() == arg) if (getegid() == arg)
test = 1; test = 1;
break; break;
case 'l':
*bp = '\0';
countprompt(bufline, &t0, 0);
if (t0 >= arg)
test = 1;
break;
case 'L': case 'L':
if (shlvl >= arg) if (shlvl >= arg)
test = 1; test = 1;
@ -249,10 +261,15 @@ putpromptchar(int doprint, int endchar)
if (!*fm || !(sep = *++fm)) if (!*fm || !(sep = *++fm))
return 0; return 0;
fm++; fm++;
/* Don't do the current truncation until we get back */
otrunclen = trunclen;
trunclen = 0;
if (!putpromptchar(test == 1 && doprint, sep) || !*++fm || if (!putpromptchar(test == 1 && doprint, sep) || !*++fm ||
!putpromptchar(test == 0 && doprint, ')')) { !putpromptchar(test == 0 && doprint, ')')) {
trunclen = otrunclen;
return 0; return 0;
} }
trunclen = otrunclen;
continue; continue;
} }
if (!doprint) if (!doprint)
@ -377,72 +394,24 @@ putpromptchar(int doprint, int endchar)
tsetcap(TCUNDERLINEEND, 1); tsetcap(TCUNDERLINEEND, 1);
break; break;
case '[': case '[':
if (idigit(*++fm)) if (idigit(*++fm))
trunclen = zstrtol(fm, &fm, 10); arg = zstrtol(fm, &fm, 10);
else if (!prompttrunc(arg, ']', doprint, endchar))
trunclen = arg; return *fm;
if (trunclen) {
truncatleft = *fm && *fm != ']' && *fm++ == '<';
bp1 = bp;
while (*fm && *fm != ']') {
if (*fm == '\\' && fm[1])
++fm;
addbufspc(1);
*bp++ = *fm++;
}
addbufspc(2);
if (bp1 == bp)
*bp++ = '<';
*bp = '\0';
zsfree(truncstr);
truncstr = ztrdup(bp = bp1);
bp1 = NULL;
} else {
while (*fm && *fm != ']') {
if (*fm == '\\' && fm[1])
fm++;
fm++;
}
}
if(!*fm)
return 0;
break; break;
case '<': case '<':
case '>': case '>':
if((trunclen = arg)) { if (!prompttrunc(arg, *fm, doprint, endchar))
char ch = *fm++; return *fm;
truncatleft = ch == '<';
bp1 = bp;
while (*fm && *fm != ch) {
if (*fm == '\\' && fm[1])
++fm;
addbufspc(1);
*bp++ = *fm++;
}
addbufspc(1);
*bp = '\0';
zsfree(truncstr);
truncstr = ztrdup(bp = bp1);
bp1 = NULL;
} else {
char ch = *fm++;
while(*fm && *fm != ch) {
if (*fm == '\\' && fm[1])
fm++;
fm++;
}
}
if(!*fm)
return 0;
break; break;
case '{': /*}*/ case '{': /*}*/
if (!dontcount++ && nonsp) { if (!dontcount++) {
addbufspc(1); addbufspc(1);
*bp++ = Inpar; *bp++ = Inpar;
} }
break; break;
case /*{*/ '}': case /*{*/ '}':
if (dontcount && !--dontcount && nonsp) { if (dontcount && !--dontcount) {
addbufspc(1); addbufspc(1);
*bp++ = Outpar; *bp++ = Outpar;
} }
@ -569,7 +538,7 @@ putpromptchar(int doprint, int endchar)
break; break;
} }
} else if(*fm == '!' && isset(PROMPTBANG)) { } else if(*fm == '!' && isset(PROMPTBANG)) {
if(doprint) if(doprint) {
if(fm[1] == '!') { if(fm[1] == '!') {
fm++; fm++;
addbufspc(1); addbufspc(1);
@ -579,6 +548,7 @@ putpromptchar(int doprint, int endchar)
sprintf(bp, "%d", curhist); sprintf(bp, "%d", curhist);
bp += strlen(bp); bp += strlen(bp);
} }
}
} else { } else {
char c = *fm == Meta ? *++fm ^ 32 : *fm; char c = *fm == Meta ? *++fm ^ 32 : *fm;
@ -604,6 +574,8 @@ pputc(char c)
c ^= 32; c ^= 32;
} }
*bp++ = c; *bp++ = c;
if (c == '\n' && !dontcount)
bufline = bp;
} }
/* Make sure there is room for `need' more characters in the buffer. */ /* Make sure there is room for `need' more characters in the buffer. */
@ -627,46 +599,19 @@ addbufspc(int need)
} }
/* stradd() adds a metafied string to the prompt, * /* stradd() adds a metafied string to the prompt, *
* in a visible representation, doing truncation. */ * in a visible representation. */
/**/ /**/
void void
stradd(char *d) stradd(char *d)
{ {
/* dlen is the full length of the string we want to add */ char *ps, *pc;
int dlen = niceztrlen(d); addbufspc(niceztrlen(d));
char *ps, *pd, *pc, *t;
int tlen, maxlen;
addbufspc(dlen);
/* This loop puts the nice representation of the string into the prompt * /* This loop puts the nice representation of the string into the prompt *
* buffer. It might be modified later. Note that bp isn't changed. */ * buffer. */
for(ps=d, pd=bp; *ps; ps++) for(ps=d; *ps; ps++)
for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++) for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++)
*pd++ = *pc; *bp++ = *pc;
if(!trunclen || dlen <= trunclen) {
/* No truncation is needed, so update bp and return, *
* leaving the full string in the prompt. */
bp += dlen;
return;
}
/* We need to truncate. t points to the truncation string -- which is *
* inserted literally, without nice representation. tlen is its *
* length, and maxlen is the amout of the main string that we want to *
* keep. Note that if the truncation string is longer than the *
* truncation length (tlen > trunclen), the truncation string is used *
* in full. */
addbufspc(tlen = ztrlen(t = truncstr));
maxlen = tlen < trunclen ? trunclen - tlen : 0;
if(truncatleft) {
memmove(bp + strlen(t), bp + dlen - maxlen, maxlen);
while(*t)
*bp++ = *t++;
bp += maxlen;
} else {
bp += maxlen;
while(*t)
*bp++ = *t++;
}
} }
/* tsetcap(), among other things, can write a termcap string into the buffer. */ /* tsetcap(), among other things, can write a termcap string into the buffer. */
@ -684,12 +629,12 @@ tsetcap(int cap, int flag)
tputs(tcstr[cap], 1, putshout); tputs(tcstr[cap], 1, putshout);
break; break;
case 1: case 1:
if (!dontcount && nonsp) { if (!dontcount) {
addbufspc(1); addbufspc(1);
*bp++ = Inpar; *bp++ = Inpar;
} }
tputs(tcstr[cap], 1, putstr); tputs(tcstr[cap], 1, putstr);
if (!dontcount && nonsp) { if (!dontcount) {
int glitch = 0; int glitch = 0;
if (cap == TCSTANDOUTBEG || cap == TCSTANDOUTEND) if (cap == TCSTANDOUTBEG || cap == TCSTANDOUTEND)
@ -764,3 +709,108 @@ countprompt(char *str, int *wp, int *hp)
if(hp) if(hp)
*hp = h; *hp = h;
} }
/**/
static int
prompttrunc(int arg, int truncchar, int doprint, int endchar)
{
if (arg) {
char ch = *fm, *ptr = bp, *truncstr;
int truncatleft = ch == '<';
/*
* If there is already a truncation active, return so that
* can be finished, backing up so that the new truncation
* can be started afterwards.
*/
if (trunclen) {
while (*--fm != '%')
;
fm--;
return 0;
}
trunclen = arg;
if (*fm != ']')
fm++;
while (*fm && *fm != truncchar) {
if (*fm == '\\' && fm[1])
++fm;
addbufspc(1);
*bp++ = *fm++;
}
if (!*fm)
return 0;
if (bp == ptr && truncchar == ']') {
addbufspc(1);
*bp++ = '<';
}
truncstr = ztrduppfx(ptr, bp - ptr);
bp = ptr;
fm++;
putpromptchar(doprint, endchar);
*bp = '\0';
if (bp - ptr > trunclen) {
/*
* We need to truncate. t points to the truncation string -- *
* which is inserted literally, without nice representation. *
* tlen is its length, and maxlen is the amount of the main *
* string that we want to keep. Note that if the truncation *
* string is longer than the truncation length (tlen > *
* trunclen), the truncation string is used in full. *
*/
char *t = truncstr;
int fullen = bp - ptr;
int tlen = ztrlen(t), maxlen;
if (tlen > fullen) {
addbufspc(tlen - fullen);
bp += tlen - fullen;
} else
bp -= fullen - trunclen;
maxlen = tlen < trunclen ? trunclen - tlen : 0;
if (truncatleft) {
if (maxlen)
memmove(ptr + strlen(t), ptr + fullen - maxlen,
maxlen);
while (*t)
*ptr++ = *t++;
} else {
ptr += maxlen;
while (*t)
*ptr++ = *t++;
}
}
zsfree(truncstr);
trunclen = 0;
/*
* We may have returned early from the previous putpromptchar *
* because we found another truncation following this one. *
* In that case we need to do the rest now. *
*/
if (!*fm)
return 0;
if (*fm != endchar) {
fm++;
/*
* With trunclen set to zero, we always reach endchar *
* (or the terminating NULL) this time round. *
*/
if (!putpromptchar(doprint, endchar))
return 0;
/* Now we have to trick it into matching endchar again */
fm--;
}
} else {
if (*fm != ']')
fm++;
while(*fm && *fm != truncchar) {
if (*fm == '\\' && fm[1])
fm++;
fm++;
}
if (trunclen || !*fm)
return 0;
}
return 1;
}

View file

@ -716,6 +716,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
int eval = 0; int eval = 0;
int nojoin = 0; int nojoin = 0;
char inbrace = 0; /* != 0 means ${...}, otherwise $... */ char inbrace = 0; /* != 0 means ${...}, otherwise $... */
char hkeys = 0; /* 1 means get keys from associative array */
char hvals = 1; /* > hkeys get values of associative array */
*s++ = '\0'; *s++ = '\0';
if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' && if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
@ -732,12 +734,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
if (*s == Inbrace) { if (*s == Inbrace) {
inbrace = 1; inbrace = 1;
s++; s++;
if (*s == '(' || *s == Inpar) { if (*s == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) {
hkeys = 1;
s++;
} else if (*s == '(' || *s == Inpar) {
char *t, sav; char *t, sav;
int tt = 0; int tt = 0;
long num; long num;
int escapes = 0; int escapes = 0;
int klen; int klen;
#define UNTOK(C) (itok(C) ? ztokens[(C) - Pound] : (C))
#define UNTOK_AND_ESCAPE(X) {\ #define UNTOK_AND_ESCAPE(X) {\
untokenize(X = dupstring(s + 1));\ untokenize(X = dupstring(s + 1));\
if (escapes) {\ if (escapes) {\
@ -851,7 +857,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
prenum = num; prenum = num;
else else
postnum = num; postnum = num;
if (s[1] != sav) if (UNTOK(s[1]) != UNTOK(sav))
break; break;
t = get_strarg(++s); t = get_strarg(++s);
if (!*t) if (!*t)
@ -865,7 +871,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
*t = sav; *t = sav;
sav = *s; sav = *s;
s = t + 1; s = t + 1;
if (*s != sav) { if (UNTOK(*s) != UNTOK(sav)) {
s--; s--;
break; break;
} }
@ -886,6 +892,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
escapes = 1; escapes = 1;
break; break;
case 'k':
hkeys = 1;
break;
case 'v':
hvals = 2;
break;
default: default:
flagerr: flagerr:
zerr("error in flags", NULL, 0); zerr("error in flags", NULL, 0);
@ -986,9 +999,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
if (getindex(&s, v) || s == os) if (getindex(&s, v) || s == os)
break; break;
} }
if ((isarr = v->isarr)) if ((isarr = v->isarr)) {
/* No way to reach here with v->inv != 0, so getvaluearr() *
* will definitely be called by getarrvalue(). Slicing of *
* associations isn't done, so use v->a and v->b for flags */
if (PM_TYPE(v->pm->flags) == PM_HASHED) {
v->a = hkeys;
v->b = hvals;
}
aval = getarrvalue(v); aval = getarrvalue(v);
else { } else {
if (v->pm->flags & PM_ARRAY) { if (v->pm->flags & PM_ARRAY) {
int tmplen = arrlen(v->pm->gets.afn(v->pm)); int tmplen = arrlen(v->pm->gets.afn(v->pm));

View file

@ -450,6 +450,8 @@ getsimptext(Cmd cmd)
taddchr('('); taddchr('(');
taddlist(v->arr); taddlist(v->arr);
taddstr(") "); taddstr(") ");
} else if (PM_TYPE(v->type) == PM_HASHED) {
/* XXX */
} else { } else {
taddstr(v->str); taddstr(v->str);
taddchr(' '); taddchr(' ');

View file

@ -510,8 +510,8 @@ adduserdir(char *s, char *t, int flags, int always)
if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s)) if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s))
return; return;
/* Never hash PWD, because it's never useful */ /* Never hash PWD unless it was explicitly requested */
if (!strcmp(s, "PWD")) if (!always && !strcmp(s, "PWD"))
return; return;
/* Normal parameter assignments generate calls to this function, * /* Normal parameter assignments generate calls to this function, *

View file

@ -59,6 +59,7 @@ freeheap
getaparam getaparam
gethashnode gethashnode
gethashnode2 gethashnode2
gethparam
getiparam getiparam
getkeystring getkeystring
getlinknode getlinknode

View file

@ -538,6 +538,7 @@ struct value {
int inv; /* should we return the index ? */ int inv; /* should we return the index ? */
int a; /* first element of array slice, or -1 */ int a; /* first element of array slice, or -1 */
int b; /* last element of array slice, or -1 */ int b; /* last element of array slice, or -1 */
char **arr; /* cache for hash turned into array */
}; };
/* structure for foo=bar assignments */ /* structure for foo=bar assignments */
@ -813,6 +814,7 @@ struct param {
char **arr; /* value if declared array (PM_ARRAY) */ char **arr; /* value if declared array (PM_ARRAY) */
char *str; /* value if declared string (PM_SCALAR) */ char *str; /* value if declared string (PM_SCALAR) */
long val; /* value if declared integer (PM_INTEGER) */ long val; /* value if declared integer (PM_INTEGER) */
HashTable hash; /* value if declared assoc (PM_HASHED) */
} u; } u;
/* pointer to function to set value of this parameter */ /* pointer to function to set value of this parameter */
@ -820,6 +822,7 @@ struct param {
void (*cfn) _((Param, char *)); void (*cfn) _((Param, char *));
void (*ifn) _((Param, long)); void (*ifn) _((Param, long));
void (*afn) _((Param, char **)); void (*afn) _((Param, char **));
void (*hfn) _((Param, HashTable));
} sets; } sets;
/* pointer to function to get value of this parameter */ /* pointer to function to get value of this parameter */
@ -827,6 +830,7 @@ struct param {
char *(*cfn) _((Param)); char *(*cfn) _((Param));
long (*ifn) _((Param)); long (*ifn) _((Param));
char **(*afn) _((Param)); char **(*afn) _((Param));
HashTable (*hfn) _((Param));
} gets; } gets;
/* pointer to function to unset this parameter */ /* pointer to function to unset this parameter */
@ -845,8 +849,9 @@ struct param {
#define PM_SCALAR 0 /* scalar */ #define PM_SCALAR 0 /* scalar */
#define PM_ARRAY (1<<0) /* array */ #define PM_ARRAY (1<<0) /* array */
#define PM_INTEGER (1<<1) /* integer */ #define PM_INTEGER (1<<1) /* integer */
#define PM_HASHED (1<<15) /* association */
#define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY)) #define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY|PM_HASHED))
#define PM_LEFT (1<<2) /* left justify and remove leading blanks */ #define PM_LEFT (1<<2) /* left justify and remove leading blanks */
#define PM_RIGHT_B (1<<3) /* right justify and fill with leading blanks */ #define PM_RIGHT_B (1<<3) /* right justify and fill with leading blanks */

6
config.guess vendored
View file

@ -557,6 +557,12 @@ EOF
# says <Richard.M.Bartel@ccMail.Census.GOV> # says <Richard.M.Bartel@ccMail.Census.GOV>
echo i586-unisys-sysv4 echo i586-unisys-sysv4
exit 0 ;; exit 0 ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit 0 ;;
*:Rhapsody:*:*)
echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
exit 0 ;;
esac esac
#echo '(No uname command or uname output not recognized.)' 1>&2 #echo '(No uname command or uname output not recognized.)' 1>&2

2
config.sub vendored
View file

@ -689,7 +689,7 @@ case $os in
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -linux* | -uxpv*) | -linux* | -uxpv* | -rhapsody* )
# Remember, each alternative MUST END IN *, to match a version number. # Remember, each alternative MUST END IN *, to match a version number.
;; ;;
-sunos5*) -sunos5*)

View file

@ -5,7 +5,7 @@ patches. (The version number built into the shell has not been changed.)
Zoli's AIX dynamic loading patch from 3933, slightly updated, without Zoli's AIX dynamic loading patch from 3933, slightly updated, without
some hunks which weren't needed on AIX 3.x so I don't know how to some hunks which weren't needed on AIX 3.x so I don't know how to
update properly. update them properly
My completion widgets patch My completion widgets patch
@ -18,24 +18,85 @@ My patch in 4477 to rename three functions to avoid clashes when
dynamic loading (particularly necessary on IRIX and AIX), including dynamic loading (particularly necessary on IRIX and AIX), including
the effect of Sven's additional fix in 4488 the effect of Sven's additional fix in 4488
My patch 4513 for case-insensitive globbing via flags, plus fixlet 4552 Sven's magna opera patch-or 4510 and patch-match 4509 to add control
of alternative matches and arbitrary mapping between characters in the
command line and the matched string, plus all known related fixes
4526, 4527, 4534, 4555, 4557
Sven's magna opera patch-or 4510 and patch-match 4509 to add control of My patch 4513 for case-insensitive globbing via flags, plus fixlet 4552
alternative matches and arbitrary mapping between characters in the
command line and the matched, plus all known fixes 4526, 4527, 4534,
4555, 4557
My ~PWD patch 4533 My ~PWD patch 4533
My suggestion for fixing the suffix on a yank in 4564 My suggestion for fixing the suffix on a yank in 4564
Bart's deltochar patch including new flags to allow commands not to Bart's deltochar patch including new flags to allow commands not to
interrupt cumulative effects in 4570 interrupt cumulative effects in 4570 (new flag merged with compctl
widgets flags).
Bart's doc fiz 4574 Bart's doc fix 4574
Sven's latest word on the fixsuffix() horror in 4576, plus a A fixsuffix() added by hand in delcharorlist() which I've somehow
fixsuffix() added by hand in delcharorlist() which I've somehow missed missed along the way. The fixsuffix() horror is probably not yet
along the way resolved; 4576 has side effects and hasn't been applied.
My latest version of lete2ctl, not posted My latest version of lete2ctl, not posted but available at
http://www.ifh.de/~pws/computing/lete2ctl .
Bart's chpwd() fix 4589
Second edition
Added line in zle_tricky.c missed when patching by hand, spotted by
Bart. (Whitespace is still non-canonical.)
Fixed up my compctl widgets patch for use with Sven's rewrite, which I
hadn't done properly before.
Bart's function fixes, 4471
Bart's doc fixes, 4472
Bart's PWD and OLDPWD reshuffle, 4589
My test-line-length patch for prompts, 4591
Configure patch from Wilfredo Sanchez in 4594, with some extra
tabbification and without the setterm() hunk, since I've already renamed
that to zsetterm(), avoiding the conflict
My globbing fix for a bug which shows up in `case' constructs, 4595
Alternative version of the ~PWD patch (allow users to hash PWD
explicitly if that's what turns them on), 4596
Bart's experimental associative array patch, 4598, plus various
additions, 4599, 4602, 4608, 4641, 4653, 4654. No documentation yet;
if you want to play with this, so far:
% typeset -A hash # create associative array $hash
% hash[one]=eins hash[two]=zwei # assign elements
% hash=(one eins two zwei) # same, assign whole array (*)
% print $hash[one] # retrieve elements
eins
% print $hash # whole array looks like normal array
eins zwei
% print ${(k)hash} # flag to get keys
one two
% print ${(kv)hash} # flag to get keys and values (**)
one eins two zwei
Comparison of (*) and (**) will reveal how to copy an associative
array, but you always need to declare it with typeset -A or an
ordinary array will appear. There is a predefined special associative
array $testhash, for testing purposes only, which will eventually
disappear.
My rewrite of prompt truncation, 4601
Bart's params error message fix, 4606
My input fix for 8 bit characters, 4612
Bart's version of the *** fix, 4624
Bart's parameter substitution flag delimiter fix, 4644
My special parameter unset fix, 4662