sh: Allow backslash-newline continuation in more places:
* directly after a $ * directly after ${ * between the characters of a multi-character operator token * within a parameter name
This commit is contained in:
parent
4c24d0f039
commit
4eb9d5ad9f
@ -125,6 +125,7 @@ static void consumetoken(int);
|
||||
static void synexpect(int) __dead2;
|
||||
static void synerror(const char *) __dead2;
|
||||
static void setprompt(int);
|
||||
static int pgetc_linecont(void);
|
||||
|
||||
|
||||
static void *
|
||||
@ -899,17 +900,17 @@ xxreadtoken(void)
|
||||
case PEOF:
|
||||
RETURN(TEOF);
|
||||
case '&':
|
||||
if (pgetc() == '&')
|
||||
if (pgetc_linecont() == '&')
|
||||
RETURN(TAND);
|
||||
pungetc();
|
||||
RETURN(TBACKGND);
|
||||
case '|':
|
||||
if (pgetc() == '|')
|
||||
if (pgetc_linecont() == '|')
|
||||
RETURN(TOR);
|
||||
pungetc();
|
||||
RETURN(TPIPE);
|
||||
case ';':
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (c == ';')
|
||||
RETURN(TENDCASE);
|
||||
else if (c == '&')
|
||||
@ -991,7 +992,7 @@ parseredir(char *out, int c)
|
||||
np = (union node *)stalloc(sizeof (struct nfile));
|
||||
if (c == '>') {
|
||||
np->nfile.fd = 1;
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (c == '>')
|
||||
np->type = NAPPEND;
|
||||
else if (c == '&')
|
||||
@ -1004,7 +1005,7 @@ parseredir(char *out, int c)
|
||||
}
|
||||
} else { /* c == '<' */
|
||||
np->nfile.fd = 0;
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (c == '<') {
|
||||
if (sizeof (struct nfile) != sizeof (struct nhere)) {
|
||||
np = (union node *)stalloc(sizeof (struct nhere));
|
||||
@ -1013,7 +1014,7 @@ parseredir(char *out, int c)
|
||||
np->type = NHERE;
|
||||
heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
|
||||
heredoc->here = np;
|
||||
if ((c = pgetc()) == '-') {
|
||||
if ((c = pgetc_linecont()) == '-') {
|
||||
heredoc->striptabs = 1;
|
||||
} else {
|
||||
heredoc->striptabs = 0;
|
||||
@ -1094,25 +1095,12 @@ parsebackq(char *out, struct nodelist **pbqlist,
|
||||
needprompt = 0;
|
||||
}
|
||||
CHECKSTRSPACE(2, oout);
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (c == '`')
|
||||
break;
|
||||
switch (c) {
|
||||
case '\\':
|
||||
if ((c = pgetc()) == '\n') {
|
||||
plinno++;
|
||||
if (doprompt)
|
||||
setprompt(2);
|
||||
else
|
||||
setprompt(0);
|
||||
/*
|
||||
* If eating a newline, avoid putting
|
||||
* the newline into the new character
|
||||
* stream (via the USTPUTC after the
|
||||
* switch).
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
c = pgetc();
|
||||
if (c != '\\' && c != '`' && c != '$'
|
||||
&& (!dblquote || c != '"'))
|
||||
USTPUTC('\\', oout);
|
||||
@ -1507,7 +1495,7 @@ readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
|
||||
USTPUTC(c, out);
|
||||
--state[level].parenlevel;
|
||||
} else {
|
||||
if (pgetc() == ')') {
|
||||
if (pgetc_linecont() == ')') {
|
||||
if (level > 0 &&
|
||||
state[level].category == TSTATE_ARITH) {
|
||||
level--;
|
||||
@ -1593,9 +1581,9 @@ parsesub: {
|
||||
int length;
|
||||
int c1;
|
||||
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (c == '(') { /* $(command) or $((arith)) */
|
||||
if (pgetc() == '(') {
|
||||
if (pgetc_linecont() == '(') {
|
||||
PARSEARITH();
|
||||
} else {
|
||||
pungetc();
|
||||
@ -1613,7 +1601,7 @@ parsesub: {
|
||||
flags = 0;
|
||||
if (c == '{') {
|
||||
bracketed_name = 1;
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
subtype = 0;
|
||||
}
|
||||
varname:
|
||||
@ -1621,7 +1609,7 @@ varname:
|
||||
length = 0;
|
||||
do {
|
||||
STPUTC(c, out);
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
length++;
|
||||
} while (!is_eof(c) && is_in_name(c));
|
||||
if (length == 6 &&
|
||||
@ -1640,22 +1628,22 @@ varname:
|
||||
if (bracketed_name) {
|
||||
do {
|
||||
STPUTC(c, out);
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
} while (is_digit(c));
|
||||
} else {
|
||||
STPUTC(c, out);
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
}
|
||||
} else if (is_special(c)) {
|
||||
c1 = c;
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (subtype == 0 && c1 == '#') {
|
||||
subtype = VSLENGTH;
|
||||
if (strchr(types, c) == NULL && c != ':' &&
|
||||
c != '#' && c != '%')
|
||||
goto varname;
|
||||
c1 = c;
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (c1 != '}' && c == '}') {
|
||||
pungetc();
|
||||
c = c1;
|
||||
@ -1680,7 +1668,7 @@ varname:
|
||||
switch (c) {
|
||||
case ':':
|
||||
flags |= VSNUL;
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
p = strchr(types, c);
|
||||
@ -1700,7 +1688,7 @@ varname:
|
||||
int cc = c;
|
||||
subtype = c == '#' ? VSTRIMLEFT :
|
||||
VSTRIMRIGHT;
|
||||
c = pgetc();
|
||||
c = pgetc_linecont();
|
||||
if (c == cc)
|
||||
subtype++;
|
||||
else
|
||||
@ -1909,6 +1897,29 @@ setprompt(int which)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pgetc_linecont(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = pgetc_macro()) == '\\') {
|
||||
c = pgetc();
|
||||
if (c == '\n') {
|
||||
plinno++;
|
||||
if (doprompt)
|
||||
setprompt(2);
|
||||
else
|
||||
setprompt(0);
|
||||
} else {
|
||||
pungetc();
|
||||
/* Allow the backslash to be pushed back. */
|
||||
pushstring("\\", 1, NULL);
|
||||
return (pgetc());
|
||||
}
|
||||
}
|
||||
return (c);
|
||||
}
|
||||
|
||||
/*
|
||||
* called by editline -- any expansions to the prompt
|
||||
* should be added here.
|
||||
|
@ -58,6 +58,14 @@ FILES+= heredoc12.0
|
||||
FILES+= line-cont1.0
|
||||
FILES+= line-cont2.0
|
||||
FILES+= line-cont3.0
|
||||
FILES+= line-cont4.0
|
||||
FILES+= line-cont5.0
|
||||
FILES+= line-cont6.0
|
||||
FILES+= line-cont7.0
|
||||
FILES+= line-cont8.0
|
||||
FILES+= line-cont9.0
|
||||
FILES+= line-cont10.0
|
||||
FILES+= line-cont11.0
|
||||
FILES+= no-space1.0
|
||||
FILES+= no-space2.0
|
||||
FILES+= only-redir1.0
|
||||
|
18
bin/sh/tests/parser/line-cont10.0
Normal file
18
bin/sh/tests/parser/line-cont10.0
Normal file
@ -0,0 +1,18 @@
|
||||
# $FreeBSD$
|
||||
|
||||
v=XaaaXbbbX
|
||||
[ "${v\
|
||||
#\
|
||||
*\
|
||||
a}.${v\
|
||||
#\
|
||||
#\
|
||||
*\
|
||||
a}.${v\
|
||||
%\
|
||||
b\
|
||||
*}.${v\
|
||||
%\
|
||||
%\
|
||||
b\
|
||||
*}" = aaXbbbX.XbbbX.XaaaXbb.XaaaX ]
|
23
bin/sh/tests/parser/line-cont11.0
Normal file
23
bin/sh/tests/parser/line-cont11.0
Normal file
@ -0,0 +1,23 @@
|
||||
# $FreeBSD$
|
||||
|
||||
T=$(mktemp "${TMPDIR:-/tmp}/sh-test.XXXXXXXX") || exit
|
||||
trap 'rm -f -- "$T"' 0
|
||||
w='#A'
|
||||
# A naive pgetc_linecont() would push back two characters here, which
|
||||
# fails if a new buffer is read between the two characters.
|
||||
c='${w#\#}'
|
||||
c=$c$c$c$c
|
||||
c=$c$c$c$c
|
||||
c=$c$c$c$c
|
||||
c=$c$c$c$c
|
||||
c=$c$c$c$c
|
||||
c=$c$c$c$c
|
||||
printf 'v=%s\n' "$c" >"$T"
|
||||
. "$T"
|
||||
if [ "${#v}" != 4096 ]; then
|
||||
echo "Length is bad (${#v})"
|
||||
exit 3
|
||||
fi
|
||||
case $v in
|
||||
*[!A]*) echo "Content is bad"; exit 3 ;;
|
||||
esac
|
8
bin/sh/tests/parser/line-cont4.0
Normal file
8
bin/sh/tests/parser/line-cont4.0
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
v=abcd
|
||||
[ "$\
|
||||
v.$\
|
||||
{v}.${\
|
||||
v}.${v\
|
||||
}" = abcd.abcd.abcd.abcd ]
|
14
bin/sh/tests/parser/line-cont5.0
Normal file
14
bin/sh/tests/parser/line-cont5.0
Normal file
@ -0,0 +1,14 @@
|
||||
# $FreeBSD$
|
||||
|
||||
bad=1
|
||||
case x in
|
||||
x\
|
||||
) ;\
|
||||
; *) exit 7
|
||||
esac &\
|
||||
& bad= &\
|
||||
& : >\
|
||||
>/dev/null
|
||||
|
||||
false |\
|
||||
| [ -z "$bad" ]
|
23
bin/sh/tests/parser/line-cont6.0
Normal file
23
bin/sh/tests/parser/line-cont6.0
Normal file
@ -0,0 +1,23 @@
|
||||
# $FreeBSD$
|
||||
|
||||
v0\
|
||||
=abc
|
||||
|
||||
v=$(cat <\
|
||||
<\
|
||||
E\
|
||||
O\
|
||||
F
|
||||
${v0}d
|
||||
EOF
|
||||
)
|
||||
|
||||
w=$(cat <\
|
||||
<\
|
||||
-\
|
||||
EOF
|
||||
efgh
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$v.$w" = "abcd.efgh" ]
|
7
bin/sh/tests/parser/line-cont7.0
Normal file
7
bin/sh/tests/parser/line-cont7.0
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
[ "$(\
|
||||
(
|
||||
1\
|
||||
+ 1)\
|
||||
)" = 2 ]
|
6
bin/sh/tests/parser/line-cont8.0
Normal file
6
bin/sh/tests/parser/line-cont8.0
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
set -- a b c d e f g h i j
|
||||
[ "${1\
|
||||
0\
|
||||
}" = j ]
|
6
bin/sh/tests/parser/line-cont9.0
Normal file
6
bin/sh/tests/parser/line-cont9.0
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
[ "${$\
|
||||
:\
|
||||
+\
|
||||
xyz}" = xyz ]
|
Loading…
x
Reference in New Issue
Block a user