mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-01 05:16:05 +01:00
37344: restore old printable quoting, add ${(q+)...}.
The \C- form is only used inside quotedzputs(). ${(q+)...} outputs a quotedzputs() representation.
This commit is contained in:
parent
9fb30cf572
commit
f5b8efa7e0
7 changed files with 247 additions and 53 deletions
|
@ -1,5 +1,10 @@
|
|||
2015-12-07 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 37344: Doc/Zsh/expn.yo, Src/subst.c, Src/utils.c, Src/zsh.h,
|
||||
Test/D04parameter.ztst, Test/V09datetime.ztst: restore old
|
||||
printable quoting of characters when not used from quotedzputs()
|
||||
and add ${(q+)...} to output the new form.
|
||||
|
||||
* 37331: Src/utils.c: use a single character to represent an
|
||||
MB_INCOMPLETE string even if multiple octets.
|
||||
|
||||
|
|
|
@ -1067,6 +1067,11 @@ If a tt(q-) is given (only a single tt(q) may appear), a minimal
|
|||
form of single quoting is used that only quotes the string if needed to
|
||||
protect special characters. Typically this form gives the most readable
|
||||
output.
|
||||
|
||||
If a tt(q+) is given, an extended form of minmal quoting is used that
|
||||
causes unprintable characters to be rendered using tt($')var(...)tt(').
|
||||
This quoting is similar to that used by the output of values by the
|
||||
tt(typeset) family of commands.
|
||||
)
|
||||
item(tt(Q))(
|
||||
Remove one level of quotes from the resulting words.
|
||||
|
|
14
Src/subst.c
14
Src/subst.c
|
@ -1887,12 +1887,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] == '-') {
|
||||
if (s[1] == '-' || s[1] == '+') {
|
||||
if (quotemod)
|
||||
goto flagerr;
|
||||
s++;
|
||||
quotemod = 1;
|
||||
quotetype = QT_SINGLE_OPTIONAL;
|
||||
quotetype = (*s == '-') ? QT_SINGLE_OPTIONAL :
|
||||
QT_QUOTEDZPUTS;
|
||||
} else {
|
||||
if (quotetype == QT_SINGLE_OPTIONAL) {
|
||||
/* extra q's after '-' not allowed */
|
||||
|
@ -3583,7 +3584,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
|
|||
ap = aval;
|
||||
|
||||
if (quotemod > 0) {
|
||||
if (quotetype > QT_BACKSLASH) {
|
||||
if (quotetype == QT_QUOTEDZPUTS) {
|
||||
for (; *ap; ap++)
|
||||
*ap = quotedzputs(*ap, NULL);
|
||||
} else if (quotetype > QT_BACKSLASH) {
|
||||
int sl;
|
||||
char *tmp;
|
||||
|
||||
|
@ -3626,7 +3630,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
|
|||
if (!copied)
|
||||
val = dupstring(val), copied = 1;
|
||||
if (quotemod > 0) {
|
||||
if (quotetype > QT_BACKSLASH) {
|
||||
if (quotetype == QT_QUOTEDZPUTS) {
|
||||
val = quotedzputs(val, NULL);
|
||||
} else if (quotetype > QT_BACKSLASH) {
|
||||
int sl;
|
||||
char *tmp;
|
||||
tmp = quotestring(val, NULL, quotetype);
|
||||
|
|
214
Src/utils.c
214
Src/utils.c
|
@ -387,6 +387,7 @@ putshout(int c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MULTIBYTE_SUPPORT
|
||||
/*
|
||||
* Turn a character into a visible representation thereof. The visible
|
||||
* string is put together in a static buffer, and this function returns
|
||||
|
@ -407,6 +408,73 @@ putshout(int c)
|
|||
* in a multibyte string.
|
||||
*/
|
||||
|
||||
/**/
|
||||
mod_export char *
|
||||
nicechar_sel(int c, int quotable)
|
||||
{
|
||||
static char buf[10];
|
||||
char *s = buf;
|
||||
c &= 0xff;
|
||||
if (ZISPRINT(c))
|
||||
goto done;
|
||||
if (c & 0x80) {
|
||||
if (isset(PRINTEIGHTBIT))
|
||||
goto done;
|
||||
*s++ = '\\';
|
||||
*s++ = 'M';
|
||||
*s++ = '-';
|
||||
c &= 0x7f;
|
||||
if(ZISPRINT(c))
|
||||
goto done;
|
||||
}
|
||||
if (c == 0x7f) {
|
||||
if (quotable) {
|
||||
*s++ = '\\';
|
||||
*s++ = 'C';
|
||||
*s++ = '-';
|
||||
} else
|
||||
*s++ = '^';
|
||||
c = '?';
|
||||
} else if (c == '\n') {
|
||||
*s++ = '\\';
|
||||
c = 'n';
|
||||
} else if (c == '\t') {
|
||||
*s++ = '\\';
|
||||
c = 't';
|
||||
} else if (c < 0x20) {
|
||||
if (quotable) {
|
||||
*s++ = '\\';
|
||||
*s++ = 'C';
|
||||
*s++ = '-';
|
||||
} else
|
||||
*s++ = '^';
|
||||
c += 0x40;
|
||||
}
|
||||
done:
|
||||
/*
|
||||
* The resulting string is still metafied, so check if
|
||||
* we are returning a character in the range that needs metafication.
|
||||
* This can't happen if the character is printed "nicely", so
|
||||
* this results in a maximum of two bytes total (plus the null).
|
||||
*/
|
||||
if (imeta(c)) {
|
||||
*s++ = Meta;
|
||||
*s++ = c ^ 32;
|
||||
} else
|
||||
*s++ = c;
|
||||
*s = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export char *
|
||||
nicechar(int c)
|
||||
{
|
||||
return nicechar_sel(c, 0);
|
||||
}
|
||||
|
||||
#else /* MULTIBYTE_SUPPORT */
|
||||
|
||||
/**/
|
||||
mod_export char *
|
||||
nicechar(int c)
|
||||
|
@ -459,6 +527,8 @@ nicechar(int c)
|
|||
return buf;
|
||||
}
|
||||
|
||||
#endif /* MULTIBYTE_SUPPORT */
|
||||
|
||||
/*
|
||||
* Return 1 if nicechar() would reformat this character.
|
||||
*/
|
||||
|
@ -527,7 +597,7 @@ mb_charinit(void)
|
|||
|
||||
/**/
|
||||
mod_export char *
|
||||
wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
|
||||
wcs_nicechar_sel(wchar_t c, size_t *widthp, char **swidep, int quotable)
|
||||
{
|
||||
static char *buf;
|
||||
static int bufalloc = 0, newalloc;
|
||||
|
@ -552,9 +622,12 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
|
|||
s = buf;
|
||||
if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
|
||||
if (c == 0x7f) {
|
||||
if (quotable) {
|
||||
*s++ = '\\';
|
||||
*s++ = 'C';
|
||||
*s++ = '-';
|
||||
} else
|
||||
*s++ = '^';
|
||||
c = '?';
|
||||
} else if (c == L'\n') {
|
||||
*s++ = '\\';
|
||||
|
@ -563,9 +636,12 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
|
|||
*s++ = '\\';
|
||||
c = 't';
|
||||
} else if (c < 0x20) {
|
||||
if (quotable) {
|
||||
*s++ = '\\';
|
||||
*s++ = 'C';
|
||||
*s++ = '-';
|
||||
} else
|
||||
*s++ = '^';
|
||||
c += 0x40;
|
||||
} else if (c >= 0x80) {
|
||||
ret = -1;
|
||||
|
@ -635,6 +711,13 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
|
|||
return buf;
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export char *
|
||||
wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
|
||||
{
|
||||
return wcs_nicechar_sel(c, widthp, swidep, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if wcs_nicechar() would reformat this character for display.
|
||||
*/
|
||||
|
@ -4918,7 +5001,7 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags)
|
|||
/* FALL THROUGH */
|
||||
case MB_INVALID:
|
||||
/* The byte didn't convert, so output it as a \M-... sequence. */
|
||||
fmt = nicechar(*ptr);
|
||||
fmt = nicechar_sel(*ptr, flags & NICEFLAG_QUOTE);
|
||||
newl = strlen(fmt);
|
||||
cnt = 1;
|
||||
/* Get mbs out of its undefined state. */
|
||||
|
@ -4933,7 +5016,7 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags)
|
|||
if (c == L'\'' && (flags & NICEFLAG_QUOTE))
|
||||
fmt = "\\'";
|
||||
else
|
||||
fmt = wcs_nicechar(c, &newl, NULL);
|
||||
fmt = wcs_nicechar_sel(c, &newl, NULL, flags & NICEFLAG_QUOTE);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4967,9 +5050,14 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags)
|
|||
if (outstrp) {
|
||||
*outptr = '\0';
|
||||
/* Use more efficient storage for returned string */
|
||||
*outstrp = (flags & NICEFLAG_HEAP) ? dupstring(outstr) : ztrdup(outstr);
|
||||
if (flags & NICEFLAG_NODUP)
|
||||
*outstrp = outstr;
|
||||
else {
|
||||
*outstrp = (flags & NICEFLAG_HEAP) ? dupstring(outstr) :
|
||||
ztrdup(outstr);
|
||||
free(outstr);
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
@ -5834,38 +5922,76 @@ quotestring(const char *s, char **e, int instring)
|
|||
return v;
|
||||
}
|
||||
|
||||
/* Unmetafy and output a string, quoted if it contains special characters. */
|
||||
/*
|
||||
* Unmetafy and output a string, quoted if it contains special
|
||||
* characters.
|
||||
*
|
||||
* If stream is NULL, return the same output with any allocation on the
|
||||
* heap.
|
||||
*/
|
||||
|
||||
/**/
|
||||
mod_export void
|
||||
mod_export char *
|
||||
quotedzputs(char const *s, FILE *stream)
|
||||
{
|
||||
int inquote = 0, c;
|
||||
char *outstr, *ptr;
|
||||
|
||||
/* check for empty string */
|
||||
if(!*s) {
|
||||
if (!stream)
|
||||
return "''";
|
||||
fputs("''", stream);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef MULTIBYTE_SUPPORT
|
||||
if (is_mb_niceformat(s)) {
|
||||
if (stream) {
|
||||
fputs("$'", stream);
|
||||
mb_niceformat(s, stream, NULL, NICEFLAG_QUOTE);
|
||||
fputc('\'', stream);
|
||||
return;
|
||||
return NULL;
|
||||
} else {
|
||||
char *substr;
|
||||
mb_niceformat(s, NULL, &substr, NICEFLAG_QUOTE|NICEFLAG_NODUP);
|
||||
outstr = (char *)zhalloc(4 + strlen(substr));
|
||||
sprintf(outstr, "$'%s'", substr);
|
||||
free(substr);
|
||||
return outstr;
|
||||
}
|
||||
}
|
||||
#endif /* MULTIBYTE_SUPPORT */
|
||||
|
||||
if (!hasspecial(s)) {
|
||||
if (stream) {
|
||||
zputs(s, stream);
|
||||
return;
|
||||
return NULL;
|
||||
} else {
|
||||
return dupstring(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (!stream) {
|
||||
const char *cptr;
|
||||
int l = strlen(s) + 2;
|
||||
for (cptr = s; *cptr; cptr++) {
|
||||
if (*cptr == Meta)
|
||||
cptr++;
|
||||
else if (*cptr == '\'')
|
||||
l += isset(RCQUOTES) ? 1 : 3;
|
||||
}
|
||||
ptr = outstr = zhalloc(l + 1);
|
||||
} else {
|
||||
ptr = outstr = NULL;
|
||||
}
|
||||
if (isset(RCQUOTES)) {
|
||||
/* use rc-style quotes-within-quotes for the whole string */
|
||||
if (stream) {
|
||||
if (fputc('\'', stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\'';
|
||||
while(*s) {
|
||||
if (*s == Meta)
|
||||
c = *++s ^ 32;
|
||||
|
@ -5873,17 +5999,34 @@ quotedzputs(char const *s, FILE *stream)
|
|||
c = *s;
|
||||
s++;
|
||||
if (c == '\'') {
|
||||
if (stream) {
|
||||
if (fputc('\'', stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\'';
|
||||
} else if (c == '\n' && isset(CSHJUNKIEQUOTES)) {
|
||||
if (stream) {
|
||||
if (fputc('\\', stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\\';
|
||||
}
|
||||
if (stream) {
|
||||
if (fputc(c, stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else {
|
||||
if (imeta(c)) {
|
||||
*ptr++ = Meta;
|
||||
*ptr++ = c ^ 32;
|
||||
} else
|
||||
*ptr++ = c;
|
||||
}
|
||||
}
|
||||
if (stream) {
|
||||
if (fputc('\'', stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\'';
|
||||
} else {
|
||||
/* use Bourne-style quoting, avoiding empty quoted strings */
|
||||
while (*s) {
|
||||
|
@ -5894,31 +6037,60 @@ quotedzputs(char const *s, FILE *stream)
|
|||
s++;
|
||||
if (c == '\'') {
|
||||
if (inquote) {
|
||||
if(fputc('\'', stream) < 0)
|
||||
return;
|
||||
if (stream) {
|
||||
if (putc('\'', stream) < 0)
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\'';
|
||||
inquote=0;
|
||||
}
|
||||
if (stream) {
|
||||
if (fputs("\\'", stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else {
|
||||
*ptr++ = '\\';
|
||||
*ptr++ = '\'';
|
||||
}
|
||||
} else {
|
||||
if (!inquote) {
|
||||
if (stream) {
|
||||
if (fputc('\'', stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\'';
|
||||
inquote=1;
|
||||
}
|
||||
if (c == '\n' && isset(CSHJUNKIEQUOTES)) {
|
||||
if (stream) {
|
||||
if (fputc('\\', stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\\';
|
||||
}
|
||||
if (stream) {
|
||||
if (fputc(c, stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else {
|
||||
if (imeta(c)) {
|
||||
*ptr++ = Meta;
|
||||
*ptr++ = c ^ 32;
|
||||
} else
|
||||
*ptr++ = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inquote) {
|
||||
if (stream) {
|
||||
if (fputc('\'', stream) < 0)
|
||||
return;
|
||||
return NULL;
|
||||
} else
|
||||
*ptr++ = '\'';
|
||||
}
|
||||
}
|
||||
if (!stream)
|
||||
*ptr++ = '\0';
|
||||
|
||||
return outstr;
|
||||
}
|
||||
|
||||
/* Double-quote a metafied string. */
|
||||
|
|
|
@ -272,7 +272,12 @@ enum {
|
|||
/*
|
||||
* As QT_BACKSLASH, but a NULL string is shown as ''.
|
||||
*/
|
||||
QT_BACKSLASH_SHOWNULL
|
||||
QT_BACKSLASH_SHOWNULL,
|
||||
/*
|
||||
* Quoting as produced by quotedzputs(), used for human
|
||||
* readability of parameter values.
|
||||
*/
|
||||
QT_QUOTEDZPUTS
|
||||
};
|
||||
|
||||
#define QT_IS_SINGLE(x) ((x) == QT_SINGLE || (x) == QT_SINGLE_OPTIONAL)
|
||||
|
@ -3055,6 +3060,7 @@ enum {
|
|||
enum {
|
||||
NICEFLAG_HEAP = 1, /* Heap allocation where needed */
|
||||
NICEFLAG_QUOTE = 2, /* Result will appear in $'...' */
|
||||
NICEFLAG_NODUP = 4, /* Leave allocated */
|
||||
};
|
||||
|
||||
/* Metafied input */
|
||||
|
|
|
@ -398,7 +398,7 @@
|
|||
foo=$'\x7f\x00'
|
||||
print -r -- ${(V)foo}
|
||||
0:${(V)...}
|
||||
>\C-?\C-@
|
||||
>^?^@
|
||||
|
||||
foo='playing '\''stupid'\'' "games" \w\i\t\h $quoting.'
|
||||
print -r ${(q)foo}
|
||||
|
|
|
@ -71,4 +71,4 @@
|
|||
|
||||
print -r -- ${(V)"$(strftime $'%Y\0%m\0%d' 100000000)"}
|
||||
0:Embedded nulls
|
||||
>1973\C-@03\C-@03
|
||||
>1973^@03^@03
|
||||
|
|
Loading…
Reference in a new issue