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>
* 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.

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
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.

View file

@ -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);

View file

@ -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) {
*s++ = '\\';
*s++ = 'C';
*s++ = '-';
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) {
*s++ = '\\';
*s++ = 'C';
*s++ = '-';
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,8 +5050,13 @@ 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);
free(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)) {
fputs("$'", stream);
mb_niceformat(s, stream, NULL, NICEFLAG_QUOTE);
fputc('\'', stream);
return;
if (stream) {
fputs("$'", stream);
mb_niceformat(s, stream, NULL, NICEFLAG_QUOTE);
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 */
if (!hasspecial(s)) {
zputs(s, stream);
return;
if (stream) {
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)) {
/* use rc-style quotes-within-quotes for the whole string */
if(fputc('\'', stream) < 0)
return;
if (stream) {
if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
while(*s) {
if (*s == Meta)
c = *++s ^ 32;
@ -5873,52 +5999,98 @@ quotedzputs(char const *s, FILE *stream)
c = *s;
s++;
if (c == '\'') {
if(fputc('\'', stream) < 0)
return;
} else if(c == '\n' && isset(CSHJUNKIEQUOTES)) {
if(fputc('\\', stream) < 0)
return;
if (stream) {
if (fputc('\'', stream) < 0)
return NULL;
} else
*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)
return;
if (stream) {
if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
} else {
/* use Bourne-style quoting, avoiding empty quoted strings */
while(*s) {
while (*s) {
if (*s == Meta)
c = *++s ^ 32;
else
c = *s;
s++;
if (c == '\'') {
if(inquote) {
if(fputc('\'', stream) < 0)
return;
if (inquote) {
if (stream) {
if (putc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
inquote=0;
}
if(fputs("\\'", stream) < 0)
return;
if (stream) {
if (fputs("\\'", stream) < 0)
return NULL;
} else {
*ptr++ = '\\';
*ptr++ = '\'';
}
} else {
if (!inquote) {
if(fputc('\'', stream) < 0)
return;
if (stream) {
if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
inquote=1;
}
if(c == '\n' && isset(CSHJUNKIEQUOTES)) {
if(fputc('\\', stream) < 0)
return;
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 (inquote) {
if(fputc('\'', stream) < 0)
return;
if (stream) {
if (fputc('\'', stream) < 0)
return NULL;
} else
*ptr++ = '\'';
}
}
if (!stream)
*ptr++ = '\0';
return outstr;
}
/* Double-quote a metafied string. */

View file

@ -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 */

View file

@ -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}

View file

@ -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