1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-06-11 19:18:01 +02:00

zsh-3.1.5-pws-5

This commit is contained in:
Tanaka Akira 1999-04-15 18:11:42 +00:00
parent 2a5a899a55
commit 20d67907c9
47 changed files with 2212 additions and 425 deletions

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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).

View file

@ -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.

View file

@ -1,4 +1,5 @@
DISTFILES_SRC='
.distfiles
c2z compctl-examples globtests globtests.ksh lete2ctl
new-completion-examples zftp-functions
'

View file

@ -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
}

View file

@ -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;

View file

@ -5,4 +5,5 @@ DISTFILES_SRC='
example.mdd example.c
files.mdd files.c
stat.mdd stat.c
zftp.mdd zftp.c
'

View file

@ -1,3 +1,6 @@
autobins="example"
autoinfixconds="ex"
autoprefixconds="len"
objects="example.o"

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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"

View file

@ -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

View file

@ -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 {

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
@ -504,13 +518,41 @@ bin_zle_compctl(char *name, char **args, char *ops, char func)
return 0;
}
/**/
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;

View file

@ -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). */
/**/
@ -272,6 +281,15 @@ completespecial(void)
docomplete(compwidget->u.cc ? COMP_WIDGET : COMP_COMPLETE);
}
/**/
void
completecall(void)
{
compfunc = compwidget->u.comp.func;
compwidget->u.comp.fn();
compfunc = NULL;
}
/**/
void
completeword(void)
@ -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. */

View file

@ -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)) {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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++;

View file

@ -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;
}

View file

@ -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;

View file

@ -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.

View file

@ -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

View file

@ -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)

View file

@ -52,7 +52,7 @@ execfor(Cmd cmd)
List list;
Forcmd node;
char *str;
int val;
int val = 0;
LinkList args;
node = cmd->u.forcmd;

View file

@ -129,26 +129,52 @@ global_permalloc(void)
return luh;
}
/* 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))
};
/* list of zsh heap */
static Heap heaps;
/* Use new heaps from now on. This returns the old heap-list. */
/**/
Heap
new_heaps(void)
{
Heap h = heaps;
heaps = NULL;
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 */
/**/

View file

@ -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 "*)

View file

@ -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=

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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 != '%') {

View file

@ -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

View file

@ -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
/****************/

View file

@ -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

View file

@ -45,7 +45,7 @@ else
fi
echo '
extern char **environ;
void *symlist1[] = {
void *symlist1[[]] = {
(void *)&environ,
(void *)0
};

View file

@ -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 \

View file

@ -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.