1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-07 21:31:17 +02:00

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.
This commit is contained in:
Peter Stephenson 2017-03-07 10:43:58 +00:00
parent a8345a40b1
commit f3f8537cfa
12 changed files with 116 additions and 67 deletions

View file

@ -1,3 +1,11 @@
2017-03-07 Peter Stephenson <p.stephenson@samsung.com>
* 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 <mikachu@gmail.com> 2017-03-07 Mikael Magnusson <mikachu@gmail.com>
* 40780: Completion/Unix/Command/_mount: Don't use =~ for simple * 40780: Completion/Unix/Command/_mount: Don't use =~ for simple

View file

@ -138,13 +138,13 @@ evalcond(Estate state, char *fromtest)
strs = arrdup(sbuf); strs = arrdup(sbuf);
l = 2; l = 2;
} }
if (name && name[0] == '-') if (name && IS_DASH(name[0]))
errname = name; errname = name;
else if (strs[0] && *strs[0] == '-') else if (strs[0] && IS_DASH(*strs[0]))
errname = strs[0]; errname = strs[0];
else else
errname = "<null>"; errname = "<null>";
if (name && name[0] == '-' && if (name && IS_DASH(name[0]) &&
(cd = getconddef((ctype == COND_MODI), name + 1, 1))) { (cd = getconddef((ctype == COND_MODI), name + 1, 1))) {
if (ctype == COND_MOD && if (ctype == COND_MOD &&
(l < cd->min || (cd->max >= 0 && l > cd->max))) { (l < cd->min || (cd->max >= 0 && l > cd->max))) {
@ -171,7 +171,7 @@ evalcond(Estate state, char *fromtest)
strs[0] = dupstring(name); strs[0] = dupstring(name);
name = s; name = s;
if (name && name[0] == '-' && if (name && IS_DASH(name[0]) &&
(cd = getconddef(0, name + 1, 1))) { (cd = getconddef(0, name + 1, 1))) {
if (l < cd->min || (cd->max >= 0 && l > cd->max)) { if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
zwarnnam(fromtest, "unknown condition: %s", zwarnnam(fromtest, "unknown condition: %s",

View file

@ -2779,9 +2779,10 @@ execcmd_exec(Estate state, Execcmd_params eparams,
char *argdata = (char *) getdata(argnode); char *argdata = (char *) getdata(argnode);
char *cmdopt; char *cmdopt;
int has_p = 0, has_vV = 0, has_other = 0; int has_p = 0, has_vV = 0, has_other = 0;
while (*argdata == '-') { while (IS_DASH(*argdata)) {
/* Just to be definite, stop on single "-", too, */ /* 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; break;
for (cmdopt = argdata+1; *cmdopt; cmdopt++) { for (cmdopt = argdata+1; *cmdopt; cmdopt++) {
switch (*cmdopt) { switch (*cmdopt) {
@ -2835,7 +2836,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* as if this is command [non-option-stuff]. This * as if this is command [non-option-stuff]. This
* isn't a good place for standard option handling. * 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)); uremnode(args, firstnode(args));
} }
if ((cflags & BINF_EXEC) && nextnode(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 * people aren't likely to mix the option style
* with the zsh style. * with the zsh style.
*/ */
while (next && *next == '-' && strlen(next) >= 2) { while (next && IS_DASH(*next) && strlen(next) >= 2) {
if (!firstnode(args)) { if (!firstnode(args)) {
zerr("exec requires a command to execute"); zerr("exec requires a command to execute");
lastval = 1; lastval = 1;
@ -2863,7 +2864,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
goto done; goto done;
} }
uremnode(args, firstnode(args)); uremnode(args, firstnode(args));
if (!strcmp(next, "--")) if (IS_DASH(next[0]) && IS_DASH(next[1]) && !next[2])
break; break;
for (cmdopt = &next[1]; *cmdopt; ++cmdopt) { for (cmdopt = &next[1]; *cmdopt; ++cmdopt) {
switch (*cmdopt) { switch (*cmdopt) {

View file

@ -1314,6 +1314,7 @@ zglob(LinkList list, LinkNode np, int nountok)
sense ^= 1; sense ^= 1;
break; break;
case '-': case '-':
case Dash:
/* Toggle matching of symbolic links */ /* Toggle matching of symbolic links */
sense ^= 2; sense ^= 2;
break; break;
@ -1608,7 +1609,7 @@ zglob(LinkList list, LinkNode np, int nountok)
++s; ++s;
} }
/* See if it's greater than, equal to, or less than */ /* 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; ++s;
data = qgetnum(&s); data = qgetnum(&s);
break; break;
@ -2025,13 +2026,13 @@ hasbraces(char *str)
if (bracechardots(str-1, NULL, NULL)) if (bracechardots(str-1, NULL, NULL))
return 1; return 1;
lbr = str - 1; lbr = str - 1;
if (*str == '-') if (IS_DASH(*str))
str++; str++;
while (idigit(*str)) while (idigit(*str))
str++; str++;
if (*str == '.' && str[1] == '.') { if (*str == '.' && str[1] == '.') {
str++; str++; str++; str++;
if (*str == '-') if (IS_DASH(*str))
str++; str++;
while (idigit(*str)) while (idigit(*str))
str++; str++;
@ -2040,7 +2041,7 @@ hasbraces(char *str)
return 1; return 1;
else if (*str == '.' && str[1] == '.') { else if (*str == '.' && str[1] == '.') {
str++; str++; str++; str++;
if (*str == '-') if (IS_DASH(*str))
str++; str++;
while (idigit(*str)) while (idigit(*str))
str++; str++;
@ -2123,7 +2124,7 @@ xpandredir(struct redir *fn, LinkList redirtab)
fn->name = s; fn->name = s;
untokenize(s); untokenize(s);
if (fn->type == REDIR_MERGEIN || fn->type == REDIR_MERGEOUT) { 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; fn->type = REDIR_CLOSE;
else if (s[0] == 'p' && !s[1]) else if (s[0] == 'p' && !s[1])
fn->fd2 = -2; 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, * str+1 is the first number in the range, dots+2 the last,
* and dots2+2 is the increment if that's given. */ * and dots2+2 is the increment if that's given. */
/* TODO: sorry about this */ /* 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 ? wid1
: (dots[2] == '0' || (dots[2] == '-' && dots[3] == '0')) : (dots[2] == '0' ||
(IS_DASH(dots[2]) && dots[3] == '0'))
? wid2 ? wid2
: (dots2 && (dots2[2] == '0' || : (dots2 && (dots2[2] == '0' ||
(dots2[2] == '-' && dots2[3] == '0'))) (IS_DASH(dots2[2]) && dots2[3] == '0')))
? wid3 ? wid3
: 0; : 0;
if (rincr < 0) { if (rincr < 0) {
@ -2392,7 +2395,7 @@ xpandbraces(LinkList list, LinkNode *np)
c2 = ztokens[c2 - STOUC(Pound)]; c2 = ztokens[c2 - STOUC(Pound)];
if ((char) c2 == Meta) if ((char) c2 == Meta)
c2 = 32 ^ p[1]; 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) while (lastch < (int)c2)
ccl[lastch++] = 1; ccl[lastch++] = 1;
lastch = -1; lastch = -1;
@ -3528,7 +3531,7 @@ zshtokenize(char *s, int flags)
} }
t = s; t = s;
while (idigit(*++s)); while (idigit(*++s));
if (*s != '-') if (!IS_DASH(*s))
goto cont; goto cont;
while (idigit(*++s)); while (idigit(*++s));
if (*s != '>') if (*s != '>')

View file

@ -1359,17 +1359,13 @@ gettokstr(int c, int sub)
case LX2_DASH: case LX2_DASH:
/* /*
* - shouldn't be treated as a special character unless * - shouldn't be treated as a special character unless
* we're in a pattern. Howeve,simply counting "[" doesn't * we're in a pattern. Unfortunately, working out for
* work as []a-z] is a valid expression and we don't know * sure in complicated expressions whether we're in a
* down here what this "[" is for as $foo[stuff] is valid * pattern is tricky. So we'll make it special and
* in zsh. So just detect an opening [, which is enough * turn it back any time we don't need it special.
* to turn this into a pattern; the Dash will be harmlessly * This is not ideal as it's a lot of work.
* untokenised if not wanted.
*/ */
if (seen_brct)
c = Dash; c = Dash;
else
c = '-';
break; break;
case LX2_BANG: case LX2_BANG:
/* /*

View file

@ -463,7 +463,7 @@ lexconstant(void)
char *nptr; char *nptr;
nptr = ptr; nptr = ptr;
if (*nptr == '-') if (IS_DASH(*nptr))
nptr++; nptr++;
if (*nptr == '0') { if (*nptr == '0') {
@ -527,7 +527,7 @@ lexconstant(void)
} }
if (*nptr == 'e' || *nptr == 'E') { if (*nptr == 'e' || *nptr == 'E') {
nptr++; nptr++;
if (*nptr == '+' || *nptr == '-') if (*nptr == '+' || IS_DASH(*nptr))
nptr++; nptr++;
while (idigit(*nptr) || *nptr == '_') while (idigit(*nptr) || *nptr == '_')
nptr++; nptr++;
@ -599,7 +599,8 @@ zzlex(void)
} }
return (unary) ? UPLUS : PLUS; return (unary) ? UPLUS : PLUS;
case '-': case '-':
if (*ptr == '-') { case Dash:
if (IS_DASH(*ptr)) {
ptr++; ptr++;
return (unary) ? PREMINUS : POSTMINUS; return (unary) ? PREMINUS : POSTMINUS;
} }

View file

@ -2316,6 +2316,19 @@ par_cond_1(void)
return r; 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 * cond_2 : BANG cond_2
| INPAR { SEPER } cond_2 { SEPER } OUTPAR | INPAR { SEPER } cond_2 { SEPER } OUTPAR
@ -2342,7 +2355,7 @@ par_cond_2(void)
s1 = tokstr; s1 = tokstr;
condlex(); condlex();
/* ksh behavior: [ -t ] means [ -t 1 ]; bash disagrees */ /* 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(s1, dupstring("1"));
return par_cond_double(dupstring("-n"), s1); return par_cond_double(dupstring("-n"), s1);
} }
@ -2352,7 +2365,7 @@ par_cond_2(void)
if (!strcmp(*testargs, "=") || if (!strcmp(*testargs, "=") ||
!strcmp(*testargs, "==") || !strcmp(*testargs, "==") ||
!strcmp(*testargs, "!=") || !strcmp(*testargs, "!=") ||
(**testargs == '-' && get_cond_num(*testargs + 1) >= 0)) { (IS_DASH(**testargs) && get_cond_num(*testargs + 1) >= 0)) {
s1 = tokstr; s1 = tokstr;
condlex(); condlex();
s2 = tokstr; s2 = tokstr;
@ -2374,8 +2387,8 @@ par_cond_2(void)
* In "test" compatibility mode, "! -a ..." and "! -o ..." * In "test" compatibility mode, "! -a ..." and "! -o ..."
* are treated as "[string] [and] ..." and "[string] [or] ...". * are treated as "[string] [and] ..." and "[string] [or] ...".
*/ */
if (!(n_testargs > 1 && if (!(n_testargs > 1 && (check_cond(*testargs, "a") ||
(!strcmp(*testargs, "-a") || !strcmp(*testargs, "-o")))) check_cond(*testargs, "o"))))
{ {
condlex(); condlex();
ecadd(WCB_COND(COND_NOT, 0)); ecadd(WCB_COND(COND_NOT, 0));
@ -2397,7 +2410,7 @@ par_cond_2(void)
return r; return r;
} }
s1 = tokstr; s1 = tokstr;
dble = (s1 && *s1 == '-' dble = (s1 && IS_DASH(*s1)
&& (!n_testargs && (!n_testargs
|| strspn(s1+1, "abcdefghknoprstuvwxzLONGS") == 1) || strspn(s1+1, "abcdefghknoprstuvwxzLONGS") == 1)
&& !s1[2]); && !s1[2]);
@ -2411,7 +2424,7 @@ par_cond_2(void)
YYERROR(ecused); YYERROR(ecused);
} }
condlex(); 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. * Something like "test -z" followed by a token.
* We'll turn the token into a string (we've also * We'll turn the token into a string (we've also
@ -2448,7 +2461,7 @@ par_cond_2(void)
} }
s2 = tokstr; s2 = tokstr;
if (!n_testargs) if (!n_testargs)
dble = (s2 && *s2 == '-' && !s2[2]); dble = (s2 && IS_DASH(*s2) && !s2[2]);
incond++; /* parentheses do globbing */ incond++; /* parentheses do globbing */
do condlex(); while (COND_SEP()); do condlex(); while (COND_SEP());
incond--; /* parentheses do grouping */ incond--; /* parentheses do grouping */
@ -2476,7 +2489,7 @@ par_cond_2(void)
static int static int
par_cond_double(char *a, char *b) 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); COND_ERROR("parse error: condition expected: %s", a);
else if (!a[2] && strspn(a+1, "abcdefgknoprstuvwxzhLONGS") == 1) { else if (!a[2] && strspn(a+1, "abcdefgknoprstuvwxzhLONGS") == 1) {
ecadd(WCB_COND(a[1], 0)); 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)); ecadd(WCB_COND(COND_REGEX, 0));
ecstr(a); ecstr(a);
ecstr(c); ecstr(c);
} else if (b[0] == '-') { } else if (IS_DASH(b[0])) {
if ((t0 = get_cond_num(b + 1)) > -1) { if ((t0 = get_cond_num(b + 1)) > -1) {
ecadd(WCB_COND(t0 + COND_NT, 0)); ecadd(WCB_COND(t0 + COND_NT, 0));
ecstr(a); ecstr(a);
@ -2545,7 +2558,7 @@ par_cond_triple(char *a, char *b, char *c)
ecstr(a); ecstr(a);
ecstr(c); ecstr(c);
} }
} else if (a[0] == '-' && a[1]) { } else if (IS_DASH(a[0]) && a[1]) {
ecadd(WCB_COND(COND_MOD, 2)); ecadd(WCB_COND(COND_MOD, 2));
ecstr(a); ecstr(a);
ecstr(b); ecstr(b);
@ -2560,7 +2573,7 @@ par_cond_triple(char *a, char *b, char *c)
static int static int
par_cond_multi(char *a, LinkList l) 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); COND_ERROR("condition expected: %s", a);
else { else {
LinkNode n; 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++) { for (hlen = FD_PRELEN, tlen = 0; *files; files++) {
struct stat st; struct stat st;
if (!strcmp(*files, "-k")) { if (check_cond(*files, "k")) {
flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD; flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD;
continue; continue;
} else if (!strcmp(*files, "-z")) { } else if (check_cond(*files, "z")) {
flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_ZSHLOAD; flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_ZSHLOAD;
continue; continue;
} }

View file

@ -1521,7 +1521,7 @@ patcomppiece(int *flagp, int paren)
patparse = nptr; patparse = nptr;
len |= 1; len |= 1;
} }
DPUTS(*patparse != '-', "BUG: - missing from numeric glob"); DPUTS(!IS_DASH(*patparse), "BUG: - missing from numeric glob");
patparse++; patparse++;
if (idigit(*patparse)) { if (idigit(*patparse)) {
to = (zrange_t) zstrtol((char *)patparse, to = (zrange_t) zstrtol((char *)patparse,

View file

@ -481,6 +481,8 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep,
for ( ; *x; x += l) { for ( ; *x; x += l) {
int rawc = -1; int rawc = -1;
convchar_t c; convchar_t c;
if (*x == Dash)
*x = '-';
if (itok(STOUC(*x))) { if (itok(STOUC(*x))) {
/* token, can't be separator, must be single byte */ /* token, can't be separator, must be single byte */
rawc = *x; rawc = *x;
@ -1766,7 +1768,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
*/ */
c = *s; c = *s;
if (itype_end(s, IIDENT, 1) == s && *s != '#' && c != Pound && 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 != Quest &&
c != '*' && c != Star && c != '@' && c != '{' && c != '*' && c != Star && c != '@' && c != '{' &&
c != Inbrace && c != '=' && c != Equals && c != Hat && 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 || if (quotetype == QT_DOLLARS ||
quotetype == QT_BACKSLASH_PATTERN) quotetype == QT_BACKSLASH_PATTERN)
goto flagerr; goto flagerr;
if (s[1] == '-' || s[1] == '+') { if (IS_DASH(s[1]) || s[1] == '+') {
if (quotemod) if (quotemod)
goto flagerr; goto flagerr;
s++; s++;
quotemod = 1; quotemod = 1;
quotetype = (*s == '-') ? QT_SINGLE_OPTIONAL : quotetype = (*s == '+') ? QT_QUOTEDZPUTS :
QT_QUOTEDZPUTS; QT_SINGLE_OPTIONAL;
} else { } else {
if (quotetype == QT_SINGLE_OPTIONAL) { if (quotetype == QT_SINGLE_OPTIONAL) {
/* extra q's after '-' not allowed */ /* 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 * properly in the first place we wouldn't
* have this nonsense. * have this nonsense.
*/ */
|| ((cc == '#' || cc == Pound) && || ((cc == '#' || cc == Pound) && s[2] == Outbrace)
s[2] == Outbrace) || IS_DASH(cc)
|| cc == '-' || (cc == ':' && s[2] == '-') || (cc == ':' && IS_DASH(s[2]))
|| (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) { || (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) {
getlen = 1 + whichlen, s++; getlen = 1 + whichlen, s++;
/* /*
@ -2605,8 +2608,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
* Again, this duplicates tests for characters we're about to * Again, this duplicates tests for characters we're about to
* examine properly later on. * examine properly later on.
*/ */
if (inbrace && if (inbrace) {
(c = *s) != '-' && c != '+' && c != ':' && c != '%' && c != '/' && c = *s;
if (!IS_DASH(c) &&
c != '+' && c != ':' && c != '%' && c != '/' &&
c != '=' && c != Equals && c != '=' && c != Equals &&
c != '#' && c != Pound && c != '#' && c != Pound &&
c != '?' && c != Quest && c != '?' && c != Quest &&
@ -2614,6 +2619,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
zerr("bad substitution"); zerr("bad substitution");
return NULL; return NULL;
} }
}
/* /*
* Join arrays up if we're in quotes and there isn't some * Join arrays up if we're in quotes and there isn't some
* override such as (@). * override such as (@).
@ -2690,8 +2696,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
/* Check for ${..?..} or ${..=..} or one of those. * /* Check for ${..?..} or ${..=..} or one of those. *
* Only works if the name is in braces. */ * Only works if the name is in braces. */
if (inbrace && ((c = *s) == '-' || if (inbrace && ((c = *s) == '+' ||
c == '+' || IS_DASH(c) ||
c == ':' || /* i.e. a doubled colon */ c == ':' || /* i.e. a doubled colon */
c == '=' || c == Equals || c == '=' || c == Equals ||
c == '%' || c == '%' ||
@ -2802,6 +2808,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
vunset = 1; vunset = 1;
/* Fall Through! */ /* Fall Through! */
case '-': case '-':
case Dash:
if (vunset) { if (vunset) {
int split_flags; int split_flags;
val = dupstring(s); val = dupstring(s);

View file

@ -2376,7 +2376,7 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore)
while (inblank(*s)) while (inblank(*s))
s++; s++;
if ((neg = (*s == '-'))) if ((neg = IS_DASH(*s)))
s++; s++;
else if (*s == '+') else if (*s == '+')
s++; s++;
@ -6118,7 +6118,9 @@ quotedzputs(char const *s, FILE *stream)
} else } else
*ptr++ = '\''; *ptr++ = '\'';
while(*s) { while(*s) {
if (*s == Meta) if (*s == Dash)
c = '-';
else if (*s == Meta)
c = *++s ^ 32; c = *++s ^ 32;
else else
c = *s; c = *s;
@ -6155,7 +6157,9 @@ quotedzputs(char const *s, FILE *stream)
} else { } else {
/* use Bourne-style quoting, avoiding empty quoted strings */ /* use Bourne-style quoting, avoiding empty quoted strings */
while (*s) { while (*s) {
if (*s == Meta) if (*s == Dash)
c = '-';
else if (*s == Meta)
c = *++s ^ 32; c = *++s ^ 32;
else else
c = *s; c = *s;

View file

@ -237,6 +237,16 @@ struct mathfunc {
#define PATCHARS "#^*()|[]<>?~\\" #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 * Types of quote. This is used in various places, so care needs
* to be taken when changing them. (Oooh, don't you look surprised.) * to be taken when changing them. (Oooh, don't you look surprised.)

View file

@ -686,3 +686,9 @@
rm glob.tmp/link rm glob.tmp/link
0:modifier ':P' resolves symlinks before '..' components 0:modifier ':P' resolves symlinks before '..' components
*>*glob.tmp/hello/world *>*glob.tmp/hello/world
foo=a
value="ac"
print ${value//[${foo}b-z]/x}
0:handling of - range in complicated pattern context
>xx