ash: use pgetc_eatbnl() in more places

Part of upstream commit:

    Date:   Thu Mar 8 08:37:11 2018 +0100
    Author: Harald van Dijk <harald@gigawatt.nl>
    parser: use pgetc_eatbnl() in more places

    dash has a pgetc_eatbnl function in parser.c which skips any
    backslash-newline combinations. It's not used everywhere it could be.
    There is also some duplicated backslash-newline handling elsewhere in
    parser.c. Replace most of the calls to pgetc() with calls to
    pgetc_eatbnl() and remove the duplicated backslash-newline handling.

    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Not adding "readtoken1(pgetc_eatbnl(), DQSYNTAX..." changes, since
readtoken1() handles the "starts with backslash + newline" case itself.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/ash.c b/shell/ash.c
index 2ed802d..a7767b4 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -12225,7 +12225,7 @@
 	np = stzalloc(sizeof(struct nfile));
 	if (c == '>') {
 		np->nfile.fd = 1;
-		c = pgetc();
+		c = pgetc_eatbnl();
 		if (c == '>')
 			np->type = NAPPEND;
 		else if (c == '|')
@@ -12247,7 +12247,7 @@
 #endif
 	else { /* c == '<' */
 		/*np->nfile.fd = 0; - stzalloc did it */
-		c = pgetc();
+		c = pgetc_eatbnl();
 		switch (c) {
 		case '<':
 			if (sizeof(struct nfile) != sizeof(struct nhere)) {
@@ -12257,7 +12257,7 @@
 			np->type = NHERE;
 			heredoc = stzalloc(sizeof(struct heredoc));
 			heredoc->here = np;
-			c = pgetc();
+			c = pgetc_eatbnl();
 			if (c == '-') {
 				heredoc->striptabs = 1;
 			} else {
@@ -12487,23 +12487,13 @@
 			int pc;
 
 			setprompt_if(needprompt, 2);
-			pc = pgetc();
+			pc = pgetc_eatbnl();
 			switch (pc) {
 			case '`':
 				goto done;
 
 			case '\\':
-				pc = pgetc();
-				if (pc == '\n') {
-					nlprompt();
-					/*
-					 * If eating a newline, avoid putting
-					 * the newline into the new character
-					 * stream (via the STPUTC after the
-					 * switch).
-					 */
-					continue;
-				}
+				pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
 				if (pc != '\\' && pc != '`' && pc != '$'
 				 && (!dblquote || pc != '"')
 				) {
@@ -12635,7 +12625,7 @@
 	}
 	setprompt_if(needprompt, 2);
 	for (;;) {                      /* until token or start of word found */
-		c = pgetc();
+		c = pgetc_eatbnl();
 		if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
 			continue;
 
@@ -12644,11 +12634,7 @@
 				continue;
 			pungetc();
 		} else if (c == '\\') {
-			if (pgetc() != '\n') {
-				pungetc();
-				break; /* return readtoken1(...) */
-			}
-			nlprompt();
+			break; /* return readtoken1(...) */
 		} else {
 			const char *p;
 
@@ -12695,7 +12681,7 @@
 	}
 	setprompt_if(needprompt, 2);
 	for (;;) {      /* until token or start of word found */
-		c = pgetc();
+		c = pgetc_eatbnl();
 		switch (c) {
 		case ' ': case '\t':
 		IF_ASH_ALIAS(case PEOA:)
@@ -12705,30 +12691,23 @@
 				continue;
 			pungetc();
 			continue;
-		case '\\':
-			if (pgetc() == '\n') {
-				nlprompt();
-				continue;
-			}
-			pungetc();
-			goto breakloop;
 		case '\n':
 			nlnoprompt();
 			RETURN(TNL);
 		case PEOF:
 			RETURN(TEOF);
 		case '&':
-			if (pgetc() == '&')
+			if (pgetc_eatbnl() == '&')
 				RETURN(TAND);
 			pungetc();
 			RETURN(TBACKGND);
 		case '|':
-			if (pgetc() == '|')
+			if (pgetc_eatbnl() == '|')
 				RETURN(TOR);
 			pungetc();
 			RETURN(TPIPE);
 		case ';':
-			if (pgetc() == ';')
+			if (pgetc_eatbnl() == ';')
 				RETURN(TENDCASE);
 			pungetc();
 			RETURN(TSEMI);
@@ -12736,11 +12715,9 @@
 			RETURN(TLP);
 		case ')':
 			RETURN(TRP);
-		default:
-			goto breakloop;
 		}
+		break;
 	}
- breakloop:
 	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
 #undef RETURN
 }
diff --git a/shell/ash_test/ash-heredoc/heredoc_backslash1.right b/shell/ash_test/ash-heredoc/heredoc_backslash1.right
new file mode 100644
index 0000000..6a61148
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_backslash1.right
@@ -0,0 +1,43 @@
+Quoted heredoc:
+a\
+	b
+a\\
+	b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+	-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ 123456 `echo  v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
+ 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
+c\
+
+Unquoted heredoc:
+a	b
+a\
+	b
+ 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+	-qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+ 123456 v-$a-\t-\-\"-\x-`-\--\z-\*-\?-
+ 123456 v-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-
+cEOF2
+
+Quoted -heredoc:
+a\
+b
+a\\
+b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ 123456 `echo  v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
+ 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
+c\
+
+Unquoted -heredoc:
+a	b
+a\
+b
+ 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+-qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+ 123456 v-$a-\t-\-\"-\x-`-\--\z-\*-\?-
+ 123456 v-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-
+cEOF4
+
+Done: 0
diff --git a/shell/ash_test/ash-heredoc/heredoc_backslash1.tests b/shell/ash_test/ash-heredoc/heredoc_backslash1.tests
new file mode 100755
index 0000000..501af54
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_backslash1.tests
@@ -0,0 +1,70 @@
+# Test for correct handling of backslashes.
+# Note that some lines in each heredoc start with a tab.
+
+a=qwerty
+
+echo Quoted heredoc:
+cat <<"EOF1"
+a\
+	b
+a\\
+	b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+	-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ 123456 `echo  v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
+ 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
+c\
+EOF1
+echo
+
+echo Unquoted heredoc:
+cat <<EOF2
+a\
+	b
+a\\
+	b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+	-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ 123456 `echo  v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-'`
+ 123456 $(echo v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-')
+c\
+EOF2
+EOF2
+echo
+
+echo Quoted -heredoc:
+cat <<-"EOF3"
+a\
+	b
+a\\
+	b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+	-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ 123456 `echo  v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'`
+ 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-')
+c\
+	EOF3
+# In -heredoc case the marker is detected even if it is indented.
+echo
+
+echo Unquoted -heredoc:
+cat <<-EOF4
+a\
+	b
+a\\
+	b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+	-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ 123456 `echo  v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-'`
+ 123456 $(echo v'-$a-\t-\\-\"-\x-\`-\--\z-\*-\?-')
+c\
+EOF4
+	EOF4
+# The marker is not detected if preceding line ends in backslash.
+# TODO: marker should be detected even if it is split by line continuation:
+# EOF\
+# 4
+# but currently hush doesn't do it. (Tab before "4" is not allowed, though.)
+echo
+
+echo "Done: $?"
diff --git a/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right
new file mode 100644
index 0000000..fdb7ebd
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right
@@ -0,0 +1,8 @@
+heredoc0
+Ok0:0
+heredoc1
+Ok1:0
+heredoc2
+Ok2:0
+heredoc3
+Ok4:0
diff --git a/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests
new file mode 100755
index 0000000..584edd0
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests
@@ -0,0 +1,25 @@
+cat <\
+<\
+EOF
+heredoc0
+EOF
+echo Ok0:$?
+
+cat <<\
+ EOF
+heredoc1
+EOF
+echo Ok1:$?
+
+cat <<\
+- EOF
+heredoc2
+	EOF
+echo Ok2:$?
+
+cat <\
+<\
+- EOF
+heredoc3
+	EOF
+echo Ok4:$?
diff --git a/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right
new file mode 100644
index 0000000..fdb7ebd
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right
@@ -0,0 +1,8 @@
+heredoc0
+Ok0:0
+heredoc1
+Ok1:0
+heredoc2
+Ok2:0
+heredoc3
+Ok4:0
diff --git a/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests
new file mode 100755
index 0000000..584edd0
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests
@@ -0,0 +1,25 @@
+cat <\
+<\
+EOF
+heredoc0
+EOF
+echo Ok0:$?
+
+cat <<\
+ EOF
+heredoc1
+EOF
+echo Ok1:$?
+
+cat <<\
+- EOF
+heredoc2
+	EOF
+echo Ok2:$?
+
+cat <\
+<\
+- EOF
+heredoc3
+	EOF
+echo Ok4:$?