git: 72f750dc7c73 - main - sh: Fix heredoc at certain places in case and for

From: Jilles Tjoelker <jilles_at_FreeBSD.org>
Date: Wed, 27 Oct 2021 19:34:02 UTC
The branch main has been updated by jilles:

URL: https://cgit.FreeBSD.org/src/commit/?id=72f750dc7c7324c3999e4d6cfbb2758694893cdd

commit 72f750dc7c7324c3999e4d6cfbb2758694893cdd
Author:     Jilles Tjoelker <jilles@FreeBSD.org>
AuthorDate: 2021-10-14 20:53:42 +0000
Commit:     Jilles Tjoelker <jilles@FreeBSD.org>
CommitDate: 2021-10-27 19:05:19 +0000

    sh: Fix heredoc at certain places in case and for
    
    After an unescaped newline, there may be a here-document. Some places in
    case and for did not check for one.
    
    Reviewed by:    bdrewery
    Differential Revision:  https://reviews.freebsd.org/D32628
---
 bin/sh/parser.c                 | 16 +++++++++-------
 bin/sh/tests/parser/Makefile    |  3 +++
 bin/sh/tests/parser/heredoc14.0 |  8 ++++++++
 bin/sh/tests/parser/heredoc15.0 |  9 +++++++++
 bin/sh/tests/parser/heredoc16.0 |  8 ++++++++
 5 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/bin/sh/parser.c b/bin/sh/parser.c
index 297d19d4d9b6..e75798800edf 100644
--- a/bin/sh/parser.c
+++ b/bin/sh/parser.c
@@ -480,9 +480,9 @@ command(void)
 		n1 = (union node *)stalloc(sizeof (struct nfor));
 		n1->type = NFOR;
 		n1->nfor.var = wordtext;
-		while (readtoken() == TNL)
-			;
-		if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) {
+		checkkwd = CHKNL;
+		if (readtoken() == TWORD && !quoteflag &&
+		    equal(wordtext, "in")) {
 			app = &ap;
 			while (readtoken() == TWORD) {
 				n2 = makename();
@@ -491,7 +491,9 @@ command(void)
 			}
 			*app = NULL;
 			n1->nfor.args = ap;
-			if (lasttoken != TNL && lasttoken != TSEMI)
+			if (lasttoken == TNL)
+				tokpushback++;
+			else if (lasttoken != TSEMI)
 				synexpect(-1);
 		} else {
 			static char argvars[5] = {
@@ -507,7 +509,7 @@ command(void)
 			 * Newline or semicolon here is optional (but note
 			 * that the original Bourne shell only allowed NL).
 			 */
-			if (lasttoken != TNL && lasttoken != TSEMI)
+			if (lasttoken != TSEMI)
 				tokpushback++;
 		}
 		checkkwd = CHKNL | CHKKWD | CHKALIAS;
@@ -526,8 +528,8 @@ command(void)
 		n1->type = NCASE;
 		consumetoken(TWORD);
 		n1->ncase.expr = makename();
-		while (readtoken() == TNL);
-		if (lasttoken != TWORD || ! equal(wordtext, "in"))
+		checkkwd = CHKNL;
+		if (readtoken() != TWORD || ! equal(wordtext, "in"))
 			synerror("expecting \"in\"");
 		cpp = &n1->ncase.cases;
 		checkkwd = CHKNL | CHKKWD, readtoken();
diff --git a/bin/sh/tests/parser/Makefile b/bin/sh/tests/parser/Makefile
index f3a15badeb52..3239f5bccd84 100644
--- a/bin/sh/tests/parser/Makefile
+++ b/bin/sh/tests/parser/Makefile
@@ -65,6 +65,9 @@ ${PACKAGE}FILES+=	heredoc10.0
 ${PACKAGE}FILES+=	heredoc11.0
 ${PACKAGE}FILES+=	heredoc12.0
 ${PACKAGE}FILES+=	heredoc13.0
+${PACKAGE}FILES+=	heredoc14.0
+${PACKAGE}FILES+=	heredoc15.0
+${PACKAGE}FILES+=	heredoc16.0
 ${PACKAGE}FILES+=	line-cont1.0
 ${PACKAGE}FILES+=	line-cont2.0
 ${PACKAGE}FILES+=	line-cont3.0
diff --git a/bin/sh/tests/parser/heredoc14.0 b/bin/sh/tests/parser/heredoc14.0
new file mode 100644
index 000000000000..036be53dc0c9
--- /dev/null
+++ b/bin/sh/tests/parser/heredoc14.0
@@ -0,0 +1,8 @@
+#
+read x <<EOF; for i in "$x"
+value
+EOF
+do
+	x=$x.$i
+done
+[ "$x" = value.value ]
diff --git a/bin/sh/tests/parser/heredoc15.0 b/bin/sh/tests/parser/heredoc15.0
new file mode 100644
index 000000000000..94c5c5f31b18
--- /dev/null
+++ b/bin/sh/tests/parser/heredoc15.0
@@ -0,0 +1,9 @@
+#
+set -- dummy
+read x <<EOF; for i
+value
+EOF
+do
+	x=$x.$i
+done
+[ "$x" = value.dummy ]
diff --git a/bin/sh/tests/parser/heredoc16.0 b/bin/sh/tests/parser/heredoc16.0
new file mode 100644
index 000000000000..84e5e02ae3e1
--- /dev/null
+++ b/bin/sh/tests/parser/heredoc16.0
@@ -0,0 +1,8 @@
+#
+read x <<EOF; case $x
+value
+EOF
+in
+	value) x=$x.extended
+esac
+[ "$x" = value.extended ]