From owner-freebsd-bugs@FreeBSD.ORG Sat Sep 22 18:20:04 2007 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 69B3716A46D for ; Sat, 22 Sep 2007 18:20:04 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 4D98413C4B9 for ; Sat, 22 Sep 2007 18:20:04 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.1/8.14.1) with ESMTP id l8MIK4tC008844 for ; Sat, 22 Sep 2007 18:20:04 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.1/8.14.1/Submit) id l8MIK4gF008843; Sat, 22 Sep 2007 18:20:04 GMT (envelope-from gnats) Resent-Date: Sat, 22 Sep 2007 18:20:04 GMT Resent-Message-Id: <200709221820.l8MIK4gF008843@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Eygene Ryabinkin Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E1A8C16A417 for ; Sat, 22 Sep 2007 18:15:52 +0000 (UTC) (envelope-from rea-fbsd@codelabs.ru) Received: from pobox.codelabs.ru (pobox.codelabs.ru [144.206.177.45]) by mx1.freebsd.org (Postfix) with ESMTP id 99A9E13C45D for ; Sat, 22 Sep 2007 18:15:52 +0000 (UTC) (envelope-from rea-fbsd@codelabs.ru) Received: from void.codelabs.ru (void.codelabs.ru [144.206.177.25]) by pobox.codelabs.ru with esmtps (TLSv1:CAMELLIA256-SHA:256) id 1IZ9WB-0009Zd-AG for FreeBSD-gnats-submit@freebsd.org; Sat, 22 Sep 2007 22:15:51 +0400 Message-Id: <20070922181550.019AE1AF41C@void.codelabs.ru> Date: Sat, 22 Sep 2007 22:15:49 +0400 (MSD) From: Eygene Ryabinkin To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: bin/116559: make case statement of Bourne shell IEEE 1003.2-conformant X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Eygene Ryabinkin List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Sep 2007 18:20:04 -0000 >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 --- 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: