summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2014-10-19 11:59:15 +0000
committerjilles <jilles@FreeBSD.org>2014-10-19 11:59:15 +0000
commit4eb9d5ad9feda4e7548b017f80c8d769f155992a (patch)
tree4ecfed1ba1b516f4033a57fe24f5b3ba1da1b1e4 /bin
parent4c24d0f039fa0d4fd238c7656db20db39ad26b7f (diff)
downloadFreeBSD-src-4eb9d5ad9feda4e7548b017f80c8d769f155992a.zip
FreeBSD-src-4eb9d5ad9feda4e7548b017f80c8d769f155992a.tar.gz
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
Diffstat (limited to 'bin')
-rw-r--r--bin/sh/parser.c75
-rw-r--r--bin/sh/tests/parser/Makefile8
-rw-r--r--bin/sh/tests/parser/line-cont10.018
-rw-r--r--bin/sh/tests/parser/line-cont11.023
-rw-r--r--bin/sh/tests/parser/line-cont4.08
-rw-r--r--bin/sh/tests/parser/line-cont5.014
-rw-r--r--bin/sh/tests/parser/line-cont6.023
-rw-r--r--bin/sh/tests/parser/line-cont7.07
-rw-r--r--bin/sh/tests/parser/line-cont8.06
-rw-r--r--bin/sh/tests/parser/line-cont9.06
10 files changed, 156 insertions, 32 deletions
diff --git a/bin/sh/parser.c b/bin/sh/parser.c
index a8ecf03..7fae29e 100644
--- a/bin/sh/parser.c
+++ b/bin/sh/parser.c
@@ -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.
diff --git a/bin/sh/tests/parser/Makefile b/bin/sh/tests/parser/Makefile
index ef528f8..3c9e62c 100644
--- a/bin/sh/tests/parser/Makefile
+++ b/bin/sh/tests/parser/Makefile
@@ -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
diff --git a/bin/sh/tests/parser/line-cont10.0 b/bin/sh/tests/parser/line-cont10.0
new file mode 100644
index 0000000..1e74108
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont10.0
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+v=XaaaXbbbX
+[ "${v\
+#\
+*\
+a}.${v\
+#\
+#\
+*\
+a}.${v\
+%\
+b\
+*}.${v\
+%\
+%\
+b\
+*}" = aaXbbbX.XbbbX.XaaaXbb.XaaaX ]
diff --git a/bin/sh/tests/parser/line-cont11.0 b/bin/sh/tests/parser/line-cont11.0
new file mode 100644
index 0000000..22e4975
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont11.0
@@ -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
diff --git a/bin/sh/tests/parser/line-cont4.0 b/bin/sh/tests/parser/line-cont4.0
new file mode 100644
index 0000000..5803276
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont4.0
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+v=abcd
+[ "$\
+v.$\
+{v}.${\
+v}.${v\
+}" = abcd.abcd.abcd.abcd ]
diff --git a/bin/sh/tests/parser/line-cont5.0 b/bin/sh/tests/parser/line-cont5.0
new file mode 100644
index 0000000..a7aa026
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont5.0
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+bad=1
+case x in
+x\
+) ;\
+; *) exit 7
+esac &\
+& bad= &\
+& : >\
+>/dev/null
+
+false |\
+| [ -z "$bad" ]
diff --git a/bin/sh/tests/parser/line-cont6.0 b/bin/sh/tests/parser/line-cont6.0
new file mode 100644
index 0000000..b12125b
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont6.0
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+v0\
+=abc
+
+v=$(cat <\
+<\
+E\
+O\
+F
+${v0}d
+EOF
+)
+
+w=$(cat <\
+<\
+-\
+EOF
+ efgh
+EOF
+)
+
+[ "$v.$w" = "abcd.efgh" ]
diff --git a/bin/sh/tests/parser/line-cont7.0 b/bin/sh/tests/parser/line-cont7.0
new file mode 100644
index 0000000..27f8aec
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont7.0
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+[ "$(\
+(
+1\
++ 1)\
+)" = 2 ]
diff --git a/bin/sh/tests/parser/line-cont8.0 b/bin/sh/tests/parser/line-cont8.0
new file mode 100644
index 0000000..88667760
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont8.0
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+set -- a b c d e f g h i j
+[ "${1\
+0\
+}" = j ]
diff --git a/bin/sh/tests/parser/line-cont9.0 b/bin/sh/tests/parser/line-cont9.0
new file mode 100644
index 0000000..4e73c8f
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont9.0
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+[ "${$\
+:\
++\
+xyz}" = xyz ]
OpenPOWER on IntegriCloud