summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/pcre.c1
-rw-r--r--Src/Zle/compcore.c2
-rw-r--r--Src/Zle/complete.mdd2
-rw-r--r--Src/Zle/zle_keymap.c1
-rw-r--r--Src/Zle/zle_main.c16
-rw-r--r--Src/Zle/zle_refresh.c81
-rw-r--r--Src/Zle/zle_thingy.c64
-rw-r--r--Src/builtin.c6
-rw-r--r--Src/exec.c19
-rw-r--r--Src/glob.c2
-rw-r--r--Src/hashtable.c5
-rw-r--r--Src/hist.c5
-rw-r--r--Src/init.c14
-rw-r--r--Src/options.c1
-rw-r--r--Src/params.c4
-rw-r--r--Src/subst.c143
-rw-r--r--Src/zsh.h16
17 files changed, 316 insertions, 66 deletions
diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c
index 2e3556a8d..cb9f8ef57 100644
--- a/Src/Modules/pcre.c
+++ b/Src/Modules/pcre.c
@@ -354,6 +354,7 @@ cond_pcre_match(char **a, int id)
unmetafy(rhre_plain, NULL);
pcre_pat = NULL;
ov = NULL;
+ ovsize = 0;
if (isset(BASHREMATCH))
avar="BASH_REMATCH";
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index b1de6c6cc..39d41bdb5 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -2303,10 +2303,10 @@ addmatches(Cadata dat, char **argv)
strcpy(tmp + llpl + gfl + is, lsuf);
tokenize(tmp);
- remnulargs(tmp);
if (haswilds(tmp)) {
if (is)
tmp[llpl + gfl] = Star;
+ remnulargs(tmp);
if ((cp = patcompile(tmp, 0, NULL)))
haspattern = 1;
}
diff --git a/Src/Zle/complete.mdd b/Src/Zle/complete.mdd
index 2aa0cde1c..77e33504d 100644
--- a/Src/Zle/complete.mdd
+++ b/Src/Zle/complete.mdd
@@ -1,7 +1,7 @@
name=zsh/complete
link=either
load=yes
-functions='Completion/*comp* Completion/AIX/*/* Completion/BSD/*/* Completion/Base/*/* Completion/Cygwin/*/* Completion/Darwin/*/* Completion/Debian/*/* Completion/Linux/*/* Completion/Mandriva/*/* Completion/Redhat/*/* Completion/Solaris/*/* Completion/Unix/*/* Completion/X/*/* Completion/Zsh/*/*'
+functions='Completion/*comp* Completion/AIX/*/* Completion/BSD/*/* Completion/Base/*/* Completion/Cygwin/*/* Completion/Darwin/*/* Completion/Debian/*/* Completion/Linux/*/* Completion/Mandriva/*/* Completion/Redhat/*/* Completion/Solaris/*/* Completion/openSUSE/*/* Completion/Unix/*/* Completion/X/*/* Completion/Zsh/*/*'
moddeps="zsh/zle"
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index a08caa069..c3731c47b 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -544,6 +544,7 @@ bindkey(Keymap km, char *seq, Thingy bind, char *str)
if(km->first[f]) {
char fs[3];
fs[0] = f;
+ fs[1] = 0;
metafy(fs, 1, META_NOALLOC);
km->multi->addnode(km->multi, ztrdup(fs),
makekeynode(km->first[f], NULL));
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 3cdc3b2ed..e1a575bdb 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1200,6 +1200,18 @@ zleread(char **lp, char **rp, int flags, int context)
putc('\r', shout);
if (tmout)
alarm(tmout);
+
+ /*
+ * On some windowing systems we may enter this function before the
+ * terminal is fully opened and sized, resulting in an infinite
+ * series of SIGWINCH when the handler prints the prompt before we
+ * have done so here. Therefore, hold any such signal until the
+ * first full refresh has completed. The important bit is that the
+ * handler must not see zleactive = 1 until ZLE really is active.
+ * See the end of adjustwinsize() in Src/utils.c
+ */
+ queue_signals();
+
zleactive = 1;
resetneeded = 1;
errflag = retflag = 0;
@@ -1209,6 +1221,8 @@ zleread(char **lp, char **rp, int flags, int context)
zrefresh();
+ unqueue_signals(); /* Should now be safe to acknowledge SIGWINCH */
+
zlecallhook("zle-line-init", NULL);
zlecore();
@@ -1913,7 +1927,7 @@ zle_main_entry(int cmd, va_list ap)
static struct builtin bintab[] = {
BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaM:ldDANmrsLRp", NULL),
BUILTIN("vared", 0, bin_vared, 1, 1, 0, "aAcehM:m:p:r:t:", NULL),
- BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDFgGIKlLmMNRU", NULL),
+ BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDFgGIKlLmMNrRTU", NULL),
};
/* The order of the entries in this table has to match the *HOOK
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 260df8bf6..17b78ce59 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -233,6 +233,12 @@ int n_region_highlights;
/**/
int region_active;
+/*
+ * Name of function to use to output termcap values, if defined.
+ */
+/**/
+char *tcout_func_name;
+
#ifdef HAVE_SELECT
/* cost of last update */
/**/
@@ -2271,11 +2277,78 @@ tc_downcurs(int ct)
return ret;
}
+/*
+ * Output a termcap value using a function defined by "zle -T tc".
+ * Loosely inspired by subst_string_by_func().
+ *
+ * cap is the internal index for the capability; it will be looked up
+ * in the table and the string passed to the function.
+ *
+ * arg is eithr an argument to the capability or -1 if there is none;
+ * if it is not -1 it will be passed as an additional argument to the
+ * function.
+ *
+ * outc is the output function; currently this is always putshout
+ * but in principle it may be used to output to a string.
+ */
+
+/**/
+static void
+tcout_via_func(int cap, int arg, int (*outc)(int))
+{
+ Shfunc tcout_func;
+ int osc, osm, old_incompfunc;
+
+ osc = sfcontext;
+ osm = stopmsg;
+ old_incompfunc = incompfunc;
+
+ sfcontext = SFC_SUBST;
+ incompfunc = 0;
+
+ if ((tcout_func = getshfunc(tcout_func_name))) {
+ LinkList l = newlinklist();
+ char buf[DIGBUFSIZE], *str;
+
+ addlinknode(l, tcout_func_name);
+ addlinknode(l, tccap_get_name(cap));
+
+ if (arg != -1) {
+ sprintf(buf, "%d", arg);
+ addlinknode(l, buf);
+ }
+
+ (void)doshfunc(tcout_func, l, 1);
+
+ str = getsparam("REPLY");
+ if (str) {
+ while (*str) {
+ int chr;
+ if (*str == Meta) {
+ chr = str[1] ^ 32;
+ str += 2;
+ } else {
+ chr = *str++;
+ }
+ (void)outc(chr);
+ }
+ }
+ }
+
+ sfcontext = osc;
+ stopmsg = osm;
+ incompfunc = old_incompfunc;
+}
+
/**/
mod_export void
tcout(int cap)
{
- tputs(tcstr[cap], 1, putshout);
+ if (tcout_func_name) {
+ tcout_via_func(cap, -1, putshout);
+ } else {
+ tputs(tcstr[cap], 1, putshout);
+ }
SELECT_ADD_COST(tclen[cap]);
}
@@ -2286,7 +2359,11 @@ tcoutarg(int cap, int arg)
char *result;
result = tgoto(tcstr[cap], arg, arg);
- tputs(result, 1, putshout);
+ if (tcout_func_name) {
+ tcout_via_func(cap, arg, putshout);
+ } else {
+ tputs(result, 1, putshout);
+ }
SELECT_ADD_COST(strlen(result));
}
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 03e73b4ca..49d715e06 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -353,6 +353,7 @@ bin_zle(char *name, char **args, Options ops, UNUSED(int func))
{ 'K', bin_zle_keymap, 1, 1 },
{ 'I', bin_zle_invalidate, 0, 0 },
{ 'F', bin_zle_fd, 0, 2 },
+ { 'T', bin_zle_transform, 0, 2},
{ 0, bin_zle_call, 0, -1 },
};
struct opn const *op, *opp;
@@ -856,6 +857,69 @@ bin_zle_fd(char *name, char **args, Options ops, UNUSED(char func))
return 0;
}
+/**/
+static int
+bin_zle_transform(char *name, char **args, Options ops, UNUSED(char func))
+{
+ /*
+ * -1: too few arguments
+ * 0: just right
+ * 1: too many arguments
+ * 2: first argument not recognised
+ */
+ int badargs = 0;
+
+ if (OPT_ISSET(ops,'L')) {
+ if (args[0]) {
+ if (args[1]) {
+ badargs = 1;
+ } else if (strcmp(args[0], "tc")) {
+ badargs = 2;
+ }
+ }
+ if (!badargs && tcout_func_name) {
+ fputs("zle -T tc ", stdout);
+ quotedzputs(tcout_func_name, stdout);
+ putchar('\n');
+ }
+ } else if (OPT_ISSET(ops,'r')) {
+ if (!args[0]) {
+ badargs = -1;
+ } else if (args[1]) {
+ badargs = 1;
+ } else if (tcout_func_name) {
+ zsfree(tcout_func_name);
+ tcout_func_name = NULL;
+ }
+ } else {
+ if (!args[0] || !args[1]) {
+ badargs = -1;
+ /* we've already checked args <= 2 */
+ } else {
+ if (!strcmp(args[0], "tc")) {
+ if (tcout_func_name) {
+ zsfree(tcout_func_name);
+ }
+ tcout_func_name = ztrdup(args[1]);
+ } else {
+ badargs = 2;
+ }
+ }
+ }
+
+ if (badargs) {
+ if (badargs == 2) {
+ zwarnnam(name, "-T: no such transformation '%s'", args[0]);
+ } else {
+ char *way = (badargs > 0) ? "many" : "few";
+ zwarnnam(name, "too %s arguments for option -T", way);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
/*******************/
/* initialiasation */
/*******************/
diff --git a/Src/builtin.c b/Src/builtin.c
index 71fc04ce1..b43c08235 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1652,6 +1652,12 @@ fclist(FILE *f, Options ops, zlong first, zlong last,
last = first;
first = tmp;
}
+ if (first > last) {
+ zwarnnam("fc", "history events are in wrong order, aborted");
+ if (f != stdout)
+ fclose(f);
+ return 1;
+ }
/* suppress "no substitution" warning if no substitution is requested */
if (!subs)
fclistdone = 1;
diff --git a/Src/exec.c b/Src/exec.c
index 9b3c50372..503e0843d 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2174,8 +2174,8 @@ addvars(Estate state, Wordcode pc, int addflags)
vl = ecgetlist(state, WC_ASSIGN_NUM(ac), EC_DUPTOK, &htok);
if (vl && htok) {
- prefork(vl, (isstr ? (PF_SINGLE|PF_ASSIGN) :
- PF_ASSIGN));
+ prefork(vl, (isstr ? (PREFORK_SINGLE|PREFORK_ASSIGN) :
+ PREFORK_ASSIGN));
if (errflag) {
state->pc = opc;
return;
@@ -2487,6 +2487,11 @@ execcmd(Estate state, int input, int output, int how, int last1)
* with the zsh style.
*/
while (next && *next == '-' && strlen(next) >= 2) {
+ if (!firstnode(args)) {
+ zerr("exec requires a command to execute");
+ errflag = lastval = 1;
+ return;
+ }
uremnode(args, firstnode(args));
if (!strcmp(next, "--"))
break;
@@ -2499,6 +2504,11 @@ execcmd(Estate state, int input, int output, int how, int last1)
/* position on last non-NULL character */
cmdopt += strlen(cmdopt+1);
} else {
+ if (!firstnode(args)) {
+ zerr("exec requires a command to execute");
+ errflag = lastval = 1;
+ return;
+ }
if (!nextnode(firstnode(args))) {
zerr("exec flag -a requires a parameter");
errflag = lastval = 1;
@@ -2521,7 +2531,8 @@ execcmd(Estate state, int input, int output, int how, int last1)
return;
}
}
- next = (char *) getdata(nextnode(firstnode(args)));
+ if (firstnode(args) && nextnode(firstnode(args)))
+ next = (char *) getdata(nextnode(firstnode(args)));
}
if (exec_argv0) {
char *str, *s;
@@ -2541,7 +2552,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
}
/* Do prefork substitutions */
- esprefork = (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0;
+ esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0;
if (args && htok)
prefork(args, esprefork);
diff --git a/Src/glob.c b/Src/glob.c
index 076d0392a..d003d95da 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -2011,7 +2011,7 @@ xpandredir(struct redir *fn, LinkList redirtab)
/* Stick the name in a list... */
init_list1(fake, fn->name);
/* ...which undergoes all the usual shell expansions */
- prefork(&fake, isset(MULTIOS) ? 0 : PF_SINGLE);
+ prefork(&fake, isset(MULTIOS) ? 0 : PREFORK_SINGLE);
/* Globbing is only done for multios. */
if (!errflag && isset(MULTIOS))
globlist(&fake, 0);
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 6fca256e3..775b6a277 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -663,8 +663,9 @@ hashdir(char **dirp)
* This is the same test as for the glob qualifier for
* executable plain files.
*/
- if (stat(pathbuf, &statbuf) == 0 &&
- S_ISREG(statbuf.st_mode) && (statbuf.st_mode & S_IXUGO))
+ if (unset(HASHEXECUTABLESONLY) ||
+ (stat(pathbuf, &statbuf) == 0 &&
+ S_ISREG(statbuf.st_mode) && (statbuf.st_mode & S_IXUGO)))
add = 1;
}
if (add) {
diff --git a/Src/hist.c b/Src/hist.c
index aeb6edda5..4d522dddb 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -1664,6 +1664,11 @@ chrealpath(char **junkptr)
errno == ENAMETOOLONG || errno == ENOMEM)
return 0;
+#ifdef HAVE_CANONICALIZE_FILE_NAME
+ if (!real)
+ return 0;
+#endif
+
if (nonreal == *junkptr) {
*real = '\0';
break;
diff --git a/Src/init.c b/Src/init.c
index 30cd40e6c..9820070fb 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -558,6 +558,19 @@ static char *tccapnams[TC_COUNT] = {
"ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB"
};
+/**/
+mod_export char *
+tccap_get_name(int cap)
+{
+ if (cap >= TC_COUNT) {
+#ifdef DEBUG
+ dputs("name of invalid capability %d requested", cap);
+#endif
+ return "";
+ }
+ return tccapnams[cap];
+}
+
/* Initialise termcap */
/**/
@@ -978,6 +991,7 @@ setupshin(char *runscript)
exit(127);
}
scriptfilename = sfname;
+ zsfree(argzero); /* ztrdup'd in parseargs */
argzero = runscript;
}
/*
diff --git a/Src/options.c b/Src/options.c
index a70d4ff11..5fbb06b11 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -140,6 +140,7 @@ static struct optname optns[] = {
{{NULL, "globsubst", OPT_EMULATE|OPT_NONZSH}, GLOBSUBST},
{{NULL, "hashcmds", OPT_ALL}, HASHCMDS},
{{NULL, "hashdirs", OPT_ALL}, HASHDIRS},
+{{NULL, "hashexecutablesonly", 0}, HASHEXECUTABLESONLY},
{{NULL, "hashlistall", OPT_ALL}, HASHLISTALL},
{{NULL, "histallowclobber", 0}, HISTALLOWCLOBBER},
{{NULL, "histbeep", OPT_ALL}, HISTBEEP},
diff --git a/Src/params.c b/Src/params.c
index 446cccc7e..59d5daf2f 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -3788,6 +3788,10 @@ static void
setlang(char *x)
{
struct localename *ln;
+ char *x2;
+
+ if ((x2 = getsparam("LC_ALL")) && *x2)
+ return;
/*
* Set the global locale to the value passed, but override
diff --git a/Src/subst.c b/Src/subst.c
index 4e8ed721d..894f9cd2f 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -44,7 +44,7 @@ char nulstring[] = {Nularg, '\0'};
* - Brace expansion
* - Tilde and equals substitution
*
- * PF_* flags are defined in zsh.h
+ * PREFORK_* flags are defined in zsh.h
*/
/**/
@@ -52,7 +52,7 @@ mod_export void
prefork(LinkList list, int flags)
{
LinkNode node, stop = 0;
- int keep = 0, asssub = (flags & PF_TYPESET) && isset(KSHTYPESET);
+ int keep = 0, asssub = (flags & PREFORK_TYPESET) && isset(KSHTYPESET);
queue_signals();
for (node = firstnode(list); node; incnode(node)) {
@@ -67,14 +67,18 @@ prefork(LinkList list, int flags)
* templates...
*/
char *cptr = (char *)getdata(node);
- filesub(&cptr, flags & (PF_TYPESET|PF_ASSIGN));
+ filesub(&cptr, flags & (PREFORK_TYPESET|PREFORK_ASSIGN));
/*
* The assignment is so simple it's not worth
* testing if cptr changed...
*/
setdata(node, cptr);
}
- if (!(node = stringsubst(list, node, flags & PF_SINGLE, asssub))) {
+ if (!(node = stringsubst(list, node,
+ flags & (PREFORK_SINGLE|PREFORK_SPLIT|
+ PREFORK_SHWORDSPLIT|
+ PREFORK_NOSHWORDSPLIT),
+ asssub))) {
unqueue_signals();
return;
}
@@ -84,7 +88,7 @@ prefork(LinkList list, int flags)
keep = 0;
if (*(char *)getdata(node)) {
remnulargs(getdata(node));
- if (unset(IGNOREBRACES) && !(flags & PF_SINGLE)) {
+ if (unset(IGNOREBRACES) && !(flags & PREFORK_SINGLE)) {
if (!keep)
stop = nextnode(node);
while (hasbraces(getdata(node))) {
@@ -94,10 +98,10 @@ prefork(LinkList list, int flags)
}
if (unset(SHFILEEXPANSION)) {
char *cptr = (char *)getdata(node);
- filesub(&cptr, flags & (PF_TYPESET|PF_ASSIGN));
+ filesub(&cptr, flags & (PREFORK_TYPESET|PREFORK_ASSIGN));
setdata(node, cptr);
}
- } else if (!(flags & PF_SINGLE) && !keep)
+ } else if (!(flags & PREFORK_SINGLE) && !keep)
uremnode(list, node);
if (errflag) {
unqueue_signals();
@@ -145,7 +149,7 @@ stringsubstquote(char *strstart, char **pstrdpos)
/**/
static LinkNode
-stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
+stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub)
{
int qt;
char *str3 = (char *)getdata(node);
@@ -213,7 +217,25 @@ stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
setdata(node, (void *) str3);
continue;
} else {
- node = paramsubst(list, node, &str, qt, ssub);
+ /*
+ * To avoid setting and unsetting the SHWORDSPLIT
+ * option, we pass flags if we need to control it for
+ * recursive expansion via multsub()
+ * If PREFORK_NOSHWORDSPLIT is set, the option is
+ * disregarded; otherwise, use it if set.
+ * If PREFORK_SPLIT is set, splitting is forced,
+ * regardless of the option
+ * If PREFORK_SHWORDSPLIT is already set, or used by the
+ * previous two to signal paramsubst(), we'll do
+ * sh-style wordsplitting on parameters.
+ */
+ if ((isset(SHWORDSPLIT) &&
+ !(pf_flags & PREFORK_NOSHWORDSPLIT)) ||
+ (pf_flags & PREFORK_SPLIT))
+ pf_flags |= PREFORK_SHWORDSPLIT;
+ node = paramsubst(
+ list, node, &str, qt,
+ pf_flags & (PREFORK_SINGLE|PREFORK_SHWORDSPLIT));
if (errflag || !node)
return NULL;
str3 = (char *)getdata(node);
@@ -268,7 +290,8 @@ stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
(qt && str[1] == '"'))))
*str = ztokens[c - Pound];
str++;
- if (!(pl = getoutput(str2 + 1, qt || ssub))) {
+ if (!(pl = getoutput(str2 + 1, qt ||
+ (pf_flags & PREFORK_SINGLE)))) {
zerr("parse error in command substitution");
return NULL;
}
@@ -278,7 +301,7 @@ stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
str = strcpy(str2, str);
continue;
}
- if (!qt && ssub && isset(GLOBSUBST))
+ if (!qt && (pf_flags & PREFORK_SINGLE) && isset(GLOBSUBST))
shtokenize(s);
l1 = str2 - str3;
l2 = strlen(s);
@@ -306,7 +329,7 @@ stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
* We are in a normal argument which looks like an assignment
* and is to be treated like one, with no word splitting.
*/
- ssub = 1;
+ pf_flags |= PREFORK_SINGLE;
}
str++;
}
@@ -371,7 +394,7 @@ singsub(char **s)
init_list1(foo, *s);
- prefork(&foo, PF_SINGLE);
+ prefork(&foo, PREFORK_SINGLE);
if (errflag)
return;
*s = (char *) ugetnode(&foo);
@@ -392,13 +415,13 @@ singsub(char **s)
/**/
static int
-multsub(char **s, int split, char ***a, int *isarr, char *sep)
+multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep)
{
int l;
char **r, **p, *x = *s;
local_list1(foo);
- if (split) {
+ if (pf_flags & PREFORK_SPLIT) {
/*
* This doesn't handle multibyte characters, but we're
* looking for whitespace separators which must be ASCII.
@@ -413,7 +436,7 @@ multsub(char **s, int split, char ***a, int *isarr, char *sep)
init_list1(foo, x);
- if (split) {
+ if (pf_flags & PREFORK_SPLIT) {
LinkNode n = firstnode(&foo);
int inq = 0, inp = 0;
MB_METACHARINIT();
@@ -467,7 +490,7 @@ multsub(char **s, int split, char ***a, int *isarr, char *sep)
}
}
- prefork(&foo, 0);
+ prefork(&foo, pf_flags);
if (errflag) {
if (isarr)
*isarr = 0;
@@ -503,8 +526,8 @@ multsub(char **s, int split, char ***a, int *isarr, char *sep)
}
/*
- * ~, = subs: assign & PF_TYPESET => typeset or magic equals
- * assign & PF_ASSIGN => normal assignment
+ * ~, = subs: assign & PREFORK_TYPESET => typeset or magic equals
+ * assign & PREFORK_ASSIGN => normal assignment
*/
/**/
@@ -519,7 +542,7 @@ filesub(char **namptr, int assign)
if (!assign)
return;
- if (assign & PF_TYPESET) {
+ if (assign & PREFORK_TYPESET) {
if ((*namptr)[1] && (eql = sub = strchr(*namptr + 1, Equals))) {
str = sub + 1;
if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) {
@@ -1437,7 +1460,7 @@ check_colon_subscript(char *str, char **endp)
/**/
static LinkNode
-paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
+paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
{
char *aptr = *str, c, cc;
char *s = aptr, *fstr, *idbeg, *idend, *ostr = (char *) getdata(n);
@@ -1514,7 +1537,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
* where we shouldn't, in particular on the multsubs for
* handling embedded values for ${...=...} and the like.
*/
- int spbreak = isset(SHWORDSPLIT) && !ssub && !qt;
+ int spbreak = (pf_flags & PREFORK_SHWORDSPLIT) &&
+ !(pf_flags & PREFORK_SINGLE) && !qt;
/* Scalar and array value, see isarr above */
char *val = NULL, **aval = NULL;
/*
@@ -1564,6 +1588,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
*/
int shsplit = 0;
/*
+ * "ssub" is true when we are called from singsub (via prefork):
+ * it means that we must join arrays and should not split words.
+ */
+ int ssub = (pf_flags & PREFORK_SINGLE);
+ /*
* The separator from (j) and (s) respectively, or (F) and (f)
* respectively (hardwired to "\n" in that case). Slightly
* confusingly also used for ${#pm}, thought that's at least
@@ -1620,7 +1649,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
* This is one of the things that decides whether multsub
* will produce an array, but in an extremely indirect fashion.
*/
- int nojoin = isset(SHWORDSPLIT) ? !(ifs && *ifs) : 0;
+ int nojoin = (pf_flags & PREFORK_SHWORDSPLIT) ? !(ifs && *ifs) : 0;
/*
* != 0 means ${...}, otherwise $... What works without braces
* is largely a historical artefact (everything works with braces,
@@ -2618,7 +2647,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
/* Fall Through! */
case '-':
if (vunset) {
- int ws = opts[SHWORDSPLIT];
+ int split_flags;
val = dupstring(s);
/* If word-splitting is enabled, we ask multsub() to split
* the substituted string at unquoted whitespace. Then, we
@@ -2627,9 +2656,20 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
* keep its array splits, and weird constructs such as
* ${str+"one two" "3 2 1" foo "$str"} to only be split
* at the unquoted spaces. */
- opts[SHWORDSPLIT] = spbreak;
- multsub(&val, spbreak && !aspar, (aspar ? NULL : &aval), &isarr, NULL);
- opts[SHWORDSPLIT] = ws;
+ if (spbreak) {
+ split_flags = PREFORK_SHWORDSPLIT;
+ if (!aspar)
+ split_flags |= PREFORK_SPLIT;
+ } else {
+ /*
+ * It's not good enough not passing the flag to use
+ * SHWORDSPLIT, because when we get to a nested
+ * paramsubst we need to ignore isset(SHWORDSPLIT).
+ */
+ split_flags = PREFORK_NOSHWORDSPLIT;
+ }
+ multsub(&val, split_flags, (aspar ? NULL : &aval),
+ &isarr, NULL);
copied = 1;
spbreak = 0;
/* Leave globsubst on if forced */
@@ -2647,21 +2687,21 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
case '=':
case Equals:
if (vunset) {
- int ws = opts[SHWORDSPLIT];
char sav = *idend;
- int l;
+ int l, split_flags;
*idend = '\0';
val = dupstring(s);
if (spsep || !arrasg) {
- opts[SHWORDSPLIT] = 0;
- multsub(&val, 0, NULL, &isarr, NULL);
+ multsub(&val, PREFORK_NOSHWORDSPLIT, NULL, &isarr, NULL);
} else {
- opts[SHWORDSPLIT] = spbreak;
- multsub(&val, spbreak, &aval, &isarr, NULL);
+ if (spbreak)
+ split_flags = PREFORK_SPLIT|PREFORK_SHWORDSPLIT;
+ else
+ split_flags = PREFORK_NOSHWORDSPLIT;
+ multsub(&val, split_flags, &aval, &isarr, NULL);
spbreak = 0;
}
- opts[SHWORDSPLIT] = ws;
if (arrasg) {
/* This is an array assignment. */
char *arr[2], **t, **a, **p;
@@ -2878,24 +2918,26 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
return NULL;
}
}
- if (horrible_offset_hack) {
- /*
- * As part of the 'orrible hoffset 'ack,
- * (what hare you? Han 'orrible hoffset 'ack,
- * sergeant major), if we are given a ksh/bash/POSIX
- * style positional parameter array which includes
- * offset 0, we use $0.
- */
- if (offset == 0 && isarr) {
- offset_hack_argzero = 1;
- } else if (offset > 0) {
- offset--;
- }
- }
if (isarr) {
- int alen = arrlen(aval), count;
+ int alen, count;
char **srcptr, **dstptr, **newarr;
+ if (horrible_offset_hack) {
+ /*
+ * As part of the 'orrible hoffset 'ack,
+ * (what hare you? Han 'orrible hoffset 'ack,
+ * sergeant major), if we are given a ksh/bash/POSIX
+ * style positional parameter array which includes
+ * offset 0, we use $0.
+ */
+ if (offset == 0) {
+ offset_hack_argzero = 1;
+ } else if (offset > 0) {
+ offset--;
+ }
+ }
+
+ alen = arrlen(aval);
if (offset < 0) {
offset += alen;
if (offset < 0)
@@ -3116,8 +3158,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
* (afterward) may split the joined value (e.g. (s:-:) sets "spsep"). One
* exception is that ${name:-word} and ${name:+word} will have already
* done any requested splitting of the word value with quoting preserved.
- * "ssub" is true when we are called from singsub (via prefork):
- * it means that we must join arrays and should not split words. */
+ */
if (ssub || (spbreak && isarr >= 0) || spsep || sep) {
if (isarr) {
val = sepjoin(aval, sep, 1);
diff --git a/Src/zsh.h b/Src/zsh.h
index dda2fa91a..cc3a67008 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1645,9 +1645,18 @@ enum {
};
/* Flags as the second argument to prefork */
-#define PF_TYPESET 0x01 /* argument handled like typeset foo=bar */
-#define PF_ASSIGN 0x02 /* argument handled like the RHS of foo=bar */
-#define PF_SINGLE 0x04 /* single word substitution */
+/* argument handled like typeset foo=bar */
+#define PREFORK_TYPESET 0x01
+/* argument handled like the RHS of foo=bar */
+#define PREFORK_ASSIGN 0x02
+/* single word substitution */
+#define PREFORK_SINGLE 0x04
+/* explicitly split nested substitution */
+#define PREFORK_SPLIT 0x08
+/* SHWORDSPLIT in parameter expn */
+#define PREFORK_SHWORDSPLIT 0x10
+/* SHWORDSPLIT forced off in nested subst */
+#define PREFORK_NOSHWORDSPLIT 0x20
/*
* Structure for adding parameters in a module.
@@ -1986,6 +1995,7 @@ enum {
GLOBSUBST,
HASHCMDS,
HASHDIRS,
+ HASHEXECUTABLESONLY,
HASHLISTALL,
HISTALLOWCLOBBER,
HISTBEEP,