diff options
-rw-r--r-- | Doc/Zsh/expn.yo | 6 | ||||
-rw-r--r-- | Src/subst.c | 49 | ||||
-rw-r--r-- | Src/utils.c | 59 |
3 files changed, 96 insertions, 18 deletions
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 1008ea4ae..6b33c9a81 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -581,12 +581,14 @@ Capitalize the resulting words. `Words' in this case refers to sequences of alphanumeric characters separated by non-alphanumerics, em(not) to words that result from field splitting. ) +item(tt(V))( +Make any special characters in the resulting words visible. +) item(tt(q))( Quote the resulting words with backslashes. If this flag is given twice, the resulting words are quoted in single quotes and if it is given three times, the words are quoted in double quotes. If it is -given four times, no real quoting is done, but any special characters -in the resulting words will be in a human-readable form. +given four times, the words are quoted in single quotes preceded a tt($). ) item(tt(Q))( Remove one level of quotes from the resulting words. diff --git a/Src/subst.c b/Src/subst.c index 45b58aef6..ffe6217f0 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -723,6 +723,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) int sortit = 0, casind = 0; int casmod = 0; int quotemod = 0, quotetype = 0, quoteerr = 0; + int visiblemod = 0; char *sep = NULL, *spsep = NULL; char *premul = NULL, *postmul = NULL, *preone = NULL, *postone = NULL; char *replstr = NULL; /* replacement string for /orig/repl */ @@ -826,6 +827,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) casind = 1; break; + case 'V': + visiblemod++; + break; + case 'q': quotemod++, quotetype++; break; @@ -1628,20 +1633,20 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) ap = aval; if (quotemod > 0) { - if (quotetype == 3) - for (; *ap; ap++) - *ap = nicedupstring(*ap); - else if (quotetype) { + if (quotetype) { int sl; char *tmp; for (; *ap; ap++) { + int pre = quotetype != 3 ? 1 : 2; tmp = bslashquote(*ap, NULL, quotetype); sl = strlen(tmp); - *ap = (char *) zhalloc(sl + 3); - strcpy((*ap) + 1, tmp); - ap[0][0] = ap[0][sl + 1] = (quotetype == 1 ? '\'' : '"'); - ap[0][sl + 2] = '\0'; + *ap = (char *) zhalloc(pre + sl + 2); + strcpy((*ap) + pre, tmp); + ap[0][pre - 1] = ap[0][pre + sl] = (quotetype != 2 ? '\'' : '"'); + ap[0][pre + sl + 1] = '\0'; + if (quotetype == 3) + ap[0][0] = '$'; } } else for (; *ap; ap++) @@ -1668,18 +1673,19 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (!copied) val = dupstring(val), copied = 1; if (quotemod > 0) { - if (quotetype == 3) - val = nicedupstring(val); - else if (quotetype) { + if (quotetype) { + int pre = quotetype != 3 ? 1 : 2; int sl; char *tmp; tmp = bslashquote(val, NULL, quotetype); sl = strlen(tmp); - val = (char *) zhalloc(sl + 3); - strcpy(val + 1, tmp); - val[0] = val[sl + 1] = (quotetype == 1 ? '\'' : '"'); - val[sl + 2] = '\0'; + val = (char *) zhalloc(pre + sl + 2); + strcpy(val + pre, tmp); + val[pre - 1] = val[pre + sl] = (quotetype != 2 ? '\'' : '"'); + val[pre + sl + 1] = '\0'; + if (quotetype == 3) + val[0] = '$'; } else val = bslashquote(val, NULL, 0); } else { @@ -1700,6 +1706,19 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } } } + if (visiblemod) { + if (isarr) { + char **ap; + if (!copied) + aval = arrdup(aval), copied = 1; + for (ap = aval; *ap; ap++) + *ap = nicedupstring(*ap); + } else { + if (!copied) + val = dupstring(val), copied = 1; + val = nicedupstring(val); + } + } if (isarr) { char *x; char *y; diff --git a/Src/utils.c b/Src/utils.c index 5f9e89882..7494837cf 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2984,7 +2984,64 @@ bslashquote(const char *s, char **e, int instring) for (; *u; u++) { if (e && *e == u) *e = v, sf = 1; - if (ispecial(*u) && + if (instring == 3) { + int c = *u; + if (c == Meta) { + c = *++u ^ 32; + } + c &= 0xff; + if(isprint(c)) { + switch (c) { + case '\\': + case '\'': + *v++ = '\\'; + *v++ = c; + break; + + default: + if(imeta(c)) { + *v++ = Meta; + *v++ = c ^ 32; + } + else { + if (isset(BANGHIST) && c == bangchar) { + *v++ = '\\'; + } + *v++ = c; + } + break; + } + } + else { + switch (c) { + case '\0': + *v++ = '\\'; + *v++ = '0'; + if ('0' <= u[1] && u[1] <= '7') { + *v++ = '0'; + *v++ = '0'; + } + break; + + case '\007': *v++ = '\\'; *v++ = 'a'; break; + case '\b': *v++ = '\\'; *v++ = 'b'; break; + case '\f': *v++ = '\\'; *v++ = 'f'; break; + case '\n': *v++ = '\\'; *v++ = 'n'; break; + case '\r': *v++ = '\\'; *v++ = 'r'; break; + case '\t': *v++ = '\\'; *v++ = 't'; break; + case '\v': *v++ = '\\'; *v++ = 'v'; break; + + default: + *v++ = '\\'; + *v++ = '0' + ((c >> 6) & 7); + *v++ = '0' + ((c >> 3) & 7); + *v++ = '0' + (c & 7); + break; + } + } + continue; + } + else if (ispecial(*u) && (!instring || (isset(BANGHIST) && *u == (char)bangchar) || (instring == 2 && |