Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Jun 2011 13:03:49 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r223186 - in head: bin/sh tools/regression/bin/sh/builtins
Message-ID:  <201106171303.p5HD3nto092050@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jilles
Date: Fri Jun 17 13:03:49 2011
New Revision: 223186
URL: http://svn.freebsd.org/changeset/base/223186

Log:
  sh: Add case statement fallthrough (with ';&' instead of ';;').
  
  Replacing ;; with the new control operator ;& will cause the next list to be
  executed as well without checking its pattern, continuing until a list ends
  with ;; or until the end of the case statement. This is like omitting
  "break" in a C "switch" statement.
  
  The sequence ;& was formerly invalid.
  
  This feature is proposed for the next POSIX issue in Austin Group issue
  #449.

Added:
  head/tools/regression/bin/sh/builtins/case9.0   (contents, props changed)
Modified:
  head/bin/sh/eval.c
  head/bin/sh/mktokens
  head/bin/sh/nodetypes
  head/bin/sh/parser.c
  head/bin/sh/sh.1

Modified: head/bin/sh/eval.c
==============================================================================
--- head/bin/sh/eval.c	Fri Jun 17 12:12:52 2011	(r223185)
+++ head/bin/sh/eval.c	Fri Jun 17 13:03:49 2011	(r223186)
@@ -386,6 +386,14 @@ evalcase(union node *n, int flags)
 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
 		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
 			if (casematch(patp, arglist.list->text)) {
+				while (cp->nclist.next &&
+				    cp->type == NCLISTFALLTHRU) {
+					if (evalskip != 0)
+						break;
+					evaltree(cp->nclist.body,
+					    flags & ~EV_EXIT);
+					cp = cp->nclist.next;
+				}
 				if (evalskip == 0) {
 					evaltree(cp->nclist.body, flags);
 				}

Modified: head/bin/sh/mktokens
==============================================================================
--- head/bin/sh/mktokens	Fri Jun 17 12:12:52 2011	(r223185)
+++ head/bin/sh/mktokens	Fri Jun 17 13:03:49 2011	(r223186)
@@ -50,6 +50,7 @@ TPIPE	0	"|"
 TLP	0	"("
 TRP	1	")"
 TENDCASE 1	";;"
+TFALLTHRU 1	";&"
 TREDIR	0	redirection
 TWORD	0	word
 TIF	0	"if"

Modified: head/bin/sh/nodetypes
==============================================================================
--- head/bin/sh/nodetypes	Fri Jun 17 12:12:52 2011	(r223185)
+++ head/bin/sh/nodetypes	Fri Jun 17 13:03:49 2011	(r223186)
@@ -96,12 +96,13 @@ NCASE ncase			# a case statement
 	expr	  nodeptr		# the word to switch on
 	cases	  nodeptr		# the list of cases (NCLIST nodes)
 
-NCLIST nclist			# a case
+NCLIST nclist			# a case ending with ;;
 	type	  int
 	next	  nodeptr		# the next case in list
 	pattern	  nodeptr		# list of patterns for this case
 	body	  nodeptr		# code to execute for this case
 
+NCLISTFALLTHRU nclist		# a case ending with ;&
 
 NDEFUN narg			# define a function.  The "next" field contains
 				# the body of the function.

Modified: head/bin/sh/parser.c
==============================================================================
--- head/bin/sh/parser.c	Fri Jun 17 12:12:52 2011	(r223185)
+++ head/bin/sh/parser.c	Fri Jun 17 13:03:49 2011	(r223186)
@@ -542,10 +542,13 @@ TRACE(("expecting DO got %s %s\n", tokna
 
 			checkkwd = CHKNL | CHKKWD | CHKALIAS;
 			if ((t = readtoken()) != TESAC) {
-				if (t != TENDCASE)
-					synexpect(TENDCASE);
+				if (t == TENDCASE)
+					;
+				else if (t == TFALLTHRU)
+					cp->type = NCLISTFALLTHRU;
 				else
-					checkkwd = CHKNL | CHKKWD, readtoken();
+					synexpect(TENDCASE);
+				checkkwd = CHKNL | CHKKWD, readtoken();
 			}
 			cpp = &cp->nclist.next;
 		}
@@ -931,8 +934,11 @@ xxreadtoken(void)
 			pungetc();
 			RETURN(TPIPE);
 		case ';':
-			if (pgetc() == ';')
+			c = pgetc();
+			if (c == ';')
 				RETURN(TENDCASE);
+			else if (c == '&')
+				RETURN(TFALLTHRU);
 			pungetc();
 			RETURN(TSEMI);
 		case '(':

Modified: head/bin/sh/sh.1
==============================================================================
--- head/bin/sh/sh.1	Fri Jun 17 12:12:52 2011	(r223185)
+++ head/bin/sh/sh.1	Fri Jun 17 13:03:49 2011	(r223186)
@@ -32,7 +32,7 @@
 .\"	from: @(#)sh.1	8.6 (Berkeley) 5/4/95
 .\" $FreeBSD$
 .\"
-.Dd June 15, 2011
+.Dd June 17, 2011
 .Dt SH 1
 .Os
 .Sh NAME
@@ -372,7 +372,7 @@ The following is a list of valid operato
 .It Control operators:
 .Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
 .It Li & Ta Li && Ta Li ( Ta Li ) Ta Li \en
-.It Li ;; Ta Li ; Ta Li | Ta Li ||
+.It Li ;; Ta Li ;& Ta Li ; Ta Li | Ta Li ||
 .El
 .It Redirection operators:
 .Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
@@ -990,6 +990,11 @@ described later),
 separated by
 .Ql \&|
 characters.
+If the selected list is terminated by the control operator
+.Ql ;&
+instead of
+.Ql ;; ,
+execution continues with the next list.
 The exit code of the
 .Ic case
 command is the exit code of the last command executed in the list or

Added: head/tools/regression/bin/sh/builtins/case9.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/bin/sh/builtins/case9.0	Fri Jun 17 13:03:49 2011	(r223186)
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+errors=0
+
+f() {
+	result=
+	case $1 in
+	a) result=${result}a ;;
+	b) result=${result}b ;&
+	c) result=${result}c ;&
+	d) result=${result}d ;;
+	e) result=${result}e ;&
+	esac
+}
+
+check() {
+	f "$1"
+	if [ "$result" != "$2" ]; then
+		printf "For %s, expected %s got %s\n" "$1" "$2" "$result"
+		errors=$((errors + 1))
+	fi
+}
+
+check '' ''
+check a a
+check b bcd
+check c cd
+check d d
+check e e
+
+if ! (case 1 in
+	1) false ;&
+	2) true ;;
+esac) then
+	echo "Subshell bad"
+	errors=$((errors + 1))
+fi
+
+exit $((errors != 0))



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106171303.p5HD3nto092050>