bin/116559: make case statement of Bourne shell IEEE
1003.2-conformant
Eygene Ryabinkin
rea-fbsd at codelabs.ru
Sat Sep 22 11:20:04 PDT 2007
>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 at 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 at 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:
More information about the freebsd-bugs
mailing list