ash: [PARSER] Handle backslash newlines properly after dollar sign
Fixes var_unbackslash1.tests failure. Upstream commit: [PARSER] Handle backslash newlines properly after dollar sign On Tue, Aug 26, 2014 at 12:34:42PM +0000, Eric Blake wrote: > On 08/26/2014 06:15 AM, Oleg Bulatov wrote: > > While playing with sh generators I found that dash and bash have different > > interpretations for <slash><newline> sequence. > > > > $ dash -c 'EDIT=xxx; echo $EDIT\ > >> OR' > > xxxOR > > Buggy. > > > > $ dash -c 'echo "$\ > > (pwd)"' > > $(pwd) > > > > Is it undefined behaviour in POSIX? > > No, it's well-defined, and dash is buggy. ... I agree. This patch should resolve this problem and similar ones affecting blackslash newlines after we encounter a dollar sign. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
8286513838
commit
73c3e074df
44
shell/ash.c
44
shell/ash.c
@ -9774,11 +9774,6 @@ popstring(void)
|
|||||||
INT_ON;
|
INT_ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
|
|
||||||
//it peeks whether it is &>, and then pushes back both chars.
|
|
||||||
//This function needs to save last *next_to_pgetc to buf[0]
|
|
||||||
//to make two pungetc() reliable. Currently,
|
|
||||||
// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
|
|
||||||
static int
|
static int
|
||||||
preadfd(void)
|
preadfd(void)
|
||||||
{
|
{
|
||||||
@ -10037,6 +10032,25 @@ pungetc(void)
|
|||||||
g_parsefile->unget++;
|
g_parsefile->unget++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This one eats backslash+newline */
|
||||||
|
static int
|
||||||
|
pgetc_eatbnl(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = pgetc()) == '\\') {
|
||||||
|
if (pgetc() != '\n') {
|
||||||
|
pungetc();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_parsefile->linno++;
|
||||||
|
setprompt_if(doprompt, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To handle the "." command, a stack of input files is used. Pushfile
|
* To handle the "." command, a stack of input files is used. Pushfile
|
||||||
* adds a new entry to the stack and popfile restores the previous level.
|
* adds a new entry to the stack and popfile restores the previous level.
|
||||||
@ -11625,7 +11639,7 @@ parsesub: {
|
|||||||
int typeloc;
|
int typeloc;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
if (c > 255 /* PEOA or PEOF */
|
if (c > 255 /* PEOA or PEOF */
|
||||||
|| (c != '(' && c != '{' && !is_name(c) && !is_special(c))
|
|| (c != '(' && c != '{' && !is_name(c) && !is_special(c))
|
||||||
) {
|
) {
|
||||||
@ -11638,7 +11652,7 @@ parsesub: {
|
|||||||
pungetc();
|
pungetc();
|
||||||
} else if (c == '(') {
|
} else if (c == '(') {
|
||||||
/* $(command) or $((arith)) */
|
/* $(command) or $((arith)) */
|
||||||
if (pgetc() == '(') {
|
if (pgetc_eatbnl() == '(') {
|
||||||
#if ENABLE_SH_MATH_SUPPORT
|
#if ENABLE_SH_MATH_SUPPORT
|
||||||
PARSEARITH();
|
PARSEARITH();
|
||||||
#else
|
#else
|
||||||
@ -11655,9 +11669,9 @@ parsesub: {
|
|||||||
USTPUTC(VSNORMAL, out);
|
USTPUTC(VSNORMAL, out);
|
||||||
subtype = VSNORMAL;
|
subtype = VSNORMAL;
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
if (c == '#') {
|
if (c == '#') {
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
if (c == '}')
|
if (c == '}')
|
||||||
c = '#'; /* ${#} - same as $# */
|
c = '#'; /* ${#} - same as $# */
|
||||||
else
|
else
|
||||||
@ -11670,18 +11684,18 @@ parsesub: {
|
|||||||
/* $[{[#]]NAME[}] */
|
/* $[{[#]]NAME[}] */
|
||||||
do {
|
do {
|
||||||
STPUTC(c, out);
|
STPUTC(c, out);
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
} while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
|
} while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
|
||||||
} else if (isdigit(c)) {
|
} else if (isdigit(c)) {
|
||||||
/* $[{[#]]NUM[}] */
|
/* $[{[#]]NUM[}] */
|
||||||
do {
|
do {
|
||||||
STPUTC(c, out);
|
STPUTC(c, out);
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
} while (isdigit(c));
|
} while (isdigit(c));
|
||||||
} else if (is_special(c)) {
|
} else if (is_special(c)) {
|
||||||
/* $[{[#]]<specialchar>[}] */
|
/* $[{[#]]<specialchar>[}] */
|
||||||
USTPUTC(c, out);
|
USTPUTC(c, out);
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
} else {
|
} else {
|
||||||
badsub:
|
badsub:
|
||||||
raise_error_syntax("bad substitution");
|
raise_error_syntax("bad substitution");
|
||||||
@ -11699,7 +11713,7 @@ parsesub: {
|
|||||||
/* c == first char after VAR */
|
/* c == first char after VAR */
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case ':':
|
case ':':
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
#if ENABLE_ASH_BASH_COMPAT
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
/* This check is only needed to not misinterpret
|
/* This check is only needed to not misinterpret
|
||||||
* ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
|
* ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
|
||||||
@ -11724,7 +11738,7 @@ parsesub: {
|
|||||||
case '#': {
|
case '#': {
|
||||||
int cc = c;
|
int cc = c;
|
||||||
subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
|
subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
if (c != cc)
|
if (c != cc)
|
||||||
goto do_pungetc;
|
goto do_pungetc;
|
||||||
subtype++;
|
subtype++;
|
||||||
@ -11736,7 +11750,7 @@ parsesub: {
|
|||||||
//TODO: encode pattern and repl separately.
|
//TODO: encode pattern and repl separately.
|
||||||
// Currently ${v/$var_with_slash/repl} is horribly broken
|
// Currently ${v/$var_with_slash/repl} is horribly broken
|
||||||
subtype = VSREPLACE;
|
subtype = VSREPLACE;
|
||||||
c = pgetc();
|
c = pgetc_eatbnl();
|
||||||
if (c != '/')
|
if (c != '/')
|
||||||
goto do_pungetc;
|
goto do_pungetc;
|
||||||
subtype++; /* VSREPLACEALL */
|
subtype++; /* VSREPLACEALL */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user