mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-21 00:01:26 +01:00
23784: Use $'\...' for quoting unparseable characters
This commit is contained in:
parent
53184f457b
commit
bfa48687c0
2 changed files with 112 additions and 53 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2007-08-20 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||||
|
|
||||||
|
* 23784: Src/utils.c: Use $'\...' quoting for unparseable and
|
||||||
|
unprintable characters when doing backslash quoting.
|
||||||
|
|
||||||
2007-08-19 Clint Adams <clint@zsh.org>
|
2007-08-19 Clint Adams <clint@zsh.org>
|
||||||
|
|
||||||
* R.Ramkumar: 23783: Completion/Zsh/Command/_command,
|
* R.Ramkumar: 23783: Completion/Zsh/Command/_command,
|
||||||
|
|
160
Src/utils.c
160
Src/utils.c
|
@ -4124,6 +4124,51 @@ hasspecial(char const *s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
addunprintable(char *v, const char *u, const char *uend)
|
||||||
|
{
|
||||||
|
for (; u < uend; u++) {
|
||||||
|
/*
|
||||||
|
* Just do this byte by byte; there's no great
|
||||||
|
* advantage in being clever with multibyte
|
||||||
|
* characters if we don't think they're printable.
|
||||||
|
*/
|
||||||
|
int c;
|
||||||
|
if (*u == Meta)
|
||||||
|
c = STOUC(*++u ^ 32);
|
||||||
|
else
|
||||||
|
c = STOUC(*u);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Quote the string s and return the result.
|
* Quote the string s and return the result.
|
||||||
*
|
*
|
||||||
|
@ -4142,8 +4187,16 @@ quotestring(const char *s, char **e, int instring)
|
||||||
{
|
{
|
||||||
const char *u, *tt;
|
const char *u, *tt;
|
||||||
char *v;
|
char *v;
|
||||||
char *buf = hcalloc(4 * strlen(s) + 1);
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int alloclen = (instring == QT_BACKSLASH ? 7 : 4) * strlen(s) + 1;
|
||||||
|
char *buf = zshcalloc(alloclen);
|
||||||
int sf = 0;
|
int sf = 0;
|
||||||
|
convchar_t cc;
|
||||||
|
const char *uend;
|
||||||
|
|
||||||
DPUTS(instring < QT_BACKSLASH || instring > QT_DOLLARS,
|
DPUTS(instring < QT_BACKSLASH || instring > QT_DOLLARS,
|
||||||
"BUG: bad quote type in quotestring");
|
"BUG: bad quote type in quotestring");
|
||||||
|
@ -4154,10 +4207,9 @@ quotestring(const char *s, char **e, int instring)
|
||||||
* As we test for printability here we need to be able
|
* As we test for printability here we need to be able
|
||||||
* to look for multibyte characters.
|
* to look for multibyte characters.
|
||||||
*/
|
*/
|
||||||
convchar_t cc;
|
|
||||||
MB_METACHARINIT();
|
MB_METACHARINIT();
|
||||||
while (*u) {
|
while (*u) {
|
||||||
const char *uend = u + MB_METACHARLENCONV(u, &cc);
|
uend = u + MB_METACHARLENCONV(u, &cc);
|
||||||
|
|
||||||
if (e && !sf && *e <= u) {
|
if (e && !sf && *e <= u) {
|
||||||
*e = v;
|
*e = v;
|
||||||
|
@ -4183,53 +4235,19 @@ quotestring(const char *s, char **e, int instring)
|
||||||
*v++ = *u++;
|
*v++ = *u++;
|
||||||
} else {
|
} else {
|
||||||
/* Not printable */
|
/* Not printable */
|
||||||
for (; u < uend; u++) {
|
v = addunprintable(v, u, uend);
|
||||||
/*
|
u = uend;
|
||||||
* Just do this byte by byte; there's no great
|
|
||||||
* advantage in being clever with multibyte
|
|
||||||
* characters if we don't think they're printable.
|
|
||||||
*/
|
|
||||||
int c;
|
|
||||||
if (*u == Meta)
|
|
||||||
c = STOUC(*++u ^ 32);
|
|
||||||
else
|
|
||||||
c = STOUC(*u);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Here the only special characters are syntactic, so
|
* Here there are syntactic special characters, so
|
||||||
* we can go through bytewise.
|
* we start by going through bytewise.
|
||||||
*/
|
*/
|
||||||
for (; *u; u++) {
|
while (*u) {
|
||||||
|
int dobackslash = 0;
|
||||||
if (e && *e == u)
|
if (e && *e == u)
|
||||||
*e = v, sf = 1;
|
*e = v, sf = 1;
|
||||||
if (*u == Tick || *u == Qtick) {
|
if (*u == Tick || *u == Qtick) {
|
||||||
|
@ -4239,8 +4257,6 @@ quotestring(const char *s, char **e, int instring)
|
||||||
while (*u && *u != c)
|
while (*u && *u != c)
|
||||||
*v++ = *u++;
|
*v++ = *u++;
|
||||||
*v++ = c;
|
*v++ = c;
|
||||||
if (!*u)
|
|
||||||
u--;
|
|
||||||
continue;
|
continue;
|
||||||
} else if ((*u == Qstring || *u == '$') && u[1] == '\'' &&
|
} else if ((*u == Qstring || *u == '$') && u[1] == '\'' &&
|
||||||
instring == QT_DOUBLE) {
|
instring == QT_DOUBLE) {
|
||||||
|
@ -4268,9 +4284,7 @@ quotestring(const char *s, char **e, int instring)
|
||||||
*v++ = *u++;
|
*v++ = *u++;
|
||||||
}
|
}
|
||||||
if (*u)
|
if (*u)
|
||||||
*v++ = *u;
|
*v++ = *u++;
|
||||||
else
|
|
||||||
u--;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (ispecial(*u) &&
|
else if (ispecial(*u) &&
|
||||||
|
@ -4296,13 +4310,51 @@ quotestring(const char *s, char **e, int instring)
|
||||||
*v++ = '"', *v++ = '\n', *v++ = '"';
|
*v++ = '"', *v++ = '\n', *v++ = '"';
|
||||||
else
|
else
|
||||||
*v++ = '\'', *v++ = '\'';
|
*v++ = '\'', *v++ = '\'';
|
||||||
|
u++;
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else {
|
||||||
*v++ = '\\';
|
/*
|
||||||
|
* We'll need a backslash, but don't add it
|
||||||
|
* yet since if the character isn't printable
|
||||||
|
* we'll have to upgrade it to $'...'.
|
||||||
|
*/
|
||||||
|
dobackslash = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(*u == Meta)
|
|
||||||
|
if (itok(*u) || instring != QT_BACKSLASH) {
|
||||||
|
/* Needs to be passed straight through. */
|
||||||
|
if (dobackslash)
|
||||||
|
*v++ = '\\';
|
||||||
*v++ = *u++;
|
*v++ = *u++;
|
||||||
*v++ = *u;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now check if the output is unprintable in the
|
||||||
|
* current character set.
|
||||||
|
*/
|
||||||
|
uend = u + MB_METACHARLENCONV(u, &cc);
|
||||||
|
if (
|
||||||
|
#ifdef MULTIBYTE_SUPPORT
|
||||||
|
cc != WEOF &&
|
||||||
|
#endif
|
||||||
|
WC_ISPRINT(cc)) {
|
||||||
|
if (dobackslash)
|
||||||
|
*v++ = '\\';
|
||||||
|
while (u < uend) {
|
||||||
|
if (*u == Meta)
|
||||||
|
*v++ = *u++;
|
||||||
|
*v++ = *u++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Not printable */
|
||||||
|
*v++ = '$';
|
||||||
|
*v++ = '\'';
|
||||||
|
v = addunprintable(v, u, uend);
|
||||||
|
*v++ = '\'';
|
||||||
|
u = uend;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*v = '\0';
|
*v = '\0';
|
||||||
|
@ -4311,7 +4363,9 @@ quotestring(const char *s, char **e, int instring)
|
||||||
*e = v, sf = 1;
|
*e = v, sf = 1;
|
||||||
DPUTS(e && !sf, "BUG: Wild pointer *e in quotestring()");
|
DPUTS(e && !sf, "BUG: Wild pointer *e in quotestring()");
|
||||||
|
|
||||||
return buf;
|
v = dupstring(buf);
|
||||||
|
zfree(buf, alloclen);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmetafy and output a string, quoted if it contains special characters. */
|
/* Unmetafy and output a string, quoted if it contains special characters. */
|
||||||
|
|
Loading…
Reference in a new issue