diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/subst.c | 49 | ||||
-rw-r--r-- | Src/utils.c | 107 | ||||
-rw-r--r-- | Src/zsh.h | 7 |
3 files changed, 144 insertions, 19 deletions
diff --git a/Src/subst.c b/Src/subst.c index 5d14c458a..0bb0b798f 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1583,6 +1583,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) switch (c) { case ')': case Outpar: + /* how can this happen? */ break; case '~': case Tilde: @@ -1653,7 +1654,17 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) break; case 'q': - quotemod++, quotetype++; + if (quotetype == QT_DOLLARS) + goto flagerr; + if (s[1] == '-') { + if (quotemod) + goto flagerr; + s++; + quotemod = 1; + quotetype = QT_SINGLE_OPTIONAL; + } else { + quotemod++, quotetype++; + } break; case 'Q': quotemod--; @@ -2801,8 +2812,26 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) * the repetitions of the (q) flag. */ if (quotemod) { - if (quotetype > QT_DOLLARS) - quotetype = QT_DOLLARS; + int pre = 0, post = 0; + + if (quotemod > 0 && quotetype > QT_BACKSLASH) { + switch (quotetype) + { + case QT_DOLLARS: + /* space for "$" */ + pre = 2; + post = 1; + break; + + case QT_SINGLE_OPTIONAL: + /* quotes will be added for us */ + break; + + default: + pre = post = 1; + break; + } + } if (isarr) { char **ap; @@ -2816,13 +2845,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) char *tmp; for (; *ap; ap++) { - int pre = quotetype != QT_DOLLARS ? 1 : 2; tmp = quotestring(*ap, NULL, quotetype); sl = strlen(tmp); - *ap = (char *) zhalloc(pre + sl + 2); + *ap = (char *) zhalloc(pre + sl + post + 1); strcpy((*ap) + pre, tmp); - ap[0][pre - 1] = ap[0][pre + sl] = - (quotetype != QT_DOUBLE ? '\'' : '"'); + if (pre) + ap[0][pre - 1] = ap[0][pre + sl] = + (quotetype != QT_DOUBLE ? '\'' : '"'); ap[0][pre + sl + 1] = '\0'; if (quotetype == QT_DOLLARS) ap[0][0] = '$'; @@ -2853,15 +2882,15 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) val = dupstring(val), copied = 1; if (quotemod > 0) { if (quotetype > QT_BACKSLASH) { - int pre = quotetype != QT_DOLLARS ? 1 : 2; int sl; char *tmp; tmp = quotestring(val, NULL, quotetype); sl = strlen(tmp); val = (char *) zhalloc(pre + sl + 2); strcpy(val + pre, tmp); - val[pre - 1] = val[pre + sl] = - (quotetype != QT_DOUBLE ? '\'' : '"'); + if (pre) + val[pre - 1] = val[pre + sl] = + (quotetype != QT_DOUBLE ? '\'' : '"'); val[pre + sl + 1] = '\0'; if (quotetype == QT_DOLLARS) val[0] = '$'; diff --git a/Src/utils.c b/Src/utils.c index 00d51a320..687a396fa 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4408,6 +4408,11 @@ addunprintable(char *v, const char *u, const char *uend) * * The last argument is a QT_ value defined in zsh.h other than QT_NONE. * + * Most quote styles other than backslash assume the quotes are to + * be added outside quotestring(). QT_SINGLE_OPTIONAL is different: + * the single quotes are only added where necessary, so the + * whole expression is handled here. + * * The string may be metafied and contain tokens. */ @@ -4417,20 +4422,50 @@ quotestring(const char *s, char **e, int instring) { const char *u, *tt; char *v; + int alloclen; + char *buf; + int sf = 0; /* - * With QT_BACKSLASH we may need to use $'\300' stuff. - * Keep memory usage within limits by allocating temporary - * storage and using heap for correct size at end. + * quotesub is used with QT_SINGLE_OPTIONAL. + * quotesub = 0: mechanism not active + * quotesub = 1: mechanism pending, no "'" yet; + * needs adding at quotestart. + * quotesub = 2: mechanism active, added opening "'"; need + * closing "'". */ - int alloclen = (instring == QT_BACKSLASH ? 7 : 4) * strlen(s) + 1; - char *buf = zshcalloc(alloclen); - int sf = 0; + int quotesub = 0; + char *quotestart; convchar_t cc; const char *uend; - DPUTS(instring < QT_BACKSLASH || instring > QT_DOLLARS, + switch (instring) + { + case QT_BACKSLASH: + /* + * With QT_BACKSLASH we may need to use $'\300' stuff. + * Keep memory usage within limits by allocating temporary + * storage and using heap for correct size at end. + */ + alloclen = strlen(s) * 7 + 1; + break; + + case QT_SINGLE_OPTIONAL: + /* + * Here, we may need to add single quotes. + */ + alloclen = strlen(s) * 4 + 3; + quotesub = 1; + break; + + default: + alloclen = strlen(s) * 4 + 1; + break; + } + tt = quotestart = v = buf = zshcalloc(alloclen); + + DPUTS(instring < QT_BACKSLASH || instring == QT_BACKTICK || + instring > QT_SINGLE_OPTIONAL, "BUG: bad quote type in quotestring"); - tt = v = buf; u = s; if (instring == QT_DOLLARS) { /* @@ -4526,12 +4561,64 @@ quotestring(const char *s, char **e, int instring) (u[-1] == '=' || u[-1] == ':')) || (*u == '~' && isset(EXTENDEDGLOB))) && (instring == QT_BACKSLASH || + instring == QT_SINGLE_OPTIONAL || (isset(BANGHIST) && *u == (char)bangchar && instring != QT_SINGLE) || (instring == QT_DOUBLE && (*u == '$' || *u == '`' || *u == '\"' || *u == '\\')) || (instring == QT_SINGLE && *u == '\''))) { - if (*u == '\n' || (instring == QT_SINGLE && *u == '\'')) { + if (instring == QT_SINGLE_OPTIONAL) { + if (quotesub == 1) { + /* + * We haven't yet had to quote at the start. + */ + if (*u == '\'') { + /* + * We don't need to. + */ + *v++ = '\\'; + } else { + /* + * It's now time to add quotes. + */ + if (v > quotestart) + { + char *addq; + + for (addq = v; addq > quotestart; addq--) + *addq = addq[-1]; + } + *quotestart = '\''; + v++; + quotesub = 2; + } + *v++ = *u++; + /* + * Next place to start quotes is here. + */ + quotestart = v; + } else if (*u == '\'') { + if (unset(RCQUOTES)) { + *v++ = '\''; + *v++ = '\\'; + *v++ = '\''; + /* Don't restart quotes unless we need them */ + quotesub = 1; + quotestart = v; + } else { + /* simplest just to use '' always */ + *v++ = '\''; + *v++ = '\''; + } + /* dealt with */ + u++; + } else { + /* else already quoting, just add */ + *v++ = *u++; + } + continue; + } else if (*u == '\n' || + (instring == QT_SINGLE && *u == '\'')) { if (unset(RCQUOTES)) { *v++ = '\''; if (*u == '\'') @@ -4589,6 +4676,8 @@ quotestring(const char *s, char **e, int instring) } } } + if (quotesub == 2) + *v++ = '\''; *v = '\0'; if (e && *e == u) diff --git a/Src/zsh.h b/Src/zsh.h index 3c1623c1f..3854116c0 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -210,8 +210,15 @@ enum { * in those cases where we need to represent a complete set. */ QT_BACKTICK, + /* + * Single quotes, but the default is not to quote unless necessary. + * This is only useful as an argument to quotestring(). + */ + QT_SINGLE_OPTIONAL }; +#define QT_IS_SINGLE(x) ((x) == QT_SINGLE || (x) == QT_SINGLE_OPTIONAL) + /* * Lexical tokens: unlike the character tokens above, these never * appear in strings and don't necessarily represent a single character. |