1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-29 19:00:57 +02:00

21862/21863: GLOB_SUBST shouldn't swallow up backslashes in parameter

substitutions that don't match anything.
This commit is contained in:
Peter Stephenson 2005-10-11 16:48:05 +00:00
parent 1eaa7fee0d
commit cca66ab341
8 changed files with 92 additions and 21 deletions

View file

@ -1,3 +1,10 @@
2005-10-11 Peter Stephenson <pws@csr.com>
* 21862/21863: Src/glob.c, Src/lex.c, Src/pattern.c, Src/subst.c,
Src/zsh.h, Test/D04parameter.ztst, Test/ztst.zsh: Ensure that
backslashes in parameters substituted by GLOB_SUBST are not
swallowed up if there is no pattern match.
2005-10-07 Peter Stephenson <pws@csr.com> 2005-10-07 Peter Stephenson <pws@csr.com>
* Stephen Rüger: 21846: Completion/Unix/Command/_chmod: too * Stephen Rüger: 21846: Completion/Unix/Command/_chmod: too

View file

@ -2487,19 +2487,29 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
mod_export void mod_export void
tokenize(char *s) tokenize(char *s)
{ {
zshtokenize(s, 0); zshtokenize(s, 0, 0);
} }
/*
* shtokenize is used when we tokenize a string with GLOB_SUBST set.
* In that case we need to retain backslashes when we turn the
* pattern back into a string, so that the string is not
* modified if it failed to match a pattern.
*
* It may be modified by the effect of SH_GLOB which turns off
* various zsh-specific options.
*/
/**/ /**/
mod_export void mod_export void
shtokenize(char *s) shtokenize(char *s)
{ {
zshtokenize(s, isset(SHGLOB)); zshtokenize(s, 1, isset(SHGLOB));
} }
/**/ /**/
static void static void
zshtokenize(char *s, int shglob) zshtokenize(char *s, int glbsbst, int shglob)
{ {
char *t; char *t;
int bslash = 0; int bslash = 0;
@ -2508,9 +2518,10 @@ zshtokenize(char *s, int shglob)
cont: cont:
switch (*s) { switch (*s) {
case Bnull: case Bnull:
case Bnullkeep:
case '\\': case '\\':
if (bslash) { if (bslash) {
s[-1] = Bnull; s[-1] = glbsbst ? Bnullkeep : Bnull;
break; break;
} }
bslash = 1; bslash = 1;
@ -2519,7 +2530,7 @@ zshtokenize(char *s, int shglob)
if (shglob) if (shglob)
break; break;
if (bslash) { if (bslash) {
s[-1] = Bnull; s[-1] = glbsbst ? Bnullkeep : Bnull;
break; break;
} }
t = s; t = s;
@ -2549,7 +2560,7 @@ zshtokenize(char *s, int shglob)
for (t = ztokens; *t; t++) for (t = ztokens; *t; t++)
if (*t == *s) { if (*t == *s) {
if (bslash) if (bslash)
s[-1] = Bnull; s[-1] = glbsbst ? Bnullkeep : Bnull;
else else
*s = (t - ztokens) + Pound; *s = (t - ztokens) + Pound;
break; break;
@ -2569,12 +2580,23 @@ remnulargs(char *s)
char *o = s, c; char *o = s, c;
while ((c = *s++)) while ((c = *s++))
if (INULL(c)) { if (c == Bnullkeep) {
/*
* An active backslash that needs to be turned back into
* a real backslash for output. However, we don't
* do that yet since we need to ignore it during
* pattern matching.
*/
continue;
} else if (INULL(c)) {
char *t = s - 1; char *t = s - 1;
while ((c = *s++)) while ((c = *s++)) {
if (!INULL(c)) if (c == Bnullkeep)
*t++ = '\\';
else if (!INULL(c))
*t++ = c; *t++ = c;
}
*t = '\0'; *t = '\0';
if (!*o) { if (!*o) {
o[0] = Nularg; o[0] = Nularg;

View file

@ -33,7 +33,7 @@
/* tokens */ /* tokens */
/**/ /**/
mod_export char ztokens[] = "#$^*()$=|{}[]`<>?~`,'\"\\"; mod_export char ztokens[] = "#$^*()$=|{}[]`<>?~`,'\"\\\\";
/* parts of the current token */ /* parts of the current token */

View file

@ -260,13 +260,13 @@ static char endseg[] = {
static char endstr[] = { static char endstr[] = {
'/', /* file only */ '/', /* file only */
'\0', Bar, Outpar, Quest, Star, Inbrack, Inpar, Inang, '\0', Bar, Outpar, Quest, Star, Inbrack, Inpar, Inang, Bnullkeep,
/* all patterns */ /* all patterns */
Tilde, Hat, Pound /* extended glob only */ Tilde, Hat, Pound /* extended glob only */
}; };
#define PATENDSTRLEN_NORM 9 #define PATENDSTRLEN_NORM 10
#define PATENDSTRLEN_EXT 12 #define PATENDSTRLEN_EXT 13
/* Default size for pattern buffer */ /* Default size for pattern buffer */
@ -1240,6 +1240,13 @@ patcomppiece(int *flagp)
*/ */
return 0; return 0;
break; break;
case Bnullkeep:
/*
* Marker for restoring a backslash in output:
* does not match a character.
*/
return patcomppiece(flagp);
break;
#ifdef DEBUG #ifdef DEBUG
default: default:
dputs("BUG: character not handled in patcomppiece"); dputs("BUG: character not handled in patcomppiece");

View file

@ -1945,7 +1945,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
*/ */
for (ptr = s; (c = *ptr) && c != '/'; ptr++) for (ptr = s; (c = *ptr) && c != '/'; ptr++)
{ {
if ((c == Bnull || c == '\\') && ptr[1]) if ((c == Bnull || c == Bnullkeep || c == '\\') && ptr[1])
{ {
if (ptr[1] == '/') if (ptr[1] == '/')
chuck(ptr); chuck(ptr);
@ -2846,11 +2846,11 @@ modify(char **str, char **ptr)
} }
zsfree(hsubr); zsfree(hsubr);
for (tt = hsubl; *tt; tt++) for (tt = hsubl; *tt; tt++)
if (INULL(*tt)) if (INULL(*tt) && *tt != Bnullkeep)
chuck(tt--); chuck(tt--);
untokenize(hsubl); untokenize(hsubl);
for (tt = hsubr = ztrdup(ptr2); *tt; tt++) for (tt = hsubr = ztrdup(ptr2); *tt; tt++)
if (INULL(*tt)) if (INULL(*tt) && *tt != Bnullkeep)
chuck(tt--); chuck(tt--);
ptr2[-1] = del; ptr2[-1] = del;
if (sav) if (sav)

View file

@ -120,7 +120,10 @@ struct mathfunc {
#define DEFAULT_IFS " \t\n\203 " #define DEFAULT_IFS " \t\n\203 "
/* Character tokens */ /*
* Character tokens.
* These should match the characters in ztokens, defined in lex.c
*/
#define Pound ((char) 0x84) #define Pound ((char) 0x84)
#define String ((char) 0x85) #define String ((char) 0x85)
#define Hat ((char) 0x86) #define Hat ((char) 0x86)
@ -141,15 +144,33 @@ struct mathfunc {
#define Tilde ((char) 0x95) #define Tilde ((char) 0x95)
#define Qtick ((char) 0x96) #define Qtick ((char) 0x96)
#define Comma ((char) 0x97) #define Comma ((char) 0x97)
/*
* Null arguments: placeholders for single and double quotes
* and backslashes.
*/
#define Snull ((char) 0x98) #define Snull ((char) 0x98)
#define Dnull ((char) 0x99) #define Dnull ((char) 0x99)
#define Bnull ((char) 0x9a) #define Bnull ((char) 0x9a)
#define Nularg ((char) 0x9b) /*
* Backslash which will be returned to "\" instead of being stripped
* when we turn the string into a printable format.
*/
#define Bnullkeep ((char) 0x9b)
/*
* Null argument that does not correspond to any character.
* This should be last as it does not appear in ztokens and
* is used to initialise the IMETA type in inittyptab().
*/
#define Nularg ((char) 0x9c)
#define INULL(x) (((x) & 0xfc) == 0x98) #define INULL(x) (((x) & 0xf8) == 0x98)
/*
* Take care to update the use of IMETA appropriately when adding
* tokens here.
*/
/* Marker used in paramsubst for rc_expand_param */ /* Marker used in paramsubst for rc_expand_param */
#define Marker ((char) 0x9c) #define Marker ((char) 0xa0)
/* chars that need to be quoted if meant literally */ /* chars that need to be quoted if meant literally */

View file

@ -196,6 +196,20 @@
>* boringfile evenmoreboringfile boringfile evenmoreboringfile >* boringfile evenmoreboringfile boringfile evenmoreboringfile
>boringfile evenmoreboringfile >boringfile evenmoreboringfile
# The following tests a bug where globsubst didn't preserve
# backslashes when printing out the original string.
str1='\\*\\'
(
setopt globsubst nonomatch
[[ \\\\ = $str1 ]] && print -r '\\ matched by' $str1
[[ \\foo\\ = $str1 ]] && print -r '\\foo matched by' $str1
[[ a\\b\\ = $str1 ]] || print -r 'a\\b not matched by' $str1
)
0:globsubst with backslashes
>\\ matched by \\*\\
>\\foo matched by \\*\\
>a\\b not matched by \\*\\
print -l "${$(print one word)}" "${=$(print two words)}" print -l "${$(print one word)}" "${=$(print two words)}"
0:splitting of $(...) inside ${...} 0:splitting of $(...) inside ${...}
>one word >one word

View file

@ -280,7 +280,7 @@ ZTST_diff() {
diff_out=$(diff "$@") diff_out=$(diff "$@")
diff_ret="$?" diff_ret="$?"
if [[ "$diff_ret" != "0" ]]; then if [[ "$diff_ret" != "0" ]]; then
echo "$diff_out" print -r "$diff_out"
fi fi
return "$diff_ret" return "$diff_ret"