1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-25 05:31:19 +02:00

zsh-3.1.5-pws-3

This commit is contained in:
Tanaka Akira 1999-04-15 18:09:05 +00:00
parent f13624e0f8
commit 9003d99d16
41 changed files with 5315 additions and 427 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
VERSION_DATE='October 29, 1998'
VERSION=3.1.5-pws-3
VERSION_DATE='December 12, 1998'

View file

@ -512,7 +512,7 @@ sitem([var(mm)tt(:)]var(ss))(minutes and seconds)
endsitem()
)
findex(local)
item(tt(local) [ {tt(PLUS())|tt(-)}tt(LRZilrtu) [var(n)]] [ var(name)[tt(=)var(value)] ] ...)(
item(tt(local) [ {tt(PLUS())|tt(-)}tt(ALRUZailrtu) [var(n)]] [ var(name)[tt(=)var(value)] ] ...)(
Same as tt(typeset), except that the options tt(-x) and
tt(-f) are not permitted.
)
@ -878,7 +878,7 @@ Equivalent to tt(whence -v).
findex(typeset)
cindex(parameters, setting)
cindex(parameters, declaring)
item(tt(typeset) [ {tt(PLUS())|tt(-)}tt(LRUZfilrtuxm) [var(n)]] [ var(name)[tt(=)var(value)] ... ])(
item(tt(typeset) [ {tt(PLUS())|tt(-)}tt(ALRUZafilrtuxm) [var(n)]] [ var(name)[tt(=)var(value)] ... ])(
Set attributes and values for shell parameters.
When invoked inside a function a new parameter is created which will be
unset when the function completes. The new parameter will not be
@ -887,6 +887,9 @@ exported provided no parameter of that name already exists.
The following attributes are valid:
startitem()
item(tt(-A))(
Declare var(name) to be an em(A)ssociation parameter (also known as a hash).
)
item(tt(-L))(
Left justify and remove leading blanks from var(value).
If var(n) is nonzero, it defines the width of the field;
@ -916,6 +919,10 @@ If var(n) is nonzero it defines the width of the field;
otherwise it is determined by the width of the value of the
first assignment.
)
item(tt(-a))(
On its own, this option produces a list of all array parameters.
If any non-options are provided, the tt(typeset) command is silently ignored.
)
item(tt(-f))(
The names refer to functions rather than parameters. No assignments
can be made, and the only other valid flags are tt(-t)
@ -1115,7 +1122,10 @@ xitem(tt(zmodload) tt(-u) [ tt(-i) ] var(name) ...)
xitem(tt(zmodload) tt(-d) [ tt(-L) ] [ var(name) [ var(dep) ... ] ])
xitem(tt(zmodload) tt(-du) var(name) [ var(dep) ... ])
xitem(tt(zmodload) tt(-a) [ tt(-iL) ] [ var(name) [ var(builtin) ... ] ])
item(tt(zmodload) tt(-au) [ tt(-i) ] var(builtin) ...)(
xitem(tt(zmodload) tt(-au) [ tt(-i) ] var(builtin) ...)
xitem(tt(zmodload) tt(-c) [ tt(-iI) ] [ var(name) [ var(cond) ... ] ])
xitem(tt(zmodload) tt(-cu) [ tt(-iI) ] var(cond) ...)
item(tt(zmodload) tt(-c) [ tt(-IL) ])(
tt(zmodload) performs operations relating to zsh's loadable modules.
This feature is not available on all operating systems,
or on all installations on a particular operating system.
@ -1182,5 +1192,14 @@ together with the tt(-u) option it removes builtins defined with
tt(zmodload -a). This is only possible if the builtin is not yet
loaded. tt(-i) suppresses the error if the builtin is already
removed (or never existed).
The tt(-c) option is used to define autoloaded condition codes. The
var(cond) strings give the names of the conditions defined by the
module. The optional tt(-I) option is used to define infix condition
names. Without this option prefix condition names are defined.
Together with the tt(-u) option definitions for autoloaded conditions
are removed. If given no condition names all defined names are listed
(as a series of tt(zmodload) commands if the tt(-L) option is given).
)
enditem()

View file

@ -312,8 +312,10 @@ noderef(Parameters)
for a description of parameters.
In the expansions discussed below that require a pattern, the form of
the pattern is the same as that used for filename generation;
see noderef(Filename Generation). In addition to the following
operations, the file modifiers described in
see noderef(Filename Generation). Note that this pattern, along with
the replacement text of a substitution, is itself subject to
parameter, command and arithmetic substitution. In addition to the
following operations, the file modifiers described in
noderef(Modifiers) in noderef(History Expansion) can be
applied: for example, tt(${i:s/foo/bar/}) performs string
substitution on the value of parameter tt($i).
@ -398,6 +400,37 @@ is used, matching is performed on each array elements separately, and
the matched array elements are removed (use the tt((M)) flag to
remove the non-matched elements).
)
xitem(tt(${)var(name)tt(/)var(pattern)tt(/)var(repl)tt(}))
item(tt(${)var(name)tt(//)var(pattern)tt(/)var(repl)tt(}))(
Substitute the longest possible match of var(pattern) in the value of
variable var(name) with the string var(repl). The first form
substitutes just the first occurrence, the second all occurrences.
The var(pattern) may begin with a var(#), in which case the
var(pattern) must match at the start of the string, or var(%), in
which case it must match at the end of the string. The var(repl) may
be an empty string, in which case the final tt(/) may also be omitted.
To quote the final tt(/) in other cases it should be preceded by two
backslashes (i.e., a quoted backslash); this is not necessary if the
tt(/) occurs inside a substituted paramter. Substitution of an array
is as described for tt(#) and tt(%) above.
The first tt(/) may be preceded by a tt(:), in which case the match
will only succeed if it matches the entire word. Note also the
effect of the tt(I) and tt(S) parameter expansion flags below: the
flags tt(M), tt(R), tt(B), tt(E) and tt(N) are not useful, however.
For example,
nofill(tt(foo="twinkle twinkle little star" sub="t*e" rep="spy"))
nofill(tt(print ${foo//${~sub}/$rep}))
nofill(tt(print ${(S)foo//${~sub}/$rep}))
Here, the tt(~) ensures that the text of tt($sub) is treated as a
pattern rather than a plain string. In the first case, the longest
match for tt(t*e) is substituted and the result is `tt(spy star)',
while in the second case, the shortest matches are taken and the
result is `tt(spy spy lispy star)'.
)
item(tt(${#)var(spec)tt(}))(
If var(spec) is one of the above substitutions, substitute
the length in characters of the result instead of
@ -549,10 +582,21 @@ for `tt(ps:\n:)'.
item(tt(S))(
(This and all remaining flags are used with the tt(${)...tt(#)...tt(}) or
tt(${)...tt(%)...tt(}) forms.)
Search substrings as well as beginnings or ends.
Search substrings as well as beginnings or ends; with tt(#) start
from the beginning and with tt(%) start from the end of the string.
With substitution via tt(${)...tt(/)...tt(}) or
tt(${)...tt(//)...tt(}), specifies that the shortest instead of the
longest match should be replaced.
)
item(tt(I:)var(expr)tt(:))(
Search the var(expr)th match (where var(expr) evaluates to a number).
This only applies when searching for substrings, either with the tt(S)
flag, or with tt(${)...tt(/)...tt(}) (only the var(expr)th match is
substituted) or tt(${)...tt(//)...tt(}) (all matches from the
var(expr)th on are substituted). The var(expr)th match is counted
such that there is either one or zero matches from each starting
position in the string, although for global subsitution matches
overlapping previous replacements are ignored.
)
item(tt(M))(
Include the matched portion in the result.

View file

@ -114,6 +114,7 @@ menu(The example Module)
menu(The files Module)
menu(The sched Module)
menu(The stat Module)
menu(The zftp Module)
menu(The zle Module)
endmenu()
texinode(The Z Shell Guide)(Introduction)(Top)(Top)

View file

@ -1,4 +1,4 @@
texinode(The stat Module)(The zle Module)(The sched Module)(Zsh Modules)
texinode(The stat Module)(The zftp Module)(The sched Module)(Zsh Modules)
sect(The stat Module)
The tt(stat) module makes available one builtin command:
@ -6,7 +6,8 @@ startitem()
findex(stat)
cindex(files, listing)
cindex(files, examining)
item(tt(stat) [ tt(-gnNlLtTrs) ] [ tt(-f) var(fd) ] [ tt(-A) var(array) ] \
item(tt(stat) [ tt(-gnNlLtTrs) ] [ tt(-f) var(fd) ] \
[ tt(-H) var(hash) ] [ tt(-A) var(array) ] \
[ tt(-F) var(fmt) ] [ tt(PLUS())var(element) ] [ var(file) ... ])(
The command acts as a front end to the tt(stat) system call (see
manref(stat)(2)).
@ -91,6 +92,11 @@ appropriate array element and in the latter case the file name
appears as a separate array element preceding all the others.
Other formatting options are respected.
)
item(tt(-H) var(hash))(
Similar to tt(-A), but instead assign the values to var(hash). The keys
are the elements listed above. If the tt(-n) option is provided then the
name of the file is included in the hash with key tt(name).
)
item(tt(-f) var(fd))(
Use the file on file descriptor var(fd) instead of
named files; no list of file names is allowed in this case.

View file

@ -1,4 +1,4 @@
texinode(The zle Module)()(The stat Module)(Zsh Modules)
texinode(The zle Module)()(The zftp Module)(Zsh Modules)
sect(The zle Module)
The tt(zle) module contains the Zsh Line Editor. See
ifzman(zmanref(zshzle))\

View file

@ -36,6 +36,9 @@ A builtin that provides a timed execution facility within the shell.
item(tt(stat))(
A builtin command interface to the tt(stat) system call.
)
item(tt(zftp))(
A builtin FTP client.
)
item(tt(zle))(
The Zsh Line Editor, including the tt(bindkey) and tt(vared) builtins.
)
@ -50,6 +53,7 @@ menu(The example Module)
menu(The files Module)
menu(The sched Module)
menu(The stat Module)
menu(The zftp Module)
menu(The zle Module)
endmenu()
includefile(Zsh/mod_cap.yo)
@ -61,4 +65,5 @@ includefile(Zsh/mod_example.yo)
includefile(Zsh/mod_files.yo)
includefile(Zsh/mod_sched.yo)
includefile(Zsh/mod_stat.yo)
includefile(Zsh/mod_zftp.yo)
includefile(Zsh/mod_zle.yo)

View file

@ -2,7 +2,7 @@
# second argument of cd and pushd.
emulate -R zsh # Requires zsh 3.0-pre4 or later
setopt localoptions
setopt localoptions extendedglob
local from
read -Ac from

View file

@ -112,5 +112,6 @@ t fooxx ((#i)FOOX)x
f fooxx ((#i)FOOX)X
f BAR (bar|(#i)foo)
t FOO (bar|(#i)foo)
t Modules (#i)*m*
EOT
print "$failed tests failed."

View file

@ -96,5 +96,6 @@ t fooxx @((#i)FOOX)x
f fooxx @((#i)FOOX)X
f BAR @(bar|(#i)foo)
t FOO @(bar|(#i)foo)
t Modules (#i)*m*
EOT
print "$failed tests failed."

View file

@ -9,7 +9,6 @@
# Runs as a filter. Should ignore anything which isn't a "complete".
# It expects each "complete" statement to be the first thing on a line.
# All the examples in the tcsh manual give sensible results.
# Author: Peter Stephenson <pws@ibmth.df.unipi.it>
#
# Option:
# -x (exact): only applies in the case of command disambiguation (is
@ -39,11 +38,6 @@
# (5) Make sure all command names with wildcards are processed together --
# they need to be lumped into one "compctl -C" or "compctl -D"
# statement for zsh.
# (6) Group completion (complete's g flag) is not built into zsh, so
# you need perl to be available to generate the groups. If this
# script is useful, I assume that's not a problem.
# (7) I don't know what `completing completions' means, so the X
# flag to complete is not handled.
# Handle options
if (@ARGV) {
@ -119,13 +113,6 @@ sub gettype {
# Nothing (n) can be handled by returning nothing. (C.f. King Lear, I.i.)
if ($c =~ /[abcjuv]/) {
$ret = "-$c";
} elsif ($c eq 'C') {
if (defined($glob)) {
$ret = "-W $glob -/g '*(.*)'";
undef($glob);
} else {
$ret = '-c';
}
} elsif ($c eq 'S') {
$ret = '-k signals';
} elsif ($c eq 'd') {
@ -134,42 +121,18 @@ sub gettype {
} else {
$ret = '-/';
}
} elsif ($c eq 'D') {
if (defined($glob)) {
$ret = "-W $glob -/";
undef($glob);
} else {
$ret = '-/';
}
} elsif ($c eq 'e') {
$ret = '-E';
} elsif ($c eq 'f' && !$glob) {
$ret = '-f';
} elsif ($c eq 'F') {
if (defined($glob)) {
$ret = "-W $glob -f";
undef($glob);
} else {
$ret = '-f';
}
} elsif ($c eq 'g') {
$ret = "-s '\$(perl -e '\\''while ((\$name) = getgrent)\n" .
"{ print \$name, \"\\n\"; }'\\'')'";
} elsif ($c eq 'l') {
$ret = q!-k "(`limit | awk '{print $1}'`)"!;
} elsif ($c eq 'p') {
$ret = "-W $glob -f", undef($glob) if defined($glob);
$ret = "-W $glob -f", undef($glob) if defined($glob);
} elsif ($c eq 's') {
$ret = '-p';
$ret = '-p';
} elsif ($c eq 't') {
$qual = '.';
} elsif ($c eq 'T') {
if (defined($glob)) {
$ret = "-W $glob -g '*(.)'";
undef($glob);
} else {
$ret = "-g '*(.)'";
}
} elsif ($c eq 'x') {
$glob =~ s/'/'\\''/g;
$ret = "-X '$glob'";
@ -227,7 +190,7 @@ $" = " - ";
while (<>) {
if (/^\s*complete\s/) {
undef(@stuff);
undef(@stuff);
$default = '';
$_ = $';
while (/\\$/) {
@ -248,7 +211,7 @@ while (<>) {
# Loop over remaining arguments to "complete".
$sep = substr($word,1,1);
$sep =~ s/(\W)/\\$1/g;
@split = split(/$sep/,$word,4);
@split = split(/$sep/,$word);
for ($i = 0; $i < 3; $i++) {
while ($split[$i] =~ /\\$/) {
substr($split[$i],-1,1) = "";
@ -262,9 +225,7 @@ while (<>) {
# The "complete" catch-all: treat this as compctl\'s
# default (requiring no pattern matching).
$default .= &gettype($type) . ' ';
defined($suffix) &&
(defined($defsuf) ? ($defsuf .= $suffix)
: ($defsuf = $suffix));
defined($suffix) && ($defsuf .= $suffix);
} else {
$pat = &getpat($pat,$arg);
$type = &gettype($type);

1281
Misc/zftp-functions Normal file

File diff suppressed because it is too large Load diff

View file

@ -49,6 +49,53 @@ bin_example(char *nam, char **args, char *ops, int func)
return 0;
}
/**/
static int
cond_p_len(Conddef c, char **a)
{
char *s1 = a[0], *s2 = a[1];
singsub(&s1);
untokenize(s1);
if (s2) {
singsub(&s2);
untokenize(s2);
return strlen(s1) == matheval(s2);
} else {
return !s1[0];
}
}
/**/
static int
cond_i_ex(Conddef c, char **a)
{
char *s1 = a[0], *s2 = a[1];
singsub(&s1);
untokenize(s1);
singsub(&s2);
untokenize(s2);
return !strcmp("example", dyncat(s1, s2));
}
/**/
static int
ex_wrapper(List list, FuncWrap w, char *name)
{
if (strncmp(name, "example", 7))
return 1;
else {
int ogd = opts[GLOBDOTS];
opts[GLOBDOTS] = 1;
runshfunc(list, w, name);
opts[GLOBDOTS] = ogd;
return 0;
}
}
/*
* boot_example is executed when the module is loaded.
*/
@ -57,11 +104,22 @@ static struct builtin bintab[] = {
BUILTIN("example", 0, bin_example, 0, -1, 0, "flags", NULL),
};
static struct conddef cotab[] = {
CONDDEF("len", 0, 1, 2, cond_p_len),
CONDDEF("ex", CONDF_INFIX, 0, 0, cond_i_ex),
};
static struct funcwrap wrapper[] = {
WRAPDEF(ex_wrapper),
};
/**/
int
boot_example(Module m)
{
return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
!addwrapper(m, wrapper));
}
#ifdef MODULE
@ -71,6 +129,8 @@ int
cleanup_example(Module m)
{
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
deletewrapper(m, wrapper);
return 0;
}
#endif

View file

@ -34,11 +34,13 @@ enum statnum { ST_DEV, ST_INO, ST_MODE, ST_NLINK, ST_UID, ST_GID,
ST_RDEV, ST_SIZE, ST_ATIM, ST_MTIM, ST_CTIM,
ST_BLKSIZE, ST_BLOCKS, ST_READLINK, ST_COUNT };
enum statflags { STF_NAME = 1, STF_FILE = 2, STF_STRING = 4, STF_RAW = 8,
STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64 };
STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64,
STF_HASH = 128 };
static char *statelts[] = { "device", "inode", "mode", "nlink",
"uid", "gid", "rdev", "size", "atime",
"mtime", "ctime", "blksize", "blocks",
"link", NULL };
#define HNAMEKEY "name"
/**/
static void
@ -287,6 +289,8 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
* file names are returned as a separate array element, type names as
* prefix to element. Note the formatting deliberately contains
* fewer frills when -A is used.
* -H hash: as for -A array, but returns a hash with the keys being those
* from stat -l
* -F fmt: specify a $TIME-like format for printing times; the default
* is the (CTIME-like) "%a %b %e %k:%M:%S". This option implies
* -s as it is not useful for numerical times.
@ -305,6 +309,7 @@ static int
bin_stat(char *name, char **args, char *ops, int func)
{
char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL;
char *hashnam = NULL, **hash = NULL, **hashptr = NULL;
int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0;
struct stat statbuf;
int found = 0, nargs;
@ -352,6 +357,16 @@ bin_stat(char *name, char **args, char *ops, int func)
}
flags |= STF_ARRAY;
break;
} else if (*arg == 'H') {
if (arg[1]) {
hashnam = arg+1;
} else if (!(hashnam = *++args)) {
zerrnam(name, "missing parameter name\n",
NULL, 0);
return 1;
}
flags |= STF_HASH;
break;
} else if (*arg == 'f') {
char *sfd;
ops['f'] = 1;
@ -385,6 +400,15 @@ bin_stat(char *name, char **args, char *ops, int func)
}
}
if ((flags & STF_ARRAY) && (flags & STF_HASH)) {
/* We don't implement setting multiple variables at once */
zwarnnam(name, "both array and hash requested", NULL, 0);
return 1;
/* Alternate method would be to make -H blank arrnam etc etc *
* and so get 'silent loss' of earlier choice, which would *
* be similar to stat -A foo -A bar filename */
}
if (ops['l']) {
/* list types and return: can also list to array */
if (arrnam) {
@ -435,7 +459,7 @@ bin_stat(char *name, char **args, char *ops, int func)
if (ops['g'])
flags |= STF_GMT;
if (!arrnam) {
if (!(arrnam || hashnam)) {
if (nargs > 1)
flags |= STF_FILE;
if (!(flags & STF_PICK))
@ -444,9 +468,20 @@ bin_stat(char *name, char **args, char *ops, int func)
if (ops['N'] || ops['f'])
flags &= ~STF_FILE;
if (ops['T'])
if (ops['T'] || ops['H'])
flags &= ~STF_NAME;
if (hashnam) {
if (nargs > 1) {
zwarnnam(name, "only one file allowed with -H", NULL, 0);
return 1;
}
arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
if (flags & STF_FILE)
arrsize++;
hashptr = hash = (char **)zcalloc((arrsize+1)*2*sizeof(char *));
}
if (arrnam) {
arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
if (flags & STF_FILE)
@ -473,13 +508,20 @@ bin_stat(char *name, char **args, char *ops, int func)
if (flags & STF_FILE)
if (arrnam)
*arrptr++ = ztrdup(*args);
else
else if (hashnam) {
*hashptr++ = ztrdup(HNAMEKEY);
*hashptr++ = ztrdup(*args);
} else
printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n");
if (iwhich > -1) {
statprint(&statbuf, outbuf, *args, iwhich, flags);
if (arrnam)
*arrptr++ = ztrdup(outbuf);
else
else if (hashnam) {
/* STF_NAME explicitly turned off for ops['H'] above */
*hashptr++ = ztrdup(statelts[iwhich]);
*hashptr++ = ztrdup(outbuf);
} else
printf("%s\n", outbuf);
} else {
int i;
@ -487,28 +529,39 @@ bin_stat(char *name, char **args, char *ops, int func)
statprint(&statbuf, outbuf, *args, i, flags);
if (arrnam)
*arrptr++= ztrdup(outbuf);
else
else if (hashnam) {
/* STF_NAME explicitly turned off for ops['H'] above */
*hashptr++ = ztrdup(statelts[i]);
*hashptr++ = ztrdup(outbuf);
} else
printf("%s\n", outbuf);
}
}
if (ops['f'])
break;
if (!arrnam && args[1] && !(flags & STF_PICK))
if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK))
putchar('\n');
}
if (arrnam)
if (ret) {
for (aptr = array; *aptr; aptr++)
zsfree(*aptr);
zfree(array, arrsize+1);
} else {
if (ret)
freearray(array);
else {
setaparam(arrnam, array);
if (errflag)
return 1;
}
if (hashnam)
if (ret)
freearray(hash);
else {
sethparam(hashnam, hash);
if (errflag)
return 1;
}
return ret;
}

2596
Src/Modules/zftp.c Normal file

File diff suppressed because it is too large Load diff

3
Src/Modules/zftp.mdd Normal file
View file

@ -0,0 +1,3 @@
autobins="zftp"
objects="zftp.o"

View file

@ -44,7 +44,7 @@ Cmlist cmatcher;
/* pointers to functions required by zle */
/**/
void (*printcompctlptr) _((char *, Compctl, int));
void (*printcompctlptr) _((char *, Compctl, int, int));
/**/
Compctl (*compctl_widgetptr) _((char *, char **));

View file

@ -605,7 +605,7 @@ execzlefunc(Thingy func)
} else {
startparamscope();
makezleparams();
doshfunc(l, NULL, 0, 1);
doshfunc(w->u.fnnam, l, NULL, 0, 1);
endparamscope();
lastcmd = 0;
}

View file

@ -72,6 +72,9 @@ makezleparams(void)
for(zp = zleparams; zp->name; zp++) {
Param pm = createparam(zp->name, zp->type | PM_SPECIAL);
if (!pm)
pm = (Param) paramtab->getnode(paramtab, zp->name);
DPUTS(!pm, "param not set in makezleparams");
pm->level = locallevel;
pm->u.data = zp->data;

View file

@ -394,7 +394,7 @@ scanlistwidgets(HashNode hn, int list)
quotedzputs(t->nam, stdout);
if (w->flags & WIDGET_COMP) {
if (printcompctlptr && w->u.cc)
printcompctlptr(NULL, w->u.cc, PRINT_LIST);
printcompctlptr(NULL, w->u.cc, PRINT_LIST, 0);
} else if(strcmp(t->nam, w->u.fnnam)) {
fputc(' ', stdout);
quotedzputs(w->u.fnnam, stdout);
@ -404,7 +404,7 @@ scanlistwidgets(HashNode hn, int list)
if (w->flags & WIDGET_COMP) {
fputs(" -C", stdout);
if (printcompctlptr && w->u.cc)
printcompctlptr(NULL, w->u.cc, PRINT_TYPE);
printcompctlptr(NULL, w->u.cc, PRINT_TYPE, 0);
} else if(strcmp(t->nam, w->u.fnnam)) {
fputs(" (", stdout);
nicezputs(w->u.fnnam, stdout);

View file

@ -2730,18 +2730,16 @@ maketildelist(void)
/**/
static int
getcpat(char *wrd, int cpatindex, char *cpat, int class)
getcpat(char *str, int cpatindex, char *cpat, int class)
{
char *str, *s, *t, *p;
char *s, *t, *p;
int d = 0;
if (!wrd || !*wrd)
if (!str || !*str)
return -1;
cpat = rembslash(cpat);
str = ztrdup(wrd);
untokenize(str);
if (!cpatindex)
cpatindex++, d = 0;
else if ((d = (cpatindex < 0)))
@ -2752,23 +2750,14 @@ getcpat(char *wrd, int cpatindex, char *cpat, int class)
d ? s-- : s++) {
for (t = s, p = cpat; *t && *p; p++) {
if (class) {
if (*p == *s && !--cpatindex) {
zsfree(str);
if (*p == *s && !--cpatindex)
return (int)(s - str + 1);
}
} else if (*t++ != *p)
break;
}
if (!class && !*p && !--cpatindex) {
zsfree(str);
t += wrd - str;
for (d = 0; --t >= wrd;)
if (! INULL(*t))
d++;
return d;
}
if (!class && !*p && !--cpatindex)
return t - str;
}
zsfree(str);
return -1;
}
@ -3336,8 +3325,9 @@ makecomplistext(Compctl occ, char *os, int incmd)
break;
case CCT_CURSUF:
case CCT_CURPRE:
s = ztrdup(clwpos < clwnum ? clwords[clwpos] : "");
s = ztrdup(clwpos < clwnum ? os : "");
untokenize(s);
if (isset(COMPLETEINWORD)) s[offs] = '\0';
sc = rembslash(cc->u.s.s[i]);
a = strlen(sc);
if (!strncmp(s, sc, a)) {
@ -3347,10 +3337,13 @@ makecomplistext(Compctl occ, char *os, int incmd)
break;
case CCT_CURSUB:
case CCT_CURSUBC:
if (clwpos < 0 || clwpos > clwnum)
if (clwpos < 0 || clwpos >= clwnum)
t = 0;
else {
a = getcpat(clwords[clwpos],
s = ztrdup(os);
untokenize(s);
if (isset(COMPLETEINWORD)) s[offs] = '\0';
a = getcpat(s,
cc->u.s.p[i],
cc->u.s.s[i],
cc->type == CCT_CURSUBC);
@ -4107,7 +4100,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
/* This flag allows us to use read -l and -c. */
incompctlfunc = 1;
/* Call the function. */
doshfunc(list, args, 0, 1);
doshfunc(cc->func, list, args, 0, 1);
incompctlfunc = 0;
/* And get the result from the reply parameter. */
if ((r = get_user_var("reply")))
@ -4270,7 +4263,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
/* No harm in allowing read -l and -c here, too */
incompctlfunc = 1;
doshfunc(list, args, 0, 1);
doshfunc(cc->ylist, list, args, 0, 1);
incompctlfunc = 0;
uv = "reply";
}
@ -4912,7 +4905,7 @@ do_ambiguous(void)
* if it is needed. */
if (isset(LISTBEEP))
feep();
if (isset(AUTOLIST) && !amenu && !showinglist)
if (isset(AUTOLIST) && !amenu && !showinglist && smatches >= 2)
showinglist = -2;
if (am)
lastambig = 1;
@ -5233,14 +5226,10 @@ listmatches(void)
Cmgroup g;
Cmatch *p, m;
Cexpl *e;
int nlines = 0, ncols, colsz, ngr = 0, nlist = 0, longest = 1, pnl = 0;
int nlines = 0, ncols, nlist = 0, longest = 1, pnl = 0;
int of = isset(LISTTYPES), opl = 0;
int listmax = getiparam("LISTMAX");
if (smatches < 2) {
showinglist = 0;
return;
}
#ifdef DEBUG
/* Sanity check */
if(!validlist) {
@ -5310,16 +5299,13 @@ listmatches(void)
e++;
}
}
if (g->lcount)
ngr++;
}
longest += 2 + of;
if ((ncols = (columns + 1) / longest)) {
colsz = (nlist + ncols - 1) / ncols;
nlines += ngr - 1 + colsz + (nlist == 0);
for (g = amatches; g; g = g->next)
nlines += (g->lcount + ncols - 1) / ncols;
} else {
ncols = 1;
colsz = 1;
opl = 1;
for (g = amatches; g; g = g->next) {
char **pp = g->ylist;
@ -5396,12 +5382,11 @@ listmatches(void)
}
}
else {
int n = g->lcount, nl = (n + ncols - 1) / ncols, i, a;
int nc = (opl ? 1 : (n + colsz - 1) / colsz);
int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, a;
char **pq;
while (n && nl--) {
i = nc;
i = ncols;
pq = pp;
while (n && i--) {
if (pq - g->ylist >= g->lcount)
@ -5412,7 +5397,7 @@ listmatches(void)
while (a--)
putc(' ', shout);
}
pq += colsz;
pq += nc;
n--;
}
if (n)
@ -5422,8 +5407,7 @@ listmatches(void)
}
}
else if (g->lcount) {
int n = g->lcount, nl = (n + ncols - 1) / ncols, i, j, a;
int nc = (opl ? 1 : (n + colsz - 1) / colsz);
int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a;
Cmatch *q;
if (n && pnl) {
@ -5431,7 +5415,7 @@ listmatches(void)
pnl = 0;
}
for (p = skipnolist(g->matches); n && nl--;) {
i = nc;
i = ncols;
q = p;
while (n && i--) {
if (!(m = *q))
@ -5460,7 +5444,7 @@ listmatches(void)
while (a--)
putc(' ', shout);
if (--n)
for (j = colsz; j && *q; j--)
for (j = nc; j && *q; j--)
q = skipnolist(q + 1);
}
if (n) {

View file

@ -567,7 +567,9 @@ vioperswapcase(void)
}
/* go back to the first line of the range */
cs = oldcs;
#if 0
vifirstnonblank();
#endif
}
vichgflag = 0;
}

View file

@ -73,7 +73,7 @@ viforwardword(void)
cs++;
if (wordflag && !n)
return;
while (cs != ll && iblank(line[cs]))
while (cs != ll && (iblank(line[cs]) || line[cs] == '\n'))
cs++;
}
}

View file

@ -120,7 +120,7 @@ static struct builtin builtins[] =
BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
#ifdef DYNAMIC
BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "Laudi", NULL),
BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicI", NULL),
#endif
};
@ -994,7 +994,7 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks)
if ((l = getshfunc("chpwd")) != &dummy_list) {
fflush(stdout);
fflush(stderr);
doshfunc(l, NULL, 0, 1);
doshfunc("chpwd", l, NULL, 0, 1);
}
dirstacksize = getiparam("DIRSTACKSIZE");

View file

@ -43,6 +43,26 @@ evalcond(Cond c)
return evalcond(c->left) && evalcond(c->right);
case COND_OR:
return evalcond(c->left) || evalcond(c->right);
case COND_MOD:
case COND_MODI:
{
Conddef cd;
if ((cd = getconddef((c->type == COND_MODI), (char *) c->left, 1))) {
if (c->type == COND_MOD) {
int l = arrlen((char **) c->right);
if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
return 0;
}
}
return cd->handler(cd, (char **) c->right);
}
else
zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
return 0;
}
}
singsub((char **)&c->left);
untokenize(c->left);

View file

@ -2602,7 +2602,7 @@ execshfunc(Cmd cmd, Shfunc shf)
deletejob(jobtab + thisjob);
}
doshfunc(shf->funcdef, cmd->args, shf->flags, 0);
doshfunc(shf->nam, shf->funcdef, cmd->args, shf->flags, 0);
if (!list_pipe)
deletefilelist(last_file_list);
@ -2650,14 +2650,13 @@ execautofn(Cmd cmd)
/**/
void
doshfunc(List list, LinkList doshargs, int flags, int noreturnval)
doshfunc(char *name, List list, LinkList doshargs, int flags, int noreturnval)
/* If noreturnval is nonzero, then reset the current return *
* value (lastval) to its value before the shell function *
* was executed. */
{
char **tab, **x, *oargv0 = NULL;
int xexittr, newexittr, oldzoptind, oldlastval;
char *ou;
void *xexitfn, *newexitfn;
char saveopts[OPT_SIZE];
int obreaks = breaks;
@ -2705,14 +2704,7 @@ doshfunc(List list, LinkList doshargs, int flags, int noreturnval)
argzero = ztrdup(argzero);
}
}
startparamscope();
ou = underscore;
underscore = ztrdup(underscore);
execlist(dupstruct(list), 1, 0);
zsfree(underscore);
underscore = ou;
endparamscope();
runshfunc(list, wrappers, name);
if (retflag) {
retflag = 0;
breaks = obreaks;
@ -2767,6 +2759,44 @@ doshfunc(List list, LinkList doshargs, int flags, int noreturnval)
} LASTALLOC;
}
/* This finally executes a shell function and any function wrappers *
* defined by modules. This works by calling the wrapper function which *
* in turn has to call back this function with the arguments it gets. */
/**/
void
runshfunc(List list, FuncWrap wrap, char *name)
{
int cont;
char *ou;
while (wrap) {
wrap->module->flags |= MOD_WRAPPER;
wrap->count++;
cont = wrap->handler(list, wrap->next, name);
wrap->count--;
if (!wrap->count) {
wrap->module->flags &= ~MOD_WRAPPER;
#ifdef DYNAMIC
if (wrap->module->flags & MOD_UNLOAD) {
wrap->module->flags &= ~MOD_UNLOAD;
unload_module(wrap->module, NULL);
}
#endif
}
if (!cont)
return;
wrap = wrap->next;
}
startparamscope();
ou = underscore;
underscore = ztrdup(underscore);
execlist(dupstruct(list), 1, 0);
zsfree(underscore);
underscore = ou;
endparamscope();
}
/* Search fpath for an undefined function. Finds the file, and returns the *
* list of its contents. */

View file

@ -129,6 +129,8 @@ struct comp {
static char *pptr; /* current place in string being matched */
static Comp tail;
static int first; /* are leading dots special? */
static int longest; /* always match longest piece of path. */
static int inclosure; /* see comment in doesmatch() */
/* Add a component to pathbuf: This keeps track of how *
* far we are into a file name, since each path component *
@ -1806,41 +1808,62 @@ matchpat(char *a, char *b)
/* do the ${foo%%bar}, ${foo#bar} stuff */
/* please do not laugh at this code. */
struct repldata {
int b, e; /* beginning and end of chunk to replace */
};
typedef struct repldata *Repldata;
/*
* List of bits of matches to concatenate with replacement string.
* The data is a struct repldata. It is not used in cases like
* ${...//#foo/bar} even though SUB_GLOBAL is set, since the match
* is anchored. It goes on the heap.
*/
static LinkList repllist;
/* Having found a match in getmatch, decide what part of string
* to return. The matched part starts b characters into string s
* and finishes e characters in: 0 <= b <= e <= strlen(s)
* (yes, empty matches should work).
* Bits 3 and higher in fl are used: the flags are
* 8: Result is matched portion.
* 16: Result is unmatched portion.
* (N.B. this should be set for standard ${foo#bar} etc. matches.)
* 32: Result is numeric position of start of matched portion.
* 64: Result is numeric position of end of matched portion.
* 128: Result is length of matched portion.
* fl is a set of the SUB_* matches defined in zsh.h from SUB_MATCH onwards;
* the lower parts are ignored.
* replstr is the replacement string for a substitution
*/
/**/
static char *
get_match_ret(char *s, int b, int e, int fl)
get_match_ret(char *s, int b, int e, int fl, char *replstr)
{
char buf[80], *r, *p, *rr;
int ll = 0, l = strlen(s), bl = 0, t = 0, i;
if (fl & 8) /* matched portion */
if (replstr) {
if ((fl & SUB_GLOBAL) && repllist) {
/* We are replacing the chunk, just add this to the list */
Repldata rd = (Repldata) halloc(sizeof(*rd));
rd->b = b;
rd->e = e;
addlinknode(repllist, rd);
return s;
}
ll += strlen(replstr);
}
if (fl & SUB_MATCH) /* matched portion */
ll += 1 + (e - b);
if (fl & 16) /* unmatched portion */
if (fl & SUB_REST) /* unmatched portion */
ll += 1 + (l - (e - b));
if (fl & 32) {
if (fl & SUB_BIND) {
/* position of start of matched portion */
sprintf(buf, "%d ", b + 1);
ll += (bl = strlen(buf));
}
if (fl & 64) {
if (fl & SUB_EIND) {
/* position of end of matched portion */
sprintf(buf + bl, "%d ", e + 1);
ll += (bl = strlen(buf));
}
if (fl & 128) {
if (fl & SUB_LEN) {
/* length of matched portion */
sprintf(buf + bl, "%d ", e - b);
ll += (bl = strlen(buf));
@ -1850,13 +1873,13 @@ get_match_ret(char *s, int b, int e, int fl)
rr = r = (char *)ncalloc(ll);
if (fl & 8) {
if (fl & SUB_MATCH) {
/* copy matched portion to new buffer */
for (i = b, p = s + b; i < e; i++)
*rr++ = *p++;
t = 1;
}
if (fl & 16) {
if (fl & SUB_REST) {
/* Copy unmatched portion to buffer. If both portions *
* requested, put a space in between (why?) */
if (t)
@ -1864,6 +1887,9 @@ get_match_ret(char *s, int b, int e, int fl)
/* there may be unmatched bits at both beginning and end of string */
for (i = 0, p = s; i < b; i++)
*rr++ = *p++;
if (replstr)
for (p = replstr; *p; )
*rr++ = *p++;
for (i = e, p = s + e; i < l; i++)
*rr++ = *p++;
t = 1;
@ -1879,64 +1905,102 @@ get_match_ret(char *s, int b, int e, int fl)
return r;
}
/* It is called from paramsubst to get the match for ${foo#bar} etc.
* Bits of fl determines the required action:
* bit 0: match the end instead of the beginning (% or %%)
* bit 1: % or # was doubled so get the longest match
* bit 2: substring match
* bit 3: include the matched portion
* bit 4: include the unmatched portion
* bit 5: the index of the beginning
* bit 6: the index of the end
* bit 7: the length of the match
* bit 8: match the complete string
/*
* Run the pattern so that we always get the longest possible match.
* This eliminates a loop where we gradually shorten the target string
* to find same. We also need to check pptr (the point successfully
* reached along the target string) explicitly.
*
* For this to work, we need the full hairy closure code, so
* set inclosure.
*/
/**/
static int
dolongestmatch(char *str, Comp c, int fist)
{
int ret;
longest = 1;
inclosure++;
ret = domatch(str, c, fist);
inclosure--;
longest = 0;
return ret;
}
/*
* This is called from paramsubst to get the match for ${foo#bar} etc.
* fl is a set of the SUB_* flags defined in zsh.h
* *sp points to the string we have to modify. The n'th match will be
* returned in *sp. ncalloc is used to get memory for the result string.
* replstr is the replacement string from a ${.../orig/repl}, in
* which case pat is the original.
*
* n is now ignored unless we are looking for a substring, in
* which case the n'th match from the start is counted such that
* there is no more than one match from each position.
*/
/**/
int
getmatch(char **sp, char *pat, int fl, int n)
getmatch(char **sp, char *pat, int fl, int n, char *replstr)
{
Comp c;
char *s = *sp, *t, sav;
int i, j, l = strlen(*sp);
char *s = *sp, *t, *start, sav;
int i, j, l = strlen(*sp), matched;
MUSTUSEHEAP("getmatch"); /* presumably covered by prefork() test */
repllist = NULL;
c = parsereg(pat);
if (!c) {
zerr("bad pattern: %s", pat, 0);
return 1;
}
if (fl & 256) {
if (fl & SUB_ALL) {
i = domatch(s, c, 0);
*sp = get_match_ret(*sp, 0, domatch(s, c, 0) ? l : 0, fl);
if (! **sp && (((fl & 8) && !i) || ((fl & 16) && i)))
*sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0);
if (! **sp && (((fl & SUB_MATCH) && !i) || ((fl & SUB_REST) && i)))
return 0;
return 1;
}
switch (fl & 7) {
switch (fl & (SUB_END|SUB_LONG|SUB_SUBSTR)) {
case 0:
/* Smallest possible match at head of string: *
* start adding characters until we get a match. */
for (i = 0, t = s; i <= l; i++, t++) {
sav = *t;
*t = '\0';
if (domatch(s, c, 0) && !--n) {
case SUB_LONG:
/*
* Largest/smallest possible match at head of string.
* First get the longest match.
*/
if (dolongestmatch(s, c, 0)) {
char *mpos = pptr;
while (!(fl & SUB_LONG) && pptr > s) {
/*
* If we want the shortest, keep backing up to the
* previous character and find the longest up to there.
* That way we can usually reach the shortest in only
* a few attempts.
*/
t = (pptr > s + 1 && pptr[-2] == Meta) ? pptr - 2 : pptr -1;
sav = *t;
*t = '\0';
if (!dolongestmatch(s, c, 0)) {
*t = sav;
break;
}
mpos = pptr;
*t = sav;
*sp = get_match_ret(*sp, 0, i, fl);
return 1;
}
if ((*t = sav) == Meta)
i++, t++;
*sp = get_match_ret(*sp, 0, mpos-s, fl, replstr);
return 1;
}
break;
case 1:
case SUB_END:
/* Smallest possible match at tail of string: *
* move back down string until we get a match. */
* move back down string until we get a match. *
* There's no optimization here. */
for (t = s + l; t >= s; t--) {
if (domatch(t, c, 0) && !--n) {
*sp = get_match_ret(*sp, t - s, l, fl);
if (domatch(t, c, 0)) {
*sp = get_match_ret(*sp, t - s, l, fl, replstr);
return 1;
}
if (t > s+1 && t[-2] == Meta)
@ -1944,29 +2008,13 @@ getmatch(char **sp, char *pat, int fl, int n)
}
break;
case 2:
/* Largest possible match at head of string: *
* delete characters from end until we get a match. */
for (t = s + l; t > s; t--) {
sav = *t;
*t = '\0';
if (domatch(s, c, 0) && !--n) {
*t = sav;
*sp = get_match_ret(*sp, 0, t - s, fl);
return 1;
}
*t = sav;
if (t >= s+2 && t[-2] == Meta)
t--;
}
break;
case 3:
case (SUB_END|SUB_LONG):
/* Largest possible match at tail of string: *
* move forward along string until we get a match. */
* move forward along string until we get a match. *
* Again there's no optimisation. */
for (i = 0, t = s; i < l; i++, t++) {
if (domatch(t, c, 0) && !--n) {
*sp = get_match_ret(*sp, i, l, fl);
if (domatch(t, c, 0)) {
*sp = get_match_ret(*sp, i, l, fl, replstr);
return 1;
}
if (*t == Meta)
@ -1974,110 +2022,147 @@ getmatch(char **sp, char *pat, int fl, int n)
}
break;
case 4:
case SUB_SUBSTR:
/* Smallest at start, but matching substrings. */
if (domatch(s + l, c, 0) && !--n) {
*sp = get_match_ret(*sp, 0, 0, fl);
if (!(fl & SUB_GLOBAL) && domatch(s + l, c, 0) && !--n) {
*sp = get_match_ret(*sp, 0, 0, fl, replstr);
return 1;
}
for (i = 1; i <= l; i++) {
for (t = s, j = i; j <= l; j++, t++) {
sav = s[j];
s[j] = '\0';
if (domatch(t, c, 0) && !--n) {
s[j] = sav;
*sp = get_match_ret(*sp, t - s, j, fl);
return 1;
} /* fall through */
case (SUB_SUBSTR|SUB_LONG):
/* longest or smallest at start with substrings */
start = s;
if (fl & SUB_GLOBAL)
repllist = newlinklist();
do {
/* loop over all matches for global substitution */
matched = 0;
for (t = start; t < s + l; t++) {
/* Find the longest match from this position. */
if (dolongestmatch(t, c, 0) && pptr > t) {
char *mpos = pptr;
while (!(fl & SUB_LONG) && pptr > t) {
/* Now reduce to find the smallest match */
char *p = (pptr > t + 1 && pptr[-2] == Meta) ?
pptr - 2 : pptr - 1;
sav = *p;
*p = '\0';
if (!dolongestmatch(t, c, 0)) {
*p = sav;
break;
}
mpos = pptr;
*p = sav;
}
if (!--n || (n <= 0 && (fl & SUB_GLOBAL)))
*sp = get_match_ret(*sp, t-s, mpos-s, fl, replstr);
if (!(fl & SUB_GLOBAL)) {
if (n) {
/*
* Looking for a later match: in this case,
* we can continue looking for matches from
* the next character, even if it overlaps
* with what we just found.
*/
continue;
} else
return 1;
}
/*
* For a global match, we need to skip the stuff
* which is already marked for replacement.
*/
matched = 1;
start = mpos;
break;
}
if ((s[j] = sav) == Meta)
j++;
if (*t == Meta)
t++;
}
if (s[i] == Meta)
i++;
}
break;
case 5:
/* Smallest at end, matching substrings */
if (domatch(s + l, c, 0) && !--n) {
*sp = get_match_ret(*sp, l, l, fl);
return 1;
}
for (i = l; i--;) {
if (i && s[i-1] == Meta)
i--;
for (t = s + l, j = i; j >= 0; j--, t--) {
sav = *t;
*t = '\0';
if (domatch(s + j, c, 0) && !--n) {
*t = sav;
*sp = get_match_ret(*sp, j, t - s, fl);
return 1;
}
*t = sav;
if (t >= s+2 && t[-2] == Meta)
t--;
if (j >= 2 && s[j-2] == Meta)
j--;
}
}
break;
case 6:
/* Largest at start, matching substrings. */
for (i = l; i; i--) {
for (t = s, j = i; j <= l; j++, t++) {
sav = s[j];
s[j] = '\0';
if (domatch(t, c, 0) && !--n) {
s[j] = sav;
*sp = get_match_ret(*sp, t - s, j, fl);
return 1;
}
if ((s[j] = sav) == Meta)
j++;
if (*t == Meta)
t++;
}
if (i >= 2 && s[i-2] == Meta)
i--;
}
if (domatch(s + l, c, 0) && !--n) {
*sp = get_match_ret(*sp, 0, 0, fl);
} while (matched);
/*
* check if we can match a blank string, if so do it
* at the start. Goodness knows if this is a good idea
* with global substitution, so it doesn't happen.
*/
if ((fl & (SUB_LONG|SUB_GLOBAL)) == SUB_LONG &&
domatch(s + l, c, 0) && !--n) {
*sp = get_match_ret(*sp, 0, 0, fl, replstr);
return 1;
}
break;
case 7:
/* Largest at end, matching substrings. */
for (i = 0; i < l; i++) {
for (t = s + l, j = i; j >= 0; j--, t--) {
sav = *t;
*t = '\0';
if (domatch(s + j, c, 0) && !--n) {
*t = sav;
*sp = get_match_ret(*sp, j, t - s, fl);
return 1;
}
*t = sav;
if (t >= s+2 && t[-2] == Meta)
t--;
if (j >= 2 && s[j-2] == Meta)
j--;
}
if (s[i] == Meta)
i++;
}
case (SUB_END|SUB_SUBSTR):
/* Shortest at end with substrings */
if (domatch(s + l, c, 0) && !--n) {
*sp = get_match_ret(*sp, l, l, fl);
*sp = get_match_ret(*sp, l, l, fl, replstr);
return 1;
} /* fall through */
case (SUB_END|SUB_LONG|SUB_SUBSTR):
/* Longest/shortest at end, matching substrings. */
for (t = s + l - 1; t >= s; t--) {
if (t > s && t[-1] == Meta)
t--;
if (dolongestmatch(t, c, 0) && pptr > t && !--n) {
/* Found the longest match */
char *mpos = pptr;
while (!(fl & SUB_LONG) && pptr > t) {
/* Look for the shortest match */
char *p = (pptr > t+1 && pptr[-2] == Meta) ?
pptr-2 : pptr-1;
sav = *p;
*p = '\0';
if (!dolongestmatch(t, c, 0) || pptr == t) {
*p = sav;
break;
}
*p = sav;
mpos = pptr;
}
*sp = get_match_ret(*sp, t-s, mpos-s, fl, replstr);
return 1;
}
}
if ((fl & SUB_LONG) && domatch(s + l, c, 0) && !--n) {
*sp = get_match_ret(*sp, l, l, fl, replstr);
return 1;
}
break;
}
/* munge the whole string */
*sp = get_match_ret(*sp, 0, 0, fl);
if (repllist && nonempty(repllist)) {
/* Put all the bits of a global search and replace together. */
LinkNode nd;
Repldata rd;
int rlen;
int lleft = 0; /* size of returned string */
i = 0; /* start of last chunk we got from *sp */
rlen = strlen(replstr);
for (nd = firstnode(repllist); nd; incnode(nd)) {
rd = (Repldata) getdata(nd);
lleft += rd->b - i; /* previous chunk of *sp */
lleft += rlen; /* the replaced bit */
i = rd->e; /* start of next chunk of *sp */
}
lleft += l - i; /* final chunk from *sp */
start = t = halloc(lleft+1);
i = 0;
for (nd = firstnode(repllist); nd; incnode(nd)) {
rd = (Repldata) getdata(nd);
memcpy(t, s + i, rd->b - i);
t += rd->b - i;
memcpy(t, replstr, rlen);
t += rlen;
i = rd->e;
}
memcpy(t, s + i, l - i);
start[lleft] = '\0';
*sp = start;
return 1;
}
/* munge the whole string: no match, so no replstr */
*sp = get_match_ret(*sp, 0, 0, fl, 0);
return 1;
}
@ -2109,9 +2194,15 @@ static int
excluded(Comp c, char *eptr)
{
char *saves = pptr;
int savei = first, ret;
int savei = first, savel = longest, ret;
first = 0;
/*
* Even if we've been told always to match the longest string,
* i.e. not anchored to the end, we want to match the full string
* we've already matched when we're trying to exclude it.
*/
longest = 0;
if (PATHADDP(c) && pathpos) {
VARARR(char, buf, pathpos + strlen(eptr) + 1);
@ -2128,6 +2219,7 @@ excluded(Comp c, char *eptr)
pptr = saves;
first = savei;
longest = savel;
return ret;
}
@ -2138,8 +2230,6 @@ struct gclose {
};
typedef struct gclose *Gclose;
static int inclosure; /* see comment in doesmatch() */
/* Add a list of matches that fit the closure. trystring is a string of
* the same length as the target string; a non-zero in that string
* indicates that we have already tried to match the patterns following
@ -2182,6 +2272,15 @@ addclosures(Comp c, LinkList closlist, int *pdone, char *trystring)
}
}
/*
* Match characters with case-insensitivity.
* Note CHARMATCH(x,y) != CHARMATCH(y,x)
*/
#define CHARMATCH(x, y) \
(x == y || (((c->stat & C_IGNCASE) ? (tulower(x) == tulower(y)) : \
(c->stat & C_LCMATCHUC) ? (islower(y) && tuupper(y) == x) : 0)))
/* see if current string in pptr matches c */
/**/
@ -2219,7 +2318,7 @@ doesmatch(Comp c)
for (; *pptr; pptr++) {
if (*pptr == Meta)
pptr++;
else if (*pptr == looka)
else if (CHARMATCH(*pptr, looka))
break;
}
if (!*(saves = pptr))
@ -2233,7 +2332,7 @@ doesmatch(Comp c)
for (done = 0; ; done++) {
saves = pptr;
if ((done || ONEHASHP(c) || OPTIONALP(c)) &&
((!c->next && (!LASTP(c) || !*pptr)) ||
((!c->next && (!LASTP(c) || !*pptr || longest)) ||
(c->next && doesmatch(c->next))))
return 1;
if (done && OPTIONALP(c))
@ -2267,7 +2366,7 @@ doesmatch(Comp c)
break;
saves = pptr;
/* do we really want this LASTP here?? */
if ((!c->next && (!LASTP(c) || !*pptr)) ||
if ((!c->next && (!LASTP(c) || !*pptr || longest)) ||
(c->next && doesmatch(c->next))) {
retflag = 1;
break;
@ -2453,7 +2552,7 @@ matchonce(Comp c)
if (!ret)
break;
if ((ret = ret2 &&
((!c->next && (!LASTP(c) || !*pptr))
((!c->next && (!LASTP(c) || !*pptr || longest))
|| (c->next && doesmatch(c->next)))) ||
(!c->next && LASTP(c)))
break;
@ -2485,7 +2584,7 @@ matchonce(Comp c)
if (CLOSUREP(c))
return 1;
if (!c->next) /* no more patterns left */
return (!LASTP(c) || !*pptr);
return (!LASTP(c) || !*pptr || longest);
/* optimisation when next pattern is not a closure */
if (!CLOSUREP(c->next)) {
c = c->next;
@ -2589,10 +2688,7 @@ matchonce(Comp c)
}
continue;
}
if (*pptr == *pat ||
(((c->stat & C_IGNCASE) ? (tulower(*pat) == tulower(*pptr)) :
(c->stat & C_LCMATCHUC) ?
(islower(*pat) && tuupper(*pat) == *pptr) : 0))) {
if (CHARMATCH(*pptr, *pat)) {
/* just plain old characters */
pptr++;
pat++;

View file

@ -414,9 +414,10 @@ scanmatchtable(HashTable ht, Comp com, int flags1, int flags2, ScanFunc scanfunc
HashNode hn = st.u.u;
st.u.u = st.u.u->next;
if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2) &&
domatch(hn->nam, com, 0))
domatch(hn->nam, com, 0)) {
scanfunc(hn, scanflags);
match++;
}
}
ht->scan = NULL;

View file

@ -117,7 +117,7 @@ loop(int toplevel, int justonce)
if (he && he->text)
addlinknode(args, he->text);
} LASTALLOC;
doshfunc(prelist, args, 0, 1);
doshfunc("preexec", prelist, args, 0, 1);
freelinklist(args, (FreeFunc) NULL);
errflag = 0;
}
@ -592,6 +592,9 @@ setupvals(void)
createnameddirtable(); /* create hash table for named directories */
createparamtable(); /* create paramater hash table */
condtab = NULL;
wrappers = NULL;
#ifdef TIOCGWINSZ
adjustwinsize();
#else

View file

@ -244,7 +244,7 @@ halloc(size_t size)
size = (size + H_ISIZE - 1) & ~(H_ISIZE - 1);
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
h_m[size < 1024 ? (size / H_ISIZE) : 1024]++;
h_m[size < (1024 * H_ISIZE) ? (size / H_ISIZE) : 1024]++;
#endif
/* find a heap with enough free space */
@ -319,6 +319,9 @@ hrealloc(char *p, size_t old, size_t new)
if (new > old) {
char *ptr = (char *) halloc(new);
memcpy(ptr, p, old);
#ifdef ZSH_MEM_DEBUG
memset(p, 0xff, old);
#endif
return ptr;
} else
return new ? p : NULL;
@ -1004,8 +1007,9 @@ zfree(void *p, int sz)
long n = (m_lfree->len - M_MIN) & ~(m_pgsz - 1);
m_lfree->len -= n;
if (brk(m_high -= n) == -1)
if (brk(m_high -= n) == -1) {
DPUTS(1, "MEM: allocation error at brk.");
}
#ifdef ZSH_MEM_DEBUG
m_b += n;

View file

@ -90,6 +90,35 @@ addbuiltins(char const *nam, Builtin binl, int size)
return hadf ? hads : 1;
}
/* The list of function wrappers defined. */
/**/
FuncWrap wrappers;
/* This adds a definition for a wrapper. Return value is one in case of *
* error and zero if all went fine. */
/**/
int
addwrapper(Module m, FuncWrap w)
{
FuncWrap p, q;
if (w->flags & WRAPF_ADDED)
return 1;
for (p = wrappers, q = NULL; p; q = p, p = p->next);
if (q)
q->next = w;
else
wrappers = w;
w->next = NULL;
w->flags |= WRAPF_ADDED;
w->module = m;
w->count = 0;
return 0;
}
#ifdef DYNAMIC
/* $module_path ($MODULE_PATH) */
@ -161,6 +190,31 @@ deletebuiltins(char const *nam, Builtin binl, int size)
return hadf ? hads : 1;
}
/* This removes the given wrapper definition from the list. Returned is *
* one in case of error and zero otherwise. */
/**/
int
deletewrapper(Module m, FuncWrap w)
{
FuncWrap p, q;
if (w->flags & WRAPF_ADDED) {
for (p = wrappers, q = NULL; p && p != w; q = p, p = p->next);
if (p) {
if (q)
q->next = p->next;
else
wrappers = p->next;
p->flags &= ~WRAPF_ADDED;
return 0;
}
}
return 1;
}
#ifdef AIXDYNAMIC
#include <sys/ldr.h>
@ -498,6 +552,8 @@ bin_zmodload(char *nam, char **args, char *ops, int func)
return bin_zmodload_dep(nam, args, ops);
else if(ops['a'])
return bin_zmodload_auto(nam, args, ops);
else if (ops['c'] || ops['C'])
return bin_zmodload_cond(nam, args, ops);
else
return bin_zmodload_load(nam, args, ops);
}
@ -630,6 +686,98 @@ bin_zmodload_auto(char *nam, char **args, char *ops)
}
}
/**/
static int
bin_zmodload_cond(char *nam, char **args, char *ops)
{
int ret = 0;
if (ops['u']) {
/* remove autoloaded conditions */
for (; *args; args++) {
Conddef cd = getconddef(ops['I'], *args, 0);
if (!cd) {
if (!ops['i']) {
zwarnnam(nam, "%s: no such condition", *args, 0);
ret = 1;
}
} else if (cd->flags & CONDF_ADDED) {
zwarnnam(nam, "%s: condition is already defined", *args, 0);
ret = 1;
} else
deleteconddef(cd);
}
return ret;
} else if (!*args) {
/* list autoloaded conditions */
Conddef p;
for (p = condtab; p; p = p->next) {
if (p->module) {
if (ops['L']) {
fputs("zmodload -c", stdout);
if (p->flags & CONDF_INFIX)
putchar('I');
printf(" %s %s\n", p->module, p->name);
} else {
fputs("post ", stdout);
if (p->flags & CONDF_INFIX)
fputs("infix ", stdout);
printf("%s (%s)\n",p->name, p->module);
}
}
}
return 0;
} else {
/* add autoloaded conditions */
char *modnam;
modnam = *args++;
if(isset(RESTRICTED) && strchr(modnam, '/')) {
zwarnnam(nam, "%s: restricted", modnam, 0);
return 1;
}
do {
char *cnam = *args ? *args++ : modnam;
if (strchr(cnam, '/')) {
zwarnnam(nam, "%s: `/' is illegal in a condition", cnam, 0);
ret = 1;
} else if (add_autocond(cnam, ops['I'], modnam) && !ops['i']) {
zwarnnam(nam, "failed to add condition %s", cnam, 0);
ret = 1;
}
} while(*args);
return ret;
}
}
/**/
int
unload_module(Module m, LinkNode node)
{
if (m->handle && cleanup_module(m))
return 1;
else {
if (m->handle)
dlclose(m->handle);
m->handle = NULL;
if(!m->deps) {
if (!node) {
for (node = firstnode(modules); node; incnode(node))
if (m == (Module) getdata(node))
break;
if (!node)
return 1;
}
remnode(modules, node);
zsfree(m->nam);
zfree(m, sizeof(*m));
}
}
return 0;
}
/**/
static int
bin_zmodload_load(char *nam, char **args, char *ops)
@ -654,20 +802,13 @@ bin_zmodload_load(char *nam, char **args, char *ops)
goto cont;
}
}
m = (Module) getdata(node);
if (m->handle && cleanup_module(m))
ret = 1;
else {
if (m->handle)
dlclose(m->handle);
m->handle = NULL;
if(!m->deps) {
remnode(modules, node);
zsfree(m->nam);
zfree(m, sizeof(*m));
}
if (!(m->flags & MOD_WRAPPER)) {
if (unload_module(m, node))
ret = 1;
}
else
m->flags |= MOD_UNLOAD;
} else if (!ops['i']) {
zwarnnam(nam, "no such module %s", *args, 0);
ret = 1;
@ -711,3 +852,166 @@ bin_zmodload_load(char *nam, char **args, char *ops)
}
#endif /* DYNAMIC */
/* The list of module-defined conditions. */
/**/
Conddef condtab;
/* This gets a condition definition with the given name. The first *
* argument says if we have to look for an infix condition. The last *
* argument is non-zero if we should autoload modules if needed. */
/**/
Conddef
getconddef(int inf, char *name, int autol)
{
Conddef p;
#ifdef DYNAMIC
int f = 1;
#endif
do {
for (p = condtab; p; p = p->next) {
if ((!!inf == !!(p->flags & CONDF_INFIX)) &&
!strcmp(name, p->name))
break;
}
#ifdef DYNAMIC
if (autol && p && p->module) {
/* This is a definition for an autoloaded condition, load the *
* module if we haven't tried that already. */
if (f) {
load_module(p->module);
f = 0;
p = NULL;
} else
break;
} else
#endif
break;
} while (!p);
return p;
}
#ifdef DYNAMIC
/* This adds the given condition definition. The return value is zero on *
* success and 1 on failure. If there is a matching definition for an *
* autoloaded condition, it is removed. */
/**/
int
addconddef(Conddef c)
{
Conddef p = getconddef((c->flags & CONDF_INFIX), c->name, 0);
if (p) {
if (!p->module || (p->flags & CONDF_ADDED))
return 1;
/* There is an autoload definition. */
deleteconddef(p);
}
c->next = condtab;
condtab = c;
return 0;
}
/* This adds multiple condition definitions. This is like addbuiltins(). */
/**/
int
addconddefs(char const *nam, Conddef c, int size)
{
int hads = 0, hadf = 0;
while (size--) {
if (c->flags & CONDF_ADDED)
continue;
if (addconddef(c)) {
zwarnnam(nam, "name clash when adding condition `%s'", c->name, 0);
hadf = 1;
} else {
c->flags |= CONDF_ADDED;
hads = 2;
}
c++;
}
return hadf ? hads : 1;
}
/* This adds a definition for autoloading a module for a condition. */
/**/
int
add_autocond(char *nam, int inf, char *module)
{
Conddef c = zalloc(sizeof(*c));
c->name = ztrdup(nam);
c->flags = (inf ? CONDF_INFIX : 0);
c->module = ztrdup(module);
if (addconddef(c)) {
zsfree(c->name);
zsfree(c->module);
zfree(c, sizeof(*c));
return 1;
}
return 0;
}
/* This removes the given condition definition from the list(s). If this *
* is a definition for a autoloaded condition, the memory is freed. */
/**/
int
deleteconddef(Conddef c)
{
Conddef p, q;
for (p = condtab, q = NULL; p && p != c; q = p, p = p->next);
if (p) {
if (q)
q->next = p->next;
else
condtab = p->next;
if (p->module) {
/* autoloaded, free it */
zsfree(p->name);
zsfree(p->module);
zfree(p, sizeof(*p));
}
return 0;
}
return -1;
}
/* This removes multiple condition definitions (like deletebuiltins()). */
/**/
int
deleteconddefs(char const *nam, Conddef c, int size)
{
int hads = 0, hadf = 0;
while (size--) {
if (!(c->flags & CONDF_ADDED))
continue;
if (deleteconddef(c)) {
zwarnnam(nam, "condition `%s' already deleted", c->name, 0);
hadf = 1;
} else
hads = 2;
c->flags &= ~CONDF_ADDED;
c++;
}
return hadf ? hads : 1;
}
#endif /* DYNAMIC */

View file

@ -303,7 +303,11 @@ copyparamtable(HashTable ht, char *name)
#define SCANPM_WANTVALS (1<<0)
#define SCANPM_WANTKEYS (1<<1)
#define SCANPM_WANTINDEX (1<<2)
#define SCANPM_WANTINDEX (1<<2) /* Useful only if nested arrays */
#define SCANPM_MATCHKEY (1<<3)
#define SCANPM_MATCHVAL (1<<4)
#define SCANPM_MATCHMANY (1<<5)
#define SCANPM_ISVAR_AT ((-1)<<15) /* Only sign bit is significant */
static unsigned numparamvals;
@ -311,13 +315,12 @@ static unsigned numparamvals;
static void
scancountparams(HashNode hn, int flags)
{
if (!(((Param)hn)->flags & PM_UNSET)) {
++numparamvals;
if ((flags & SCANPM_WANTKEYS) && (flags & SCANPM_WANTVALS))
++numparamvals;
if ((flags & SCANPM_WANTKEYS) && (flags & SCANPM_WANTVALS))
++numparamvals;
}
}
static Comp scancomp;
static char **paramvals;
/**/
@ -325,33 +328,45 @@ static void
scanparamvals(HashNode hn, int flags)
{
struct value v;
if (numparamvals && (flags & (SCANPM_MATCHVAL|SCANPM_MATCHKEY)) &&
!(flags & SCANPM_MATCHMANY))
return;
v.pm = (Param)hn;
if (!(v.pm->flags & PM_UNSET)) {
if (flags & SCANPM_WANTKEYS) {
paramvals[numparamvals++] = v.pm->nam;
if (!(flags & SCANPM_WANTVALS))
return;
}
v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED));
v.inv = (flags & SCANPM_WANTINDEX);
v.a = 0;
v.b = -1;
paramvals[numparamvals++] = getstrvalue(&v);
if ((flags & SCANPM_MATCHKEY) && !domatch(v.pm->nam, scancomp, 0)) {
return;
}
if (flags & SCANPM_WANTKEYS) {
paramvals[numparamvals++] = v.pm->nam;
if (!(flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)))
return;
}
v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED));
v.inv = 0;
v.a = 0;
v.b = -1;
paramvals[numparamvals] = getstrvalue(&v);
if (flags & SCANPM_MATCHVAL) {
if (domatch(paramvals[numparamvals], scancomp, 0)) {
numparamvals += ((flags & SCANPM_WANTVALS) ? 1 :
!(flags & SCANPM_WANTKEYS));
} else if (flags & SCANPM_WANTKEYS)
--numparamvals; /* Value didn't match, discard key */
} else
++numparamvals;
}
/**/
char **
paramvalarr(HashTable ht, unsigned flags)
paramvalarr(HashTable ht, int flags)
{
MUSTUSEHEAP("paramvalarr");
numparamvals = 0;
if (ht)
scanhashtable(ht, 0, 0, 0, scancountparams, flags);
scanhashtable(ht, 0, 0, PM_UNSET, scancountparams, flags);
paramvals = (char **) alloc((numparamvals + 1) * sizeof(char *));
if (ht) {
numparamvals = 0;
scanhashtable(ht, 0, 0, 0, scanparamvals, flags);
scanhashtable(ht, 0, 0, PM_UNSET, scanparamvals, flags);
}
paramvals[numparamvals] = 0;
return paramvals;
@ -369,15 +384,10 @@ getvaluearr(Value v)
else if (PM_TYPE(v->pm->flags) == PM_ARRAY)
return v->arr = v->pm->gets.afn(v->pm);
else if (PM_TYPE(v->pm->flags) == PM_HASHED) {
unsigned flags = 0;
if (v->a)
flags |= SCANPM_WANTKEYS;
if (v->b > v->a)
flags |= SCANPM_WANTVALS;
v->arr = paramvalarr(v->pm->gets.hfn(v->pm), flags);
v->arr = paramvalarr(v->pm->gets.hfn(v->pm), v->isarr);
/* Can't take numeric slices of associative arrays */
v->a = 0;
v->b = -1;
v->b = numparamvals;
return v->arr;
} else
return NULL;
@ -737,7 +747,19 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
down = !down;
num = -num;
}
*inv = ind;
if (v->isarr & SCANPM_WANTKEYS)
*inv = (ind || !(v->isarr & SCANPM_WANTVALS));
else if (v->isarr & SCANPM_WANTVALS)
*inv = 0;
else {
if (ind) {
v->isarr |= SCANPM_WANTKEYS;
v->isarr &= ~SCANPM_WANTVALS;
}
if (!down)
v->isarr &= ~SCANPM_MATCHMANY;
*inv = ind;
}
for (t=s, i=0; *t && ((*t != ']' && *t != Outbrack && *t != ',') || i); t++)
if (*t == '[' || *t == Inbrack)
@ -829,7 +851,21 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
if ((c = parsereg(s))) {
if (v->isarr) {
ta = getarrvalue(v);
if (PM_TYPE(v->pm->flags) == PM_HASHED) {
scancomp = c;
if (ind)
v->isarr |= SCANPM_MATCHKEY;
else
v->isarr |= SCANPM_MATCHVAL;
if (down)
v->isarr |= SCANPM_MATCHMANY;
if ((ta = getvaluearr(v)) && *ta) {
*inv = v->inv;
*w = v->b;
return 1;
}
} else
ta = getarrvalue(v);
if (!ta || !*ta)
return 0;
if (down)
@ -920,8 +956,8 @@ getindex(char **pptr, Value v)
if (*tbrack == Outbrack)
*tbrack = ']';
if ((s[0] == '*' || s[0] == '@') && s[1] == ']') {
if (v->isarr)
v->isarr = (s[0] == '*') ? 1 : -1;
if (v->isarr && s[0] == '@')
v->isarr |= SCANPM_ISVAR_AT;
v->a = 0;
v->b = -1;
s += 2;
@ -941,7 +977,7 @@ getindex(char **pptr, Value v)
} else
a = -ztrlen(t + a + strlen(t));
}
if (a > 0 && isset(KSHARRAYS))
if (a > 0 && (isset(KSHARRAYS) || (v->pm->flags & PM_HASHED)))
a--;
v->inv = 1;
v->isarr = 0;
@ -984,6 +1020,13 @@ getindex(char **pptr, Value v)
/**/
Value
getvalue(char **pptr, int bracks)
{
return fetchvalue(pptr, bracks, 0);
}
/**/
Value
fetchvalue(char **pptr, int bracks, int flags)
{
char *s, *t;
char sav;
@ -1039,8 +1082,16 @@ getvalue(char **pptr, int bracks)
if (!pm || (pm->flags & PM_UNSET))
return NULL;
v = (Value) hcalloc(sizeof *v);
if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))
v->isarr = isvarat ? -1 : 1;
if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)) {
/* Overload v->isarr as the flag bits for hashed arrays. */
v->isarr = flags | (isvarat ? SCANPM_ISVAR_AT : 0);
/* If no flags were passed, we need something to represent *
* `true' yet differ from an explicit WANTVALS. This is a *
* bit of a hack, but makes some sense: When no subscript *
* is provided, all values are substituted. */
if (!v->isarr)
v->isarr = SCANPM_MATCHMANY;
}
v->pm = pm;
v->inv = 0;
v->a = 0;
@ -1079,7 +1130,7 @@ getstrvalue(Value v)
if (!v)
return hcalloc(1);
HEAPALLOC {
if (v->inv) {
if (v->inv && !(v->pm->flags & PM_HASHED)) {
sprintf(buf, "%d", v->a);
s = dupstring(buf);
LASTALLOC_RETURN s;
@ -1087,6 +1138,13 @@ getstrvalue(Value v)
switch(PM_TYPE(v->pm->flags)) {
case PM_HASHED:
/* (!v->isarr) should be impossible unless emulating ksh */
if (!v->isarr && emulation == EMULATE_KSH) {
s = dupstring("[0]");
if (getindex(&s, v) == 0)
s = getstrvalue(v);
LASTALLOC_RETURN s;
} /* else fall through */
case PM_ARRAY:
ss = getvaluearr(v);
if (v->isarr)
@ -1486,6 +1544,39 @@ setaparam(char *s, char **val)
return v->pm;
}
/**/
Param
sethparam(char *s, char **kvarr)
{
Value v;
Param pm;
char *t;
if (!isident(s)) {
zerr("not an identifier: %s", s, 0);
freearray(kvarr);
errflag = 1;
return NULL;
}
t=ztrdup(s); /* Is this a memory leak? */
/* Why does getvalue(s, 1) set s to empty string? */
if ((v = getvalue(&t, 1)))
if (v->pm->flags & PM_SPECIAL) {
zerr("not overriding a special: %s", s, 0);
freearray(kvarr);
errflag = 1;
return NULL;
} else
unsetparam(s);
pm = createparam(s, PM_HASHED);
DPUTS(!pm, "BUG: parameter not created");
arrhashsetfn(pm, kvarr);
return pm;
}
/**/
Param
setiparam(char *s, long val)
@ -2538,24 +2629,28 @@ printparamnode(HashNode hn, int printflags)
return;
}
quotedzputs(p->nam, stdout);
if (printflags & PRINT_KV_PAIR)
putchar(' ');
else
putchar('=');
/* How the value is displayed depends *
* on the type of the parameter */
quotedzputs(p->nam, stdout);
putchar('=');
switch (PM_TYPE(p->flags)) {
case PM_SCALAR:
/* string: simple output */
if (p->gets.cfn && (t = p->gets.cfn(p)))
quotedzputs(t, stdout);
putchar('\n');
break;
case PM_INTEGER:
/* integer */
printf("%ld\n", p->gets.ifn(p));
printf("%ld", p->gets.ifn(p));
break;
case PM_ARRAY:
/* array */
putchar('(');
if (!(printflags & PRINT_KV_PAIR))
putchar('(');
u = p->gets.afn(p);
if(*u) {
quotedzputs(*u++, stdout);
@ -2564,17 +2659,25 @@ printparamnode(HashNode hn, int printflags)
quotedzputs(*u++, stdout);
}
}
printf(")\n");
if (!(printflags & PRINT_KV_PAIR))
putchar(')');
break;
case PM_HASHED:
/* association */
putchar('(');
if (!(printflags & PRINT_KV_PAIR))
putchar('(');
{
HashTable ht = p->gets.hfn(p);
if (ht)
scanhashtable(ht, 0, 0, 0, ht->printnode, 0);
scanhashtable(ht, 0, 0, PM_UNSET,
ht->printnode, PRINT_KV_PAIR);
}
printf(")\n");
if (!(printflags & PRINT_KV_PAIR))
putchar(')');
break;
}
if (printflags & PRINT_KV_PAIR)
putchar(' ');
else
putchar('\n');
}

View file

@ -114,7 +114,7 @@ par_event(void)
}
if (tok == ENDINPUT)
return NULL;
if ((sl = par_sublist()))
if ((sl = par_sublist())) {
if (tok == ENDINPUT) {
l = (List) make_list();
l->type = Z_SYNC;
@ -137,6 +137,7 @@ par_event(void)
yylex();
} else
l = NULL;
}
if (!l) {
if (errflag) {
yyerror();
@ -181,7 +182,7 @@ par_list(void)
while (tok == SEPER)
yylex();
if ((sl = par_sublist()))
if ((sl = par_sublist())) {
if (tok == SEPER || tok == AMPER || tok == AMPERBANG) {
l = (List) make_list();
l->left = sl;
@ -197,6 +198,7 @@ par_list(void)
l->left = sl;
l->type = Z_SYNC;
}
}
return l;
}
@ -1139,13 +1141,14 @@ par_cond_2(void)
condlex();
return c;
}
if (tok != STRING)
if (tok != STRING) {
if (tok && tok != LEXERR && condlex == testlex) {
s1 = tokstr;
condlex();
return par_cond_double("-n", s1);
} else
YYERROR;
}
s1 = tokstr;
if (condlex == testlex)
dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1
@ -1165,7 +1168,7 @@ par_cond_2(void)
c->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0);
return c;
}
if (tok != STRING)
if (tok != STRING) {
if (tok != LEXERR && condlex == testlex) {
if (!dble)
return par_cond_double("-n", s1);
@ -1173,6 +1176,7 @@ par_cond_2(void)
return par_cond_double(s1, "1");
} else
YYERROR;
}
s2 = tokstr;
incond++; /* parentheses do globbing */
condlex();
@ -1180,7 +1184,19 @@ par_cond_2(void)
if (tok == STRING && !dble) {
s3 = tokstr;
condlex();
return par_cond_triple(s1, s2, s3);
if (tok == STRING) {
LinkList l = newlinklist();
addlinknode(l, s2);
addlinknode(l, s3);
while (tok == STRING) {
addlinknode(l, tokstr);
condlex();
}
return par_cond_multi(s1, l);
} else
return par_cond_triple(s1, s2, s3);
} else
return par_cond_double(s1, s2);
}
@ -1312,11 +1328,22 @@ par_cond_double(char *a, char *b)
{
Cond n = (Cond) make_cond();
if (a[0] != '-' || !a[1] || a[2])
COND_ERROR("parse error: condition expected: %s", a);
n->left = (void *) b;
n->type = a[1];
n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0);
n->left = (void *) b;
if (a[0] != '-' || !a[1])
COND_ERROR("parse error: condition expected: %s", a);
else if (!a[2] && strspn(a+1, "abcdefgknoprstuwxzhLONGS") == 1)
n->type = a[1];
else {
char *d[2];
n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0);
n->type = COND_MOD;
n->left = (void *) (a + 1);
d[0] = b;
d[1] = NULL;
n->right = (void *) arrdup(d);
}
return n;
}
@ -1343,6 +1370,9 @@ par_cond_triple(char *a, char *b, char *c)
Cond n = (Cond) make_cond();
int t0;
n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0);
n->left = (void *) a;
n->right = (void *) c;
if ((b[0] == Equals || b[0] == '=') &&
(!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2])))
n->type = COND_STREQ;
@ -1351,13 +1381,46 @@ par_cond_triple(char *a, char *b, char *c)
else if (b[0] == '-') {
if ((t0 = get_cond_num(b + 1)) > -1)
n->type = t0 + COND_NT;
else
COND_ERROR("unrecognized condition: %s", b);
else {
char *d[3];
n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0);
n->type = COND_MODI;
n->left = (void *) (b + 1);
d[0] = a;
d[1] = c;
d[2] = NULL;
n->right = (void *) arrdup(d);
}
} else if (a[0] == '-' && a[1]) {
char *d[3];
n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0);
n->type = COND_MOD;
n->left = (void *) (a + 1);
d[0] = b;
d[1] = c;
d[2] = NULL;
n->right = (void *) arrdup(d);
} else
COND_ERROR("condition expected: %s", b);
n->left = (void *) a;
n->right = (void *) c;
n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0);
return n;
}
/**/
static Cond
par_cond_multi(char *a, LinkList l)
{
Cond n = (Cond) make_cond();
n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0);
if (a[0] != '-' || !a[1])
COND_ERROR("condition expected: %s", a);
else {
n->type = COND_MOD;
n->left = (void *) a;
n->right = (void *) listarr(l);
}
return n;
}

View file

@ -712,7 +712,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
addlinknode(args, num);
} LASTALLOC;
trapreturn = -1;
doshfunc(sigfn, args, 0, 1);
doshfunc(name, sigfn, args, 0, 1);
freelinklist(args, (FreeFunc) NULL);
zsfree(name);
} else HEAPALLOC {

View file

@ -99,7 +99,7 @@ stringsubst(LinkList list, LinkNode node, int ssub)
char *str = str3;
while (!errflag && *str) {
if ((qt = *str == Qstring) || *str == String)
if ((qt = *str == Qstring) || *str == String) {
if (str[1] == Inpar) {
str++;
goto comsub;
@ -125,7 +125,7 @@ stringsubst(LinkList list, LinkNode node, int ssub)
str3 = (char *)getdata(node);
continue;
}
else if ((qt = *str == Qtick) || *str == Tick)
} else if ((qt = *str == Qtick) || *str == Tick)
comsub: {
LinkList pl;
char *s, *str2 = str;
@ -135,8 +135,12 @@ stringsubst(LinkList list, LinkNode node, int ssub)
if (*str == Inpar) {
endchar = Outpar;
str[-1] = '\0';
#ifdef DEBUG
if (skipparens(Inpar, Outpar, &str))
DPUTS(1, "BUG: parse error in command substitution");
dputs("BUG: parse error in command substitution");
#else
skipparens(Inpar, Outpar, &str);
#endif
str--;
} else {
endchar = *str;
@ -298,7 +302,7 @@ filesub(char **namptr, int assign)
if (!assign)
return;
if (assign < 3)
if (assign < 3) {
if ((*namptr)[1] && (sub = strchr(*namptr + 1, Equals))) {
if (assign == 1)
for (ptr = *namptr; ptr != sub; ptr++)
@ -311,6 +315,7 @@ filesub(char **namptr, int assign)
}
} else
return;
}
ptr = *namptr;
while ((sub = strchr(ptr, ':'))) {
@ -691,7 +696,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
char *aptr = *str;
char *s = aptr, *fstr, *idbeg, *idend, *ostr = (char *) getdata(n);
int colf; /* != 0 means we found a colon after the name */
int doub = 0; /* != 0 means we have %%, not %, or ##, not # */
int isarr = 0;
int plan9 = isset(RCEXPANDPARAM);
int globsubst = isset(GLOBSUBST);
@ -705,11 +709,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
Value v;
int flags = 0;
int flnum = 0;
int substr = 0;
int sortit = 0, casind = 0;
int casmod = 0;
char *sep = NULL, *spsep = NULL;
char *premul = NULL, *postmul = NULL, *preone = NULL, *postone = NULL;
char *replstr = NULL; /* replacement string for /orig/repl */
long prenum = 0, postnum = 0;
int copied = 0;
int arrasg = 0;
@ -717,7 +721,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
int nojoin = 0;
char inbrace = 0; /* != 0 means ${...}, otherwise $... */
char hkeys = 0; /* 1 means get keys from associative array */
char hvals = 1; /* > hkeys get values of associative array */
char hvals = 0; /* > hkeys get values of associative array */
*s++ = '\0';
if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
@ -764,22 +768,22 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
nojoin = 1;
break;
case 'M':
flags |= 8;
flags |= SUB_MATCH;
break;
case 'R':
flags |= 16;
flags |= SUB_REST;
break;
case 'B':
flags |= 32;
flags |= SUB_BIND;
break;
case 'E':
flags |= 64;
flags |= SUB_EIND;
break;
case 'N':
flags |= 128;
flags |= SUB_LEN;
break;
case 'S':
substr = 1;
flags |= SUB_SUBSTR;
break;
case 'I':
flnum = get_intarg(&s);
@ -940,7 +944,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
s++;
} else
globsubst = 1;
} else if (*s == '+')
} else if (*s == '+') {
if (iident(s[1]))
chkset = 1, s++;
else if (!inbrace) {
@ -951,7 +955,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
zerr("bad substitution", NULL, 0);
return NULL;
}
else
} else
break;
}
globsubst = globsubst && !qt;
@ -974,8 +978,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
copied = 1;
*s = sav;
v = (Value) NULL;
} else if (!(v = getvalue(&s, (unset(KSHARRAYS) || inbrace) ? 1 : -1)))
vunset = 1;
} else {
/* 2 == SCANPM_WANTKEYS, 1 == SCANPM_WANTVALS, see params.c */
if (!(v = fetchvalue(&s, (unset(KSHARRAYS) || inbrace) ? 1 : -1,
(hkeys ? 2 : 0) + ((hvals > hkeys) ? 1 : 0))))
vunset = 1;
}
while (v || ((inbrace || (unset(KSHARRAYS) && vunset)) && isbrack(*s))) {
if (!v) {
Param pm;
@ -1000,13 +1008,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
break;
}
if ((isarr = v->isarr)) {
/* No way to reach here with v->inv != 0, so getvaluearr() *
* will definitely be called by getarrvalue(). Slicing of *
* associations isn't done, so use v->a and v->b for flags */
if (PM_TYPE(v->pm->flags) == PM_HASHED) {
v->a = hkeys;
v->b = hvals;
}
/* No way to get here with v->inv != 0, so getvaluearr() *
* is called by getarrvalue(); needn't test PM_HASHED. */
aval = getarrvalue(v);
} else {
if (v->pm->flags & PM_ARRAY) {
@ -1124,23 +1127,72 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
*s == '=' || *s == Equals ||
*s == '%' ||
*s == '#' || *s == Pound ||
*s == '?' || *s == Quest)) {
*s == '?' || *s == Quest ||
*s == '/')) {
if (!flnum)
flnum++;
if (*s == '%')
flags |= 1;
flags |= SUB_END;
/* Check for ${..%%..} or ${..##..} */
if ((*s == '%' || *s == '#' || *s == Pound) && *s == s[1]) {
s++;
doub = 1;
/* we have %%, not %, or ##, not # */
flags |= SUB_LONG;
}
s++;
if (s[-1] == '/') {
char *ptr;
/*
* previous flags are irrelevant, except for (S) which
* indicates shortest substring; else look for longest.
*/
flags = (flags & SUB_SUBSTR) ? 0 : SUB_LONG;
if (*s == '/') {
/* doubled, so replace all occurrences */
flags |= SUB_GLOBAL;
s++;
}
/* Check for anchored substitution */
if (*s == '%') {
/* anchor at tail */
flags |= SUB_END;
s++;
} else if (*s == '#' || *s == Pound) {
/* anchor at head: this is the `normal' case in getmatch */
s++;
} else
flags |= SUB_SUBSTR;
/*
* Find the / marking the end of the search pattern.
* If there isn't one, we're just going to delete that,
* i.e. replace it with an empty string.
*
* This allows quotation of the slash with '\\/'. Why
* two? Well, for a non-quoted string we can check for
* Bnull+/, which is what you get from `\/', but inside
* double quotes the Bnull isn't there, so it's not
* consistent.
*/
for (ptr = s; *ptr && *ptr != '/'; ptr++)
if (*ptr == '\\' && ptr[1] == '/')
chuck(ptr);
replstr = (*ptr && ptr[1]) ? ptr+1 : "";
singsub(&replstr);
untokenize(replstr);
*ptr = '\0';
}
flags |= (doub << 1) | (substr << 2) | (colf << 8);
if (!(flags & 0xf8))
flags |= 16;
if (colf)
flags |= SUB_ALL;
/*
* With no special flags, i.e. just a # or % or whatever,
* the matched portion is removed and we keep the rest.
* We also want the rest when we're doing a substitution.
*/
if (!(flags & (SUB_MATCH|SUB_REST|SUB_BIND|SUB_EIND|SUB_LEN)))
flags |= SUB_REST;
if (colf && !vunset)
vunset = (isarr) ? !*aval : !*val || (*val == Nularg && !val[1]);
@ -1234,6 +1286,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
case '%':
case '#':
case Pound:
case '/':
if (qt)
if (parse_subst_string(s)) {
zerr("parse error in ${...%c...} substitution",
@ -1247,14 +1300,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
char **pp = aval = (char **)ncalloc(sizeof(char *) * (arrlen(aval) + 1));
while ((*pp = *ap++)) {
if (getmatch(pp, s, flags, flnum))
if (getmatch(pp, s, flags, flnum, replstr))
pp++;
}
copied = 1;
} else {
if (vunset)
val = dupstring("");
getmatch(&val, s, flags, flnum);
getmatch(&val, s, flags, flnum, replstr);
copied = 1;
}
break;

View file

@ -410,6 +410,27 @@ getcond(Cond nm, int addpar)
taddstr(" || ");
getcond(nm->right, _Cond(nm->right)->type == COND_AND);
break;
case COND_MOD:
{
/* Module defined prefix condition. */
char **p = (char **) nm->right;
taddstr("-");
taddstr(nm->left);
for (; *p; p++) {
taddstr(" ");
taddstr(*p);
}
}
break;
case COND_MODI:
/* Module defined infix condition. */
taddstr(((char **) nm->right)[0]);
taddstr(" -");
taddstr(nm->left);
taddstr(" ");
taddstr(((char **) nm->right)[1]);
break;
default:
if (nm->type <= COND_GE) {
/* Binary test: `a = b' etc. */

View file

@ -634,7 +634,7 @@ preprompt(void)
/* If a shell function named "precmd" exists, *
* then execute it. */
if ((list = getshfunc("precmd")) != &dummy_list)
doshfunc(list, NULL, 0, 1);
doshfunc("precmd", list, NULL, 0, 1);
if (errflag)
return;
@ -643,7 +643,7 @@ preprompt(void)
* executed "periodic", then execute it now. */
if (period && (time(NULL) > lastperiodic + period) &&
(list = getshfunc("periodic")) != &dummy_list) {
doshfunc(list, NULL, 0, 1);
doshfunc("periodic", list, NULL, 0, 1);
lastperiodic = time(NULL);
}
if (errflag)
@ -732,7 +732,7 @@ checkmailpath(char **s)
}
} else {
if (st.st_size && st.st_atime <= st.st_mtime &&
st.st_mtime > lastmailcheck)
st.st_mtime > lastmailcheck) {
if (!u) {
fprintf(shout, "You have new mail.\n");
fflush(shout);
@ -751,6 +751,7 @@ checkmailpath(char **s)
underscore = usav;
} LASTALLOC;
}
}
if (isset(MAILWARNING) && st.st_atime > st.st_mtime &&
st.st_atime > lastmailcheck && st.st_size) {
fprintf(shout, "The mail in %s has been read.\n", unmeta(*s));
@ -1066,14 +1067,14 @@ zstrtol(const char *s, char **t, int base)
else if (*s == '+')
s++;
if (!base)
if (!base) {
if (*s != '0')
base = 10;
else if (*++s == 'x' || *s == 'X')
base = 16, s++;
else
base = 8;
}
if (base <= 10)
for (; *s >= '0' && *s < ('0' + base); s++)
ret = ret * base + *s - '0';
@ -2137,22 +2138,24 @@ dupstruct2(void *a)
n = dupstring(on);
break;
case NT_LIST | NT_NODE:
if (heap)
if (heap) {
if (useheap)
n = duplist(on, (VFunc) dupstruct2);
else
n = list2arr(on, (VFunc) dupstruct2);
}
else if (useheap)
n = arr2list(on, (VFunc) dupstruct2);
else
n = duparray(on, (VFunc) dupstruct2);
break;
case NT_LIST | NT_STR:
if (heap)
if (heap) {
if (useheap)
n = duplist(on, (VFunc) dupstring);
else
n = list2arr(on, (VFunc) ztrdup);
}
else if (useheap)
n = arr2list(on, (VFunc) dupstring);
else
@ -2378,11 +2381,12 @@ inittyptab(void)
for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Nularg); t0++)
typtab[t0] |= ITOK | IMETA;
for (s = ifs ? ifs : DEFAULT_IFS; *s; s++) {
if (inblank(*s))
if (inblank(*s)) {
if (s[1] == *s)
s++;
else
typtab[STOUC(*s)] |= IWSEP;
}
typtab[STOUC(*s == Meta ? *++s ^ 32 : *s)] |= ISEP;
}
for (s = wordchars ? wordchars : DEFAULT_WORDCHARS; *s; s++)
@ -2405,6 +2409,21 @@ arrdup(char **s)
return y;
}
/**/
char **
listarr(LinkList l)
{
char **x, **y;
LinkNode n;
x = y = (char **) ncalloc((countlinknodes(l) + 1) * sizeof(char *));
for (n = firstnode(l); n; incnode(n))
*x++ = dupstring((char *) getdata(n));
*x = NULL;
return y;
}
/**/
static char *
spname(char *oldname)
@ -3009,11 +3028,12 @@ niceztrdup(char const *s)
char *p = buf, *n, *ret;
while ((c = *s++)) {
if (itok(c))
if (itok(c)) {
if (c <= Comma)
c = ztokens[c - Pound];
else
continue;
}
if (c == Meta)
c = *s++ ^ 32;
n = nicechar(c);
@ -3034,11 +3054,12 @@ nicezputs(char const *s, FILE *stream)
int c;
while ((c = *s++)) {
if (itok(c))
if (itok(c)) {
if (c <= Comma)
c = ztokens[c - Pound];
else
continue;
}
if (c == Meta)
c = *s++ ^ 32;
if(fputs(nicechar(c), stream) < 0)
@ -3057,11 +3078,12 @@ niceztrlen(char const *s)
int c;
while ((c = *s++)) {
if (itok(c))
if (itok(c)) {
if (c <= Comma)
c = ztokens[c - Pound];
else
continue;
}
if (c == Meta)
c = *s++ ^ 32;
l += strlen(nicechar(STOUC(c)));
@ -3328,13 +3350,14 @@ getkeystring(char *s, int *len, int fromwhere, int *misc)
}
default:
if ((idigit(*s) && *s < '8') || *s == 'x') {
if (!fromwhere)
if (!fromwhere) {
if (*s == '0')
s++;
else if (*s != 'x') {
*t++ = '\\', s--;
continue;
}
}
if (s[1] && s[2] && s[3]) {
svchar = s[3];
s[3] = '\0';

View file

@ -1,8 +1,10 @@
#!
SHTTY
addbuiltins
addconddefs
addedx
addhashnode
addwrapper
aliastab
alloc_stackp
appstr
@ -30,7 +32,9 @@ ctxtlex
curhist
current_limits
deletebuiltins
deleteconddefs
deletehashtable
deletewrapper
domatch
doshfunc
dputs
@ -65,6 +69,7 @@ getkeystring
getlinknode
getshfunc
getsparam
gettempname
glob_pre
glob_suf
global_heapalloc
@ -82,6 +87,7 @@ hgetc
hgetline
histentarr
histentct
holdintr
hptr
hrealloc
inbufct
@ -94,6 +100,7 @@ inpop
inpush
inredir
insertlinknode
install_handler
intr
inwhat
isfirstln
@ -108,6 +115,7 @@ limits
line
lines
locallevel
matheval
metadiffer
metafy
metalen
@ -124,6 +132,7 @@ niceztrdup
niceztrlen
noaliases
noerrs
noholdintr
noop_function
noop_function_int
optiontab
@ -157,8 +166,10 @@ resetneeded
restoredir
reswdtab
retflag
runshfunc
scanhashtable
setaparam
sethparam
setlimits
setsparam
settyinfo
@ -166,6 +177,8 @@ shfunctab
shingetline
shout
shttyinfo
sigfuncs
sigtrapped
singsub
skipparens
spaceinlineptr
@ -184,6 +197,7 @@ struncpy
tclen
tcstr
termflags
thisjob
tgoto
tok
tokenize
@ -201,6 +215,7 @@ ugetnode
uinsertlinknode
unmeta
unmetafy
unsetparam_pm
untokenize
uremnode
useheap
@ -210,6 +225,7 @@ zalloc
zbeep
zcalloc
zchdir
zclose
zerr
zerrnam
zexit
@ -222,6 +238,7 @@ zleparse
zlereadptr
zputs
zreaddir
zrealloc
zsetlimit
zsfree
zshcs

View file

@ -233,6 +233,7 @@ typedef struct alias *Alias;
typedef struct param *Param;
typedef struct cmdnam *Cmdnam;
typedef struct shfunc *Shfunc;
typedef struct funcwrap *FuncWrap;
typedef struct builtin *Builtin;
typedef struct nameddir *Nameddir;
typedef struct module *Module;
@ -242,6 +243,7 @@ typedef struct job *Job;
typedef struct value *Value;
typedef struct varasg *Varasg;
typedef struct cond *Cond;
typedef struct conddef *Conddef;
typedef struct cmd *Cmd;
typedef struct pline *Pline;
typedef struct sublist *Sublist;
@ -455,6 +457,26 @@ struct cond {
#define COND_GT 13
#define COND_LE 14
#define COND_GE 15
#define COND_MOD 16
#define COND_MODI 17
typedef int (*CondHandler) _((Conddef, char **));
struct conddef {
Conddef next; /* next in list */
char *name; /* the condition name */
int flags; /* see CONDF_* below */
int min; /* minimum number of strings */
int max; /* maximum number of strings */
CondHandler handler; /* handler function */
char *module; /* module to autoload */
};
#define CONDF_INFIX 1
#define CONDF_ADDED 2
#define CONDDEF(name, flags, min, max, handler) \
{ NULL, name, flags, min, max, handler, NULL }
struct forcmd { /* for/select */
/* Cmd->args contains list of words to loop thru */
@ -750,6 +772,23 @@ struct shfunc {
List funcdef; /* function definition */
};
/* node in list of function call wrappers */
typedef int (*WrapFunc) _((List, FuncWrap, char *));
struct funcwrap {
FuncWrap next;
int flags;
WrapFunc handler;
Module module;
int count;
};
#define WRAPF_ADDED 1
#define WRAPDEF(func) \
{ NULL, 0, func, NULL, 0 }
/* node in builtin command hash table (builtintab) */
typedef int (*HandlerFunc) _((char *, char **, char *, int));
@ -800,6 +839,8 @@ struct module {
};
#define MOD_BUSY (1<<0)
#define MOD_WRAPPER (1<<1)
#define MOD_UNLOAD (1<<2)
/* node used in parameter hash table (paramtab) */
@ -872,6 +913,23 @@ struct param {
#define PM_RESTRICTED (1<<13) /* cannot be changed in restricted mode */
#define PM_UNSET (1<<14) /* has null value */
/*
* Flags for doing matches inside parameter substitutions, i.e.
* ${...#...} and friends. This could be an enum, but so
* could a lot of other things.
*/
#define SUB_END 0x0001 /* match end instead of begining, % or %% */
#define SUB_LONG 0x0002 /* % or # doubled, get longest match */
#define SUB_SUBSTR 0x0004 /* match a substring */
#define SUB_MATCH 0x0008 /* include the matched portion */
#define SUB_REST 0x0010 /* include the unmatched portion */
#define SUB_BIND 0x0020 /* index of beginning of string */
#define SUB_EIND 0x0040 /* index of end of string */
#define SUB_LEN 0x0080 /* length of match */
#define SUB_ALL 0x0100 /* match complete string */
#define SUB_GLOBAL 0x0200 /* global substitution ${..//all/these} */
/* node for named directory hash table (nameddirtab) */
struct nameddir {
@ -891,13 +949,14 @@ struct nameddir {
#define PRINT_NAMEONLY (1<<0)
#define PRINT_TYPE (1<<1)
#define PRINT_LIST (1<<2)
#define PRINT_KV_PAIR (1<<3)
/* flags for printing for the whence builtin */
#define PRINT_WHENCE_CSH (1<<3)
#define PRINT_WHENCE_VERBOSE (1<<4)
#define PRINT_WHENCE_SIMPLE (1<<5)
#define PRINT_WHENCE_FUNCDEF (1<<6)
#define PRINT_WHENCE_WORD (1<<7)
#define PRINT_WHENCE_CSH (1<<4)
#define PRINT_WHENCE_VERBOSE (1<<5)
#define PRINT_WHENCE_SIMPLE (1<<6)
#define PRINT_WHENCE_FUNCDEF (1<<7)
#define PRINT_WHENCE_WORD (1<<8)
/***********************************/
/* Definitions for history control */

View file

@ -428,6 +428,8 @@ fi
AC_CHECK_LIB(cap, cap_get_proc)
AC_CHECK_LIB(socket, socket)
dnl ---------------------
dnl CHECK TERMCAP LIBRARY
dnl ---------------------

View file

@ -47,7 +47,8 @@ Bart's chpwd() fix 4589
Second edition
Added line in zle_tricky.c missed when patching by hand, spotted by
Bart. (Whitespace is still non-canonical.)
Bart. (Whitespace is still non-canonical in the completion code where
I have merged patches by hand.)
Fixed up my compctl widgets patch for use with Sven's rewrite, which I
hadn't done properly before.
@ -58,7 +59,9 @@ Bart's doc fixes, 4472
Bart's PWD and OLDPWD reshuffle, 4589
My test-line-length patch for prompts, 4591
My test-line-length patch for prompts, 4591 (`%(40l.yes.no)' outputs
`yes' if at least 40 characters have already appeared on the line,
`no' otherwise.)
Configure patch from Wilfredo Sanchez in 4594, with some extra
tabbification and without the setterm() hunk, since I've already renamed
@ -84,12 +87,16 @@ one two
% print ${(kv)hash} # flag to get keys and values (**)
one eins two zwei
Comparison of (*) and (**) will reveal how to copy an associative
array, but you always need to declare it with typeset -A or an
ordinary array will appear. There is a predefined special associative
array $testhash, for testing purposes only, which will eventually
disappear.
array, `hash2=(${(kv}hash})', but you always need to `typeset -A
hash2' first or an ordinary array will appear. There is a predefined
special associative array $testhash, for testing purposes only, which
will eventually disappear.
My rewrite of prompt truncation, 4601
My rewrite of prompt truncation, 4601 --- note this introduces a
slight incompatibility in that the string to be truncated now runs by
default to the end of the string, instead of only covering individual
%-substitutions. If necessary, stick in an extra '%>>' to turn
truncation off at the point you want.
Bart's params error message fix, 4606
@ -100,3 +107,65 @@ Bart's version of the *** fix, 4624
Bart's parameter substitution flag delimiter fix, 4644
My special parameter unset fix, 4662
Third edition
I've taken the plunge and changed $ZSH_VERSION, the current one is now
3.1.5.pws-1 . It seemed rational to have something incremental at the
end for testing, so I abandoned using the date.
4482 (cdmatch2)and 4641 (${assoc[0]}) now applied; 4641 was supposed
to be there before.
nroff manual pages deleted, you now need yodl.
deleted modules-bltin by hand, which `make distclean' somehow missed.
Caused problems when building a statically linked shell.
Bart's scanmatchtable fix, 4674
Commented out vifirstnonblank() in vioperswapcase(), pending any
better patch for it.
Bart's viforwardword fix, 4678
My case-independent globbing fix, 4693
Sven's zle_tricky.c, 4697
Sven's patch to ignore completions if the cursor is not in a part to
be completed, 4698, plus addition, 4707
I have not added Sven's zerr() patch, 4699, in case it has side
effects, but I haven't heard anything on the subject and I haven't
looked at it.
Sven's pennockite heap memory patch, 4700
Sven's condition module patch, 4716, and addition, 4732, and the
function wrapper patch, 4734, and additions, 4742, 4769: the module.c
bits of these have been moved around a little to avoid clashes with
the AIXDYNAMIC stuff. The wrapper stuff is still not finished, but
doesn't currently impinge on use of the shell.
Phil Pennock's patch to use associative arrays in stat, 4727
Unposted fix for use of printcompctlptr in completion widgets:
printcompctl() had acquired another argument.
My bash-like ${foo/orig/new} patch, 4736, and the version to do
shortest matching together with optimizations of all pattern matching
in variable strings, 4754.
Phil's patch for typeset -a docs, 4737
Nobody wanted my fix for `FOO=x eval external', so it's not there.
zftp, 4761
Bart's fix for conddef without dynamical modules, 4762
Bart's associative array patches for implentation of subscripting flags,
4763, plus fix 4766; typeset output 4764
Sven's completion listing fix, 4767