Module Name:    src
Committed By:   kre
Date:           Wed May  3 04:51:05 UTC 2017

Modified Files:
        src/bin/sh: input.c input.h parser.c

Log Message:
Deal with \newline line continuations more correctly.
They can occur anywhere (*anywhere*) not only where it
happens to be convenient to the parser...

This fix from FreeBSD (thanks again folks).

To make this work, pushstring()'s signature needed to change to allow a
const char * as its string arg, which meant sprinkling some const other
places for a brighter appearance (and handling fallout).

All this because I wanted to see what number would come from

echo $\
{\
L\
I\
N\
E\
N\
O\
}

and was surprised at the result!    That works now...

The bug would also affect stuff like

true &\
& false

and all kinds of other uses where the \newline occurred in the
"wrong" place.

An ATF test for sh syntax is coming... (sometime.)


To generate a diff of this commit:
cvs rdiff -u -r1.54 -r1.55 src/bin/sh/input.c
cvs rdiff -u -r1.17 -r1.18 src/bin/sh/input.h
cvs rdiff -u -r1.120 -r1.121 src/bin/sh/parser.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/sh/input.c
diff -u src/bin/sh/input.c:1.54 src/bin/sh/input.c:1.55
--- src/bin/sh/input.c:1.54	Wed May  3 04:13:53 2017
+++ src/bin/sh/input.c	Wed May  3 04:51:04 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: input.c,v 1.54 2017/05/03 04:13:53 kre Exp $	*/
+/*	$NetBSD: input.c,v 1.55 2017/05/03 04:51:04 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
 #else
-__RCSID("$NetBSD: input.c,v 1.54 2017/05/03 04:13:53 kre Exp $");
+__RCSID("$NetBSD: input.c,v 1.55 2017/05/03 04:51:04 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -71,7 +71,7 @@ __RCSID("$NetBSD: input.c,v 1.54 2017/05
 MKINIT
 struct strpush {
 	struct strpush *prev;	/* preceding string on stack */
-	char *prevstring;
+	const char *prevstring;
 	int prevnleft;
 	int prevlleft;
 	struct alias *ap;	/* if push was associated with an alias */
@@ -89,7 +89,7 @@ struct parsefile {
 	int fd;			/* file descriptor (or -1 if string) */
 	int nleft;		/* number of chars left in this line */
 	int lleft;		/* number of chars left in this buffer */
-	char *nextc;		/* next char in buffer */
+	const char *nextc;	/* next char in buffer */
 	char *buf;		/* input buffer */
 	struct strpush *strpush; /* for pushing strings at this level */
 	struct strpush basestrpush; /* so pushing one is fast */
@@ -99,7 +99,7 @@ struct parsefile {
 int plinno = 1;			/* input line number */
 int parsenleft;			/* copy of parsefile->nleft */
 MKINIT int parselleft;		/* copy of parsefile->lleft */
-char *parsenextc;		/* copy of parsefile->nextc */
+const char *parsenextc;		/* copy of parsefile->nextc */
 MKINIT struct parsefile basepf;	/* top level input file */
 MKINIT char basebuf[BUFSIZ];	/* buffer for top level input file */
 struct parsefile *parsefile = &basepf;	/* current input file */
@@ -262,7 +262,9 @@ again:
 		}
 	}
 
-	q = p = parsenextc;
+		/* p = (not const char *)parsenextc; */
+	p = parsefile->buf + (parsenextc - parsefile->buf);
+	q = p;
 
 	/* delete nul characters */
 #ifndef SMALL
@@ -341,7 +343,7 @@ pungetc(void)
  * We handle aliases this way.
  */
 void
