diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/pcre.c | 1 | ||||
-rw-r--r-- | Src/Zle/compcore.c | 2 | ||||
-rw-r--r-- | Src/Zle/complete.mdd | 2 | ||||
-rw-r--r-- | Src/Zle/zle_keymap.c | 1 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 16 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 81 | ||||
-rw-r--r-- | Src/Zle/zle_thingy.c | 64 | ||||
-rw-r--r-- | Src/builtin.c | 6 | ||||
-rw-r--r-- | Src/exec.c | 19 | ||||
-rw-r--r-- | Src/glob.c | 2 | ||||
-rw-r--r-- | Src/hashtable.c | 5 | ||||
-rw-r--r-- | Src/hist.c | 5 | ||||
-rw-r--r-- | Src/init.c | 14 | ||||
-rw-r--r-- | Src/options.c | 1 | ||||
-rw-r--r-- | Src/params.c | 4 | ||||
-rw-r--r-- | Src/subst.c | 143 | ||||
-rw-r--r-- | Src/zsh.h | 16 |
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); @@ -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, |