Date: Sat, 22 Sep 2007 22:15:49 +0400 (MSD) From: Eygene Ryabinkin <rea-fbsd@codelabs.ru> To: FreeBSD-gnats-submit@FreeBSD.org Subject: bin/116559: make case statement of Bourne shell IEEE 1003.2-conformant Message-ID: <20070922181550.019AE1AF41C@void.codelabs.ru> Resent-Message-ID: <200709221820.l8MIK4gF008843@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 116559 >Category: bin >Synopsis: make case statement of Bourne shell IEEE 1003.2-conformant >Confidential: no >Severity: critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat Sep 22 18:20:02 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Eygene Ryabinkin >Release: FreeBSD 7.0-CURRENT i386 >Organization: Code Labs >Environment: System: FreeBSD XXX 7.0-CURRENT FreeBSD 7.0-CURRENT #10: Wed Sep 12 16:16:49 MSD 2007 root@XXX:/usr/src/sys/i386/compile/XXX i386 >Description: IEEE 1003.2 specifies that the return value of the 'case' construct that did not matched any patterns shall be zero. It is not the case for the current FreeBSD /bin/sh. >How-To-Repeat: Run the test script that is embedded into the patch comments. >Fix: The following patch will correct and document the expected behaviour. --- sh.patch begins here --- According to the standard (http://opengroup.org/onlinepubs/000095399, Shell and Utilities Volume (XCU), Case Conditional Construct), the 'case' statement shall return zero if no patterns were matched. Currently, Bourne shell in FreeBSD does not change the exit code on the 'case' construct that had not matched anything; it is completely transparent in this regard. The following test script shall not produce any messages with the 1003.2-conformant shells and its return code shall be zero: ----- err () { echo "ERROR: $@" } case_and_immediate () { false case Ultra in Super) false ;; Hyper) true ;; esac && echo ok } case_while_immediate () { false while case Ultra in Super) break ;; esac do echo ok break done } retval=0 for test in \ case_and_immediate \ case_while_immediate do result=`$test` if test "$result" != ok; then err "$test" failed retval=$(($retval + 1)) fi done exit $retval ----- The real rationale for this change is that some utilities are using constructs like ----- while case "#?" in 0) break ;; esac do case "$1" in --someflag) ... ;; ... esac done ----- for the argument parsing. The example I had before my eyes is Git 1.5.3.2, script named git-commit. Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru> --- eval.c | 1 + sh.1 | 4 ++++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/eval.c b/eval.c index 9b41f63..6d24df2 100644 --- a/eval.c +++ b/eval.c @@ -367,6 +367,7 @@ evalcase(union node *n, int flags) setstackmark(&smark); arglist.lastp = &arglist.list; oexitstatus = exitstatus; + exitstatus = 0; expandarg(n->ncase.expr, &arglist, EXP_TILDE); for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { diff --git a/sh.1 b/sh.1 index 72aa5c5..41779fe 100644 --- a/sh.1 +++ b/sh.1 @@ -861,6 +861,10 @@ described later), separated by .Dq Li \&| characters. +The exit code of the +.Ic case +command is the exit code of the last command executed in the list +or zero if no patterns were matched. .Ss Grouping Commands Together Commands may be grouped by writing either .Bd -literal -offset indent --- sh.patch ends here --- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070922181550.019AE1AF41C>