-pushstring(char *s, int len, struct alias *ap)
+pushstring(const char *s, int len, struct alias *ap)
 {
 	struct strpush *sp;
 

Index: src/bin/sh/input.h
diff -u src/bin/sh/input.h:1.17 src/bin/sh/input.h:1.18
--- src/bin/sh/input.h:1.17	Wed May  3 04:13:53 2017
+++ src/bin/sh/input.h	Wed May  3 04:51:04 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: input.h,v 1.17 2017/05/03 04:13:53 kre Exp $	*/
+/*	$NetBSD: input.h,v 1.18 2017/05/03 04:51:04 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -43,7 +43,7 @@
  */
 extern int plinno;
 extern int parsenleft;		/* number of characters left in input buffer */
-extern char *parsenextc;	/* next character in input buffer */
+extern const char *parsenextc;	/* next character in input buffer */
 extern int init_editline;	/* 0 == not setup, 1 == OK, -1 == failed */
 
 struct alias;
@@ -52,7 +52,7 @@ char *pfgets(char *, int);
 int pgetc(void);
 int preadbuffer(void);
 void pungetc(void);
-void pushstring(char *, int, struct alias *);
+void pushstring(const char *, int, struct alias *);
 void popstring(void);
 void setinputfile(const char *, int);
 void setinputfd(int, int);

Index: src/bin/sh/parser.c
diff -u src/bin/sh/parser.c:1.120 src/bin/sh/parser.c:1.121
--- src/bin/sh/parser.c:1.120	Wed Jun  1 02:47:05 2016
+++ src/bin/sh/parser.c	Wed May  3 04:51:04 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: parser.c,v 1.120 2016/06/01 02:47:05 kre Exp $	*/
+/*	$NetBSD: parser.c,v 1.121 2017/05/03 04:51:04 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
 #else
-__RCSID("$NetBSD: parser.c,v 1.120 2016/06/01 02:47:05 kre Exp $");
+__RCSID("$NetBSD: parser.c,v 1.121 2017/05/03 04:51:04 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -119,6 +119,7 @@ STATIC int noexpand(char *);
 STATIC void synexpect(int, const char *) __dead;
 STATIC void synerror(const char *) __dead;
 STATIC void setprompt(int);
+STATIC int pgetc_linecont(void);
 
 
 static const char EOFhere[] = "EOF reading here (<<) document";
@@ -1005,17 +1006,17 @@ xxreadtoken(void)
 			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 ';':
-			if (pgetc() == ';')
+			if (pgetc_linecont() == ';')
 				RETURN(TENDCASE);
 			pungetc();
 			RETURN(TSEMI);
@@ -1281,7 +1282,7 @@ parsebackq(VSS *const stack, char * cons
 				setprompt(2);
 				needprompt = 0;
 			}
-			switch (pc = pgetc()) {
+			switch (pc = pgetc_linecont()) {
 			case '`':
 				goto done;
 
@@ -1405,7 +1406,7 @@ parseredir(const char *out,  int c)
 	if (c == '>') {
 		if (fd < 0)
 			fd = 1;
-		c = pgetc();
+		c = pgetc_linecont();
 		if (c == '>')
 			np->type = NAPPEND;
 		else if (c == '|')
@@ -1419,7 +1420,7 @@ parseredir(const char *out,  int c)
 	} else {	/* c == '<' */
 		if (fd < 0)
 			fd = 0;
-		switch (c = pgetc()) {
+		switch (c = pgetc_linecont()) {
 		case '<':
 			if (sizeof (struct nfile) != sizeof (struct nhere)) {
 				np = stalloc(sizeof(struct nhere));
@@ -1429,7 +1430,7 @@ parseredir(const char *out,  int c)
 			heredoc = stalloc(sizeof(struct heredoc));
 			heredoc->here = np;
 			heredoc->startline = plinno;
-			if ((c = pgetc()) == '-') {
+			if ((c = pgetc_linecont()) == '-') {
 				heredoc->striptabs = 1;
 			} else {
 				heredoc->striptabs = 0;
@@ -1623,7 +1624,7 @@ readtoken1(int firstc, char const *syn, 
 				USTPUTC(c, out);
 				--parenlevel;
 			} else {
-				if (pgetc() == ')') {
+				if (pgetc_linecont() == ')') {
 					if (--arinest == 0) {
 						TS_POP();
 						USTPUTC(CTLENDARI, out);
@@ -1707,12 +1708,12 @@ parsesub: {
 	int i;
 	int linno;
 
-	c = pgetc();
+	c = pgetc_linecont();
 	if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
 		USTPUTC('$', out);
 		pungetc();
 	} else if (c == '(') {	/* $(command) or $((arith)) */
-		if (pgetc() == '(') {
+		if (pgetc_linecont() == '(') {
 			PARSEARITH();
 		} else {
 			pungetc();
@@ -1725,7 +1726,7 @@ parsesub: {
 		subtype = VSNORMAL;
 		flags = 0;
 		if (c == OPENBRACE) {
-			c = pgetc();
+			c = pgetc_linecont();
 			if (c == '#') {
 				if ((c = pgetc()) == CLOSEBRACE)
 					c = '#';
@@ -1739,7 +1740,7 @@ parsesub: {
 			p = out;
 			do {
 				STPUTC(c, out);
-				c = pgetc();
+				c = pgetc_linecont();
 			} while (is_in_name(c));
 			if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) {
 				/* Replace the variable name with the
@@ -1756,12 +1757,12 @@ parsesub: {
 		} else if (is_digit(c)) {
 			do {
 				USTPUTC(c, out);
-				c = pgetc();
+				c = pgetc_linecont();
 			} while (subtype != VSNORMAL && is_digit(c));
 		}
 		else if (is_special(c)) {
 			USTPUTC(c, out);
-			c = pgetc();
+			c = pgetc_linecont();
 		}
 		else {
 badsub:
@@ -1774,7 +1775,7 @@ badsub:
 			switch (c) {
 			case ':':
 				flags |= VSNUL;
-				c = pgetc();
+				c = pgetc_linecont();
 				/*FALLTHROUGH*/
 			default:
 				p = strchr(types, c);
@@ -1788,7 +1789,7 @@ badsub:
 					int cc = c;
 					subtype = c == '#' ? VSTRIMLEFT :
 							     VSTRIMRIGHT;
-					c = pgetc();
+					c = pgetc_linecont();
 					if (c == cc)
 						subtype++;
 					else
@@ -1959,6 +1960,34 @@ setprompt(int which)
 }
 
 /*
+ * handle getting the next character, while ignoring \ \n
+ * (which is a little tricky as we only have one char of pushback
+ * and we need that one elsewhere).
+ */
+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.
  */

Reply via email to