svn commit: r273276 - in head/bin/sh: . tests/parser

Jilles Tjoelker jilles at FreeBSD.org
Sun Oct 19 11:59:18 UTC 2014


Author: jilles
Date: Sun Oct 19 11:59:15 2014
New Revision: 273276
URL: https://svnweb.freebsd.org/changeset/base/273276

Log:
  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

Added:
  head/bin/sh/tests/parser/line-cont10.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont11.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont4.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont5.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont6.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont7.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont8.0   (contents, props changed)
  head/bin/sh/tests/parser/line-cont9.0   (contents, props changed)
Modified:
  head/bin/sh/parser.c
  head/bin/sh/tests/parser/Makefile

Modified: head/bin/sh/parser.c
==============================================================================
--- head/bin/sh/parser.c	Sun Oct 19 11:31:23 2014	(r273275)
+++ head/bin/sh/parser.c	Sun Oct 19 11:59:15 2014	(r273276)
@@ -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 **
 				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 *initi
 					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.

Modified: head/bin/sh/tests/parser/Makefile
==============================================================================
--- head/bin/sh/tests/parser/Makefile	Sun Oct 19 11:31:23 2014	(r273275)
+++ head/bin/sh/tests/parser/Makefile	Sun Oct 19 11:59:15 2014	(r273276)
@@ -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

Added: head/bin/sh/tests/parser/line-cont10.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont10.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+v=XaaaXbbbX
+[ "${v\
+#\
+*\
+a}.${v\
+#\
+#\
+*\
+a}.${v\
+%\
+b\
+*}.${v\
+%\
+%\
+b\
+*}" = aaXbbbX.XbbbX.XaaaXbb.XaaaX ]

Added: head/bin/sh/tests/parser/line-cont11.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont11.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -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

Added: head/bin/sh/tests/parser/line-cont4.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont4.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+v=abcd
+[ "$\
+v.$\
+{v}.${\
+v}.${v\
+}" = abcd.abcd.abcd.abcd ]

Added: head/bin/sh/tests/parser/line-cont5.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont5.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+bad=1
+case x in
+x\
+) ;\
+; *) exit 7
+esac &\
+& bad= &\
+& : >\
+>/dev/null
+
+false |\
+| [ -z "$bad" ]

Added: head/bin/sh/tests/parser/line-cont6.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont6.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+v0\
+=abc
+
+v=$(cat <\
+<\
+E\
+O\
+F
+${v0}d
+EOF
+)
+
+w=$(cat <\
+<\
+-\
+EOF
+	efgh
+EOF
+)
+
+[ "$v.$w" = "abcd.efgh" ]

Added: head/bin/sh/tests/parser/line-cont7.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont7.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+[ "$(\
+(
+1\
++ 1)\
+)" = 2 ]

Added: head/bin/sh/tests/parser/line-cont8.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont8.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+set -- a b c d e f g h i j
+[ "${1\
+0\
+}" = j ]

Added: head/bin/sh/tests/parser/line-cont9.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/bin/sh/tests/parser/line-cont9.0	Sun Oct 19 11:59:15 2014	(r273276)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+[ "${$\
+:\
++\
+xyz}" = xyz ]


More information about the svn-src-head mailing list