1
0
Fork 0
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:
Peter Stephenson 2015-12-07 21:49:07 +00:00
parent 9fb30cf572
commit f5b8efa7e0
7 changed files with 247 additions and 53 deletions

View file

@ -1,5 +1,10 @@
2015-12-07 Peter Stephenson <p.w.stephenson@ntlworld.com> 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 * 37331: Src/utils.c: use a single character to represent an
MB_INCOMPLETE string even if multiple octets. MB_INCOMPLETE string even if multiple octets.

View file

@ -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 form of single quoting is used that only quotes the string if needed to
protect special characters. Typically this form gives the most readable protect special characters. Typically this form gives the most readable
output. 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))( item(tt(Q))(
Remove one level of quotes from the resulting words. Remove one level of quotes from the resulting words.

View file

@ -1887,12 +1887,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] == '-') { if (s[1] == '-' || s[1] == '+') {
if (quotemod) if (quotemod)
goto flagerr; goto flagerr;
s++; s++;
quotemod = 1; quotemod = 1;
quotetype = QT_SINGLE_OPTIONAL; quotetype = (*s == '-') ? QT_SINGLE_OPTIONAL :
QT_QUOTEDZPUTS;
} else { } else {
if (quotetype == QT_SINGLE_OPTIONAL) { if (quotetype == QT_SINGLE_OPTIONAL) {
/* extra q's after '-' not allowed */ /* extra q's after '-' not allowed */
@ -3583,7 +3584,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
ap = aval; ap = aval;
if (quotemod > 0) { 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; int sl;
char *tmp; char *tmp;
@ -3626,7 +3630,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
if (!copied) if (!copied)
val = dupstring(val), copied = 1; val = dupstring(val), copied = 1;
if (quotemod > 0) { if (quotemod > 0) {
if (quotetype > QT_BACKSLASH) { if (quotetype == QT_QUOTEDZPUTS) {
val = quotedzputs(val, NULL);
} else if (quotetype > QT_BACKSLASH) {
int sl; int sl;
char *tmp; char *tmp;
tmp = quotestring(val, NULL, quotetype); tmp = quotestring(val, NULL, quotetype);

View file

@ -387,6 +387,7 @@ putshout(int c)
return 0; return 0;
} }
#ifdef MULTIBYTE_SUPPORT
/* /*
* Turn a character into a visible representation thereof. The visible * Turn a character into a visible representation thereof. The visible
* string is put together in a static buffer, and this function returns * string is put together in a static buffer, and this function returns
@ -407,6 +408,73 @@ putshout(int c)
* in a multibyte string. * 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 * mod_export char *
nicechar(int c) nicechar(int c)
@ -459,6 +527,8 @@ nicechar(int c)
return buf; return buf;
} }
#endif /* MULTIBYTE_SUPPORT */
/* /*
* Return 1 if nicechar() would reformat this character. * Return 1 if nicechar() would reformat this character.
*/ */
@ -527,7 +597,7 @@ mb_charinit(void)
/**/ /**/
mod_export char * 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 char *buf;
static int bufalloc = 0, newalloc; static int bufalloc = 0, newalloc;
@ -552,9 +622,12 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
s = buf; s = buf;
if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
if (c == 0x7f) { if (c == 0x7f) {
*s++ = '\\'; if (quotable) {
*s++ = 'C'; *s++ = '\\';
*s++ = '-'; *s++ = 'C';
*s++ = '-';
} else
*s++ = '^';
c = '?'; c = '?';
} else if (c == L'\n') { } else if (c == L'\n') {
*s++ = '\\'; *s++ = '\\';
@ -563,9 +636,12 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
*s++ = '\\'; *s++ = '\\';
c = 't'; c = 't';
} else if (c < 0x20) { } else if (c < 0x20) {
*s++ = '\\'; if (quotable) {
*s++ = 'C'; *s++ = '\\';
*s++ = '-'; *s++ = 'C';
*s++ = '-';
} else
*s++ = '^';
c += 0x40; c += 0x40;
} else if (c >= 0x80) { } else if (c >= 0x80) {
ret = -1; ret = -1;
@ -635,6 +711,13 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
return buf; 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. * 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 */ /* FALL THROUGH */
case MB_INVALID: case MB_INVALID:
/* The byte didn't convert, so output it as a \M-... sequence. */ /* 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); newl = strlen(fmt);
cnt = 1; cnt = 1;
/* Get mbs out of its undefined state. */ /* 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)) if (c == L'\'' && (flags & NICEFLAG_QUOTE))
fmt = "\\'"; fmt = "\\'";
else else
fmt = wcs_nicechar(c, &newl, NULL); fmt = wcs_nicechar_sel(c, &newl, NULL, flags & NICEFLAG_QUOTE);
break; break;
} }
@ -4967,8 +5050,13 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags)
if (outstrp) { if (outstrp) {
*outptr = '\0'; *outptr = '\0';
/* Use more efficient storage for returned string */ /* Use more efficient storage for returned string */
*outstrp = (flags & NICEFLAG_HEAP) ? dupstring(outstr) : ztrdup(outstr); if (flags & NICEFLAG_NODUP)
free(outstr); *outstrp = outstr;
else {
*outstrp = (flags & NICEFLAG_HEAP) ? dupstring(outstr) :
ztrdup(outstr);
free(outstr);
}
} }
return l; return l;
@ -5834,38 +5922,76 @@ quotestring(const char *s, char **e, int instring)
return v; 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) quotedzputs(char const *s, FILE *stream)
{ {
int inquote = 0, c; int inquote = 0, c;
char *outstr, *ptr;
/* check for empty string */ /* check for empty string */
if(!*s) { if(!*s) {
if (!stream)
return "''";
fputs("''", stream); fputs("''", stream);
return; return NULL;
} }
#ifdef MULTIBYTE_SUPPORT #ifdef MULTIBYTE_SUPPORT
if (is_mb_niceformat(s)) { if (is_mb_niceformat(s)) {
fputs("$'", stream); if (stream) {
mb_niceformat(s, stream, NULL, NICEFLAG_QUOTE); fputs("$'", stream);
fputc('\'', stream); mb_niceformat(s, stream, NULL, NICEFLAG_QUOTE);
return; fputc('\'', stream);
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 */ #endif /* MULTIBYTE_SUPPORT */
if (!hasspecial(s)) { if (!hasspecial(s)) {
zputs(s, stream); if (stream) {
return; zputs(s, stream);
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)) { if (isset(RCQUOTES)) {
/* use rc-style quotes-within-quotes for the whole string */ /* use rc-style quotes-within-quotes for the whole string */
if(fputc('\'', stream) < 0) if (stream) {
return; if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
while(*s) { while(*s) {
if (*s == Meta) if (*s == Meta)
c = *++s ^ 32; c = *++s ^ 32;
@ -5873,52 +5999,98 @@ quotedzputs(char const *s, FILE *stream)
c = *s; c = *s;
s++; s++;
if (c == '\'') { if (c == '\'') {
if(fputc('\'', stream) < 0) if (stream) {
return; if (fputc('\'', stream) < 0)
} else if(c == '\n' && isset(CSHJUNKIEQUOTES)) { return NULL;
if(fputc('\\', stream) < 0) } else
return; *ptr++ = '\'';
} else if (c == '\n' && isset(CSHJUNKIEQUOTES)) {
if (stream) {
if (fputc('\\', stream) < 0)
return NULL;
} else
*ptr++ = '\\';
}
if (stream) {
if (fputc(c, stream) < 0)
return NULL;
} else {
if (imeta(c)) {
*ptr++ = Meta;
*ptr++ = c ^ 32;
} else
*ptr++ = c;
} }
if(fputc(c, stream) < 0)
return;
} }
if(fputc('\'', stream) < 0) if (stream) {
return; if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
} 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 == Meta)
c = *++s ^ 32; c = *++s ^ 32;
else else
c = *s; c = *s;
s++; s++;
if (c == '\'') { if (c == '\'') {
if(inquote) { if (inquote) {
if(fputc('\'', stream) < 0) if (stream) {
return; if (putc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
inquote=0; inquote=0;
} }
if(fputs("\\'", stream) < 0) if (stream) {
return; if (fputs("\\'", stream) < 0)
return NULL;
} else {
*ptr++ = '\\';
*ptr++ = '\'';
}
} else { } else {
if (!inquote) { if (!inquote) {
if(fputc('\'', stream) < 0) if (stream) {
return; if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
inquote=1; inquote=1;
} }
if(c == '\n' && isset(CSHJUNKIEQUOTES)) { if (c == '\n' && isset(CSHJUNKIEQUOTES)) {
if(fputc('\\', stream) < 0) if (stream) {
return; if (fputc('\\', stream) < 0)
return NULL;
} else
*ptr++ = '\\';
}
if (stream) {
if (fputc(c, stream) < 0)
return NULL;
} else {
if (imeta(c)) {
*ptr++ = Meta;
*ptr++ = c ^ 32;
} else
*ptr++ = c;
} }
if(fputc(c, stream) < 0)
return;
} }
} }
if (inquote) { if (inquote) {
if(fputc('\'', stream) < 0) if (stream) {
return; if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
} }
} }
if (!stream)
*ptr++ = '\0';
return outstr;
} }
/* Double-quote a metafied string. */ /* Double-quote a metafied string. */

View file

@ -272,7 +272,12 @@ enum {
/* /*
* As QT_BACKSLASH, but a NULL string is shown as ''. * 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) #define QT_IS_SINGLE(x) ((x) == QT_SINGLE || (x) == QT_SINGLE_OPTIONAL)
@ -3055,6 +3060,7 @@ enum {
enum { enum {
NICEFLAG_HEAP = 1, /* Heap allocation where needed */ NICEFLAG_HEAP = 1, /* Heap allocation where needed */
NICEFLAG_QUOTE = 2, /* Result will appear in $'...' */ NICEFLAG_QUOTE = 2, /* Result will appear in $'...' */
NICEFLAG_NODUP = 4, /* Leave allocated */
}; };
/* Metafied input */ /* Metafied input */

View file

@ -398,7 +398,7 @@
foo=$'\x7f\x00' foo=$'\x7f\x00'
print -r -- ${(V)foo} print -r -- ${(V)foo}
0:${(V)...} 0:${(V)...}
>\C-?\C-@ >^?^@
foo='playing '\''stupid'\'' "games" \w\i\t\h $quoting.' foo='playing '\''stupid'\'' "games" \w\i\t\h $quoting.'
print -r ${(q)foo} print -r ${(q)foo}

View file

@ -71,4 +71,4 @@
print -r -- ${(V)"$(strftime $'%Y\0%m\0%d' 100000000)"} print -r -- ${(V)"$(strftime $'%Y\0%m\0%d' 100000000)"}
0:Embedded nulls 0:Embedded nulls
>1973\C-@03\C-@03 >1973^@03^@03