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.
This commit is contained in:
Jilles Tjoelker 2011-06-17 13:03:49 +00:00
parent ce97208218
commit c9afaa6389
6 changed files with 67 additions and 7 deletions

View File

@ -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);
}

View File

@ -50,6 +50,7 @@ TPIPE 0 "|"
TLP 0 "("
TRP 1 ")"
TENDCASE 1 ";;"
TFALLTHRU 1 ";&"
TREDIR 0 redirection
TWORD 0 word
TIF 0 "if"

View File

@ -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.

View File

@ -542,10 +542,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;
}
@ -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 '(':

View File

@ -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 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
@ -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

View File

@ -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))