bin/156306: sh(1): request for exp-run for various changes

Jilles Tjoelker jilles at stack.nl
Sun Apr 10 15:30:11 UTC 2011


>Number:         156306
>Category:       bin
>Synopsis:       sh(1): request for exp-run for various changes
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Apr 10 15:30:10 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Jilles Tjoelker
>Release:        FreeBSD 9.0-CURRENT i386
>Organization:
The FreeBSD Project
>Environment:
The patch applies to r219623-r220520 for sure and likely some later versions.
>Description:
I would like an -exp run for the attached patch.

Changes are:
* fix PR bin/104432, remove exp and let builtins
* fix PR bin/151720, flag error for ${#foo[x]}
* add $'quoting'
* apply set -u to variables in arithmetic
>How-To-Repeat:
-
>Fix:

--- sh-exp-20110410.patch begins here ---
Index: bin/sh/builtins.def
===================================================================
--- bin/sh/builtins.def	(revision 219743)
+++ bin/sh/builtins.def	(working copy)
@@ -60,7 +60,6 @@
 evalcmd		-s eval
 execcmd		-s exec
 exitcmd		-s exit
-expcmd		exp let
 exportcmd	-s export -s readonly
 #exprcmd		expr
 falsecmd	false
Index: bin/sh/arith_yacc.c
===================================================================
--- bin/sh/arith_yacc.c	(revision 219743)
+++ bin/sh/arith_yacc.c	(working copy)
@@ -97,6 +97,8 @@
 	arith_t result;
 
 	str = lookupvar(varname);
+	if (uflag && str == NULL)
+		yyerror("variable not set");
 	if (str == NULL || *str == '\0')
 		str = "0";
 	errno = 0;
@@ -338,41 +340,3 @@
 	return result;
 }
 
-/*
- *  The exp(1) builtin.
- */
-int
-expcmd(int argc, char **argv)
-{
-	const char *p;
-	char *concat;
-	char **ap;
-	arith_t i;
-
-	if (argc > 1) {
-		p = argv[1];
-		if (argc > 2) {
-			/*
-			 * Concatenate arguments.
-			 */
-			STARTSTACKSTR(concat);
-			ap = argv + 2;
-			for (;;) {
-				while (*p)
-					STPUTC(*p++, concat);
-				if ((p = *ap++) == NULL)
-					break;
-				STPUTC(' ', concat);
-			}
-			STPUTC('\0', concat);
-			p = grabstackstr(concat);
-		}
-	} else
-		p = "";
-
-	i = arith(p);
-
-	out1fmt(ARITH_FORMAT_STR "\n", i);
-	return !i;
-}
-
Index: bin/sh/arith.h
===================================================================
--- bin/sh/arith.h	(revision 219743)
+++ bin/sh/arith.h	(working copy)
@@ -36,4 +36,3 @@
 
 arith_t arith(const char *);
 void arith_lex_reset(void);
-int expcmd(int, char **);
Index: bin/sh/mksyntax.c
===================================================================
--- bin/sh/mksyntax.c	(revision 219743)
+++ bin/sh/mksyntax.c	(working copy)
@@ -64,6 +64,7 @@
 	{ "CWORD",	"character is nothing special" },
 	{ "CNL",	"newline character" },
 	{ "CBACK",	"a backslash character" },
+	{ "CSBACK",	"a backslash character in single quotes" },
 	{ "CSQUOTE",	"single quote" },
 	{ "CDQUOTE",	"double quote" },
 	{ "CENDQUOTE",	"a terminating quote" },
@@ -224,6 +225,7 @@
 	init();
 	fputs("\n/* syntax table used when in single quotes */\n", cfile);
 	add("\n", "CNL");
+	add("\\", "CSBACK");
 	add("'", "CENDQUOTE");
 	/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
 	add("!*?[=~:/-", "CCTL");
