summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:11:42 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:11:42 +0000
commit20d67907c95265356b51dbdce8ecc0c1ede9e66b (patch)
tree69b0777db02f96555b3a0587cd630025062a7f09
parentzsh-3.1.5-pws-4 (diff)
downloadzsh-20d67907c95265356b51dbdce8ecc0c1ede9e66b.tar
zsh-20d67907c95265356b51dbdce8ecc0c1ede9e66b.tar.gz
zsh-20d67907c95265356b51dbdce8ecc0c1ede9e66b.tar.bz2
zsh-20d67907c95265356b51dbdce8ecc0c1ede9e66b.tar.lz
zsh-20d67907c95265356b51dbdce8ecc0c1ede9e66b.tar.xz
zsh-20d67907c95265356b51dbdce8ecc0c1ede9e66b.tar.zst
zsh-20d67907c95265356b51dbdce8ecc0c1ede9e66b.zip
zsh-3.1.5-pws-5zsh-3.1.5-pws-5
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Zsh/builtins.yo7
-rw-r--r--Doc/Zsh/compctl.yo24
-rw-r--r--Doc/Zsh/mod_zftp.yo21
-rw-r--r--Etc/MACHINES6
-rw-r--r--Misc/.distfiles1
-rw-r--r--Misc/new-completion-examples453
-rw-r--r--Src/Builtins/rlimits.c14
-rw-r--r--Src/Modules/.distfiles1
-rw-r--r--Src/Modules/example.mdd3
-rw-r--r--Src/Modules/files.c6
-rw-r--r--Src/Modules/stat.c11
-rw-r--r--Src/Modules/zftp.c142
-rw-r--r--Src/Zle/comp1.c44
-rw-r--r--Src/Zle/comp1.export13
-rw-r--r--Src/Zle/compctl.c582
-rw-r--r--Src/Zle/compctl.mdd4
-rw-r--r--Src/Zle/iwidgets.list16
-rw-r--r--Src/Zle/zle.h18
-rw-r--r--Src/Zle/zle_keymap.c4
-rw-r--r--Src/Zle/zle_main.c28
-rw-r--r--Src/Zle/zle_refresh.c105
-rw-r--r--Src/Zle/zle_thingy.c50
-rw-r--r--Src/Zle/zle_tricky.c448
-rw-r--r--Src/builtin.c296
-rw-r--r--Src/cond.c6
-rw-r--r--Src/exec.c18
-rw-r--r--Src/glob.c4
-rw-r--r--Src/hashtable.c6
-rw-r--r--Src/hist.c6
-rw-r--r--Src/input.c3
-rw-r--r--Src/jobs.c17
-rw-r--r--Src/lex.c25
-rw-r--r--Src/loop.c2
-rw-r--r--Src/mem.c54
-rw-r--r--Src/mkbltnmlst.sh8
-rw-r--r--Src/mkmakemod.sh23
-rw-r--r--Src/module.c2
-rw-r--r--Src/params.c12
-rw-r--r--Src/subst.c5
-rw-r--r--Src/watch.c3
-rw-r--r--Src/zsh.export9
-rw-r--r--Src/zsh.h34
-rw-r--r--Util/zsh-development-guide21
-rw-r--r--aczsh.m42
-rw-r--r--configure.in19
-rw-r--r--patchlist.txt53
47 files changed, 2210 insertions, 423 deletions
diff --git a/Config/version.mk b/Config/version.mk
index 309c19772..05e8483fd 100644
--- a/Config/version.mk
+++ b/Config/version.mk
@@ -27,5 +27,5 @@
# This must also serve as a shell script, so do not add spaces around the
# `=' signs.
-VERSION=3.1.5-pws-4
-VERSION_DATE='December 17, 1998'
+VERSION=3.1.5-pws-5
+VERSION_DATE='January 19, 1998'
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 2df70cd98..82562fcbe 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -947,9 +947,10 @@ otherwise it is determined by the width of the value of the
first assignment.
)
item(tt(-a))(
-The names refer to array parameters. For historical reasons, scalar
-parameters are created even when this flag is specified, but the
-output is restricted to arrays (including associative arrays).
+The names refer to array parameters. An array parameter may be
+created this way, but it may not be assigned to in the tt(typeset)
+statement. When displaying, both normal and associative arrays are
+shown.
)
item(tt(-f))(
The names refer to functions rather than parameters. No assignments
diff --git a/Doc/Zsh/compctl.yo b/Doc/Zsh/compctl.yo
index 37296b716..e9634a26f 100644
--- a/Doc/Zsh/compctl.yo
+++ b/Doc/Zsh/compctl.yo
@@ -85,7 +85,7 @@ the standard behavior for all commands. For example, if your access
to the user database is too slow and/or it contains too many users (so
that completion after `tt(~)' is too slow to be usable), you can use
-nofill(tt(compctl -Tx 'C[0,*/*]' -f - 's[~]' -k friends -S/))
+nofill(tt(compctl -Tx 'C[0,*/*]' -f - 's[~]' -k friends -S/ -tn))
to complete the strings in the array tt(friends) after a `tt(~)'.
The first argument is necessary so that this form of ~-completion is
@@ -432,16 +432,18 @@ the sorted ones. I.e. it is possible to have a sorted and a unsorted group
with the same name and the matches in those groups will not be mixed.
)
item(tt(-t) var(continue))(
-The var(continue)-string contains a set of characters that specify if
-and when completion should continue to produce matches where it normally
-would not do that. The character tt(c) means that completion continues
-with the next suitable compctl (i.e. if you don't specify this in a
-tt(compctl -T), compctls for commands are never used). The character
-tt(PLUS()) is used to continue with the matches for the next alternative
-completion (see below). The characters tt(-) and tt(x) may be used in
-sub-lists for extended completion (see below). They will make the completion
-code use the flag list after the next tt(-) (if the corresponding pattern
-matches) and the default flag list (those before the tt(-x)), respectively.
+The var(continue)-string contains a character that specifies which set
+of completion flags should be used next. Normally those of the next
+matching compctl are used, i.e. pattern compctls and normal compctls
+after tt(-T) and after a pattern compctl. If var(continue) is the
+character tt(PLUS()) the flags for the next alternative completion
+(see below) are used. The characters tt(-) and tt(x) can be used in
+sub-lists for extended completion (see below). They will make the
+completion code use the flag list after the next tt(-) (if the
+corresponding pattern matches) and the default flag list (those before
+the tt(-x)), respectively. if var(continue) is the character tt(n) no
+other flag lists are used, i.e. the generation of matches stops
+immediately.
)
item(tt(-M) var(match-spec))(
This defines additional matching control specifications that should be used
diff --git a/Doc/Zsh/mod_zftp.yo b/Doc/Zsh/mod_zftp.yo
index a15be60d6..c08130bf5 100644
--- a/Doc/Zsh/mod_zftp.yo
+++ b/Doc/Zsh/mod_zftp.yo
@@ -92,6 +92,27 @@ nofill(tt(LPAR()zftp open; zftp get foo >bar; zftp close)tt(RPAR() &))
--- here, the connection is restricted to a background subshell and
you are free to open a simultaneous connection in the foreground.
)
+item(tt(test))(
+Test the connection; if the server has reported
+that it has closed the connection (maybe due to a timeout), return
+status 2; if no connection was open anyway, return status 1; else
+return status 0. The tt(test) subcommand is
+silent, apart from messages printed by the tt($ZFTP_VERBOSE)
+mechanism, or error messages if the connection closes. There is no
+network overhead for this test.
+
+The test is only supported on systems with either the tt(select(2)) or
+tt(poll(2)) system calls; otherwise the message tt(not
+supported on this system) is printed instead.
+
+It is useful to put the code
+
+nofill(tt([[ -n $ZFTP_HOST ]] && zftp test))
+
+into the shell function tt(precmd) for testing the connection before
+every prompt. However, tt(zftp) will call tt(test) at the start of any
+other subcommand when a connection is open.
+)
item(tt(cd) var(directory))(
Change the remote directory to var(directory). Also alters the shell
variable tt(ZFTP_PWD).
diff --git a/Etc/MACHINES b/Etc/MACHINES
index 303508a93..7002f6db4 100644
--- a/Etc/MACHINES
+++ b/Etc/MACHINES
@@ -45,7 +45,8 @@ HP: HP-UX 9, 10.20
Should build `out-of-the-box'.
IBM: AIX
- Should build `out-of-the-box'.
+ Should build `out-of-the-box'. On AIX 3.x (at least),
+ --enable-zsh-mem will not work.
Linux: Linux (i386) [3.1.4]
If you are using an early minor version of libc 5, then a bug
@@ -92,3 +93,6 @@ Sun: Solaris 2.*
To avoid this, make sure you compile zsh without any reference
to /usr/ucblib in your LD_LIBRARY_PATH. You can easily do this
by just unsetting LD_LIBRARY_PATH before building zsh.
+
+ Under Solaris 2.7, dynamically loaded library support with
+ --enable-dynamic currently does not work.
diff --git a/Misc/.distfiles b/Misc/.distfiles
index a02614511..fab78c0d1 100644
--- a/Misc/.distfiles
+++ b/Misc/.distfiles
@@ -1,4 +1,5 @@
DISTFILES_SRC='
.distfiles
c2z compctl-examples globtests globtests.ksh lete2ctl
+ new-completion-examples zftp-functions
'
diff --git a/Misc/new-completion-examples b/Misc/new-completion-examples
new file mode 100644
index 000000000..659679891
--- /dev/null
+++ b/Misc/new-completion-examples
@@ -0,0 +1,453 @@
+# Define a new widget behaving like `expand-or-complete' but calling the
+# function `main-complete' to generate matches.
+
+zle -c my-comp expand-or-complete main-complete
+
+bindkey '\C-i' my-comp
+
+
+# Below is a proposed main loop and the things it needs.
+
+# One associative array for normal completions and one for patterns.
+
+typeset -A comps
+
+
+# These may be used to define completion handlers. First argument is the
+# name of the function/variable containing the definition, the other
+# arguments are the command names for which this definition should be used.
+# With only one argument the function/variable-name __$1 is used.
+
+defcomp() {
+ local v
+
+ if [[ $# -eq 1 ]] then
+ comps[$1]="__$1"
+ else
+ v="$1"
+ shift
+ for i; do
+ comps[$i]="$v"
+ done
+ fi
+}
+
+defpatcomp() {
+ if [[ ${+patcomps} == 1 ]] then
+ patcomps=("$patcomps[@]" "$2 $1" )
+ else
+ patcomps=( "$2 $1" )
+ fi
+}
+
+
+# These can be used to easily save and restore the state of the special
+# variables used by the completion code.
+
+alias compsave='local _opre _oipre _oargs _ocur;_opre="$PREFIX";_oipre="$IPREFIX";_oargs=( "$@" );_ocur="$CURRENT"'
+alias compreset='PREFIX="$_opre";IPREFIX="$_oipre";argv=( "$_oargs[@]" );CURRENT="$_ocur"'
+
+# This is an easy way to get completion for sub-commands.
+
+alias compsub='do-complete "$@" || return 1'
+
+# This searches $1 in the array for normal completions and calls the result.
+
+compalso() {
+ 1="$comps[$1]"
+ [[ -z "$1" ]] || call-complete "$@"
+}
+
+# This generates matches. The first argument is something we got from one
+# of the associative arrays above. This is expected to be either the name
+# of a variable in which case we use its value as arguments to complist,
+# or it is the name of a function in which case we call this function with
+# the arguments from the command line as its arguments.
+
+call-complete() {
+ local var
+
+ eval var\=\$\{\+$1\}
+ if [[ "$var" == 0 ]] then
+ "$@"
+ else
+ eval complist \$\{${1}\[\@\]\}
+ fi
+}
+
+# The main loop of the competion code. This is what is called when TAB is
+# pressed. The completion code gives us the special variables and the
+# arguments from the command line are gives as positional parameters.
+
+main-complete() {
+ emulate -R zsh
+ local comp
+ setopt localoptions nullglob rcexpandparam globdots
+ unsetopt markdirs globsubst shwordsplit nounset
+
+ # An entry for `--first--' is the replacement for `compctl -T'
+ # The `|| return 1' is used throughout: if a function producing matches
+ # returns non-zero this is interpreted as `do not try to produce more matches'
+ # (this is the replacement for `compctl -t').
+
+ comp="$comps[--first--]"
+ [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+
+ # For arguments we use the `do-complete' function below called via the
+ # convenience alias `compsub'.
+
+ if [[ $CONTEXT == argument || $CONTEXT == command ]] then
+ compsub
+ else
+ # Let's see if we have a special completion definition for the other
+ # possible contexts.
+
+ comp=''
+
+ case $CONTEXT in
+ redirect) comp="$comps[--redir--]";;
+ math) comp="$comps[--math--]";;
+ subscript) comp="$comps[--subscr--]";;
+ value) comp="$comps[--value--]";;
+ condition) comp="$comps[--cond--]";;
+ esac
+
+ # If not, we use default completion, if any.
+
+ [[ -z "$comp" ]] && comp="$comps[--default--]"
+ [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+ fi
+}
+
+# This does completion for a command (in command position and for the
+# arguments).
+
+do-complete() {
+ local comp cmd1 cmd2 pat val
+
+ # Completing in command position? If not we set up `cmd1' and `cmd2' as
+ # two strings we have search in the completion definition arrays (e.g.
+ # a path and the last path name component).
+
+ if [[ $CONTEXT == command ]] then
+ comp="$comps[--command--]"
+ [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+ return 0
+ elif [[ "$COMMAND[1]" == '=' ]] then
+ eval cmd1\=$COMMAND
+ cmd2="$COMMAND[2,-1]"
+ elif [[ "$COMMAND" == */* ]] then
+ cmd1="$COMMAND"
+ cmd2="${COMMAND:t}"
+ else
+ cmd1="$COMMAND"
+ eval cmd2=$(whence -p $COMMAND)
+ fi
+
+ # See if there are any matching pattern completions.
+
+ for i in "$patcomps[@]"; do
+ pat="${i% *}"
+ val="${i#* }"
+ if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]] then
+ call-complete "$val" "$@" || return 1
+ fi
+ done
+
+ # Now look up the two names in the normal completion array.
+
+ comp="${comps[$cmd1]:-$comps[$cmd2]}"
+
+ # And generate the matches, probably using default completion.
+
+ [[ -z "$comp" ]] && comp="$comps[--default--]"
+ [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+}
+
+# Do sub-completion for pre-command modifiers.
+
+defcomp __precmd - noglob nocorrect exec command builtin
+__precmd() {
+ COMMAND="$1"
+ shift
+ (( CURRENT-- ))
+ if [[ CURRENT -eq 0 ]] then
+ CONTEXT=command
+ else
+ CONTEXT=argument
+ fi
+ compsub
+}
+
+# Utility function for in-path completion.
+# First argument should be an complist-option (e.g. -f, -/, -g). The other
+# arguments should be glob patterns, one per argument.
+# E.g.: files -g '*.tex' '*.texi'
+# This is intended as a replacement for `complist -f', `complist -/', and
+# `complist -g ...' (but don't use it with other options).
+# This function behaves as if you have a matcher definition like:
+# compctl -M 'r:|[-.,_/]=* r:|=* m:{a-z}={A-Z} m:-=_ m:.=,'
+# so you may want to modify this.
+
+pfiles() {
+ local nm str pa pre epre a b c s rest
+
+ setopt localoptions nullglob rcexpandparam globdots extendedglob
+ unsetopt markdirs globsubst shwordsplit nounset
+
+ nm=$NMATCHES
+ if [[ $# -eq 0 ]] then
+ complist -f
+ elif [[ "$1" = -g ]] then
+ complist -g "$argv[2,-1]"
+ shift
+ else
+ complist $1
+ shift
+ fi
+ [[ -nmatches nm ]] || return
+
+ str="$PREFIX*$SUFFIX"
+
+ [[ -z "$1" ]] && 1='*'
+ if [[ $str[1] = \~ ]] then
+ pre="${str%%/*}/"
+ eval epre\=$pre
+ str="${str#*/}"
+ pa=''
+ else
+ pre=''
+ epre=''
+ if [[ $str[1] = / ]] then
+ str="$str[2,-1]"
+ pa='/'
+ else
+ pa=''
+ fi
+ fi
+ str="$str:gs/,/*,/:gs/_/*_/:gs./.*/.:gs/-/*[-_]/:gs/./*[.,]/:gs-*[.,]*[.,]*/-../-:gs.**.*."
+ while [[ "$str" = */* ]] do
+ rest="${str#*/}"
+ a="${epre}${pa}(#l)${str%%/*}(-/)"
+ a=( $~a )
+ if [[ $#a -eq 0 ]] then
+ return
+ elif [[ $#a -gt 1 ]] then
+ c=()
+ s=( $rest$@ )
+ s=( "${(@)s:gs.**.*.}" )
+ for i in $a; do
+ b=( $~i/(#l)$~s )
+ eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \)
+ [[ $#b -ne 0 ]] && c=( $c $i )
+ done
+ if [[ $#c -eq 0 ]] then
+ return
+ elif [[ $#c -ne 1 ]] then
+ a="$epre$pa"
+ c=( $~c/(#l)$~s )
+ eval c\=\( \$\{c:/\*\(${(j:|:)fignore}\)\} \)
+ c=( ${c#$a} )
+ for i in $c; do
+ compadd -p "$pre$pa" -W "$a" -s "/${i#*/}" -f "${i%%/*}"
+ done
+ return
+ fi
+ a=( "$c[1]" )
+ fi
+ a="$a[1]"
+ pa="$pa${a##*/}/"
+ str="$rest"
+ done
+ a="$epre$pa"
+ s=( $str$@ )
+ s=( "${(@)s:gs.**.*.}" )
+ b=( $~a(#l)$~s )
+ eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \)
+ compadd -p "$pre$pa" -W "$epre$pa" -f ${b#$a}
+}
+
+# Utility function for completing files of a given type or any file.
+# In many cases you will want to call this one instead of pfiles().
+
+files() {
+ local nm
+
+ nm=$NMATCHES
+ pfiles "$@"
+
+ [[ $# -ne 0 && -nmatches nm ]] && pfiles
+}
+
+# Simple default, command, and math completion defined with variables.
+
+defcomp __default --default--
+__default() {
+ files
+}
+
+defcomp __command --command--
+__command=( -c )
+
+defcomp __math --math--
+__math=( -v )
+
+defcomp __subscr --subscr--
+__subscr() {
+ compalso --math-- "$@"
+ # ...probably other stuff
+}
+
+# A simple pattern completion, just as an example.
+
+defpatcomp __x_options '*/X11/*'
+__x_options() {
+ complist -J options -k '(-display -name -xrm)'
+}
+
+# A better example: completion for `find'.
+
+defcomp find
+__find() {
+ compsave
+
+ if [[ -mbetween -(ok|exec) \\\; ]] then
+ compsub
+ elif [[ -iprefix - ]] then
+ complist -s 'daystart {max,min,}depth follow noleaf version xdev \
+ {a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links \
+ {i,}{l,}name {no,}{user,group} path perm regex size true uid used \
+ exec {f,}print{f,0,} ok prune ls'
+ compreset
+ elif [[ -position 1 ]] then
+ complist -g '. ..'
+ files -g '(-/)'
+ elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]] then
+ files
+ elif [[ -current -1 -fstype ]] then
+ complist -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)'
+ elif [[ -current -1 -group ]] then
+ complist -k groups
+ elif [[ -current -1 -user ]] then
+ complist -u
+ fi
+}
+
+# Various completions...
+
+defcomp __gunzip gunzip zcat
+__gunzip() {
+ files -g '*.[gG][z]'
+}
+
+defcomp gzip
+__gzip() {
+ files -g '*~*.[gG][zZ]'
+}
+
+defcomp xfig
+__xfig() {
+ files -g '*.fig'
+}
+
+defcomp __make make gmake
+__make() {
+ complist -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)"
+}
+
+defcomp __ps gs ghostview gview psnup psselect pswrap pstops pstruct lpr
+__ps() {
+ files -g '*([pP][sS]|eps)'
+}
+
+defcomp __which which whence
+__which=( -caF )
+
+defcomp __rlogin rlogin rsh ssh
+__rlogin() {
+ if [[ -position 1 ]] then
+ complist -k hosts
+ elif [[ -position 2 ]] then
+ complist -k '(-l)'
+ elif [[ -position 3 && -word 1 artus ]] then
+ complist -k '(puck root)'
+ fi
+}
+
+defcomp __dvi xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype
+__dvi() {
+ files -g '*.(dvi|DVI)'
+}
+
+defcomp __dirs rmdir df du dircmp cd
+__dirs() {
+ files -/ '*(-/)'
+}
+
+defcomp __jobs fg bg jobs
+__jobs=(-j -P '%?')
+
+defcomp kill
+__kill() {
+ if [[ -iprefix '-' ]] then
+ complist -k signals
+ else
+ complist -P '%?' -j
+ fi
+}
+
+defcomp __uncompress uncompress zmore
+__uncompress() {
+ files -g '*.Z'
+}
+
+defcomp compress
+__compress() {
+ files -g '*~*.Z'
+}
+
+defcomp __tex tex latex glatex slitex gslitex
+__tex() {
+ files -g '*.(tex|TEX|texinfo|texi)'
+}
+
+defcomp __options setopt unsetopt
+__options=(-M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o)
+
+defcomp __funcs unfunction
+__funcs=(-F)
+
+defcomp __aliases unalias
+__aliases=(-a)
+
+defcomp __vars unset
+__vars=(-v)
+
+defcomp __enabled disable
+__enabled=(-FBwa)
+
+defcomp __disabled enable
+__disabled=(-dFBwa)
+
+defcomp __pdf acroread
+__pdf() {
+ files -g '*.(pdf|PDF)'
+}
+
+defcomp tar
+__tar() {
+ local nm tf
+ compsave
+
+ tf="$2"
+ nm=$NMATCHES
+ if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]] then
+ complist -k "( $(tar tf $tf) )"
+ compreset
+ elif [[ -mword 1 *c*f* && -position 3 100000 ]] then
+ files
+ compreset
+ elif [[ -mcurrent -1 *f* && -position 2 ]] then
+ files -g '*.(tar|TAR)'
+ fi
+}
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 31dcb71b1..2af8dc6ac 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -264,7 +264,7 @@ bin_limit(char *nam, char **argv, char *ops, int func)
* together more than one of these. It's easier to understand from *
* the code: */
val = zstrtorlimt(s, &s, 10);
- if (*s)
+ if (*s) {
if ((*s == 'h' || *s == 'H') && !s[1])
val *= 3600L;
else if ((*s == 'm' || *s == 'M') && !s[1])
@@ -275,6 +275,7 @@ bin_limit(char *nam, char **argv, char *ops, int func)
zwarnnam("limit", "unknown scaling factor: %s", s, 0);
return 1;
}
+ }
}
# ifdef RLIMIT_NPROC
else if (lim == RLIMIT_NPROC)
@@ -339,12 +340,12 @@ bin_unlimit(char *nam, char **argv, char *ops, int func)
/* Without arguments, remove all limits. */
if (!*argv) {
for (limnum = 0; limnum != RLIM_NLIMITS; limnum++) {
- if (hard)
+ if (hard) {
if (euid && current_limits[limnum].rlim_max != RLIM_INFINITY)
ret++;
else
limits[limnum].rlim_max = RLIM_INFINITY;
- else
+ } else
limits[limnum].rlim_cur = limits[limnum].rlim_max;
}
if (ops['s'])
@@ -373,13 +374,13 @@ bin_unlimit(char *nam, char **argv, char *ops, int func)
return 1;
}
/* remove specified limit */
- if (hard)
+ if (hard) {
if (euid && current_limits[lim].rlim_max != RLIM_INFINITY) {
zwarnnam(nam, "can't remove hard limits", NULL, 0);
ret++;
} else
limits[lim].rlim_max = RLIM_INFINITY;
- else
+ } else
limits[lim].rlim_cur = limits[lim].rlim_max;
if (ops['s'] && zsetlimit(lim, nam))
ret++;
@@ -478,11 +479,12 @@ bin_ulimit(char *name, char **argv, char *ops, int func)
}
}
if (!*argv || **argv == '-') {
- if (res < 0)
+ if (res < 0) {
if (*argv || nres)
continue;
else
res = RLIMIT_FSIZE;
+ }
resmask |= 1 << res;
nres++;
continue;
diff --git a/Src/Modules/.distfiles b/Src/Modules/.distfiles
index 4c98f97ea..23c7eae3f 100644
--- a/Src/Modules/.distfiles
+++ b/Src/Modules/.distfiles
@@ -5,4 +5,5 @@ DISTFILES_SRC='
example.mdd example.c
files.mdd files.c
stat.mdd stat.c
+ zftp.mdd zftp.c
'
diff --git a/Src/Modules/example.mdd b/Src/Modules/example.mdd
index 89f12097c..f2cd50693 100644
--- a/Src/Modules/example.mdd
+++ b/Src/Modules/example.mdd
@@ -1,3 +1,6 @@
autobins="example"
+autoinfixconds="ex"
+autoprefixconds="len"
+
objects="example.o"
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index f52c54338..c1948e1fd 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -195,18 +195,18 @@ bin_ln(char *nam, char **args, char *ops, int func)
if(func == BIN_MV) {
- move = rename;
+ move = (MoveFunc) rename;
flags = ops['f'] ? 0 : MV_ASKNW;
flags |= MV_ATOMIC;
} else {
flags = ops['f'] ? MV_FORCE : 0;
#ifdef HAVE_LSTAT
if(ops['s'])
- move = symlink;
+ move = (MoveFunc) symlink;
else
#endif
{
- move = link;
+ move = (MoveFunc) link;
if(!ops['d'])
flags |= MV_NODIRS;
}
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 5c56be5c6..6f80e2a96 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -346,7 +346,7 @@ bin_stat(char *name, char **args, char *ops, int func)
} else {
for (; *arg; arg++) {
if (strchr("glLnNrstT", *arg))
- ops[*arg] = 1;
+ ops[STOUC(*arg)] = 1;
else if (*arg == 'A') {
if (arg[1]) {
arrnam = arg+1;
@@ -505,7 +505,7 @@ bin_stat(char *name, char **args, char *ops, int func)
continue;
}
- if (flags & STF_FILE)
+ if (flags & STF_FILE) {
if (arrnam)
*arrptr++ = ztrdup(*args);
else if (hashnam) {
@@ -513,6 +513,7 @@ bin_stat(char *name, char **args, char *ops, int func)
*hashptr++ = ztrdup(*args);
} else
printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n");
+ }
if (iwhich > -1) {
statprint(&statbuf, outbuf, *args, iwhich, flags);
if (arrnam)
@@ -544,7 +545,7 @@ bin_stat(char *name, char **args, char *ops, int func)
putchar('\n');
}
- if (arrnam)
+ if (arrnam) {
if (ret)
freearray(array);
else {
@@ -552,8 +553,9 @@ bin_stat(char *name, char **args, char *ops, int func)
if (errflag)
return 1;
}
+ }
- if (hashnam)
+ if (hashnam) {
if (ret)
freearray(hash);
else {
@@ -561,6 +563,7 @@ bin_stat(char *name, char **args, char *ops, int func)
if (errflag)
return 1;
}
+ }
return ret;
}
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 4bcd80c7f..d71fa642f 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -62,9 +62,19 @@
/* it's a TELNET based protocol, but don't think I like doing this */
#include <arpa/telnet.h>
+/*
+ * We use poll() in preference to select because some subset of manuals says
+ * that's the thing to do, plus it's a bit less fiddly. I don't actually
+ * have access to a system with poll but not select, however, though
+ * both bits of the code have been tested on a machine with both.
+ */
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#endif
+
/* pinch the definition from <netinet/in.h> for deficient headers */
#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
+# define INADDR_NONE 0xffffffff
#endif
/*
@@ -124,7 +134,8 @@ enum {
ZFTP_HERE = 0x0100, /* here rather than over there */
ZFTP_CDUP = 0x0200, /* CDUP rather than CWD */
ZFTP_REST = 0x0400, /* restart: set point in remote file */
- ZFTP_RECV = 0x0800 /* receive rather than send */
+ ZFTP_RECV = 0x0800, /* receive rather than send */
+ ZFTP_TEST = 0x1000 /* test command, don't test */
};
typedef struct zftpcmd *Zftpcmd;
@@ -134,6 +145,7 @@ static struct zftpcmd zftpcmdtab[] = {
{ "params", zftp_params, 0, 4, 0 },
{ "login", zftp_login, 0, 3, ZFTP_CONN },
{ "user", zftp_login, 0, 3, ZFTP_CONN },
+ { "test", zftp_test, 0, 0, ZFTP_TEST },
{ "cd", zftp_cd, 1, 1, ZFTP_CONN|ZFTP_LOGI },
{ "cdup", zftp_cd, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_CDUP },
{ "dir", zftp_dir, 0, -1, ZFTP_CONN|ZFTP_LOGI },
@@ -674,8 +686,8 @@ zfgetmsg()
zfgetline(line, 256, tmout);
ptr = line;
- if (zfdrrrring || !isdigit((int)*ptr) || !isdigit((int)ptr[1]) ||
- !isdigit((int)ptr[2])) {
+ if (zfdrrrring || !isdigit(STOUC(*ptr)) || !isdigit(STOUC(ptr[1])) ||
+ !isdigit(STOUC(ptr[2]))) {
/* timeout, or not talking FTP. not really interested. */
zcfinish = 2;
if (!zfclosing)
@@ -820,7 +832,7 @@ zfopendata(char *name)
zwarnnam(name, "Must set preference S or P to transfer data", NULL, 0);
return 1;
}
- zdfd = zfmovefd(socket(AF_INET, SOCK_STREAM, 0));
+ zdfd = socket(AF_INET, SOCK_STREAM, 0);
if (zdfd < 0) {
zwarnnam(name, "can't get data socket: %e", NULL, errno);
return 1;
@@ -851,7 +863,7 @@ zfopendata(char *name)
* lastmsg already has the reply code expunged.
*/
for (ptr = lastmsg; *ptr; ptr++)
- if (isdigit(*ptr))
+ if (isdigit(STOUC(*ptr)))
break;
if (sscanf(ptr, "%d,%d,%d,%d,%d,%d",
nums, nums+1, nums+2, nums+3, nums+4, nums+5) != 6) {
@@ -986,11 +998,11 @@ zfgetdata(char *name, char *rest, char *cmd, int getsize)
char *ptr = strstr(lastmsg, "bytes");
zfstatus |= ZFST_NOSZ|ZFST_TRSZ;
if (ptr) {
- while (ptr > lastmsg && !isdigit(*ptr))
+ while (ptr > lastmsg && !isdigit(STOUC(*ptr)))
ptr--;
- while (ptr > lastmsg && isdigit(ptr[-1]))
+ while (ptr > lastmsg && isdigit(STOUC(ptr[-1])))
ptr--;
- if (isdigit(*ptr)) {
+ if (isdigit(STOUC(*ptr))) {
zfstatus &= ~ZFST_NOSZ;
if (getsize) {
long sz = zstrtol(ptr, NULL, 10);
@@ -1017,6 +1029,13 @@ zfgetdata(char *name, char *rest, char *cmd, int getsize)
return 1;
}
zdfd = newfd; /* this is now the actual data fd */
+ } else {
+ /*
+ * We avoided dup'ing zdfd up to this point, to try to keep
+ * things simple, so we now need to move it out of the way
+ * of the user-visible fd's.
+ */
+ zdfd = zfmovefd(zdfd);
}
@@ -1659,7 +1678,7 @@ zftp_open(char *name, char **args, int flags)
}
zsock.sin_port = zservp->s_port;
- zcfd = zfmovefd(socket(zsock.sin_family, SOCK_STREAM, 0));
+ zcfd = socket(zsock.sin_family, SOCK_STREAM, 0);
if (zcfd < 0) {
zwarnnam(name, "socket failed: %e", NULL, errno);
zfunsetparam("ZFTP_HOST");
@@ -1667,12 +1686,6 @@ zftp_open(char *name, char **args, int flags)
return 1;
}
-#if defined(F_SETFD) && defined(FD_CLOEXEC)
- /* If the shell execs a program, we don't want this fd left open. */
- len = FD_CLOEXEC;
- fcntl(zcfd, F_SETFD, &len);
-#endif
-
/*
* now connect the socket. manual pages all say things like `this is all
* explained oh-so-wonderfully in some other manual page'. not.
@@ -1708,6 +1721,19 @@ zftp_open(char *name, char **args, int flags)
/* now we can talk to the control connection */
zcfinish = 0;
+
+ /*
+ * Move the fd out of the user-visible range. We need to do
+ * this after the connect() on some systems.
+ */
+ zcfd = zfmovefd(zcfd);
+
+#if defined(F_SETFD) && defined(FD_CLOEXEC)
+ /* If the shell execs a program, we don't want this fd left open. */
+ len = FD_CLOEXEC;
+ fcntl(zcfd, F_SETFD, &len);
+#endif
+
len = sizeof(zsock);
if (getsockname(zcfd, (struct sockaddr *)&zsock, &len) < 0) {
zwarnnam(name, "getsockname failed: %e", NULL, errno);
@@ -2022,6 +2048,69 @@ zftp_login(char *name, char **args, int flags)
return zfgetcwd();
}
+/*
+ * See if the server wants to tell us something. On a timeout, we usually
+ * have a `421 Timeout' or something such waiting for us, so we read
+ * it here. As well as being called explicitly by the user
+ * (precmd is a very good place for this, it's cheap since it has
+ * no network overhead), we call it in the bin_zftp front end if we
+ * have a connection and weren't going to call it anyway.
+ *
+ * Poll-free and select-free systems are few and far between these days,
+ * but I'm willing to consider suggestions.
+ */
+
+/**/
+static int
+zftp_test(char *name, char **args, int flags)
+{
+#if defined(HAVE_POLL) || defined(HAVE_SELECT)
+ int ret;
+# ifdef HAVE_POLL
+ struct pollfd pfd;
+# else
+ fd_set f;
+ struct timeval tv;
+# endif /* HAVE_POLL */
+
+ if (zcfd == -1)
+ return 1;
+
+# ifdef HAVE_POLL
+# ifndef POLLIN
+ /* safety first, though I think POLLIN is more common */
+# define POLLIN POLLNORM
+# endif /* HAVE_POLL */
+ pfd.fd = zcfd;
+ pfd.events = POLLIN;
+ if ((ret = poll(&pfd, 1, 0)) < 0 && errno != EINTR && errno != EAGAIN)
+ zfclose();
+ else if (ret > 0 && pfd.revents) {
+ /* handles 421 (maybe a bit noisily?) */
+ zfgetmsg();
+ }
+# else
+ FD_ZERO(&f);
+ FD_SET(zcfd, &f);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ if ((ret = select(zcfd +1, (SELECT_ARG_2_T) &f, NULL, NULL, &tv)) < 0
+ && errno != EINTR)
+ zfclose();
+ else if (ret > 0) {
+ /* handles 421 */
+ zfgetmsg();
+ }
+# endif /* HAVE_POLL */
+ /* if we now have zcfd == -1, then we've just been dumped out. */
+ return (zcfd == -1) ? 2 : 0;
+#else
+ zfwarnnam(name, "not supported on this system.", NULL, 0);
+ return 3;
+#endif /* defined(HAVE_POLL) || defined(HAVE_SELECT) */
+}
+
+
/* do ls or dir on the remote directory */
/**/
@@ -2476,7 +2565,7 @@ bin_zftp(char *name, char **args, char *ops, int func)
char fullname[11] = "zftp ";
char *cnam = *args++, *prefs, *ptr;
Zftpcmd zptr;
- int n, ret;
+ int n, ret = 0;
for (zptr = zftpcmdtab; zptr->nam; zptr++)
if (!strcmp(zptr->nam, cnam))
@@ -2521,8 +2610,25 @@ bin_zftp(char *name, char **args, char *ops, int func)
"B" : "S"), ZFPM_READONLY);
}
}
+#if defined(HAVE_SELECT) || defined (HAVE_POLL)
+ if (zcfd != -1 && !(zptr->flags & ZFTP_TEST)) {
+ /*
+ * Test the connection for a bad fd or incoming message, but
+ * only if the connection was last heard of open, and
+ * if we are not about to call the test command anyway.
+ * Not worth it unless we have select() or poll().
+ */
+ ret = zftp_test("zftp test", NULL, 0);
+ }
+#endif
if ((zptr->flags & ZFTP_CONN) && zcfd == -1) {
- zwarnnam(fullname, "not connected.", NULL, 0);
+ if (ret != 2) {
+ /*
+ * with ret == 2, we just got dumped out in the test,
+ * so enough messages already.
+ */
+ zwarnnam(fullname, "not connected.", NULL, 0);
+ }
return 1;
}
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index a0c013901..42bc92bb2 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -41,7 +41,7 @@ struct compctl cc_compos, cc_default, cc_first, cc_dummy;
/**/
Cmlist cmatcher;
-/* pointers to functions required by zle */
+/* pointers to functions required by zle and defined by compctl */
/**/
void (*printcompctlptr) _((char *, Compctl, int, int));
@@ -49,6 +49,24 @@ void (*printcompctlptr) _((char *, Compctl, int, int));
/**/
Compctl (*compctl_widgetptr) _((char *, char **));
+/**/
+void (*makecompparamsptr) _((void));
+
+/* pointers to functions required by compctl and defined by zle */
+
+/**/
+void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, int, int, int, int, int, char **));
+
+/**/
+char *(*comp_strptr) _((int*,int*));
+
+/**/
+int (*getcpatptr) _((char *, int, char *, int));
+
+/**/
+void (*makecomplistcallptr) _((Compctl));
+
+
/* Hash table for completion info for commands */
/**/
@@ -72,6 +90,23 @@ char **clwords;
/**/
int incompctlfunc;
+/* != 0 if we are in a new style completion function */
+
+/**/
+int incompfunc;
+
+/* global variables for shell parameters in new style completion */
+
+/**/
+long compcurrent,
+ compnmatches;
+
+/**/
+char *compcontext,
+ *compcommand,
+ *compprefix,
+ *compsuffix,
+ *compiprefix;
/* This variable and the functions rembslash() and quotename() came from *
* zle_tricky.c, but are now used in compctl.c, too. */
@@ -443,6 +478,8 @@ setup_comp1(Module m)
cc_first.refc = 10000;
cc_first.mask = 0;
cc_first.mask2 = CC_CCCONT;
+ compcontext = compcommand = compprefix = compsuffix =
+ compiprefix = NULL;
return 0;
}
@@ -469,6 +506,11 @@ finish_comp1(Module m)
deletehashtable(compctltab);
zfree(clwords, clwsize * sizeof(char *));
compctlreadptr = fallback_compctlread;
+ zsfree(compcontext);
+ zsfree(compcommand);
+ zsfree(compprefix);
+ zsfree(compiprefix);
+ zsfree(compsuffix);
return 0;
}
diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export
index 1ac9195df..c90161740 100644
--- a/Src/Zle/comp1.export
+++ b/Src/Zle/comp1.export
@@ -1,4 +1,5 @@
#!
+addmatchesptr
cc_compos
cc_default
cc_dummy
@@ -8,14 +9,26 @@ clwords
clwpos
clwsize
cmatcher
+compcommand
+compcontext
compctl_widgetptr
compctltab
+compcurrent
+compiprefix
+compnmatches
+compprefix
+comp_strptr
+compsuffix
freecmatcher
freecmlist
freecompcond
freecompctl
+getcpatptr
incompctlfunc
+incompfunc
instring
+makecomplistcallptr
+makecompparamsptr
patcomps
printcompctlptr
quotename
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 4d192fef8..1913d3828 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -373,7 +373,7 @@ parse_class(Cpattern p, unsigned char *s, unsigned char e)
/**/
static int
-get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
+get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl)
{
/* Parse the basic flags for completion:
* first is a flag that we are not in extended completion,
@@ -394,12 +394,17 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
if(argv[0] && argv[0][0] == '-')
argv++;
*av = argv;
- freecompctl(cc);
- cclist = COMP_REMOVE;
- return 0;
+ if (cl)
+ return 1;
+ else {
+ freecompctl(cc);
+ cclist = COMP_REMOVE;
+ return 0;
+ }
}
memset((void *)&cct, 0, sizeof(cct));
+ cct.mask2 = CC_CCCONT;
/* Loop through the flags until we have no more: *
* those with arguments are not properly allocated yet, *
@@ -505,6 +510,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
{
char *p;
+ if (cl) {
+ zerrnam(name, "illegal option -%c", NULL, **argv);
+ return 1;
+ }
if ((*argv)[1]) {
p = (*argv) + 1;
*argv = "" - 1;
@@ -516,26 +525,28 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
p = *++argv;
*argv = "" - 1;
}
- while (*p) {
- switch (*p) {
- case '+':
- cct.mask2 |= CC_XORCONT;
- break;
- case 'c':
- cct.mask2 |= CC_CCCONT;
- break;
- case '-':
- cct.mask2 |= CC_PATCONT;
- break;
- case 'x':
- cct.mask2 |= CC_DEFCONT;
- break;
- default:
- zwarnnam(name, "invalid retry specification character `%c'",
- NULL, *p);
- return 1;
- }
- p++;
+ switch (*p) {
+ case '+':
+ cct.mask2 = CC_XORCONT;
+ break;
+ case 'n':
+ cct.mask2 = 0;
+ break;
+ case '-':
+ cct.mask2 = CC_PATCONT;
+ break;
+ case 'x':
+ cct.mask2 = CC_DEFCONT;
+ break;
+ default:
+ zwarnnam(name, "invalid retry specification character `%c'",
+ NULL, *p);
+ return 1;
+ }
+ if (p[1]) {
+ zwarnnam(name, "too many retry specification characters: `%s'",
+ p + 1, 0);
+ return 1;
}
}
break;
@@ -645,7 +656,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
}
break;
case 'l':
- if ((*argv)[1]) {
+ if (cl) {
+ zerrnam(name, "illegal option -%c", NULL, **argv);
+ return 1;
+ } else if ((*argv)[1]) {
cct.subcmd = (*argv) + 1;
*argv = "" - 1;
} else if (!argv[1]) {
@@ -745,6 +759,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
*argv = "" - 1;
break;
case 'C':
+ if (cl) {
+ zerrnam(name, "illegal option -%c", NULL, **argv);
+ return 1;
+ }
if (first && !hx) {
cclist |= COMP_COMMAND;
} else {
@@ -754,6 +772,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
}
break;
case 'D':
+ if (cl) {
+ zerrnam(name, "illegal option -%c", NULL, **argv);
+ return 1;
+ }
if (first && !hx) {
isdef = 1;
cclist |= COMP_DEFAULT;
@@ -764,7 +786,11 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
}
break;
case 'T':
- if (first && !hx) {
+ if (cl) {
+ zerrnam(name, "illegal option -%c", NULL, **argv);
+ return 1;
+ }
+ if (first && !hx) {
cclist |= COMP_FIRST;
} else {
zwarnnam(name, "misplaced first completion (-T) flag",
@@ -773,6 +799,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
}
break;
case 'L':
+ if (cl) {
+ zerrnam(name, "illegal option -%c", NULL, **argv);
+ return 1;
+ }
if (!first || hx) {
zwarnnam(name, "illegal use of -L flag", NULL, 0);
return 1;
@@ -780,6 +810,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
cclist |= COMP_LIST;
break;
case 'x':
+ if (cl) {
+ zerrnam(name, "extended completion not allowed", NULL, 0);
+ return 1;
+ }
if (!argv[1]) {
zwarnnam(name, "condition expected after -%c", NULL,
**argv);
@@ -811,6 +845,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
if (*++argv && (!ready || ready == 2) &&
**argv == '+' && !argv[0][1]) {
+ if (cl) {
+ zerrnam(name, "xor'ed completion illegal", NULL, 0);
+ return 1;
+ }
/* There's an alternative (+) completion: assign
* what we have so far before moving on to that.
*/
@@ -835,6 +873,7 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
cc->xor = (Compctl) zcalloc(sizeof(*cc));
cc = cc->xor;
memset((void *)&cct, 0, sizeof(cct));
+ cct.mask2 = CC_CCCONT;
}
}
}
@@ -1084,7 +1123,7 @@ get_xcompctl(char *name, char ***av, Compctl cc, int isdef)
(*next)->cond = m;
argv++;
/* End of the condition; get the flags that go with it. */
- if (get_compctl(name, &argv, *next, 0, isdef))
+ if (get_compctl(name, &argv, *next, 0, isdef, 0))
return 1;
if ((!argv || !*argv) && (cclist & COMP_SPECIAL))
/* default, first, or command completion finished */
@@ -1362,17 +1401,16 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
t >>= 1;
}
}
- if (flags2 & (CC_XORCONT | CC_CCCONT | CC_PATCONT | CC_DEFCONT)) {
+ if (flags2 & (CC_XORCONT | CC_PATCONT | CC_DEFCONT)) {
printf(" -t");
if (flags2 & CC_XORCONT)
putchar('+');
- if (flags2 & CC_CCCONT)
- putchar('c');
if (flags2 & CC_PATCONT)
putchar('-');
if (flags2 & CC_DEFCONT)
putchar('x');
- }
+ } else if (!(flags2 & CC_CCCONT))
+ printf(" -tn");
/* now flags with arguments */
printif(cc->mstr, 'M');
if (flags2 & CC_NOSORT)
@@ -1518,7 +1556,7 @@ bin_compctl(char *name, char **argv, char *ops, int func)
return ret - 1;
cc = (Compctl) zcalloc(sizeof(*cc));
- if (get_compctl(name, &argv, cc, 1, 0)) {
+ if (get_compctl(name, &argv, cc, 1, 0, 0)) {
freecompctl(cc);
return 1;
}
@@ -1610,7 +1648,7 @@ compctl_widget(char *name, char **argv)
cclist = 0;
showmask = 0;
- if (get_compctl(name, &argv, cc, 1, 0)) {
+ if (get_compctl(name, &argv, cc, 1, 0, 0)) {
freecompctl(cc);
return NULL;
}
@@ -1632,8 +1670,478 @@ compctl_widget(char *name, char **argv)
return cc;
}
+/**/
+static int
+bin_complist(char *name, char **argv, char *ops, int func)
+{
+ Compctl cc;
+ int ret = 0;
+
+ if (!incompfunc) {
+ zerrnam(name, "can only be called from completion function", NULL, 0);
+ return 1;
+ }
+ cc = (Compctl) zcalloc(sizeof(*cc));
+ cclist = 0;
+ showmask = 0;
+
+ if (get_compctl(name, &argv, cc, 1, 0, 1))
+ ret = 1;
+ else if (*argv) {
+ zerrnam(name, "command names illegal", NULL, 0);
+ ret = 1;
+ } else
+ makecomplistcallptr(cc);
+
+ freecompctl(cc);
+ return ret;
+}
+
+/**/
+static int
+bin_compadd(char *name, char **argv, char *ops, int func)
+{
+ char *p, **sp, *e;
+ char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
+ char *pre = NULL, *suf = NULL, *group = NULL;
+ int f = 0, q = 0, m = 0, ns = 0, a = 0;
+
+ if (!incompfunc) {
+ zerrnam(name, "can only be called from completion function", NULL, 0);
+ return 1;
+ }
+ for (; *argv && **argv == '-'; argv++) {
+ for (p = *argv + 1; *p; p++) {
+ sp = NULL;
+ switch (*p) {
+ case 'q':
+ f |= CMF_REMOVE;
+ break;
+ case 'Q':
+ q = 1;
+ break;
+ case 'f':
+ f |= CMF_FILE;
+ break;
+ case 'n':
+ f |= CMF_NOLIST;
+ break;
+ case 'U':
+ m = 1;
+ break;
+ case 'P':
+ sp = &pre;
+ e = "string expected after -%c";
+ break;
+ case 'S':
+ sp = &suf;
+ e = "string expected after -%c";
+ break;
+ case 'J':
+ sp = &group;
+ e = "group name expected after -%c";
+ break;
+ case 'V':
+ if (!group)
+ ns = 1;
+ sp = &group;
+ e = "group name expected after -%c";
+ break;
+ case 'i':
+ sp = &ipre;
+ e = "string expected after -%c";
+ break;
+ case 'p':
+ sp = &ppre;
+ e = "string expected after -%c";
+ break;
+ case 's':
+ sp = &psuf;
+ e = "string expected after -%c";
+ break;
+ case 'W':
+ sp = &prpre;
+ e = "string expected after -%c";
+ break;
+ case 'a':
+ a = 1;
+ break;
+ case '-':
+ argv++;
+ goto ca_args;
+ default:
+ zerrnam(name, "bad option: -%c", NULL, *p);
+ return 1;
+ }
+ if (sp) {
+ if (*sp) {
+ zerrnam(name, "doubled option: -%c", NULL, *p);
+ return 1;
+ }
+ if (p[1]) {
+ *sp = p + 1;
+ p = "" - 1;
+ } else if (argv[1]) {
+ *sp = *++argv;
+ p = "" - 1;
+ } else {
+ zerrnam(name, e, NULL, *p);
+ return 1;
+ }
+ }
+ }
+ }
+ ca_args:
+ if (!*argv) {
+ zerrnam(name, "missing completions", NULL, 0);
+ return 1;
+ }
+ addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group,
+ f, q, m, ns, a, argv);
+ return 0;
+}
+
+#define VAR(X) ((void *) (&(X)))
+static struct compparam {
+ char *name;
+ int type;
+ void *var;
+} compparams[] = {
+ { "CURRENT", PM_INTEGER, VAR(compcurrent) },
+ { "CONTEXT", PM_SCALAR, VAR(compcontext) },
+ { "COMMAND", PM_SCALAR, VAR(compcommand) },
+ { "PREFIX", PM_SCALAR, VAR(compprefix) },
+ { "SUFFIX", PM_SCALAR, VAR(compsuffix) },
+ { "IPREFIX", PM_SCALAR, VAR(compiprefix) },
+ { "NMATCHES", PM_INTEGER, VAR(compnmatches) },
+ { NULL, 0, NULL }
+};
+
+/**/
+void makecompparams(void)
+{
+ struct compparam *cp;
+
+ for (cp = compparams; cp->name; cp++) {
+ Param pm = createparam(cp->name, cp->type | PM_SPECIAL);
+ if (!pm)
+ pm = (Param) paramtab->getnode(paramtab, cp->name);
+ DPUTS(!pm, "param not set in makecompparams");
+
+ pm->level = locallevel;
+ pm->u.data = cp->var;
+ switch(PM_TYPE(cp->type)) {
+ case PM_SCALAR:
+ pm->sets.cfn = strvarsetfn;
+ pm->gets.cfn = strvargetfn;
+ break;
+ case PM_INTEGER:
+ pm->sets.ifn = intvarsetfn;
+ pm->gets.ifn = intvargetfn;
+ break;
+ }
+ pm->unsetfn = compunsetfn;
+ }
+}
+
+/**/
+static void
+compunsetfn(Param pm, int exp)
+{
+ if (exp)
+ stdunsetfn(pm, exp);
+}
+
+/**/
+static int
+comp_wrapper(List list, FuncWrap w, char *name)
+{
+ if (!incompfunc)
+ return 1;
+ else {
+ char *octxt, *ocmd, *opre, *osuf, *oipre;
+ long ocur;
+
+ ocur = compcurrent;
+ octxt = dupstring(compcontext);
+ ocmd = dupstring(compcommand);
+ opre = dupstring(compprefix);
+ osuf = dupstring(compsuffix);
+ oipre = dupstring(compiprefix);
+
+ runshfunc(list, w, name);
+
+ compcurrent = ocur;
+ zsfree(compcontext);
+ compcontext = ztrdup(octxt);
+ zsfree(compcommand);
+ compcommand = ztrdup(ocmd);
+ zsfree(compprefix);
+ compprefix = ztrdup(opre);
+ zsfree(compsuffix);
+ compsuffix = ztrdup(osuf);
+ zsfree(compiprefix);
+ compiprefix = ztrdup(oipre);
+
+ return 0;
+ }
+}
+
+/**/
+static void
+ignore_prefix(int l)
+{
+ char *o, sav = compprefix[l];
+
+ compprefix[l] = '\0';
+ o = compiprefix;
+ compiprefix = tricat(o, compprefix, "");
+ zsfree(o);
+ compprefix[l] = sav;
+ o = compprefix;
+ compprefix = ztrdup(o + l);
+ zsfree(o);
+}
+
+/**/
+static int
+comp_check(void)
+{
+ if (!incompfunc) {
+ zerr("condition can only be used in completion function", NULL, 0);
+ return 0;
+ }
+ return 1;
+}
+
+/**/
+static void
+restrict_range(int b, int e)
+{
+ int i = e - b;
+ char **p = (char **) zcalloc((i + 1) * sizeof(char *)), **q, **pp;
+
+ for (q = p, pp = pparams + b + 1; i; i--, q++, pp++)
+ *q = ztrdup(*pp);
+ zsfree(compcommand);
+ compcommand = ztrdup(pparams[b]);
+ freearray(pparams);
+ pparams = p;
+ zsfree(compcontext);
+ if ((compcurrent -= b + 1))
+ compcontext = ztrdup("arg");
+ else
+ compcontext = ztrdup("cmd");
+}
+
+/**/
+static int
+cond_prefix(char **a, int id)
+{
+ if (comp_check())
+ return strpfx(cond_str(a, 0), compprefix);
+ return 0;
+}
+
+/**/
+static int
+cond_iprefix(char **a, int id)
+{
+ if (comp_check()) {
+ char *s = cond_str(a, 0);
+
+ if (strpfx(s, compprefix)) {
+ ignore_prefix(strlen(s));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**/
+static int
+cond_position(char **a, int id)
+{
+ if (comp_check()) {
+ int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : b);
+ int l = arrlen(pparams), t, i = compcurrent - 1;
+
+ if (b > 0)
+ b--;
+ if (e > 0)
+ e--;
+ if (b < 0)
+ b += l;
+ if (e < 0)
+ e += l;
+ t = (b >= 0 && e >= 0 && i >= b && i <= e && b <= e);
+
+ if (t && a[1]) {
+ if (b > l)
+ b = l;
+ if (e > l)
+ e = l;
+ restrict_range(b, e);
+ }
+ return t;
+ }
+ return 0;
+}
+
+/**/
+static int
+cond_word(char **a, int id)
+{
+ if (comp_check()) {
+ int o = ((id & 2) ? compcurrent : 0) + cond_val(a, 0);
+ int l = arrlen(pparams);
+ char *s;
+
+ if (o < 0)
+ o += l;
+
+ o--;
+ if (o < 0 || o >= l)
+ return 0;
+
+ s = pparams[o];
+ return ((id & 1) ? cond_match(a, 1, s) : !strcmp(s, cond_str(a, 1)));
+ }
+ return 0;
+}
+
+/**/
+static int
+cond_strcl(char **a, int id)
+{
+ if (comp_check()) {
+ char *s;
+ int i;
+
+ if (a[1]) {
+ s = cond_str(a, 1);
+ i = cond_val(a, 0);
+ } else {
+ s = cond_str(a, 0);
+ i = -1;
+ }
+ if (!getcpatptr) {
+ zerr("zle not loaded, zle condition not available", NULL, 0);
+ return 1;
+ }
+ i = getcpatptr(comp_strptr(NULL, NULL), i, s, id);
+ if (i != -1) {
+ ignore_prefix(i);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**/
+static int
+cond_words(char **a, int id)
+{
+ if (comp_check()) {
+ int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : -1);
+ int l = arrlen(pparams);
+
+ return (l >= b && l <= e);
+ }
+ return 0;
+}
+
+/**/
+static int
+cond_range(char **a, int id)
+{
+ if (comp_check()) {
+ char *s, **p;
+ int i, l = arrlen(pparams), t = 0, b = 0, e = l - 1;
+ Comp c;
+
+ i = compcurrent - 1;
+ if (i < 0 || i >= l)
+ return 0;
+
+ if (id & 1) {
+ s = a[0];
+ singsub(&s);
+ c = parsereg(s);
+ } else
+ s = cond_str(a, 0);
+
+ for (i--, p = pparams + i; i >= 0; p--, i--) {
+ if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) {
+ b = i + 1;
+ t = 1;
+ break;
+ }
+ }
+ if (t && (id & 2)) {
+ int tt = 0;
+
+ if (id & 1) {
+ s = a[1];
+ singsub(&s);
+ c = parsereg(s);
+ } else
+ s = cond_str(a, 1);
+
+ for (i++, p = pparams + i; i < l; p++, i++) {
+ if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) {
+ e = i - 1;
+ tt = 1;
+ break;
+ }
+ }
+ if (tt && i < compcurrent)
+ t = 0;
+ }
+ if (e < b)
+ t = 0;
+ if (t)
+ restrict_range(b, e);
+ return t;
+ }
+ return 0;
+}
+
+/**/
+static int
+cond_nmatches(char **a, int id)
+{
+ if (comp_check())
+ return compnmatches == cond_val(a, 0);
+ return 0;
+}
+
static struct builtin bintab[] = {
BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL),
+ BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL),
+ BUILTIN("compadd", 0, bin_compadd, 1, -1, 0, NULL, NULL),
+};
+
+static struct conddef cotab[] = {
+ CONDDEF("prefix", 0, cond_prefix, 1, 1, 0),
+ CONDDEF("iprefix", 0, cond_iprefix, 1, 1, 0),
+ CONDDEF("position", 0, cond_position, 1, 2, 0),
+ CONDDEF("word", 0, cond_word, 2, 2, 0),
+ CONDDEF("mword", 0, cond_word, 2, 2, 1),
+ CONDDEF("current", 0, cond_word, 2, 2, 2),
+ CONDDEF("mcurrent", 0, cond_word, 2, 2, 3),
+ CONDDEF("string", 0, cond_strcl, 1, 2, 0),
+ CONDDEF("class", 0, cond_strcl, 1, 2, 1),
+ CONDDEF("words", 0, cond_words, 1, 2, 0),
+ CONDDEF("between", 0, cond_range, 2, 2, 2),
+ CONDDEF("mbetween", 0, cond_range, 2, 2, 3),
+ CONDDEF("after", 0, cond_range, 1, 1, 0),
+ CONDDEF("mafter", 0, cond_range, 1, 1, 1),
+ CONDDEF("nmatches", 0, cond_nmatches, 1, 1, 0),
+};
+
+static struct funcwrap wrapper[] = {
+ WRAPDEF(comp_wrapper),
};
/**/
@@ -1643,6 +2151,7 @@ setup_compctl(Module m)
compctltab->printnode = printcompctlp;
printcompctlptr = printcompctl;
compctl_widgetptr = compctl_widget;
+ makecompparamsptr = makecompparams;
return 0;
}
@@ -1650,7 +2159,9 @@ setup_compctl(Module m)
int
boot_compctl(Module m)
{
- if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)))
+ if(!(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
+ addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
+ !addwrapper(m, wrapper)))
return 1;
return 0;
}
@@ -1662,6 +2173,8 @@ int
cleanup_compctl(Module m)
{
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
+ deletewrapper(m, wrapper);
return 0;
}
@@ -1672,6 +2185,7 @@ finish_compctl(Module m)
compctltab->printnode = NULL;
printcompctlptr = NULL;
compctl_widgetptr = NULL;
+ makecompparamsptr = NULL;
return 0;
}
diff --git a/Src/Zle/compctl.mdd b/Src/Zle/compctl.mdd
index c83ecda29..48aabe38a 100644
--- a/Src/Zle/compctl.mdd
+++ b/Src/Zle/compctl.mdd
@@ -1,5 +1,7 @@
moddeps="comp1"
-autobins="compctl"
+autobins="compctl complist compadd"
+
+autoprefixconds="prefix iprefix position word mword current mcurrent string class words between mbetween after mafter nmatches"
objects="compctl.o"
diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index 52e70fad5..12425d872 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -25,11 +25,11 @@
"beginning-of-line-hist", beginningoflinehist, 0
"capitalize-word", capitalizeword, 0
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
-"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX
+"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"copy-prev-word", copyprevword, 0
"copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX
"delete-char", deletechar, ZLE_KEEPSUFFIX
-"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX
+"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"delete-word", deleteword, ZLE_KEEPSUFFIX
"describe-key-briefly", describekeybriefly, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"digit-argument", digitargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
@@ -48,8 +48,8 @@
"execute-named-cmd", NULL, 0
"expand-cmd-path", expandcmdpath, 0
"expand-history", expandhistory, 0
-"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
-"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX
+"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
+"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"expand-word", expandword, 0
"forward-char", forwardchar, 0
"forward-word", forwardword, 0
@@ -68,11 +68,11 @@
"kill-region", killregion, ZLE_KILL | ZLE_KEEPSUFFIX
"kill-whole-line", killwholeline, ZLE_KILL | ZLE_KEEPSUFFIX
"kill-word", killword, ZLE_KILL | ZLE_KEEPSUFFIX
-"list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
+"list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_ISCOMP
"list-expand", listexpand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"magic-space", magicspace, 0
-"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
-"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
+"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
+"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"overwrite-mode", overwritemode, 0
"pound-insert", poundinsert, 0
@@ -84,7 +84,7 @@
"quote-region", quoteregion, 0
"redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"redo", redo, 0
-"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
+"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 71a929f87..f12505bd3 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -47,23 +47,29 @@ struct widget {
ZleIntFunc fn; /* pointer to internally implemented widget */
char *fnnam; /* name of the shell function for user-defined widget */
Compctl cc; /* for use with a WIDGET_COMP widget */
+ struct {
+ ZleIntFunc fn; /* internal widget function to call */
+ char *wid; /* name of widget to call */
+ char *func; /* name of shell function to call */
+ } comp;
} u;
};
#define WIDGET_INT (1<<0) /* widget is internally implemented */
#define WIDGET_COMP (1<<1) /* Special completion widget */
-#define ZLE_MENUCMP (1<<2) /* DON'T invalidate completion list */
-#define ZLE_YANK (1<<3)
-#define ZLE_LINEMOVE (1<<4) /* command is a line-oriented movement */
-#define ZLE_LASTCOL (1<<5) /* command maintains lastcol correctly */
-#define ZLE_KILL (1<<6)
+#define WIDGET_NCOMP (1<<2) /* new style completion widget */
+#define ZLE_MENUCMP (1<<3) /* DON'T invalidate completion list */
+#define ZLE_YANK (1<<4)
+#define ZLE_LINEMOVE (1<<5) /* command is a line-oriented movement */
+#define ZLE_LASTCOL (1<<6) /* command maintains lastcol correctly */
+#define ZLE_KILL (1<<7)
#define ZLE_KEEPSUFFIX (1<<9) /* DON'T remove added suffix */
#define ZLE_USEMENU (1<<10) /* Do ) use menu completion for */
#define ZLE_NOMENU (1<<11) /* Don't ) widget, else use default */
#define ZLE_USEGLOB (1<<12) /* Do ) use glob completion for */
#define ZLE_NOGLOB (1<<13) /* Don't ) widget, else use default */
#define ZLE_NOTCOMMAND (1<<14) /* widget should not alter lastcmd */
-
+#define ZLE_ISCOMP (1<<15) /* usable for new style completion */
/* thingies */
struct thingy {
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 7de96bd03..1ffe6f156 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -598,10 +598,10 @@ bin_bindkey(char *name, char **argv, char *ops, int func)
int n;
/* select operation and ensure no clashing arguments */
- for(op = opns; op->o && !ops[op->o]; op++) ;
+ for(op = opns; op->o && !ops[STOUC(op->o)]; op++) ;
if(op->o)
for(opp = op; (++opp)->o; )
- if(ops[opp->o]) {
+ if(ops[STOUC(opp->o)]) {
zwarnnam(name, "incompatible operation selection options",
NULL, 0);
return 1;
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 515405a0d..2c0d3655e 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -443,9 +443,9 @@ zleread(char *lp, char *rp, int ha)
insmode = unset(OVERSTRIKE);
eofsent = 0;
resetneeded = 0;
- lpptbuf = promptexpand(lp, 1, NULL, NULL);
+ lpromptbuf = promptexpand(lp, 1, NULL, NULL);
pmpt_attr = txtchange;
- rpptbuf = promptexpand(rp, 1, NULL, NULL);
+ rpromptbuf = promptexpand(rp, 1, NULL, NULL);
rpmpt_attr = txtchange;
histallowed = ha;
PERMALLOC {
@@ -529,8 +529,8 @@ zleread(char *lp, char *rp, int ha)
statusline = NULL;
invalidatelist();
trashzle();
- free(lpptbuf);
- free(rpptbuf);
+ free(lpromptbuf);
+ free(rpromptbuf);
zleactive = 0;
alarm(0);
} LASTALLOC;
@@ -565,13 +565,14 @@ execzlefunc(Thingy func)
showmsg(msg);
zsfree(msg);
feep();
- } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_COMP)) {
+ } else if((w = func->widget)->flags &
+ (WIDGET_INT|WIDGET_COMP | WIDGET_NCOMP)) {
int wflags = w->flags;
if(!(wflags & ZLE_KEEPSUFFIX))
removesuffix();
if(!(wflags & ZLE_MENUCMP) ||
- ((wflags & WIDGET_COMP) && compwidget != w)) {
+ ((wflags & (WIDGET_COMP|WIDGET_NCOMP)) && compwidget != w)) {
/* If we are doing a special completion, and the widget
* is not the one currently in use for special completion,
* we are starting a new completion.
@@ -586,6 +587,9 @@ execzlefunc(Thingy func)
if (wflags & WIDGET_COMP) {
compwidget = w;
completespecial();
+ } else if (wflags & WIDGET_NCOMP) {
+ compwidget = w;
+ completecall();
} else
w->u.fn();
if (!(wflags & ZLE_NOTCOMMAND))
@@ -855,7 +859,7 @@ trashzle(void)
static struct builtin bintab[] = {
BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaMldDANmrsLR", NULL),
BUILTIN("vared", 0, bin_vared, 1, 7, 0, NULL, NULL),
- BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgG", NULL),
+ BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgGc", NULL),
};
/**/
@@ -869,6 +873,11 @@ setup_zle(Module m)
spaceinlineptr = spaceinline;
zlereadptr = zleread;
+ addmatchesptr = addmatches;
+ comp_strptr = comp_str;
+ getcpatptr = getcpat;
+ makecomplistcallptr = makecomplistcall;
+
/* initialise the thingies */
init_thingies();
@@ -931,6 +940,11 @@ finish_zle(Module m)
spaceinlineptr = noop_function_int;
zlereadptr = fallback_zleread;
+ addmatchesptr = NULL;
+ comp_strptr = NULL;
+ getcpatptr = NULL;
+ makecomplistcallptr = NULL;
+
return 0;
}
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 27e9f2071..c8d6c70a7 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -33,7 +33,7 @@
/* Expanded prompts */
/**/
-char *lpptbuf, *rpptbuf;
+char *lpromptbuf, *rpromptbuf;
/* Text attributes after displaying prompts */
@@ -77,17 +77,17 @@ int cost;
/* Oct/Nov 94: <mason> some code savagely redesigned to fix several bugs -
refreshline() & tc_rightcurs() majorly rewritten; zrefresh() fixed -
I've put my fingers into just about every routine in here -
- any queries about updates to mason@werple.net.au */
+ any queries about updates to mason@primenet.com.au */
static char **nbuf = NULL, /* new video buffer line-by-line char array */
**obuf = NULL; /* old video buffer line-by-line char array */
static int more_start, /* more text before start of screen? */
more_end, /* more stuff after end of screen? */
- lppth, /* lines taken up by the prompt */
olnct, /* previous number of lines */
ovln, /* previous video cursor position line */
- pptw, rpw, /* prompt widths on screen */
- rppth, /* right prompt height */
+ lpromptw, rpromptw, /* prompt widths on screen */
+ lprompth, /* lines taken up by the prompt */
+ rprompth, /* right prompt height */
vcs, vln, /* video cursor position column & line */
vmaxln, /* video maximum number of lines */
winw, winh, rwinh, /* window width & height */
@@ -100,7 +100,6 @@ resetvideo(void)
int ln;
static int lwinw = -1, lwinh = -1; /* last window width & height */
- genprompts();
winw = columns; /* terminal width */
if (termflags & TERM_SHORT)
winh = 1;
@@ -132,13 +131,16 @@ resetvideo(void)
*obuf[ln] = '\0';
}
- if (pptw) {
- memset(nbuf[0], ' ', pptw);
- memset(obuf[0], ' ', pptw);
- nbuf[0][pptw] = obuf[0][pptw] = '\0';
+ countprompt(lpromptbuf, &lpromptw, &lprompth);
+ countprompt(rpromptbuf, &rpromptw, &rprompth);
+
+ if (lpromptw) {
+ memset(nbuf[0], ' ', lpromptw);
+ memset(obuf[0], ' ', lpromptw);
+ nbuf[0][lpromptw] = obuf[0][lpromptw] = '\0';
}
- vcs = pptw;
+ vcs = lpromptw;
olnct = nlnct = 0;
if (showinglist > 0)
showinglist = -2;
@@ -280,21 +282,25 @@ zrefresh(void)
tsetcap(TCSTANDOUTEND, 0);
tsetcap(TCUNDERLINEEND, 0);
- if (!clearflag)
+ if (!clearflag) {
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
else
cleareol = 1; /* request: clear to end of line */
+ }
if (t0 > -1)
olnct = t0;
if (termflags & TERM_SHORT)
vcs = 0;
- else if (!clearflag && lpptbuf[0])
- zputs(lpptbuf, shout);
+ else if (!clearflag && lpromptbuf[0]) {
+ zputs(lpromptbuf, shout);
+ if (lpromptw == 0)
+ zputs("\n", shout); /* works with both hasam and !hasam */
+ }
if (clearflag) {
zputc('\r', shout);
vcs = 0;
- moveto(0, pptw);
+ moveto(0, lpromptw);
}
fflush(shout);
clearf = clearflag;
@@ -326,7 +332,7 @@ zrefresh(void)
if (!*nbuf)
*nbuf = (char *)zalloc(winw + 2);
- s = (unsigned char *)(nbuf[ln = 0] + pptw);
+ s = (unsigned char *)(nbuf[ln = 0] + lpromptw);
t = line;
sen = (unsigned char *)(*nbuf + winw);
for (; t < line+ll; t++) {
@@ -425,15 +431,16 @@ zrefresh(void)
/* determine whether the right-prompt exists and can fit on the screen */
if (!more_start)
- put_rpmpt = rppth == 1 && rpptbuf[0] && !strchr(rpptbuf, '\t') &&
- (int)strlen(nbuf[0]) + rpw < winw - 1;
+ put_rpmpt = rprompth == 1 && rpromptbuf[0] &&
+ !strchr(rpromptbuf, '\t') &&
+ (int)strlen(nbuf[0]) + rpromptw < winw - 1;
else {
/* insert >.... on first line if there is more text before start of screen */
- memset(nbuf[0], ' ', pptw);
- t0 = winw - pptw;
+ memset(nbuf[0], ' ', lpromptw);
+ t0 = winw - lpromptw;
t0 = t0 > 5 ? 5 : t0;
- strncpy(nbuf[0] + pptw, ">....", t0);
- memset(nbuf[0] + pptw + t0, ' ', winw - t0 - pptw);
+ strncpy(nbuf[0] + lpromptw, ">....", t0);
+ memset(nbuf[0] + lpromptw + t0, ' ', winw - t0 - lpromptw);
nbuf[0][winw] = nbuf[0][winw + 1] = '\0';
}
@@ -477,8 +484,8 @@ zrefresh(void)
/* output the right-prompt if appropriate */
if (put_rpmpt && !ln && !oput_rpmpt) {
- moveto(0, winw - 1 - rpw);
- zputs(rpptbuf, shout);
+ moveto(0, winw - 1 - rpromptw);
+ zputs(rpromptbuf, shout);
vcs = winw - 1;
/* reset character attributes to that set by the main prompt */
txtchange = pmpt_attr;
@@ -659,12 +666,12 @@ refreshline(int ln)
/* 2c: if we're on the first line, start checking at the end of the prompt;
we shouldn't be doing anything within the prompt */
- if (ln == 0 && pptw) {
- i = pptw - ccs;
+ if (ln == 0 && lpromptw) {
+ i = lpromptw - ccs;
j = strlen(ol);
nl += i;
ol += (i > j ? j : i); /* if ol is too short, point it to '\0' */
- ccs = pptw;
+ ccs = lpromptw;
}
/* 3: main display loop - write out the buffer using whatever tricks we can */
@@ -815,7 +822,7 @@ moveto(int ln, int cl)
instead of TCDOWN */
while (ln > vln) {
- if (vln < vmaxln - 1)
+ if (vln < vmaxln - 1) {
if (ln > vmaxln - 1) {
if (tc_downcurs(vmaxln - 1 - vln))
vcs = 0;
@@ -826,6 +833,7 @@ moveto(int ln, int cl)
vln = ln;
continue;
}
+ }
zputc('\r', shout), vcs = 0; /* safety precaution */
while (ln > vln) {
zputc('\n', shout);
@@ -893,21 +901,23 @@ tc_rightcurs(int cl)
/* otherwise _carefully_ write the contents of the video buffer.
if we're anywhere in the prompt, goto the left column and write the whole
- prompt out unless ztrlen(lpptbuf) == pptw : we can cheat then */
- if (vln == 0 && i < pptw) {
- if (strlen(lpptbuf) == pptw)
- fputs(lpptbuf + i, shout);
- else if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpptbuf)))
+ prompt out unless ztrlen(lpromptbuf) == lpromptw : we can cheat then */
+ if (vln == 0 && i < lpromptw) {
+ if (strlen(lpromptbuf) == lpromptw)
+ fputs(lpromptbuf + i, shout);
+ else if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpromptbuf)))
/* it is cheaper to send TCRIGHT than reprint the whole prompt */
- for (ct = pptw - i; ct--; )
+ for (ct = lpromptw - i; ct--; )
tcout(TCRIGHT);
else {
if (i != 0)
zputc('\r', shout);
- tc_upcurs(lppth - 1);
- zputs(lpptbuf, shout);
+ tc_upcurs(lprompth - 1);
+ zputs(lpromptbuf, shout);
+ if (lpromptw == 0)
+ zputs("\n", shout); /* works with both hasam and !hasam */
}
- i = pptw;
+ i = lpromptw;
ct = cl - i;
}
@@ -969,7 +979,7 @@ redisplay(void)
{
moveto(0, 0);
zputc('\r', shout); /* extra care */
- tc_upcurs(lppth - 1);
+ tc_upcurs(lprompth - 1);
resetneeded = 1;
clearflag = 0;
}
@@ -987,7 +997,7 @@ singlerefresh(void)
nlnct = 1;
/* generate the new line buffer completely */
- for (vsiz = 1 + pptw, t0 = 0; t0 != ll; t0++, vsiz++)
+ for (vsiz = 1 + lpromptw, t0 = 0; t0 != ll; t0++, vsiz++)
if (line[t0] == '\t')
vsiz = (vsiz | 7) + 1;
else if (icntrl(line[t0]))
@@ -1002,9 +1012,10 @@ singlerefresh(void)
cs = 0;
}
- memcpy(vbuf, strchr(lpptbuf, 0) - pptw, pptw); /* only use last part of prompt */
- vbuf[pptw] = '\0';
- vp = vbuf + pptw;
+ /* only use last part of prompt */
+ memcpy(vbuf, strchr(lpromptbuf, 0) - lpromptw, lpromptw);
+ vbuf[lpromptw] = '\0';
+ vp = vbuf + lpromptw;
for (t0 = 0; t0 != ll; t0++) {
if (line[t0] == '\t')
@@ -1104,13 +1115,3 @@ singmoveto(int pos)
}
}
}
-
-/* recheck size of prompts */
-
-/**/
-static void
-genprompts(void)
-{
- countprompt(lpptbuf, &pptw, &lppth);
- countprompt(rpptbuf, &rpw, &rppth);
-}
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 68329be65..2e21b5add 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -246,7 +246,10 @@ freewidget(Widget w)
{
if ((w->flags & WIDGET_COMP) && w->u.cc)
freecompctl(w->u.cc);
- else if(!(w->flags & WIDGET_INT))
+ else if (w->flags & WIDGET_NCOMP) {
+ zsfree(w->u.comp.wid);
+ zsfree(w->u.comp.func);
+ } else if(!(w->flags & WIDGET_INT))
zsfree(w->u.fnnam);
zfree(w, sizeof(*w));
}
@@ -337,16 +340,17 @@ bin_zle(char *name, char **args, char *ops, int func)
{ 'A', bin_zle_link, 2, 2 },
{ 'N', bin_zle_new, 1, 2 },
{ 'C', bin_zle_compctl, 1, -1},
+ { 'c', bin_zle_complete, 3, 3 },
{ 0, bin_zle_call, 0, -1 },
};
struct opn const *op, *opp;
int n;
/* select operation and ensure no clashing arguments */
- for(op = opns; op->o && !ops[op->o]; op++) ;
+ for(op = opns; op->o && !ops[STOUC(op->o)]; op++) ;
if(op->o)
for(opp = op; (++opp)->o; )
- if(ops[opp->o]) {
+ if(ops[STOUC(opp->o)]) {
zerrnam(name, "incompatible operation selection options",
NULL, 0);
return 1;
@@ -395,6 +399,11 @@ scanlistwidgets(HashNode hn, int list)
if (w->flags & WIDGET_COMP) {
if (printcompctlptr && w->u.cc)
printcompctlptr(NULL, w->u.cc, PRINT_LIST, 0);
+ } else if (w->flags & WIDGET_NCOMP) {
+ fputc(' ', stdout);
+ quotedzputs(w->u.comp.wid, stdout);
+ fputc(' ', stdout);
+ quotedzputs(w->u.comp.func, stdout);
} else if(strcmp(t->nam, w->u.fnnam)) {
fputc(' ', stdout);
quotedzputs(w->u.fnnam, stdout);
@@ -405,6 +414,11 @@ scanlistwidgets(HashNode hn, int list)
fputs(" -C", stdout);
if (printcompctlptr && w->u.cc)
printcompctlptr(NULL, w->u.cc, PRINT_TYPE, 0);
+ } else if (w->flags & WIDGET_NCOMP) {
+ fputs(" -c ", stdout);
+ nicezputs(w->u.comp.wid, stdout);
+ fputc(' ', stdout);
+ nicezputs(w->u.comp.func, stdout);
} else if(strcmp(t->nam, w->u.fnnam)) {
fputs(" (", stdout);
nicezputs(w->u.fnnam, stdout);
@@ -506,11 +520,39 @@ bin_zle_compctl(char *name, char **args, char *ops, char func)
/**/
static int
+bin_zle_complete(char *name, char **args, char *ops, char func)
+{
+ Thingy t;
+ Widget w, cw;
+
+ t = rthingy(args[1]);
+ cw = t->widget;
+ unrefthingy(t);
+ if (!(cw->flags & ZLE_ISCOMP)) {
+ zerrnam(name, "invalid widget `%s'", args[1], 0);
+ return 1;
+ }
+ w = zalloc(sizeof(*w));
+ w->flags = WIDGET_NCOMP|ZLE_MENUCMP|ZLE_KEEPSUFFIX;
+ w->first = NULL;
+ w->u.comp.fn = cw->u.fn;
+ w->u.comp.wid = ztrdup(args[1]);
+ w->u.comp.func = ztrdup(args[2]);
+ if (bindwidget(w, rthingy(args[0]))) {
+ freewidget(w);
+ zerrnam(name, "widget name `%s' is protected", args[0], 0);
+ return 1;
+ }
+ return 0;
+}
+
+/**/
+static int
bin_zle_call(char *name, char **args, char *ops, char func)
{
Thingy t;
- if(!zleactive || incompctlfunc) {
+ if(!zleactive || incompctlfunc || incompfunc) {
zerrnam(name, "widgets can only be called when ZLE is active",
NULL, 0);
return 1;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 8c976449e..a958752ca 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -237,6 +237,15 @@ struct aminfo {
static Aminfo ainfo, fainfo;
+/* This contains the name of the function to call if this is for a new *
+ * style completion. */
+
+static char *compfunc = NULL;
+
+/* The memory heap to use for new style completion generation. */
+
+static Heap compheap;
+
/* Find out if we have to insert a tab (instead of trying to complete). */
/**/
@@ -274,6 +283,15 @@ completespecial(void)
/**/
void
+completecall(void)
+{
+ compfunc = compwidget->u.comp.func;
+ compwidget->u.comp.fn();
+ compfunc = NULL;
+}
+
+/**/
+void
completeword(void)
{
usemenu = isset(MENUCOMPLETE);
@@ -408,11 +426,15 @@ reversemenucomplete(void)
void
acceptandmenucomplete(void)
{
+ int sl = suffixlen[' '];
+
if (!menucmp) {
feep();
return;
}
- cs = menuend + menuinsc;
+ cs = menupos + menulen + menuinsc;
+ if (sl)
+ backdel(sl);
inststrlen(" ", 1, 1);
menuinsc = menulen = 0;
menupos = cs;
@@ -439,6 +461,13 @@ static int lastambig;
static char *cmdstr;
+/* This hold the name of the variable we are working on. */
+
+static char *varname;
+
+/* != 0 if we are in a subscript */
+
+static int insubscr;
/* Check if the given string is the name of a parameter and if this *
* parameter is one worth expanding. */
@@ -614,16 +643,13 @@ docomplete(int lst)
lst = COMP_EXPAND;
else {
int t0, n = 0;
- char *fc;
struct hashnode *hn;
for (t0 = cmdnamtab->hsize - 1; t0 >= 0; t0--)
for (hn = cmdnamtab->nodes[t0]; hn;
hn = hn->next) {
- if (strpfx(q, hn->nam) && (fc = findcmd(hn->nam))) {
- zsfree(fc);
+ if (strpfx(q, hn->nam) && findcmd(hn->nam, 0))
n++;
- }
if (n == 2)
break;
}
@@ -889,7 +915,7 @@ unmetafy_line(void)
static char *
get_comp_string(void)
{
- int t0, tt0, i, j, k, cp, rd, sl, ocs;
+ int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins;
char *s = NULL, *linptr, *tmp, *p, *tt = NULL;
zsfree(brbeg);
@@ -943,13 +969,16 @@ get_comp_string(void)
linredir = inredir;
zsfree(cmdstr);
cmdstr = NULL;
+ zsfree(varname);
+ varname = NULL;
+ insubscr = 0;
zleparse = 1;
clwpos = -1;
lexsave();
inpush(dupstrspace((char *) linptr), 0, NULL);
strinbeg();
stophist = 2;
- i = tt0 = cp = rd = 0;
+ i = tt0 = cp = rd = ins = oins = 0;
/* This loop is possibly the wrong way to do this. It goes through *
* the previously massaged command line using the lexer. It stores *
@@ -963,8 +992,10 @@ get_comp_string(void)
* this would be to pass the command line through the parser too, *
* and get the arguments that way. Maybe in 3.1... */
do {
- lincmd = incmdpos;
- linredir = inredir;
+ lincmd = ((incmdpos && !ins) || (oins == 2 && i == 2) ||
+ (ins == 3 && i == 1));
+ linredir = (inredir && !ins);
+ oins = ins;
/* Get the next token. */
ctxtlex();
if (tok == DINPAR)
@@ -973,7 +1004,9 @@ get_comp_string(void)
/* We reached the end. */
if (tok == ENDINPUT)
break;
- if (tok == BAR || tok == AMPER ||
+ if ((ins && (tok == DO || tok == SEPER)) ||
+ (ins == 2 && i == 2) || (ins == 3 && i == 3) ||
+ tok == BAR || tok == AMPER ||
tok == BARAMP || tok == AMPERBANG ||
((tok == DBAR || tok == DAMPER) && !incond)) {
/* This is one of the things that separate commands. If we *
@@ -982,11 +1015,13 @@ get_comp_string(void)
if (tt)
break;
/* Otherwise reset the variables we are collecting data in. */
- i = tt0 = cp = rd = 0;
+ i = tt0 = cp = rd = ins = 0;
}
- if (lincmd && tok == STRING) {
+ if (lincmd && (tok == STRING || tok == FOR || tok == FOREACH ||
+ tok == SELECT || tok == REPEAT || tok == CASE)) {
/* The lexer says, this token is in command position, so *
* store the token string (to find the right compctl). */
+ ins = (tok == REPEAT ? 2 : (tok != STRING));
zsfree(cmdstr);
cmdstr = ztrdup(tokstr);
i = 0;
@@ -1004,9 +1039,13 @@ get_comp_string(void)
rd = linredir;
if (inwhat == IN_NOTHING && incond)
inwhat = IN_COND;
- }
+ } else if (linredir)
+ continue;
if (!tokstr)
continue;
+ /* Hack to allow completion after `repeat n do'. */
+ if (oins == 2 && !i && !strcmp(tokstr, "do"))
+ ins = 3;
/* We need to store the token strings of all words (for some of *
* the more complicated compctl -x things). They are stored in *
* the clwords array. Make this array big enough. */
@@ -1069,10 +1108,16 @@ get_comp_string(void)
/* We found a simple string. */
s = ztrdup(clwords[clwpos]);
} else if (t0 == ENVSTRING) {
+ char sav;
/* The cursor was inside a parameter assignment. */
for (s = tt; iident(*s); s++);
+ sav = *s;
+ *s = '\0';
+ zsfree(varname);
+ varname = ztrdup(tt);
+ *s = sav;
if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb)
- s = NULL, inwhat = IN_MATH;
+ s = NULL, inwhat = IN_MATH, insubscr = 1;
else if (*s == '=') {
s++;
wb += s - tt;
@@ -1110,14 +1155,32 @@ get_comp_string(void)
* foo[_ wrong (note no $). If we are in a subscript, treat it *
* as being in math. */
if (inwhat != IN_MATH) {
- int i = 0;
+ int i = 0, hn = 0;
+ char *nb = (*s == String ? s + 1 : NULL), *ne = NULL;
+
for (tt = s; ++tt < s + cs - wb;)
- if (*tt == Inbrack)
+ if (*tt == String) {
+ hn = 0;
+ nb = tt + 1;
+ } else if (*tt == Inbrack) {
i++;
- else if (i && *tt == Outbrack)
+ if (nb && !hn) {
+ hn = 1;
+ ne = tt;
+ }
+ } else if (i && *tt == Outbrack)
i--;
- if (i)
+ if (i) {
inwhat = IN_MATH;
+ insubscr = 1;
+ if (hn && nb && ne) {
+ char sav = *ne;
+ *ne = '\0';
+ zsfree(varname);
+ varname = ztrdup(nb);
+ *ne = sav;
+ }
+ }
}
if (inwhat == IN_MATH) {
/* In mathematical expression, we complete parameter names (even *
@@ -2336,6 +2399,119 @@ instmatch(Cmatch m)
return r;
}
+/**/
+void
+addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
+ char *suf, char *group,
+ int flags, int quote, int menu, int nosort, int alt, char **argv)
+{
+ char *s, *t;
+ int lpl, lsl, i;
+ Aminfo ai = (alt ? fainfo : ainfo);
+ Cmatch cm;
+
+ if (menu && isset(AUTOMENU))
+ usemenu = 1;
+ SWITCHHEAPS(compheap) {
+ HEAPALLOC {
+ if (ipre)
+ ipre = dupstring(ipre);
+ if (ppre) {
+ ppre = dupstring(ppre);
+ lpl = strlen(ppre);
+ } else
+ lpl = 0;
+ if (psuf) {
+ psuf = dupstring(psuf);
+ lsl = strlen(psuf);
+ } else
+ lsl = 0;
+ if (pre)
+ pre = dupstring(pre);
+ if (suf)
+ suf = dupstring(suf);
+ if (!prpre && (prpre = ppre)) {
+ singsub(&prpre);
+ untokenize(prpre);
+ } else
+ prpre = dupstring(prpre);
+ if (group) {
+ endcmgroup(NULL);
+ begcmgroup(group, nosort);
+ if (nosort)
+ mgroup->flags |= CGF_NOSORT;
+ }
+ if (ai->pprefix) {
+ if (pre)
+ ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0';
+ else
+ ai->pprefix[0] = '\0';
+ } else
+ ai->pprefix = dupstring(pre ? pre : "");
+
+ for (; (s = *argv); argv++) {
+ if (ai->firstm) {
+ if ((i = pfxlen(ai->firstm->str, s)) < ai->prerest)
+ ai->prerest = i;
+ if ((i = sfxlen(ai->firstm->str, s)) < ai->suflen)
+ ai->suflen = i;
+ }
+ t = s;
+ if (ppre)
+ t = dyncat(ppre, t);
+ if (ipre && *ipre) {
+ ai->noipre = 0;
+ if (ai->icpl > lpl)
+ ai->icpl = lpl;
+ if (ai->icsl > lsl)
+ ai->icsl = lsl;
+ if (ai->iaprefix)
+ ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0';
+ else
+ ai->iaprefix = dupstring(t);
+ if (ai->iprefix) {
+ if (strcmp(ipre, ai->iprefix))
+ ai->iprefix = "";
+ } else
+ ai->iprefix = dupstring(ipre);
+
+ t = dyncat(ipre, t);
+ } else
+ ai->iprefix = "";
+ if (ai->cpl > lpl)
+ ai->cpl = lpl;
+ if (ai->csl > lsl)
+ ai->csl = lsl;
+ if (ai->aprefix)
+ ai->aprefix[pfxlen(ai->aprefix, t)] = '\0';
+ else
+ ai->aprefix = dupstring(t);
+ mnum++;
+ ai->count++;
+
+ cm = (Cmatch) halloc(sizeof(struct cmatch));
+ cm->ppre = ppre;
+ cm->psuf = psuf;
+ cm->prpre = prpre;
+ if (!quote)
+ s = quotename(s, NULL, NULL, NULL);
+ cm->str = dupstring(s);
+ cm->ipre = cm->ripre = ipre;
+ cm->pre = pre;
+ cm->suf = suf;
+ cm->flags = flags;
+ cm->brpl = brpl;
+ cm->brsl = brsl;
+ addlinknode((alt ? fmatches : matches), cm);
+
+ if (expl)
+ expl->fcount++;
+ if (!ai->firstm)
+ ai->firstm = cm;
+ }
+ } LASTALLOC;
+ } SWITCHBACKHEAPS;
+}
/* This adds a match to the list of matches. The string to add is given *
* in s, the type of match is given in the global variable addwhat and *
@@ -2351,7 +2527,7 @@ addmatch(char *s, char *t)
{
int test = 0, sl = strlen(s), pl = rpl, cc = 0, isf = 0;
int mpl = 0, msl = 0, bpl = brpl, bsl = brsl;
- char *e = NULL, *tt, *te, *fc, *ms = NULL;
+ char *e = NULL, *tt, *te, *ms = NULL;
Comp cp = patcomp;
HashNode hn;
Param pm;
@@ -2377,6 +2553,8 @@ addmatch(char *s, char *t)
hn = (HashNode) t;
pm = (Param) t;
+ if (incompfunc)
+ s = dupstring(s);
if (!addwhat) {
test = 1;
} else if (addwhat == -1 || addwhat == -5 || addwhat == -6 ||
@@ -2427,11 +2605,8 @@ addmatch(char *s, char *t)
}
}
if (test) {
- fc = NULL;
- if (addwhat == -7 && !(fc = findcmd(s)))
+ if (addwhat == -7 && !findcmd(s, 0))
return;
- if (fc)
- zsfree(fc);
isf = CMF_FILE;
if (addwhat == CC_FILES || addwhat == -6 ||
@@ -2515,7 +2690,6 @@ addmatch(char *s, char *t)
}
if (!test)
return;
-
if (!ms && !ispattern && ai->firstm) {
if ((test = sl - pfxlen(ai->firstm->str, s)) < ai->prerest)
ai->prerest = test;
@@ -2602,8 +2776,13 @@ addmatch(char *s, char *t)
cm->str = (ms ? ms : s);
cm->ipre = (ipre && *ipre ? ipre : NULL);
cm->ripre = (ripre && *ripre ? ripre : NULL);
- cm->pre = curcc->prefix;
- cm->suf = curcc->suffix;
+ if (incompfunc) {
+ cm->pre = dupstring(curcc->prefix);
+ cm->suf = dupstring(curcc->suffix);
+ } else {
+ cm->pre = curcc->prefix;
+ cm->suf = curcc->suffix;
+ }
cm->flags = mflags | isf;
cm->brpl = bpl;
cm->brsl = bsl;
@@ -2729,7 +2908,7 @@ maketildelist(void)
/* This does the check for compctl -x `n' and `N' patterns. */
/**/
-static int
+int
getcpat(char *str, int cpatindex, char *cpat, int class)
{
char *s, *t, *p;
@@ -2951,6 +3130,8 @@ docompletion(char *s, int lst, int incmd)
else if (nmatches == 1) {
/* Only one match. */
+ while (!amatches->mcount)
+ amatches = amatches->next;
do_single(amatches->matches[0]);
invalidatelist();
}
@@ -3051,7 +3232,98 @@ makecomplist(char *s, int incmd, int lst)
ccused = newlinklist();
ccstack = newlinklist();
- makecomplistglobal(s, incmd, lst);
+ if (compfunc) {
+ List list;
+ int lv = lastval;
+
+ if ((list = getshfunc(compfunc)) != &dummy_list) {
+ LinkList args = newlinklist();
+ char **p, *tmp;
+ int aadd = 0, usea = 1;
+
+ addlinknode(args, compfunc);
+
+ zsfree(compcontext);
+ zsfree(compcommand);
+ compcommand = "";
+ if (inwhat == IN_MATH) {
+ if (insubscr) {
+ compcontext = "subscript";
+ compcommand = varname ? varname : "";
+ } else
+ compcontext = "math";
+ usea = 0;
+ } else if (lincmd)
+ compcontext = (insubscr ? "subscript" : "command");
+ else if (linredir)
+ compcontext = "redirect";
+ else
+ switch (inwhat) {
+ case IN_ENV:
+ compcontext = "value";
+ compcommand = varname;
+ usea = 0;
+ break;
+ case IN_COND:
+ compcontext = "condition";
+ break;
+ default:
+ if (cmdstr) {
+ compcontext = "argument";
+ compcommand = cmdstr;
+ } else {
+ compcontext = "value";
+ if (clwords[0])
+ compcommand = clwords[0];
+ }
+ aadd = 1;
+ }
+ compcontext = ztrdup(compcontext);
+ tmp = quotename(compcommand, NULL, NULL, NULL);
+ untokenize(tmp);
+ compcommand = ztrdup(tmp);
+ if (usea && (!aadd || clwords[0]))
+ for (p = clwords + aadd; *p; p++) {
+ tmp = dupstring(*p);
+ untokenize(tmp);
+ addlinknode(args, tmp);
+ }
+ zsfree(compprefix);
+ zsfree(compsuffix);
+ if (unset(COMPLETEINWORD)) {
+ tmp = quotename(s, NULL, NULL, NULL);
+ untokenize(tmp);
+ compprefix = ztrdup(tmp);
+ compsuffix = ztrdup("");
+ } else {
+ char *ss = s + offs, sav;
+
+ tmp = quotename(s, &ss, NULL, NULL);
+ sav = *ss;
+ *ss = '\0';
+ untokenize(tmp);
+ compprefix = ztrdup(tmp);
+ *ss = sav;
+ untokenize(ss);
+ compsuffix = ztrdup(ss);
+ }
+ zsfree(compiprefix);
+ compiprefix = ztrdup("");
+ compcurrent = (usea ? (clwpos + 1 - aadd) : 1);
+ compnmatches = mnum;
+ incompfunc = 1;
+ startparamscope();
+ makecompparamsptr();
+ NEWHEAPS(compheap) {
+ doshfunc(compfunc, list, args, 0, 1);
+ } OLDHEAPS;
+ endparamscope();
+ lastcmd = 9;
+ incompfunc = 0;
+ }
+ lastval = lv;
+ } else
+ makecomplistglobal(s, incmd, lst);
endcmgroup(NULL);
@@ -3082,6 +3354,83 @@ makecomplist(char *s, int incmd, int lst)
return 1;
}
+/* This should probably be moved into tokenize(). */
+
+static char *
+ctokenize(char *p)
+{
+ char *r = p;
+ int bslash = 0;
+
+ tokenize(p);
+
+ for (p = r; *p; p++) {
+ if (*p == '\\')
+ bslash = 1;
+ else {
+ if (*p == '$') {
+ if (bslash)
+ p[-1] = Bnull;
+ else
+ *p = String;
+ }
+ bslash = 0;
+ }
+ }
+ return r;
+}
+
+/**/
+char *
+comp_str(int *ipl, int *pl)
+{
+ char *p = dupstring(compprefix);
+ char *s = dupstring(compsuffix);
+ char *ip = dupstring(compiprefix);
+ char *str;
+ int lp, ls, lip;
+
+ ctokenize(p);
+ remnulargs(p);
+ ctokenize(s);
+ remnulargs(s);
+ ctokenize(ip);
+ remnulargs(ip);
+ ls = strlen(s);
+ lip = strlen(ip);
+ lp = strlen(p);
+ str = halloc(lip + lp + ls + 1);
+ strcpy(str, ip);
+ strcat(str, p);
+ strcat(str, s);
+
+ if (ipl)
+ *ipl = lip;
+ if (pl)
+ *pl = lp;
+
+ return str;
+}
+
+/**/
+void
+makecomplistcall(Compctl cc)
+{
+ SWITCHHEAPS(compheap) {
+ HEAPALLOC {
+ int ooffs = offs, lip, lp;
+ char *str = comp_str(&lip, &lp);
+
+ offs = lip + lp;
+ cc->refc++;
+ ccont = 0;
+ makecomplistor(cc, str, lincmd, lip, 0);
+ offs = ooffs;
+ compnmatches = mnum;
+ } LASTALLOC;
+ } SWITCHBACKHEAPS;
+}
+
/* This function gets the compctls for the given command line and *
* adds all completions for them. */
@@ -3159,7 +3508,7 @@ makecomplistcmd(char *os, int incmd)
/* If the command string starts with `=', try the path name of the *
* command. */
if (cmdstr && cmdstr[0] == Equals) {
- char *c = findcmd(cmdstr + 1);
+ char *c = findcmd(cmdstr + 1, 1);
if (c) {
zsfree(cmdstr);
@@ -3191,7 +3540,7 @@ makecomplistpc(char *os, int incmd)
{
Patcomp pc;
Comp pat;
- char *s = findcmd(cmdstr);
+ char *s = findcmd(cmdstr, 1);
for (pc = patcomps; pc; pc = pc->next) {
if ((pat = parsereg(pc->pat)) &&
@@ -3468,12 +3817,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
ccont |= (cc->mask2 & (CC_CCCONT | CC_DEFCONT | CC_PATCONT));
- if (findnode(ccstack, cc))
+ if (!incompfunc && findnode(ccstack, cc))
return;
addlinknode(ccstack, cc);
- if (allccs) {
+ if (!incompfunc && allccs) {
if (findnode(allccs, cc)) {
uremnode(ccstack, firstnode(ccstack));
return;
@@ -4107,7 +4456,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
}
/* This flag allows us to use read -l and -c. */
- incompctlfunc = 1;
+ if (!incompfunc)
+ incompctlfunc = 1;
sfcontext = SFC_COMPLETE;
/* Call the function. */
doshfunc(cc->func, list, args, 0, 1);
@@ -4126,7 +4476,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
char *j, *jj;
for (i = 0; i < MAXJOB; i++)
- if (jobtab[i].stat & STAT_INUSE) {
+ if ((jobtab[i].stat & STAT_INUSE) &&
+ jobtab[i].procs && jobtab[i].procs->text) {
int stopped = jobtab[i].stat & STAT_STOPPED;
j = jj = dupstring(jobtab[i].procs->text);
@@ -4274,7 +4625,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
}
/* No harm in allowing read -l and -c here, too */
- incompctlfunc = 1;
+ if (!incompfunc)
+ incompctlfunc = 1;
sfcontext = SFC_COMPLETE;
doshfunc(cc->ylist, list, args, 0, 1);
sfcontext = osc;
@@ -4528,10 +4880,12 @@ makearray(LinkList l, int s, int *np, int *nlp)
for (bp = ap; bp[1] && matcheq(*ap, bp[1]); bp++, n--);
ap = bp;
/* Mark those, that would show the same string in the list. */
- for (; bp[1] && !strcmp((*ap)->str, (bp[1])->str); bp++) {
- (bp[1])->flags |= CMF_NOLIST; nl++;
- }
+ for (; bp[1] && !strcmp((*ap)->str, (bp[1])->str); bp++)
+ (bp[1])->flags |= CMF_NOLIST;
}
+ for (ap = rp; *ap; ap++)
+ if ((*ap)->flags & CMF_NOLIST)
+ nl++;
*cp = NULL;
}
if (np)
@@ -4991,10 +5345,14 @@ do_single(Cmatch m)
if (m->suf) {
havesuff = 1;
menuinsc = ztrlen(m->suf);
- if (menuwe && (m->flags & CMF_REMOVE)) {
- makesuffix(menuinsc);
- if (menuinsc == 1)
- suffixlen[m->suf[0]] = 1;
+ menulen -= menuinsc;
+ if (menuwe) {
+ menuend += menuinsc;
+ if (m->flags & CMF_REMOVE) {
+ makesuffix(menuinsc);
+ if (menuinsc == 1)
+ suffixlen[STOUC(m->suf[0])] = 1;
+ }
}
} else {
/* There is no user-specified suffix, *
@@ -5463,7 +5821,8 @@ listmatches(void)
}
if (n) {
putc('\n', shout);
- p = skipnolist(p + 1);
+ if (n && nl)
+ p = skipnolist(p + 1);
}
}
}
@@ -5671,7 +6030,7 @@ expandcmdpath(void)
feep();
return;
}
- str = findcmd(s);
+ str = findcmd(s, 1);
zsfree(s);
if (!str) {
feep();
@@ -5686,7 +6045,6 @@ expandcmdpath(void)
cs += cmdwe - cmdwb + strlen(str);
if (cs > ll)
cs = ll;
- zsfree(str);
}
/* Extra function added by AR Iano-Fletcher. */
diff --git a/Src/builtin.c b/Src/builtin.c
index 6c41ce2fd..f6941286d 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -680,7 +680,7 @@ bin_cd(char *nam, char **argv, char *ops, int func)
goto brk;
}
} while (*++s);
- for (s = *argv; *++s; ops[*s] = 1);
+ for (s = *argv; *++s; ops[STOUC(*s)] = 1);
}
brk:
chaselinks = ops['P'] || (isset(CHASELINKS) && !ops['L']);
@@ -790,7 +790,7 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
zsfree(remnode(dirstack, dir));
return NULL;
}
- if (dest != getdata(dir)) {
+ if (dest != (char *)getdata(dir)) {
zsfree(getdata(dir));
setdata(dir, dest);
}
@@ -1224,13 +1224,14 @@ bin_fc(char *nam, char **argv, char *ops, int func)
if (!editor)
editor = DEFAULT_FCEDIT;
- if (fcedit(editor, fil))
+ if (fcedit(editor, fil)) {
if (stuff(fil))
zwarnnam("fc", "%e: %s", s, errno);
else {
loop(0,1);
retval = lastval;
}
+ }
}
}
unlink(fil);
@@ -1464,6 +1465,117 @@ getasg(char *s)
return &asg;
}
+/* function to set a single parameter */
+
+/**/
+int
+typeset_single(char *cname, char *pname, Param pm, int func,
+ int on, int off, int roff, char *value)
+{
+ int usepm, tc;
+
+ /* use the existing pm? */
+ usepm = pm && !(pm->flags & PM_UNSET);
+
+ /* Always use an existing pm if special at current locallevel */
+ if (pm && (pm->flags & PM_SPECIAL) && pm->level == locallevel)
+ usepm = 1;
+
+ /*
+ * Don't use a non-special existing param if
+ * - the local level has changed, and
+ * - the function is not `export'.
+ */
+ if (usepm && !(pm->flags & PM_SPECIAL) &&
+ locallevel != pm->level && func != BIN_EXPORT)
+ usepm = 0;
+
+ /* attempting a type conversion? */
+ if ((tc = usepm && (((off & pm->flags) | (on & ~pm->flags)) &
+ (PM_INTEGER|PM_HASHED|PM_ARRAY))))
+ usepm = 0;
+ if (tc && (pm->flags & PM_SPECIAL)) {
+ zerrnam(cname, "%s: can't change type of a special parameter",
+ pname, 0);
+ return 1;
+ }
+
+ if (usepm) {
+ if (!on && !roff && !value) {
+ paramtab->printnode((HashNode)pm, 0);
+ return 0;
+ }
+ if ((pm->flags & PM_RESTRICTED && isset(RESTRICTED))) {
+ zerrnam(cname, "%s: restricted", pname, 0);
+ return 1;
+ }
+ if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
+ !(pm->flags & PM_READONLY & ~off))
+ uniqarray((*pm->gets.afn) (pm));
+ pm->flags = (pm->flags | on) & ~off;
+ /* This auxlen/pm->ct stuff is a nasty hack. */
+ if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
+ auxlen)
+ pm->ct = auxlen;
+ if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
+ if (pm->flags & PM_EXPORTED) {
+ if (!(pm->flags & PM_UNSET) && !pm->env && !value)
+ pm->env = addenv(pname, getsparam(pname));
+ } else if (pm->env) {
+ delenv(pm->env);
+ zsfree(pm->env);
+ pm->env = NULL;
+ }
+ if (value)
+ setsparam(pname, ztrdup(value));
+ } else if (value) {
+ zwarnnam(cname, "can't assign new value for array %s", pname, 0);
+ return 1;
+ }
+ return 0;
+ }
+
+ /*
+ * We're here either because we're creating a new parameter,
+ * or we're adding a parameter at a different local level,
+ * or we're converting the type of a parameter. In the
+ * last case only, we need to delete the old parameter.
+ */
+ if (tc) {
+ if (pm->flags & PM_READONLY) {
+ on |= ~off & PM_READONLY;
+ pm->flags &= ~PM_READONLY;
+ }
+ /*
+ * Try to carry over a value, but not when changing from,
+ * to, or between non-scalar types.
+ */
+ if (!value && !((pm->flags|on) & (PM_ARRAY|PM_HASHED)))
+ value = dupstring(getsparam(pname));
+ /* pname may point to pm->nam which is about to disappear */
+ pname = dupstring(pname);
+ unsetparam_pm(pm, 0, 1);
+ }
+ /*
+ * Create a new node for a parameter with the flags in `on' minus the
+ * readonly flag
+ */
+ pm = createparam(pname, on & ~PM_READONLY);
+ DPUTS(!pm, "BUG: parameter not created");
+ pm->ct = auxlen;
+ if (func != BIN_EXPORT)
+ pm->level = locallevel;
+ if (value && !(pm->flags & (PM_ARRAY|PM_HASHED)))
+ setsparam(pname, ztrdup(value));
+ pm->flags |= (on & PM_READONLY);
+ if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) {
+ zerrnam(cname, "%s: can't assign initial value for array", pname, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
/* declare, export, integer, local, readonly, typeset */
/**/
@@ -1475,7 +1587,7 @@ bin_typeset(char *name, char **argv, char *ops, int func)
Comp com;
char *optstr = "aiALRZlurtxU";
int on = 0, off = 0, roff, bit = PM_ARRAY;
- int initon, initoff, of, i;
+ int i;
int returnval = 0, printflags = 0;
/* hash -f is really the builtin `functions' */
@@ -1486,9 +1598,9 @@ bin_typeset(char *name, char **argv, char *ops, int func)
* Unfortunately, this depends on the order *
* these flags are defined in zsh.h */
for (; *optstr; optstr++, bit <<= 1)
- if (ops[*optstr] == 1)
+ if (ops[STOUC(*optstr)] == 1)
on |= bit;
- else if (ops[*optstr] == 2)
+ else if (ops[STOUC(*optstr)] == 2)
off |= bit;
roff = off;
@@ -1521,7 +1633,11 @@ bin_typeset(char *name, char **argv, char *ops, int func)
/* With the -m option, treat arguments as glob patterns */
if (ops['m']) {
+ MUSTUSEHEAP("typeset -m");
while ((asg = getasg(*argv++))) {
+ LinkList pmlist = newlinklist();
+ LinkNode pmnode;
+
tokenize(asg->name); /* expand argument */
if (!(com = parsereg(asg->name))) {
untokenize(asg->name);
@@ -1529,143 +1645,45 @@ bin_typeset(char *name, char **argv, char *ops, int func)
returnval = 1;
continue;
}
- /* If no options or values are given, display all *
- * parameters matching the glob pattern. */
- if (!(on || roff || asg->value)) {
- scanmatchtable(paramtab, com, 0, 0, paramtab->printnode, 0);
- continue;
- }
- /* Since either options or values are given, we search *
- * through the parameter table and change all parameters *
- * matching the glob pattern to have these flags and/or *
- * value. */
+ /*
+ * Search through the parameter table and change all parameters
+ * matching the glob pattern to have these flags and/or value.
+ * Bad news: if the parameter gets altered, e.g. by
+ * a type conversion, then paramtab can be shifted around,
+ * so we need to store the parameters to alter on a separate
+ * list for later use.
+ */
for (i = 0; i < paramtab->hsize; i++) {
- for (pm = (Param) paramtab->nodes[i]; pm; pm = (Param) pm->next) {
+ for (pm = (Param) paramtab->nodes[i]; pm;
+ pm = (Param) pm->next) {
if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED))
continue;
- if (domatch(pm->nam, com, 0)) {
- /* set up flags if we have any */
- if (on || roff) {
- if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
- !(pm->flags & PM_READONLY & ~off))
- 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;
- 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)
- pm->ct = auxlen;
- /* did we just export this? */
- if ((pm->flags & PM_EXPORTED) && !pm->env) {
- pm->env = addenv(pm->nam, (asg->value) ? asg->value : getsparam(pm->nam));
- } else if (!(pm->flags & PM_EXPORTED) && pm->env) {
- /* did we just unexport this? */
- delenv(pm->env);
- zsfree(pm->env);
- pm->env = NULL;
- }
- }
- }
- /* set up a new value if given */
- if (asg->value) {
- setsparam(pm->nam, ztrdup(asg->value));
- }
- }
+ if (domatch(pm->nam, com, 0))
+ addlinknode(pmlist, pm);
}
}
+ for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) {
+ pm = (Param) getdata(pmnode);
+ if (typeset_single(name, pm->nam, pm, func, on, off, roff,
+ asg->value))
+ returnval = 1;
+ }
}
return returnval;
}
- /* Save the values of on, off, and func */
- initon = on;
- initoff = off;
- of = func;
-
/* Take arguments literally. Don't glob */
while ((asg = getasg(*argv++))) {
- /* restore the original values of on, off, and func */
- on = initon;
- off = initoff;
- func = of;
- on &= ~PM_ARRAY;
-
/* check if argument is a valid identifier */
if (!isident(asg->name)) {
zerr("not an identifier: %s", asg->name, 0);
returnval = 1;
continue;
}
- bit = 0; /* flag for switching int<->not-int */
- if ((pm = (Param)paramtab->getnode(paramtab, asg->name)) &&
- (((pm->flags & PM_SPECIAL) && pm->level == locallevel) ||
- (!(pm->flags & PM_UNSET) &&
- ((locallevel == pm->level) || func == BIN_EXPORT) &&
- !(bit = (((off & pm->flags) | (on & ~pm->flags)) &
- (PM_INTEGER|PM_HASHED)))))) {
- /* if no flags or values are given, just print this parameter */
- if (!on && !roff && !asg->value) {
- paramtab->printnode((HashNode) pm, 0);
- continue;
- }
- if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerrnam(name, "%s: restricted", pm->nam, 0);
- returnval = 1;
- continue;
- }
- if((pm->flags & PM_SPECIAL) &&
- PM_TYPE((pm->flags | on) & ~off) != PM_TYPE(pm->flags)) {
- zerrnam(name, "%s: cannot change type of a special parameter",
- pm->nam, 0);
- returnval = 1;
- continue;
- }
- if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
- !(pm->flags & PM_READONLY & ~off))
- uniqarray((*pm->gets.afn) (pm));
- pm->flags = (pm->flags | on) & ~off;
- if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
- auxlen)
- pm->ct = auxlen;
- if (PM_TYPE(pm->flags) != PM_ARRAY &&
- PM_TYPE(pm->flags) != PM_HASHED) {
- if (pm->flags & PM_EXPORTED) {
- if (!(pm->flags & PM_UNSET) && !pm->env && !asg->value)
- pm->env = addenv(asg->name, getsparam(asg->name));
- } else if (pm->env) {
- delenv(pm->env);
- zsfree(pm->env);
- pm->env = NULL;
- }
- if (asg->value)
- setsparam(asg->name, ztrdup(asg->value));
- }
- } else {
- if (bit) {
- if (pm->flags & PM_READONLY) {
- on |= ~off & PM_READONLY;
- pm->flags &= ~PM_READONLY;
- }
- if (!asg->value)
- asg->value = dupstring(getsparam(asg->name));
- unsetparam(asg->name);
- }
- /* create a new node for a parameter with the *
- * flags in `on' minus the readonly flag */
- pm = createparam(ztrdup(asg->name), on & ~PM_READONLY);
- DPUTS(!pm, "BUG: parameter not created");
- pm->ct = auxlen;
- if (func != BIN_EXPORT)
- pm->level = locallevel;
- if (asg->value)
- setsparam(asg->name, ztrdup(asg->value));
- pm->flags |= (on & PM_READONLY);
- }
+ if (typeset_single(name, asg->name,
+ (Param)paramtab->getnode(paramtab, asg->name),
+ func, on, off, roff, asg->value))
+ returnval = 1;
}
return returnval;
}
@@ -1989,7 +2007,7 @@ bin_whence(char *nam, char **argv, char *ops, int func)
puts(wd ? ": none" : " not found");
returnval = 1;
}
- } else if ((cnam = findcmd(*argv))) {
+ } else if ((cnam = findcmd(*argv, 1))) {
/* Found external command. */
if (wd) {
printf("%s: command\n", *argv);
@@ -2001,7 +2019,6 @@ bin_whence(char *nam, char **argv, char *ops, int func)
print_if_link(cnam);
fputc('\n', stdout);
}
- zsfree(cnam);
} else {
/* Not found at all. */
if (v || csh || wd)
@@ -2328,9 +2345,17 @@ bin_print(char *name, char **args, char *ops, int func)
args[n] = getkeystring(args[n], &len[n],
func != BIN_ECHO && !ops['e'], &nnl);
/* -P option -- interpret as a prompt sequence */
- if(ops['P'])
- args[n] = unmetafy(promptexpand(metafy(args[n], len[n],
- META_NOALLOC), 0, NULL, NULL), &len[n]);
+ if(ops['P']) {
+ /*
+ * promptexpand uses permanent storage: to avoid
+ * messy memory management, stick it on the heap
+ * instead.
+ */
+ char *str = unmetafy(promptexpand(metafy(args[n], len[n],
+ META_NOALLOC), 0, NULL, NULL), &len[n]);
+ args[n] = dupstring(str);
+ free(str);
+ }
/* -D option -- interpret as a directory, and use ~ */
if(ops['D']) {
Nameddir d = finddir(args[n]);
@@ -2778,8 +2803,9 @@ zexit(int val, int from_signal)
LASTALLOC_RETURN;
}
}
- if (in_exit++ && from_signal)
+ if (in_exit++ && from_signal) {
LASTALLOC_RETURN;
+ }
if (isset(MONITOR))
/* send SIGHUP to any jobs left running */
killrunjobs(from_signal);
@@ -3181,13 +3207,14 @@ bin_read(char *name, char **args, char *ops, int func)
}
if (c == EOF || (c == '\n' && !zbuf))
break;
- if (!bslash && isep(c) && bptr == buf)
+ if (!bslash && isep(c) && bptr == buf) {
if (iwsep(c))
continue;
else if (!first) {
first = 1;
continue;
}
+ }
bslash = c == '\\' && !bslash && !ops['r'];
if (bslash)
continue;
@@ -3240,7 +3267,7 @@ zread(void)
char cc, retry = 0;
/* use zbuf if possible */
- if (zbuf)
+ if (zbuf) {
/* If zbuf points to anything, it points to the next character in the
buffer. This may be a null byte to indicate EOF. If reading from the
buffer, move on the buffer pointer. */
@@ -3248,6 +3275,7 @@ zread(void)
return zbuf++, STOUC(*zbuf++ ^ 32);
else
return (*zbuf) ? STOUC(*zbuf++) : EOF;
+ }
for (;;) {
/* read a character from readfd */
switch (read(readfd, &cc, 1)) {
diff --git a/Src/cond.c b/Src/cond.c
index 906e81938..a46833f66 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -54,7 +54,7 @@ evalcond(Cond c)
int l = arrlen((char **) c->right);
if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
- zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
+ zerr("unrecognized condition: `%s'", (char *) c->left, 0);
return 0;
}
}
@@ -68,13 +68,13 @@ evalcond(Cond c)
int l = arrlen(a);
if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
- zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
+ zerr("unrecognized condition: `%s'", (char *) c->left, 0);
return 0;
}
a[0] = (char *) c->left;
return cd->handler(a, cd->condid);
} else
- zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
+ zerr("unrecognized condition: `%s'", (char *) c->left, 0);
}
return 0;
}
diff --git a/Src/exec.c b/Src/exec.c
index 911559a02..e563db6a4 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -457,13 +457,17 @@ execute(Cmdnam not_used_yet, int dash)
_exit(1);
}
-#define try(X) { if (iscom(X)) return ztrdup(X); }
+#define RET_IF_COM(X) { if (iscom(X)) return docopy ? dupstring(X) : arg0; }
-/* get the full pathname of an external command */
+/*
+ * Get the full pathname of an external command.
+ * If the second argument is zero, return the first argument if found;
+ * if non-zero, return the path using heap memory. (RET_IF_COM(X), above).
+ */
/**/
char *
-findcmd(char *arg0)
+findcmd(char *arg0, int docopy)
{
char **pp;
char *z, *s, buf[MAXCMDLEN];
@@ -476,7 +480,7 @@ findcmd(char *arg0)
return NULL;
for (s = arg0; *s; s++)
if (*s == '/') {
- try(arg0);
+ RET_IF_COM(arg0);
if (arg0 == s || unset(PATHDIRS)) {
return NULL;
}
@@ -496,13 +500,13 @@ findcmd(char *arg0)
*z++ = '/';
}
strcpy(z, arg0);
- try(buf);
+ RET_IF_COM(buf);
}
strcpy(nn, cn->u.name ? *(cn->u.name) : "");
strcat(nn, "/");
strcat(nn, cn->nam);
}
- try(nn);
+ RET_IF_COM(nn);
}
for (pp = path; *pp; pp++) {
z = buf;
@@ -511,7 +515,7 @@ findcmd(char *arg0)
*z++ = '/';
}
strcpy(z, arg0);
- try(buf);
+ RET_IF_COM(buf);
}
return NULL;
}
diff --git a/Src/glob.c b/Src/glob.c
index 9c1d08aa4..6536e0f06 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -2318,7 +2318,7 @@ doesmatch(Comp c)
for (; *pptr; pptr++) {
if (*pptr == Meta)
pptr++;
- else if (CHARMATCH(*pptr, looka))
+ else if (CHARMATCH(STOUC(*pptr), STOUC(looka)))
break;
}
if (!*(saves = pptr))
@@ -2688,7 +2688,7 @@ matchonce(Comp c)
}
continue;
}
- if (CHARMATCH(*pptr, *pat)) {
+ if (CHARMATCH(STOUC(*pptr), STOUC(*pat))) {
/* just plain old characters */
pptr++;
pat++;
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 60fb3df80..b816f1892 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -172,7 +172,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
ht->nodes[hashval] = hn;
replacing:
hn->next = hp->next;
- if(ht->scan)
+ if(ht->scan) {
if(ht->scan->sorted) {
HashNode *tab = ht->scan->u.s.tab;
int i;
@@ -181,6 +181,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
tab[i] = hn;
} else if(ht->scan->u.u == hp)
ht->scan->u.u = hn;
+ }
ht->freenode(hp);
return;
}
@@ -270,7 +271,7 @@ removehashnode(HashTable ht, char *nam)
ht->nodes[hashval] = hp->next;
gotit:
ht->ct--;
- if(ht->scan)
+ if(ht->scan) {
if(ht->scan->sorted) {
HashNode *tab = ht->scan->u.s.tab;
int i;
@@ -279,6 +280,7 @@ removehashnode(HashTable ht, char *nam)
tab[i] = NULL;
} else if(ht->scan->u.u == hp)
ht->scan->u.u = hp->next;
+ }
return hp;
}
diff --git a/Src/hist.c b/Src/hist.c
index a4c5735c1..d77b2febd 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -392,7 +392,7 @@ histsubchar(int c)
c = ingetc();
}
*ptr = 0;
- if (!*buf)
+ if (!*buf) {
if (c != '%') {
if (isset(CSHJUNKIEHISTORY))
ev = curhist - 1;
@@ -408,6 +408,7 @@ histsubchar(int c)
else
ev = defev;
evset = 0;
+ }
} else if ((t0 = atoi(buf))) {
ev = (t0 < 0) ? curhist + t0 : t0;
evset = 1;
@@ -749,11 +750,12 @@ hend(void)
save = 0;
else {
*hptr = '\0';
- if (hptr[-1] == '\n')
+ if (hptr[-1] == '\n') {
if (chline[1]) {
*--hptr = '\0';
} else
save = 0;
+ }
if (!*chline || !strcmp(chline, "\n") ||
(isset(HISTIGNORESPACE) && spaceflag))
save = 0;
diff --git a/Src/input.c b/Src/input.c
index 45c65b2bf..66a21000c 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -219,7 +219,7 @@ inputline(void)
char *ingetcline, *ingetcpmptl = NULL, *ingetcpmptr = NULL;
/* If reading code interactively, work out the prompts. */
- if (interact && isset(SHINSTDIN))
+ if (interact && isset(SHINSTDIN)) {
if (!isfirstln)
ingetcpmptl = prompt2;
else {
@@ -227,6 +227,7 @@ inputline(void)
if (rprompt)
ingetcpmptr = rprompt;
}
+ }
if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) {
/*
* If not using zle, read the line straight from the input file.
diff --git a/Src/jobs.c b/Src/jobs.c
index 74fa8cda0..e94dd77e2 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -462,7 +462,7 @@ printjob(Job jn, int lng, int synch)
if (jn->stat & STAT_SUPERJOB &&
jn->procs->status == SP_RUNNING && !pn->next)
pn->status = SP_RUNNING;
- if (pn->status != SP_RUNNING)
+ if (pn->status != SP_RUNNING) {
if (WIFSIGNALED(pn->status)) {
sig = WTERMSIG(pn->status);
llen = strlen(sigmsg[sig]);
@@ -483,6 +483,7 @@ printjob(Job jn, int lng, int synch)
} else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
WEXITSTATUS(pn->status))
sflag = 1;
+ }
}
/* print if necessary */
@@ -508,7 +509,7 @@ printjob(Job jn, int lng, int synch)
break;
len2 += strlen(qn->text) + 2;
}
- if (job != thisjob)
+ if (job != thisjob) {
if (fline)
fprintf(fout, "[%ld] %c ",
(long)(jn - jobtab),
@@ -516,7 +517,7 @@ printjob(Job jn, int lng, int synch)
: (job == prevjob) ? '-' : ' ');
else
fprintf(fout, (job > 9) ? " " : " ");
- else
+ } else
fprintf(fout, "zsh: ");
if (lng & 1)
fprintf(fout, "%ld ", (long) pn->pid);
@@ -531,18 +532,19 @@ printjob(Job jn, int lng, int synch)
lng &= ~3;
} else
fprintf(fout, "%*s", skip, "");
- if (pn->status == SP_RUNNING)
+ if (pn->status == SP_RUNNING) {
if (!conted)
fprintf(fout, "running%*s", len - 7 + 2, "");
else
fprintf(fout, "continued%*s", len - 9 + 2, "");
- else if (WIFEXITED(pn->status))
+ }
+ else if (WIFEXITED(pn->status)) {
if (WEXITSTATUS(pn->status))
fprintf(fout, "exit %-4d%*s", WEXITSTATUS(pn->status),
len - 9 + 2, "");
else
fprintf(fout, "done%*s", len - 4 + 2, "");
- else if (WIFSTOPPED(pn->status))
+ } else if (WIFSTOPPED(pn->status))
fprintf(fout, "%-*s", len + 2, sigmsg[WSTOPSIG(pn->status)]);
else if (WCOREDUMP(pn->status))
fprintf(fout, "%s (core dumped)%*s",
@@ -1071,7 +1073,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
/* If you immediately type "exit" after "jobs", this *
* will prevent zexit from complaining about stopped jobs */
stopmsg = 2;
- if (!*argv)
+ if (!*argv) {
/* This block handles all of the default cases (no arguments). bg,
fg and disown act on the current job, and jobs and wait act on all the
jobs. */
@@ -1100,6 +1102,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
waitjob(job, SIGINT);
return 0;
}
+ }
/* Defaults have been handled. We now have an argument or two, or three...
In the default case for bg, fg and disown, the argument will be provided by
diff --git a/Src/lex.c b/Src/lex.c
index 6f4f2dd20..b08dfed5b 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -457,11 +457,11 @@ add(int c)
#define SETPARBEGIN {if (zleparse && !(inbufflags & INP_ALIAS) && cs >= ll+1-inbufct) parbegin = inbufct;}
#define SETPAREND {\
- if (zleparse && !(inbufflags & INP_ALIAS) && parbegin != -1 && parend == -1)\
+ if (zleparse && !(inbufflags & INP_ALIAS) && parbegin != -1 && parend == -1) {\
if (cs >= ll + 1 - inbufct)\
parbegin = -1;\
else\
- parend = inbufct;}
+ parend = inbufct;} }
static int
cmd_or_math(int cs_type)
@@ -823,20 +823,22 @@ gettokstr(int c, int sub)
case LX2_OUTPAR:
if ((sub || in_brace_param) && isset(SHGLOB))
break;
- if (!in_brace_param && !pct--)
+ if (!in_brace_param && !pct--) {
if (sub) {
pct = 0;
break;
} else
goto brk;
+ }
c = Outpar;
break;
case LX2_BAR:
- if (!pct && !in_brace_param)
+ if (!pct && !in_brace_param) {
if (sub)
break;
else
goto brk;
+ }
if (unset(SHGLOB) || (!sub && !in_brace_param))
c = Bar;
break;
@@ -912,8 +914,9 @@ gettokstr(int c, int sub)
*bptr = '\0';
return STRING;
}
- if (in_brace_param)
+ if (in_brace_param) {
cmdpush(CS_BRACE);
+ }
bct++;
}
break;
@@ -922,8 +925,9 @@ gettokstr(int c, int sub)
break;
if (!bct)
break;
- if (in_brace_param)
+ if (in_brace_param) {
cmdpop();
+ }
if (bct-- == in_brace_param)
in_brace_param = 0;
c = Outbrace;
@@ -933,11 +937,12 @@ gettokstr(int c, int sub)
c = Comma;
break;
case LX2_OUTANG:
- if (!intpos)
+ if (!intpos) {
if (in_brace_param || sub)
break;
else
goto brk;
+ }
e = hgetc();
if (e != '(') {
hungetc(e);
@@ -1101,11 +1106,12 @@ gettokstr(int c, int sub)
break;
}
add(c);
- if (c == '\'')
+ if (c == '\'') {
if ((inquote = !inquote))
STOPHIST
else
ALLOWHIST
+ }
}
if (inquote)
ALLOWHIST
@@ -1260,8 +1266,9 @@ dquote_parse(char endchar, int sub)
}
if (intick == 2)
ALLOWHIST
- if (intick)
+ if (intick) {
cmdpop();
+ }
while (bct--)
cmdpop();
if (lexstop)
diff --git a/Src/loop.c b/Src/loop.c
index 5fbf2b841..95ec4832a 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -52,7 +52,7 @@ execfor(Cmd cmd)
List list;
Forcmd node;
char *str;
- int val;
+ int val = 0;
LinkList args;
node = cmd->u.forcmd;
diff --git a/Src/mem.c b/Src/mem.c
index 32822ab8c..703920215 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -129,25 +129,51 @@ global_permalloc(void)
return luh;
}
-/* heappush saves the current heap state using this structure */
+/* list of zsh heap */
-struct heapstack {
- struct heapstack *next; /* next one in list for this heap */
- size_t used;
-};
+static Heap heaps;
-/* A zsh heap. */
+/* Use new heaps from now on. This returns the old heap-list. */
-struct heap {
- struct heap *next; /* next one */
- size_t used; /* bytes used from the heap */
- struct heapstack *sp; /* used by pushheap() to save the value used */
-#define arena(X) ((char *) (X) + sizeof(struct heap))
-};
+/**/
+Heap
+new_heaps(void)
+{
+ Heap h = heaps;
-/* list of zsh heap */
+ heaps = NULL;
-static Heap heaps;
+ return h;
+}
+
+/* Re-install the old heaps again, freeing the new ones. */
+
+/**/
+void
+old_heaps(Heap old)
+{
+ Heap h, n;
+
+ for (h = heaps; h; h = n) {
+ n = h->next;
+ DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
+ zfree(h, sizeof(*h));
+ }
+ heaps = old;
+}
+
+/* Temporarily switch to other heaps (or back again). */
+
+/**/
+Heap
+switch_heaps(Heap new)
+{
+ Heap h = heaps;
+
+ heaps = new;
+
+ return h;
+}
/* save states of zsh heaps */
diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh
index 2f988ec8f..efaa803ad 100644
--- a/Src/mkbltnmlst.sh
+++ b/Src/mkbltnmlst.sh
@@ -24,11 +24,17 @@ for x_mod in $x_mods; do
*" $x_mod "*) ;;
*) echo "/* non-linked-in known module \`$x_mod' */"
eval "loc=\$loc_$x_mod"
- unset moddeps autobins
+ unset moddeps autobins autoinfixconds autoprefixconds
. $srcdir/../$loc/${x_mod}.mdd
for bin in $autobins; do
echo " add_autobin(\"$bin\", \"$x_mod\");"
done
+ for cond in $autoinfixconds; do
+ echo " add_autocond(\"$cond\", 1, \"$x_mod\");"
+ done
+ for cond in $autoprefixconds; do
+ echo " add_autocond(\"$cond\", 0, \"$x_mod\");"
+ done
for dep in $moddeps; do
case $bin_mods in
*" $dep "*)
diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh
index 9c90b75e5..2f79acbc3 100644
--- a/Src/mkmakemod.sh
+++ b/Src/mkmakemod.sh
@@ -17,15 +17,18 @@
# defines one module. The .mdd file is actually a shell script, which will
# be sourced. It may define the following shell variables:
#
-# moddeps modules on which this module depends (default none)
-# nozshdep non-empty indicates no dependence on the `zsh' pseudo-module
-# alwayslink if non-empty, always link the module into the executable
-# autobins builtins defined by the module, for autoloading
-# objects .o files making up this module (*must* be defined)
-# proto .pro files for this module (default generated from $objects)
-# headers extra headers for this module (default none)
-# hdrdeps extra headers on which the .mdh depends (default none)
-# otherincs extra headers that are included indirectly (default none)
+# moddeps modules on which this module depends (default none)
+# nozshdep non-empty indicates no dependence on the `zsh' pseudo-module
+# alwayslink if non-empty, always link the module into the executable
+# autobins builtins defined by the module, for autoloading
+# autoinfixconds infix condition codes defined by the module, for
+# autoloading (without the leading `-')
+# autoprefixconds like autoinfixconds, but for prefix condition codes
+# objects .o files making up this module (*must* be defined)
+# proto .pro files for this module (default generated from $objects)
+# headers extra headers for this module (default none)
+# hdrdeps extra headers on which the .mdh depends (default none)
+# otherincs extra headers that are included indirectly (default none)
#
# The .mdd file may also include a Makefile.in fragment between lines
# `:<<\Make' and `Make' -- this will be copied into Makemod.in.
@@ -167,7 +170,7 @@ if $first_stage; then
for module in $here_modules; do
unset moddeps nozshdep alwayslink hasexport
- unset autobins
+ unset autobins autoinfixconds autoprefixconds
unset objects proto headers hdrdeps otherincs
. $top_srcdir/$the_subdir/${module}.mdd
test -n "${moddeps+set}" || moddeps=
diff --git a/Src/module.c b/Src/module.c
index 5780eb134..f91650a7f 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -227,7 +227,6 @@ deletewrapper(Module m, FuncWrap w)
static char *dlerrstr[256];
-/**/
static void *
load_and_bind(const char *fn)
{
@@ -277,7 +276,6 @@ load_and_bind(const char *fn)
# define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
# define dlclose(handle) shl_unload((shl_t)(handle))
-/**/
static
void *
hpux_dlsym(void *handle, char *name)
diff --git a/Src/params.c b/Src/params.c
index 89a1ed6a1..3dc7e1a1b 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -765,7 +765,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
} else if (rev) {
v->isarr |= SCANPM_WANTVALS;
}
- if (!down)
+ if (!down && PM_TYPE(v->pm->flags) == PM_HASHED)
v->isarr &= ~SCANPM_MATCHMANY;
*inv = ind;
}
@@ -1534,6 +1534,12 @@ setaparam(char *s, char **val)
if (!(v = getvalue(&s, 1)))
createparam(t, PM_ARRAY);
*ss = '[';
+ if (PM_TYPE(v->pm->flags) == PM_HASHED) {
+ zerr("attempt to set slice of associative array", NULL, 0);
+ freearray(val);
+ errflag = 1;
+ return NULL;
+ }
v = NULL;
} else {
if (!(v = getvalue(&s, 1)))
@@ -1571,13 +1577,13 @@ sethparam(char *s, char **val)
}
if (strchr(s, '[')) {
freearray(val);
- zerr("attempt to set slice of associative array", NULL, 0);
+ zerr("nested associative arrays not yet supported", NULL, 0);
errflag = 1;
return NULL;
} else {
if (!(v = getvalue(&s, 1)))
createparam(t, PM_HASHED);
- else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
+ else if (!(PM_TYPE(v->pm->flags) & PM_HASHED) &&
!(v->pm->flags & PM_SPECIAL)) {
unsetparam(t);
createparam(t, PM_HASHED);
diff --git a/Src/subst.c b/Src/subst.c
index cc7e87d3d..5211ee0ee 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -387,11 +387,11 @@ filesubstr(char **namptr, int assign)
for (pp = str + 1; !isend2(*pp); pp++);
sav = *pp;
*pp = 0;
- if (!(cnam = findcmd(str + 1))) {
+ if (!(cnam = findcmd(str + 1, 1))) {
Alias a = (Alias) aliastab->getnode(aliastab, str + 1);
if (a)
- cnam = ztrdup(a->text);
+ cnam = a->text;
else {
if (isset(NOMATCH))
zerr("%s not found", str + 1, 0);
@@ -399,7 +399,6 @@ filesubstr(char **namptr, int assign)
}
}
*namptr = dupstring(cnam);
- zsfree(cnam);
if (sav) {
*pp = sav;
*namptr = dyncat(*namptr, pp);
diff --git a/Src/watch.c b/Src/watch.c
index 2532e0a63..6fe77afcd 100644
--- a/Src/watch.c
+++ b/Src/watch.c
@@ -235,7 +235,7 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
# endif /* WATCH_UTMP_UT_HOST */
while (*fmt)
- if (*fmt == '\\')
+ if (*fmt == '\\') {
if (*++fmt) {
if (prnt)
putchar(*fmt);
@@ -244,6 +244,7 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
return fmt;
else
break;
+ }
else if (*fmt == fini)
return ++fmt;
else if (*fmt != '%') {
diff --git a/Src/zsh.export b/Src/zsh.export
index d8b0ddf19..c85bfbad4 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -23,6 +23,7 @@ closem
cmdnamtab
columns
compctlreadptr
+cond_match
cond_str
cond_val
coprocin
@@ -104,6 +105,8 @@ inredir
insertlinknode
install_handler
intr
+intvargetfn
+intvarsetfn
inwhat
isfirstln
jobtab
@@ -126,6 +129,7 @@ mypgrp
mypid
nameddirtab
ncalloc
+new_heaps
newhashtable
newlinklist
nicechar
@@ -137,6 +141,7 @@ noerrs
noholdintr
noop_function
noop_function_int
+old_heaps
optiontab
opts
paramtab
@@ -148,6 +153,7 @@ path
pathchecked
popheap
postedit
+pparams
ppid
prefork
prepromptfns
@@ -197,6 +203,9 @@ strpfx
strsfx
strucpy
struncpy
+strvargetfn
+strvarsetfn
+switch_heaps
tclen
tcstr
termflags
diff --git a/Src/zsh.h b/Src/zsh.h
index a31a7469b..dabcd90c8 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1305,6 +1305,22 @@ struct ttyinfo {
* Memory management *
*********************/
+/* heappush saves the current heap state using this structure */
+
+struct heapstack {
+ struct heapstack *next; /* next one in list for this heap */
+ size_t used;
+};
+
+/* A zsh heap. */
+
+struct heap {
+ struct heap *next; /* next one */
+ size_t used; /* bytes used from the heap */
+ struct heapstack *sp; /* used by pushheap() to save the value used */
+#define arena(X) ((char *) (X) + sizeof(struct heap))
+};
+
#ifndef DEBUG
# define HEAPALLOC do { int nonlocal_useheap = global_heapalloc(); do
@@ -1318,6 +1334,13 @@ struct ttyinfo {
# define LASTALLOC_RETURN \
if ((nonlocal_useheap ? global_heapalloc() : \
global_permalloc()), 0) {;} else return
+
+# define NEWHEAPS(h) do { Heap oldheaps = h = new_heaps(); do
+# define OLDHEAPS while (0); old_heaps(oldheaps); } while (0);
+
+# define SWITCHHEAPS(h) do { Heap oldheaps = switch_heaps(h); do
+# define SWITCHBACKHEAPS while (0); switch_heaps(oldheaps); } while (0);
+
#else
# define HEAPALLOC do { int nonlocal_useheap = global_heapalloc(); \
alloc_stackp++; do
@@ -1333,6 +1356,17 @@ struct ttyinfo {
# define LASTALLOC_RETURN \
if ((nonlocal_useheap ? global_heapalloc() : \
global_permalloc()),alloc_stackp--,0){;}else return
+
+# define NEWHEAPS(h) do { Heap oldheaps = h = new_heaps(); \
+ alloc_stackp++; do
+# define OLDHEAPS while (0); alloc_stackp--; \
+ old_heaps(oldheaps); } while (0);
+
+# define SWITCHHEAPS(h) do { Heap oldheaps = switch_heaps(h); \
+ alloc_stackp++; do
+# define SWITCHBACKHEAPS while (0); alloc_stackp--; \
+ switch_heaps(oldheaps); } while (0);
+
#endif
/****************/
diff --git a/Util/zsh-development-guide b/Util/zsh-development-guide
index 73ac120ab..f779b17b3 100644
--- a/Util/zsh-development-guide
+++ b/Util/zsh-development-guide
@@ -120,15 +120,18 @@ Modules are described by a file named `foo.mdd' for a module
is build. To describe the module it can/should set the following shell
variables:
- - moddeps modules on which this module depends (default none)
- - nozshdep non-empty indicates no dependence on the `zsh' pseudo-module
- - alwayslink if non-empty, always link the module into the executable
- - autobins builtins defined by the module, for autoloading
- - objects .o files making up this module (*must* be defined)
- - proto .pro files for this module (default generated from $objects)
- - headers extra headers for this module (default none)
- - hdrdeps extra headers on which the .mdh depends (default none)
- - otherincs extra headers that are included indirectly (default none)
+ - moddeps modules on which this module depends (default none)
+ - nozshdep non-empty indicates no dependence on the `zsh' pseudo-module
+ - alwayslink if non-empty, always link the module into the executable
+ - autobins builtins defined by the module, for autoloading
+ - autoinfixconds infix condition codes defined by the module, for
+ autoloading (without the leading `-')
+ - autoprefixconds like autoinfixconds, but for prefix condition codes
+ - objects .o files making up this module (*must* be defined)
+ - proto .pro files for this module (default generated from $objects)
+ - headers extra headers for this module (default none)
+ - hdrdeps extra headers on which the .mdh depends (default none)
+ - otherincs extra headers that are included indirectly (default none)
Be sure to put the values in quotes. For further enlightenment have a
look at the `mkmakemod.sh' script in the Src directory of the
diff --git a/aczsh.m4 b/aczsh.m4
index dfc40ce6f..08c167d2f 100644
--- a/aczsh.m4
+++ b/aczsh.m4
@@ -45,7 +45,7 @@ else
fi
echo '
extern char **environ;
- void *symlist1[] = {
+ void *symlist1[[]] = {
(void *)&environ,
(void *)0
};
diff --git a/configure.in b/configure.in
index 4fc45fe7c..1b2692ea1 100644
--- a/configure.in
+++ b/configure.in
@@ -340,7 +340,7 @@ AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
termios.h sys/param.h sys/filio.h string.h memory.h \
limits.h fcntl.h libc.h sys/utsname.h sys/resource.h \
locale.h errno.h stdlib.h unistd.h sys/capability.h \
- utmp.h utmpx.h sys/types.h pwd.h grp.h)
+ utmp.h utmpx.h sys/types.h pwd.h grp.h poll.h)
if test $dynamic = yes; then
AC_CHECK_HEADERS(dlfcn.h)
AC_CHECK_HEADERS(dl.h)
@@ -467,9 +467,22 @@ elif test $zsh_cv_decl_ospeed_must_define = yes; then
fi
dnl Check if tgetent accepts NULL (and will allocate its own termcap buffer)
+dnl Some termcaps reportedly accept a zero buffer, but then dump core
+dnl in tgetstr().
AC_CACHE_CHECK(if tgetent accepts NULL,
zsh_cv_func_tgetent_accepts_null,
-[AC_TRY_RUN([main(){int i = tgetent((char*)0,"vt100");exit(!i || i == -1);}],
+[AC_TRY_RUN([
+main()
+{
+ int i = tgetent((char*)0,"vt100");
+ if (i > 0) {
+ char tbuf[1024], *u;
+ u = tbuf;
+ tgetstr("cl", &u);
+ }
+ exit(!i || i == -1);
+}
+],
zsh_cv_func_tgetent_accepts_null=yes,
zsh_cv_func_tgetent_accepts_null=no,
zsh_cv_func_tgetent_accepts_null=no)])
@@ -615,7 +628,7 @@ dnl need to integrate this function
dnl AC_FUNC_STRFTIME
AC_CHECK_FUNCS(memcpy memmove \
- strftime waitpid select tcsetpgrp tcgetattr strstr lstat \
+ strftime waitpid select poll tcsetpgrp tcgetattr strstr lstat \
getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \
sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \
sigprocmask setuid seteuid setreuid setresuid setsid strerror \
diff --git a/patchlist.txt b/patchlist.txt
index 2179665ca..6ec3ec351 100644
--- a/patchlist.txt
+++ b/patchlist.txt
@@ -213,3 +213,56 @@ Sven's ignored character fix, 4828
More Sven condition patches, 4837, 4842
Final (???) isident() fix from Sven, 4845
+
+ pws-5
+
+Name of top level directory is now zsh-3.1.5-pws-5
+
+Missing part of Bart's sethparam() changes, 4851
+
+zftp test subcommand, 4852
+
+Geoff's refresh fix for a line the same length as the terminal width,
+4855
+
+Bart's fix for array slices, 4874
+
+Sven's accept-and-menu-complete-fix, 4878
+
+Sven's group completion fix, 4879
+
+Sven's module condition fixes, 4880
+
+Oliver Kiddle's autoconf fix, 4887
+
+My zftp fix (actually due to Andrej Borsenkow) for systems which only
+allow dup'ing sockets after they are connected, 4888.
+
+Bart's fix to making setting associative array elements inside
+substitutions consistent, 4893
+
+My typeset neatness and -a and -m fix, 4902
+
+My brief Etc/MACHINES addition, 4912
+
+My modification to findcmd() for memory leaks, 4923, plus comment
+alteration by Bart, 4924
+
+Sven's patch for completion after various reserved words, 4930
+
+My patch for compiler warnings, 4931
+
+My configuration fix for when tgetent() accepts a null argument but
+then tgetstr() dumps core, 4939
+
+Sven's alteration of `-t' behaviour, 4940. This is slightly
+incompatible with previous patched versions of 3.1.5 since now you don't
+need '-tc' with -T. However, you now do need '-tn' in cases where you
+don't want normal completion tried after a -T matches.
+
+Sven's new completion functions, 4850, 4881, 4941, 4942, 4943, 4944,
+4946, 4949, plus my addition of function pointers, 4945. The example
+file is now in Misc/new-completion-examples.
+
+(Effect of) fix from Helmut Jarausch in 4947 partly due to change
+missed in patch.