From c4dba4f2e654f40160ff97fdf691e9a33ea129b0 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Tue, 3 Jan 2017 14:41:38 -0800 Subject: users/22319: ${ary1:^ary2} should not change isarr state of expansion of ary1 Unless ary1 is made from a scalar, semantics of (@) in double quotes is lost. --- Src/subst.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Src/subst.c') diff --git a/Src/subst.c b/Src/subst.c index 64b440027..737a0a902 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -3066,7 +3066,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, if (sval) zip = hmkarray(sval); } - if (!isarr) aval = mkarray(val); + if (!isarr) { + aval = mkarray(val); + isarr = 1; + } if (zip) { char **out; int alen, ziplen, outlen, i = 0; @@ -3089,7 +3092,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, out[i*2] = NULL; aval = out; copied = 1; - isarr = 1; } } else { if (unset(UNSET)) { -- cgit v1.2.3 From 4d6097657cb8f19846c5b9e09069f6d4e43882e0 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 18 Jan 2017 09:57:55 +0000 Subject: 40375: autoload with explicit path mustn't trash already loaded function. Also remove unnecessary dupstring() on already duplicated string when expanding =cmd. --- ChangeLog | 6 ++++++ Src/builtin.c | 25 +++++++++++++++++++++++++ Src/subst.c | 8 ++++---- 3 files changed, 35 insertions(+), 4 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 1a4b4c2ce..189399ac5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-01-18 Peter Stephenson + + * 40375: Src/builtin.c, Src/subst.c: autoload with explicit path + mustn't trash already loaded function. Also drive-by removal of + duplicated duplication in =cmd expansion. + 2017-01-17 Peter Stephenson * unposted: Completion/Zsh/Command/_typeset: autoload ~... also diff --git a/Src/builtin.c b/Src/builtin.c index b1b6e2e30..7a04a79a7 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3369,6 +3369,31 @@ bin_functions(char *name, char **argv, Options ops, int func) removetrapnode(signum); } + if (**argv == '/') { + char *base = strrchr(*argv, '/') + 1; + if (*base && + (shf = (Shfunc) shfunctab->getnode(shfunctab, base))) { + char *dir; + /* turn on/off the given flags */ + shf->node.flags = + (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off; + if (shf->node.flags & PM_UNDEFINED) { + /* update path if not yet loaded */ + if (base == *argv + 1) + dir = "/"; + else { + dir = *argv; + base[-1] = '\0'; + } + dircache_set(&shf->filename, NULL); + dircache_set(&shf->filename, dir); + } + if (check_autoload(shf, shf->node.nam, ops, func)) + returnval = 1; + continue; + } + } + /* Add a new undefined (autoloaded) function to the * * hash table with the corresponding flags set. */ shf = (Shfunc) zshcalloc(sizeof *shf); diff --git a/Src/subst.c b/Src/subst.c index 737a0a902..670f3f0c6 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -622,7 +622,7 @@ filesub(char **namptr, int assign) char * equalsubstr(char *str, int assign, int nomatch) { - char *pp, *cnam, *cmdstr, *ret; + char *pp, *cnam, *cmdstr; for (pp = str; !isend2(*pp); pp++) ; @@ -634,10 +634,10 @@ equalsubstr(char *str, int assign, int nomatch) zerr("%s not found", cmdstr); return NULL; } - ret = dupstring(cnam); if (*pp) - ret = dyncat(ret, pp); - return ret; + return dyncat(cnam, pp); + else + return cnam; /* already duplicated */ } /**/ -- cgit v1.2.3 From b3c186028e8c13f9bc7afd0bd21d769874759c27 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Mon, 20 Feb 2017 09:57:25 -0800 Subject: 40593: SHWORDSPLIT + unset IFS should cause default splitting of $@ --- ChangeLog | 3 +++ Src/subst.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index df1097493..2f187a74b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2017-02-19 Barton E. Schaefer + * 40593: Src/subst.c: SHWORDSPLIT + unset IFS should cause default + splitting of $@ and other array references with (@) or [@] + * 40576 (tweaked): Src/exec.c: entersubsh(): small improvement to loop that resets trap handlers; unblock any signals that were blocked for trap handling diff --git a/Src/subst.c b/Src/subst.c index 670f3f0c6..1c2397c05 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -3476,7 +3476,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, val = sepjoin(aval, sep, 1); isarr = 0; ms_flags = 0; - } else if (force_split && (spsep || nojoin == 2)) { + } else if (force_split && + (spsep || nojoin == 2 || (!ifs && isarr < 0))) { /* Hack to simulate splitting individual elements: * forced joining as previously determined, or * join on what we later use to forcibly split -- cgit v1.2.3 From 74fe4d0950d5db0bba9d8ec182c4a827728cff60 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Mon, 20 Feb 2017 13:22:55 -0800 Subject: 40598: paramsubst() should always return scalar when PREFORK_SINGLE was passed --- ChangeLog | 5 ++++- Src/subst.c | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 0d3352a8e..60a5164d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ -2017-02-20 Barton E. Schaefer +2017-02-20 Barton E. Schaefer + + * 40598: Src/subst.c: paramsubst() should always return scalar + when PREFORK_SINGLE was passed in from prefork() * Martijn Dekker: 40565 (tweaked): test cases for assigning array to scalar with various combinations of SHWORDSPLIT and IFS diff --git a/Src/subst.c b/Src/subst.c index 1c2397c05..4df53bdb7 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -3475,7 +3475,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, if (nojoin == 0 || sep) { val = sepjoin(aval, sep, 1); isarr = 0; - ms_flags = 0; } else if (force_split && (spsep || nojoin == 2 || (!ifs && isarr < 0))) { /* Hack to simulate splitting individual elements: @@ -3485,6 +3484,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, val = sepjoin(aval, (nojoin == 1 ? NULL : spsep), 1); isarr = 0; } + if (!isarr) + ms_flags = 0; } if (force_split && !isarr) { aval = sepsplit(val, spsep, 0, 1); @@ -4007,6 +4008,18 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, y = dupstring(nulstring); setdata(n, (void *) y); } + if (isarr && ssub) { + /* prefork() wants a scalar, so join no matter what else */ + LinkNode tn; + + aval = hlinklist2array(l, 0); + val = sepjoin(aval, NULL, 1); + n = firstnode(l); + for (tn = lastnode(l); tn && tn != n; tn = lastnode(l)) + uremnode(l, tn); + setdata(n, (void *) val); + l->list.flags &= ~LF_ARRAY; + } if (eval) *str = (char *) getdata(n); -- cgit v1.2.3 From 4b8db48c6bd3c0230a5d81f49e478857adf9cda8 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 25 Feb 2017 15:55:14 -0800 Subject: 40640: the (A) parameter flag forces array result even if assignment syntax is not used --- ChangeLog | 6 ++++++ Doc/Zsh/expn.yo | 14 ++++++++++++-- Src/subst.c | 11 +++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 4d5b91205..5907112fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-02-25 Barton E. Schaefer + + * 40640 (plus doc typo fixed): Doc/Zsh/expn.yo, Src/subst.c: the + (A) parameter flag forces array result even if assignment syntax + is not used + 2017-02-25 Daniel Shahaf * unposted: Completion/Zsh/Context/_brace_parameter: Port 40617 diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 43ecd3155..016d8aef0 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -955,15 +955,25 @@ This is distinct from em(field splitting) by the tt(f), tt(s) or tt(z) flags, which still applies within each array element. ) item(tt(A))( -Assign as an array parameter with `tt(${)...tt(=)...tt(})', +Convert the substitution into an array expression, even if it otherwise +would be scalar. This has lower precedence than subscripting, so one +level of nested expansion is required in order that subscripts apply +to array elements. Thus tt(${${LPAR()A)tt(RPAR())var(name)tt(}[1]}) +yields the full value of var(name) when var(name) is scalar. + +This assigns an array parameter with `tt(${)...tt(=)...tt(})', `tt(${)...tt(:=)...tt(})' or `tt(${)...tt(::=)...tt(})'. -If this flag is repeated (as in `tt(AA)'), assign an associative +If this flag is repeated (as in `tt(AA)'), assigns an associative array parameter. Assignment is made before sorting or padding; if field splitting is active, the var(word) part is split before assignment. The var(name) part may be a subscripted range for ordinary arrays; when assigning an associative array, the var(word) part em(must) be converted to an array, for example by using `tt(${(AA)=)var(name)tt(=)...tt(})' to activate field splitting. + +Surrounding context such as additional nesting or use of the value +in a scalar assignment may cause the array to be joined back into +a single string again. ) item(tt(a))( Sort in array index order; when combined with `tt(O)' sort in reverse diff --git a/Src/subst.c b/Src/subst.c index 4df53bdb7..02dbe2864 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2902,6 +2902,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, } else setaparam(idbeg, a); isarr = 1; + arrasg = 0; } else { untokenize(val); setsparam(idbeg, ztrdup(val)); @@ -3784,6 +3785,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, insertlinknode(l, n, dupstring(fstr)); /* appended, no incnode */ *fstr = '\0'; } + if (arrasg && !isarr) { + /* + * Caller requested this be forced to an array even if scalar. + * Any point in distinguishing arrasg == 2 (assoc array) here? + */ + l->list.flags |= LF_ARRAY; + aval = hmkarray(val); + isarr = 1; + DPUTS(!val, "value is NULL in paramsubst, empty array"); + } if (isarr) { char *x; char *y; -- cgit v1.2.3 From f3f8537cfa05414ad14494e809d9ebfeef86ebbc Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 7 Mar 2017 10:43:58 +0000 Subject: 40760: Always tokenize unquoted - to Dash. This fixes use of pattern match character ranges in unusual contexts. Attempt to detect a tokenized - in cases where we don't care. --- ChangeLog | 8 ++++++++ Src/cond.c | 8 ++++---- Src/exec.c | 11 ++++++----- Src/glob.c | 23 +++++++++++++---------- Src/lex.c | 16 ++++++---------- Src/math.c | 7 ++++--- Src/parse.c | 41 +++++++++++++++++++++++++++-------------- Src/pattern.c | 2 +- Src/subst.c | 41 ++++++++++++++++++++++++----------------- Src/utils.c | 10 +++++++--- Src/zsh.h | 10 ++++++++++ Test/D02glob.ztst | 6 ++++++ 12 files changed, 116 insertions(+), 67 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 3532aa044..8fcf7e069 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-03-07 Peter Stephenson + + * 40760: Src/cond.c, Src/exec.c, Src/glob.c, Src/lex.c, + Src/math.c, Src/parse.c, Src/pattern.c, Src/subst.c, + Src/utils.c, Src/zsh.h, Test/D02glob.ztst: Always tokenise '-' + to Dash to eliminate niggles with range matches in complicated + contexts. Match both - or Dash in contexts that don't care. + 2017-03-07 Mikael Magnusson * 40780: Completion/Unix/Command/_mount: Don't use =~ for simple diff --git a/Src/cond.c b/Src/cond.c index 8ab019307..9b739f6c1 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -138,13 +138,13 @@ evalcond(Estate state, char *fromtest) strs = arrdup(sbuf); l = 2; } - if (name && name[0] == '-') + if (name && IS_DASH(name[0])) errname = name; - else if (strs[0] && *strs[0] == '-') + else if (strs[0] && IS_DASH(*strs[0])) errname = strs[0]; else errname = ""; - if (name && name[0] == '-' && + if (name && IS_DASH(name[0]) && (cd = getconddef((ctype == COND_MODI), name + 1, 1))) { if (ctype == COND_MOD && (l < cd->min || (cd->max >= 0 && l > cd->max))) { @@ -171,7 +171,7 @@ evalcond(Estate state, char *fromtest) strs[0] = dupstring(name); name = s; - if (name && name[0] == '-' && + if (name && IS_DASH(name[0]) && (cd = getconddef(0, name + 1, 1))) { if (l < cd->min || (cd->max >= 0 && l > cd->max)) { zwarnnam(fromtest, "unknown condition: %s", diff --git a/Src/exec.c b/Src/exec.c index 6af4ddbf3..8b3224652 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2779,9 +2779,10 @@ execcmd_exec(Estate state, Execcmd_params eparams, char *argdata = (char *) getdata(argnode); char *cmdopt; int has_p = 0, has_vV = 0, has_other = 0; - while (*argdata == '-') { + while (IS_DASH(*argdata)) { /* Just to be definite, stop on single "-", too, */ - if (!argdata[1] || (argdata[1] == '-' && !argdata[2])) + if (!argdata[1] || + (IS_DASH(argdata[1]) && !argdata[2])) break; for (cmdopt = argdata+1; *cmdopt; cmdopt++) { switch (*cmdopt) { @@ -2835,7 +2836,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, * as if this is command [non-option-stuff]. This * isn't a good place for standard option handling. */ - if (!strcmp(argdata, "--")) + if (IS_DASH(argdata[0]) && IS_DASH(argdata[1]) && !argdata[2]) uremnode(args, firstnode(args)); } if ((cflags & BINF_EXEC) && nextnode(firstnode(args))) { @@ -2855,7 +2856,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, * people aren't likely to mix the option style * with the zsh style. */ - while (next && *next == '-' && strlen(next) >= 2) { + while (next && IS_DASH(*next) && strlen(next) >= 2) { if (!firstnode(args)) { zerr("exec requires a command to execute"); lastval = 1; @@ -2863,7 +2864,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, goto done; } uremnode(args, firstnode(args)); - if (!strcmp(next, "--")) + if (IS_DASH(next[0]) && IS_DASH(next[1]) && !next[2]) break; for (cmdopt = &next[1]; *cmdopt; ++cmdopt) { switch (*cmdopt) { diff --git a/Src/glob.c b/Src/glob.c index ff6b2583b..87127e15f 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -1314,6 +1314,7 @@ zglob(LinkList list, LinkNode np, int nountok) sense ^= 1; break; case '-': + case Dash: /* Toggle matching of symbolic links */ sense ^= 2; break; @@ -1608,7 +1609,7 @@ zglob(LinkList list, LinkNode np, int nountok) ++s; } /* See if it's greater than, equal to, or less than */ - if ((g_range = *s == '+' ? 1 : *s == '-' ? -1 : 0)) + if ((g_range = *s == '+' ? 1 : IS_DASH(*s) ? -1 : 0)) ++s; data = qgetnum(&s); break; @@ -2025,13 +2026,13 @@ hasbraces(char *str) if (bracechardots(str-1, NULL, NULL)) return 1; lbr = str - 1; - if (*str == '-') + if (IS_DASH(*str)) str++; while (idigit(*str)) str++; if (*str == '.' && str[1] == '.') { str++; str++; - if (*str == '-') + if (IS_DASH(*str)) str++; while (idigit(*str)) str++; @@ -2040,7 +2041,7 @@ hasbraces(char *str) return 1; else if (*str == '.' && str[1] == '.') { str++; str++; - if (*str == '-') + if (IS_DASH(*str)) str++; while (idigit(*str)) str++; @@ -2123,7 +2124,7 @@ xpandredir(struct redir *fn, LinkList redirtab) fn->name = s; untokenize(s); if (fn->type == REDIR_MERGEIN || fn->type == REDIR_MERGEOUT) { - if (s[0] == '-' && !s[1]) + if (IS_DASH(s[0]) && !s[1]) fn->type = REDIR_CLOSE; else if (s[0] == 'p' && !s[1]) fn->fd2 = -2; @@ -2329,12 +2330,14 @@ xpandbraces(LinkList list, LinkNode *np) * str+1 is the first number in the range, dots+2 the last, * and dots2+2 is the increment if that's given. */ /* TODO: sorry about this */ - int minw = (str[1] == '0' || (str[1] == '-' && str[2] == '0')) + int minw = (str[1] == '0' || + (IS_DASH(str[1]) && str[2] == '0')) ? wid1 - : (dots[2] == '0' || (dots[2] == '-' && dots[3] == '0')) + : (dots[2] == '0' || + (IS_DASH(dots[2]) && dots[3] == '0')) ? wid2 : (dots2 && (dots2[2] == '0' || - (dots2[2] == '-' && dots2[3] == '0'))) + (IS_DASH(dots2[2]) && dots2[3] == '0'))) ? wid3 : 0; if (rincr < 0) { @@ -2392,7 +2395,7 @@ xpandbraces(LinkList list, LinkNode *np) c2 = ztokens[c2 - STOUC(Pound)]; if ((char) c2 == Meta) c2 = 32 ^ p[1]; - if (c1 == '-' && lastch >= 0 && p < str2 && lastch <= (int)c2) { + if (IS_DASH(c1) && lastch >= 0 && p < str2 && lastch <= (int)c2) { while (lastch < (int)c2) ccl[lastch++] = 1; lastch = -1; @@ -3528,7 +3531,7 @@ zshtokenize(char *s, int flags) } t = s; while (idigit(*++s)); - if (*s != '-') + if (!IS_DASH(*s)) goto cont; while (idigit(*++s)); if (*s != '>') diff --git a/Src/lex.c b/Src/lex.c index 889612825..59e9d1472 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -1359,17 +1359,13 @@ gettokstr(int c, int sub) case LX2_DASH: /* * - shouldn't be treated as a special character unless - * we're in a pattern. Howeve,simply counting "[" doesn't - * work as []a-z] is a valid expression and we don't know - * down here what this "[" is for as $foo[stuff] is valid - * in zsh. So just detect an opening [, which is enough - * to turn this into a pattern; the Dash will be harmlessly - * untokenised if not wanted. + * we're in a pattern. Unfortunately, working out for + * sure in complicated expressions whether we're in a + * pattern is tricky. So we'll make it special and + * turn it back any time we don't need it special. + * This is not ideal as it's a lot of work. */ - if (seen_brct) - c = Dash; - else - c = '-'; + c = Dash; break; case LX2_BANG: /* diff --git a/Src/math.c b/Src/math.c index f19c0ed61..f9613001a 100644 --- a/Src/math.c +++ b/Src/math.c @@ -463,7 +463,7 @@ lexconstant(void) char *nptr; nptr = ptr; - if (*nptr == '-') + if (IS_DASH(*nptr)) nptr++; if (*nptr == '0') { @@ -527,7 +527,7 @@ lexconstant(void) } if (*nptr == 'e' || *nptr == 'E') { nptr++; - if (*nptr == '+' || *nptr == '-') + if (*nptr == '+' || IS_DASH(*nptr)) nptr++; while (idigit(*nptr) || *nptr == '_') nptr++; @@ -599,7 +599,8 @@ zzlex(void) } return (unary) ? UPLUS : PLUS; case '-': - if (*ptr == '-') { + case Dash: + if (IS_DASH(*ptr)) { ptr++; return (unary) ? PREMINUS : POSTMINUS; } diff --git a/Src/parse.c b/Src/parse.c index 699ea49a2..6fe283dcb 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -2316,6 +2316,19 @@ par_cond_1(void) return r; } +/* + * Return 1 if condition matches. This also works for non-elided options. + * + * input is test string, may begin - or Dash. + * cond is condition following the -. + */ +static int check_cond(const char *input, const char *cond) +{ + if (!IS_DASH(input[0])) + return 0; + return !strcmp(input + 1, cond); +} + /* * cond_2 : BANG cond_2 | INPAR { SEPER } cond_2 { SEPER } OUTPAR @@ -2342,7 +2355,7 @@ par_cond_2(void) s1 = tokstr; condlex(); /* ksh behavior: [ -t ] means [ -t 1 ]; bash disagrees */ - if (unset(POSIXBUILTINS) && !strcmp(s1, "-t")) + if (unset(POSIXBUILTINS) && check_cond(s1, "t")) return par_cond_double(s1, dupstring("1")); return par_cond_double(dupstring("-n"), s1); } @@ -2352,7 +2365,7 @@ par_cond_2(void) if (!strcmp(*testargs, "=") || !strcmp(*testargs, "==") || !strcmp(*testargs, "!=") || - (**testargs == '-' && get_cond_num(*testargs + 1) >= 0)) { + (IS_DASH(**testargs) && get_cond_num(*testargs + 1) >= 0)) { s1 = tokstr; condlex(); s2 = tokstr; @@ -2374,8 +2387,8 @@ par_cond_2(void) * In "test" compatibility mode, "! -a ..." and "! -o ..." * are treated as "[string] [and] ..." and "[string] [or] ...". */ - if (!(n_testargs > 1 && - (!strcmp(*testargs, "-a") || !strcmp(*testargs, "-o")))) + if (!(n_testargs > 1 && (check_cond(*testargs, "a") || + check_cond(*testargs, "o")))) { condlex(); ecadd(WCB_COND(COND_NOT, 0)); @@ -2397,7 +2410,7 @@ par_cond_2(void) return r; } s1 = tokstr; - dble = (s1 && *s1 == '-' + dble = (s1 && IS_DASH(*s1) && (!n_testargs || strspn(s1+1, "abcdefghknoprstuvwxzLONGS") == 1) && !s1[2]); @@ -2411,7 +2424,7 @@ par_cond_2(void) YYERROR(ecused); } condlex(); - if (n_testargs == 2 && tok != STRING && tokstr && s1[0] == '-') { + if (n_testargs == 2 && tok != STRING && tokstr && IS_DASH(s1[0])) { /* * Something like "test -z" followed by a token. * We'll turn the token into a string (we've also @@ -2446,9 +2459,9 @@ par_cond_2(void) } else YYERROR(ecused); } - s2 = tokstr; + s2 = tokstr; if (!n_testargs) - dble = (s2 && *s2 == '-' && !s2[2]); + dble = (s2 && IS_DASH(*s2) && !s2[2]); incond++; /* parentheses do globbing */ do condlex(); while (COND_SEP()); incond--; /* parentheses do grouping */ @@ -2476,7 +2489,7 @@ par_cond_2(void) static int par_cond_double(char *a, char *b) { - if (a[0] != '-' || !a[1]) + if (!IS_DASH(a[0]) || !a[1]) COND_ERROR("parse error: condition expected: %s", a); else if (!a[2] && strspn(a+1, "abcdefgknoprstuvwxzhLONGS") == 1) { ecadd(WCB_COND(a[1], 0)); @@ -2534,7 +2547,7 @@ par_cond_triple(char *a, char *b, char *c) ecadd(WCB_COND(COND_REGEX, 0)); ecstr(a); ecstr(c); - } else if (b[0] == '-') { + } else if (IS_DASH(b[0])) { if ((t0 = get_cond_num(b + 1)) > -1) { ecadd(WCB_COND(t0 + COND_NT, 0)); ecstr(a); @@ -2545,7 +2558,7 @@ par_cond_triple(char *a, char *b, char *c) ecstr(a); ecstr(c); } - } else if (a[0] == '-' && a[1]) { + } else if (IS_DASH(a[0]) && a[1]) { ecadd(WCB_COND(COND_MOD, 2)); ecstr(a); ecstr(b); @@ -2560,7 +2573,7 @@ par_cond_triple(char *a, char *b, char *c) static int par_cond_multi(char *a, LinkList l) { - if (a[0] != '-' || !a[1]) + if (!IS_DASH(a[0]) || !a[1]) COND_ERROR("condition expected: %s", a); else { LinkNode n; @@ -3256,10 +3269,10 @@ build_dump(char *nam, char *dump, char **files, int ali, int map, int flags) for (hlen = FD_PRELEN, tlen = 0; *files; files++) { struct stat st; - if (!strcmp(*files, "-k")) { + if (check_cond(*files, "k")) { flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD; continue; - } else if (!strcmp(*files, "-z")) { + } else if (check_cond(*files, "z")) { flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_ZSHLOAD; continue; } diff --git a/Src/pattern.c b/Src/pattern.c index 928790f45..75db01634 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -1521,7 +1521,7 @@ patcomppiece(int *flagp, int paren) patparse = nptr; len |= 1; } - DPUTS(*patparse != '-', "BUG: - missing from numeric glob"); + DPUTS(!IS_DASH(*patparse), "BUG: - missing from numeric glob"); patparse++; if (idigit(*patparse)) { to = (zrange_t) zstrtol((char *)patparse, diff --git a/Src/subst.c b/Src/subst.c index 02dbe2864..2214b3d4f 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -481,6 +481,8 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, for ( ; *x; x += l) { int rawc = -1; convchar_t c; + if (*x == Dash) + *x = '-'; if (itok(STOUC(*x))) { /* token, can't be separator, must be single byte */ rawc = *x; @@ -1766,7 +1768,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, */ c = *s; if (itype_end(s, IIDENT, 1) == s && *s != '#' && c != Pound && - c != '-' && c != '!' && c != '$' && c != String && c != Qstring && + !IS_DASH(c) && + c != '!' && c != '$' && c != String && c != Qstring && c != '?' && c != Quest && c != '*' && c != Star && c != '@' && c != '{' && c != Inbrace && c != '=' && c != Equals && c != Hat && @@ -1895,13 +1898,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, if (quotetype == QT_DOLLARS || quotetype == QT_BACKSLASH_PATTERN) goto flagerr; - if (s[1] == '-' || s[1] == '+') { + if (IS_DASH(s[1]) || s[1] == '+') { if (quotemod) goto flagerr; s++; quotemod = 1; - quotetype = (*s == '-') ? QT_SINGLE_OPTIONAL : - QT_QUOTEDZPUTS; + quotetype = (*s == '+') ? QT_QUOTEDZPUTS : + QT_SINGLE_OPTIONAL; } else { if (quotetype == QT_SINGLE_OPTIONAL) { /* extra q's after '-' not allowed */ @@ -2208,9 +2211,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * properly in the first place we wouldn't * have this nonsense. */ - || ((cc == '#' || cc == Pound) && - s[2] == Outbrace) - || cc == '-' || (cc == ':' && s[2] == '-') + || ((cc == '#' || cc == Pound) && s[2] == Outbrace) + || IS_DASH(cc) + || (cc == ':' && IS_DASH(s[2])) || (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) { getlen = 1 + whichlen, s++; /* @@ -2605,14 +2608,17 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * Again, this duplicates tests for characters we're about to * examine properly later on. */ - if (inbrace && - (c = *s) != '-' && c != '+' && c != ':' && c != '%' && c != '/' && - c != '=' && c != Equals && - c != '#' && c != Pound && - c != '?' && c != Quest && - c != '}' && c != Outbrace) { - zerr("bad substitution"); - return NULL; + if (inbrace) { + c = *s; + if (!IS_DASH(c) && + c != '+' && c != ':' && c != '%' && c != '/' && + c != '=' && c != Equals && + c != '#' && c != Pound && + c != '?' && c != Quest && + c != '}' && c != Outbrace) { + zerr("bad substitution"); + return NULL; + } } /* * Join arrays up if we're in quotes and there isn't some @@ -2690,8 +2696,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, /* Check for ${..?..} or ${..=..} or one of those. * * Only works if the name is in braces. */ - if (inbrace && ((c = *s) == '-' || - c == '+' || + if (inbrace && ((c = *s) == '+' || + IS_DASH(c) || c == ':' || /* i.e. a doubled colon */ c == '=' || c == Equals || c == '%' || @@ -2802,6 +2808,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, vunset = 1; /* Fall Through! */ case '-': + case Dash: if (vunset) { int split_flags; val = dupstring(s); diff --git a/Src/utils.c b/Src/utils.c index 7f3ddad40..9669944f6 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2376,7 +2376,7 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore) while (inblank(*s)) s++; - if ((neg = (*s == '-'))) + if ((neg = IS_DASH(*s))) s++; else if (*s == '+') s++; @@ -6118,7 +6118,9 @@ quotedzputs(char const *s, FILE *stream) } else *ptr++ = '\''; while(*s) { - if (*s == Meta) + if (*s == Dash) + c = '-'; + else if (*s == Meta) c = *++s ^ 32; else c = *s; @@ -6155,7 +6157,9 @@ quotedzputs(char const *s, FILE *stream) } else { /* use Bourne-style quoting, avoiding empty quoted strings */ while (*s) { - if (*s == Meta) + if (*s == Dash) + c = '-'; + else if (*s == Meta) c = *++s ^ 32; else c = *s; diff --git a/Src/zsh.h b/Src/zsh.h index f2c279002..10931512d 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -237,6 +237,16 @@ struct mathfunc { #define PATCHARS "#^*()|[]<>?~\\" +/* + * Check for a possibly tokenized dash. + * + * A dash only needs to be a token in a character range, [a-z], but + * it's difficult in general to ensure that. So it's turned into + * a token at the usual point in the lexer. However, we need + * to check for a literal dash at many points. + */ +#define IS_DASH(x) ((x) == '-' || (x) == Dash) + /* * Types of quote. This is used in various places, so care needs * to be taken when changing them. (Oooh, don't you look surprised.) diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst index 1385d57d9..413381f92 100644 --- a/Test/D02glob.ztst +++ b/Test/D02glob.ztst @@ -686,3 +686,9 @@ rm glob.tmp/link 0:modifier ':P' resolves symlinks before '..' components *>*glob.tmp/hello/world + + foo=a + value="ac" + print ${value//[${foo}b-z]/x} +0:handling of - range in complicated pattern context +>xx -- cgit v1.2.3 From 420fc41b7cccab7f1ee07abab2cb7c72501cf91e Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 11 Mar 2017 14:39:17 -0800 Subject: 40832: fix $x:P when PWD=/ --- ChangeLog | 4 ++++ Src/subst.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 2e72fb759..9744a1ee7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-03-11 Barton E. Schaefer + + * 40832: Src/subst.c: fix $x:P when PWD=/ + 2017-03-11 John Leuenhagen * unposted (github pull request #15): diff --git a/Src/subst.c b/Src/subst.c index 2214b3d4f..e639c96a8 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -4336,7 +4336,11 @@ modify(char **str, char **ptr) break; case 'P': if (*copy != '/') { - copy = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", copy); + char *here = zgetcwd(); + if (here[strlen(here)-1] != '/') + copy = zhtricat(metafy(here, -1, META_HEAPDUP), "/", copy); + else + copy = dyncat(here, copy); } copy = xsymlink(copy, 1); break; @@ -4418,7 +4422,11 @@ modify(char **str, char **ptr) break; case 'P': if (**str != '/') { - *str = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *str); + char *here = zgetcwd(); + if (here[strlen(here)-1] != '/') + *str = zhtricat(metafy(here, -1, META_HEAPDUP), "/", *str); + else + *str = dyncat(here, *str); } *str = xsymlink(*str, 1); break; -- cgit v1.2.3 From 207263a61e54a413d02c52f08d7771dd082d20f1 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 2 Apr 2017 14:43:27 -0700 Subject: 40929 (replaces 40598): paramsubst() should always return scalar when PREFORK_SINGLE was passed in from prefork() Previous commit (74fe4d09) consumed too much of the input linked list, leading to later expansions being skipped. This commit converts from array to string sooner, but may thereby alter rc_expand_param and array element uniqueness behavior. --- ChangeLog | 5 +++++ Src/subst.c | 21 ++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 044bbb0df..892d1f25e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-04-02 Barton E. Schaefer + + * 40929 (replaces 40598): Src/subst.c: paramsubst() should always + return scalar when PREFORK_SINGLE was passed in from prefork() + 2017-04-01 Barton E. Schaefer * Sebastian: 40782: Completion/Unix/Type/_hosts: avoid dependency diff --git a/Src/subst.c b/Src/subst.c index e639c96a8..5b1bf8988 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -446,7 +446,7 @@ singsub(char **s) * NULL to use IFS). The return value is true iff the expansion resulted * in an empty list. * - * *ms_flags is set to bits in the enum above as neeed. + * *ms_flags is set to bits in the enum above as needed. */ /**/ @@ -3779,6 +3779,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * as a scalar.) */ + if (isarr && ssub) { + /* prefork() wants a scalar, so join no matter what else */ + val = sepjoin(aval, NULL, 1); + isarr = 0; + l->list.flags &= ~LF_ARRAY; + } + /* * If a multsub result had whitespace at the start and we're * splitting and there's a previous string, now's the time to do so. @@ -4026,18 +4033,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, y = dupstring(nulstring); setdata(n, (void *) y); } - if (isarr && ssub) { - /* prefork() wants a scalar, so join no matter what else */ - LinkNode tn; - - aval = hlinklist2array(l, 0); - val = sepjoin(aval, NULL, 1); - n = firstnode(l); - for (tn = lastnode(l); tn && tn != n; tn = lastnode(l)) - uremnode(l, tn); - setdata(n, (void *) val); - l->list.flags &= ~LF_ARRAY; - } if (eval) *str = (char *) getdata(n); -- cgit v1.2.3