sh: Add case statement fallthrough (with ';&' instead of ';;').
authorPeter Avalos <pavalos@dragonflybsd.org>
Sun, 21 Aug 2011 21:45:13 +0000 (14:45 -0700)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sun, 21 Aug 2011 21:45:13 +0000 (14:45 -0700)
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.

Obtained-from:   FreeBSD 223186

bin/sh/eval.c
bin/sh/mktokens
bin/sh/nodetypes
bin/sh/parser.c
bin/sh/sh.1
tools/regression/bin/sh/builtins/case9.0 [new file with mode: 0644]

index ecc53f4..32ee05e 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  * @(#)eval.c  8.9 (Berkeley) 6/8/95
- * $FreeBSD: src/bin/sh/eval.c,v 1.110 2011/06/16 21:50:28 jilles Exp $
+ * $FreeBSD: src/bin/sh/eval.c,v 1.111 2011/06/17 13:03:49 jilles Exp $
  */
 
 #include <sys/time.h>
@@ -387,6 +387,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);
                                }
index a5c4471..9e79eab 100644 (file)
@@ -36,7 +36,7 @@
 # SUCH DAMAGE.
 #
 #      @(#)mktokens    8.1 (Berkeley) 5/31/93
-# $FreeBSD: src/bin/sh/mktokens,v 1.11 2011/05/22 15:24:56 jilles Exp $
+# $FreeBSD: src/bin/sh/mktokens,v 1.12 2011/06/17 13:03:49 jilles Exp $
 
 # The following is a list of tokens.  The second column is nonzero if the
 # token marks the end of a list.  The third column is the name to print in
@@ -54,6 +54,7 @@ TPIPE 0       "|"
 TLP    0       "("
 TRP    1       ")"
 TENDCASE 1     ";;"
+TFALLTHRU 1    ";&"
 TREDIR 0       redirection
 TWORD  0       word
 TIF    0       "if"
index f04d77d..e311f23 100644 (file)
@@ -34,7 +34,7 @@
 # SUCH DAMAGE.
 #
 #      @(#)nodetypes   8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/nodetypes,v 1.10 2005/01/10 08:39:25 imp Exp $
+# $FreeBSD: src/bin/sh/nodetypes,v 1.11 2011/06/17 13:03:49 jilles Exp $
 
 # This file describes the nodes used in parse trees.  Unindented lines
 # contain a node type followed by a structure tag.  Subsequent indented
@@ -100,12 +100,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.
index 82a2a77..1aaaac9 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  * @(#)parser.c        8.7 (Berkeley) 5/16/95
- * $FreeBSD: src/bin/sh/parser.c,v 1.113 2011/06/09 23:12:23 jilles Exp $
+ * $FreeBSD: src/bin/sh/parser.c,v 1.114 2011/06/17 13:03:49 jilles Exp $
  */
 
 #include <stdio.h>
@@ -541,10 +541,13 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
 
                        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;
                }
@@ -930,8 +933,11 @@ xxreadtoken(void)
                        pungetc();
                        RETURN(TPIPE);
                case ';':
-                       if (pgetc() == ';')
+                       c = pgetc();
+                       if (c == ';')
                                RETURN(TENDCASE);
+                       else if (c == '&')
+                               RETURN(TFALLTHRU);
                        pungetc();
                        RETURN(TSEMI);
                case '(':
index d2cf516..cdb0e7a 100644 (file)
@@ -34,7 +34,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    from: @(#)sh.1  8.6 (Berkeley) 5/4/95
-.\" $FreeBSD: src/bin/sh/sh.1,v 1.169 2011/06/15 21:48:10 jilles Exp $
+.\" $FreeBSD: src/bin/sh/sh.1,v 1.170 2011/06/17 13:03:49 jilles Exp $
 .\"
 .Dd August 21, 2011
 .Dt SH 1
@@ -383,7 +383,7 @@ The following is a list of valid operators:
 .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
@@ -1001,6 +1001,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
diff --git a/tools/regression/bin/sh/builtins/case9.0 b/tools/regression/bin/sh/builtins/case9.0
new file mode 100644 (file)
index 0000000..19b18fd
--- /dev/null
@@ -0,0 +1,39 @@
+# $FreeBSD: src/tools/regression/bin/sh/builtins/case9.0,v 1.1 2011/06/17 13:03:49 jilles Exp $
+
+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))