Index: bin/sh/parser.c
===================================================================
--- bin/sh/parser.c	(revision 219743)
+++ bin/sh/parser.c	(working copy)
@@ -1127,6 +1127,127 @@
 
 
 /*
+ * Called to parse a backslash escape sequence inside $'...'.
+ * The backslash has already been read.
+ */
+static char *
+readcstyleesc(char *out)
+{
+	int c, v, i, n;
+
+	c = pgetc();
+	switch (c) {
+	case '\0':
+		synerror("Unterminated quoted string");
+	case '\n':
+		plinno++;
+		if (doprompt)
+			setprompt(2);
+		else
+			setprompt(0);
+		return out;
+	case '\\':
+	case '\'':
+	case '"':
+		v = c;
+		break;
+	case 'a': v = '\a'; break;
+	case 'b': v = '\b'; break;
+	case 'e': v = '\033'; break;
+	case 'f': v = '\f'; break;
+	case 'n': v = '\n'; break;
+	case 'r': v = '\r'; break;
+	case 't': v = '\t'; break;
+	case 'v': v = '\v'; break;
+	case 'x':
+		  v = 0;
+		  for (;;) {
+			  c = pgetc();
+			  if (c >= '0' && c <= '9')
+				  v = (v << 4) + c - '0';
+			  else if (c >= 'A' && c <= 'F')
+				  v = (v << 4) + c - 'A' + 10;
+			  else if (c >= 'a' && c <= 'f')
+				  v = (v << 4) + c - 'a' + 10;
+			  else
+				  break;
+		  }
+		  pungetc();
+		  break;
+	case '0': case '1': case '2': case '3':
+	case '4': case '5': case '6': case '7':
+		  v = c - '0';
+		  c = pgetc();
+		  if (c >= '0' && c <= '7') {
+			  v <<= 3;
+			  v += c - '0';
+			  c = pgetc();
+			  if (c >= '0' && c <= '7') {
+				  v <<= 3;
+				  v += c - '0';
+			  } else
+				  pungetc();
+		  } else
+			  pungetc();
+		  break;
+	case 'c':
+		  c = pgetc();
+		  if (c < 0x3f || c > 0x7a || c == 0x60)
+			  synerror("Bad escape sequence");
+		  if (c == '\\' && pgetc() != '\\')
+			  synerror("Bad escape sequence");
+		  if (c == '?')
+			  v = 127;
+		  else
+			  v = c & 0x1f;
+		  break;
+	case 'u':
+	case 'U':
+		  n = c == 'U' ? 8 : 4;
+		  v = 0;
+		  for (i = 0; i < n; i++) {
+			  c = pgetc();
+			  if (c >= '0' && c <= '9')
+				  v = (v << 4) + c - '0';
+			  else if (c >= 'A' && c <= 'F')
+				  v = (v << 4) + c - 'A' + 10;
+			  else if (c >= 'a' && c <= 'f')
+				  v = (v << 4) + c - 'a' + 10;
+			  else
+				  synerror("Bad escape sequence");
+		  }
+		  if (v == 0 || (v >= 0xd800 && v <= 0xdfff))
+			  synerror("Bad escape sequence");
+		  /* We really need iconv here. */
+		  if (v > 127)
+			  v = '?';
+		  break;
+	default:
+		  synerror("Bad escape sequence");
+	}
+	v = (char)v;
+	/*
+	 * We can't handle NUL bytes.
+	 * POSIX says we should skip till the closing quote.
+	 */
+	if (v == '\0') {
+		while ((c = pgetc()) != '\'') {
+			if (c == '\\')
+				c = pgetc();
+			if (c == PEOF)
+				synerror("Unterminated quoted string");
+		}
+		pungetc();
+		return out;
+	}
+	if (SQSYNTAX[v] == CCTL)
+		USTPUTC(CTLESC, out);
+	USTPUTC(v, out);
+	return out;
+}
+
+
+/*
  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
  * is not NULL, read a here document.  In the latter case, eofmark is the
  * word which marks the end of the document and striptabs is true if
@@ -1158,6 +1279,7 @@
 	struct tokenstate state_static[MAXNEST_static];
 	int maxnest = MAXNEST_static;
 	struct tokenstate *state = state_static;
+	int sqiscstyle = 0;
 
 	startlinno = plinno;
 	quotef = 0;
@@ -1188,6 +1310,12 @@
 					setprompt(0);
 				c = pgetc();
 				goto loop;		/* continue outer loop */
+			case CSBACK:
+				if (sqiscstyle) {
+					out = readcstyleesc(out);
+					break;
+				}
+				/* FALLTHROUGH */
 			case CWORD:
 				USTPUTC(c, out);
 				break;
@@ -1232,6 +1360,7 @@
 			case CSQUOTE:
 				USTPUTC(CTLQUOTEMARK, out);
 				state[level].syntax = SQSYNTAX;
+				sqiscstyle = 0;
 				break;
 			case CDQUOTE:
 				USTPUTC(CTLQUOTEMARK, out);
@@ -1450,11 +1579,7 @@
 	int c1;
 
 	c = pgetc();
-	if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) &&
-	    !is_special(c)) {
-		USTPUTC('$', out);
-		pungetc();
-	} else if (c == '(') {	/* $(command) or $((arith)) */
+	if (c == '(') {	/* $(command) or $((arith)) */
 		if (pgetc() == '(') {
 			PARSEARITH();
 		} else {
@@ -1465,7 +1590,7 @@
 			    state[level].syntax == DQSYNTAX ||
 			    state[level].syntax == ARISYNTAX);
 		}
-	} else {
+	} else if (c == '{' || is_name(c) || is_special(c)) {
 		USTPUTC(CTLVAR, out);
 		typeloc = out - stackblock();
 		USTPUTC(VSNORMAL, out);
@@ -1569,6 +1694,8 @@
 				}
 			}
 		} else if (subtype != VSERROR) {
+			if (subtype == VSLENGTH && c != '}')
+				subtype = VSERROR;
 			pungetc();
 		}
 		STPUTC('=', out);
@@ -1610,6 +1737,14 @@
 				newvarnest++;
 			}
 		}
+	} else if (c == '\'' && state[level].syntax == BASESYNTAX) {
+		/* $'cstylequotes' */
+		USTPUTC(CTLQUOTEMARK, out);
+		state[level].syntax = SQSYNTAX;
+		sqiscstyle = 1;
+	} else {
+		USTPUTC('$', out);
+		pungetc();
 	}
 	goto parsesub_return;
 }
--- sh-exp-20110410.patch ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list