diff options
author | jilles <jilles@FreeBSD.org> | 2012-01-15 21:39:38 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2012-01-15 21:39:38 +0000 |
commit | 0ae130814a5b5ff84bc63b403e50eab143d5eddc (patch) | |
tree | 1b3dae3bc843b68f70d43cdc73e4cb560bc9baeb | |
parent | 286401123342863782d27c80567e650d22f2ac91 (diff) | |
download | FreeBSD-src-0ae130814a5b5ff84bc63b403e50eab143d5eddc.zip FreeBSD-src-0ae130814a5b5ff84bc63b403e50eab143d5eddc.tar.gz |
sh: Fix some bugs with exit status from case containing ;&.
Also, rework evalcase() to not evaluate any tree. Instead, return the
NCLISTFALLTHRU node and handle it in evaltree().
Fixed bugs:
* If a ;& list with non-zero exit status is followed by an empty ;; or final
list, the exit status of the case command should be equal to the exit
status of the ;& list, not 0.
* An empty ;& case should not reset $?.
-rw-r--r-- | bin/sh/eval.c | 33 | ||||
-rw-r--r-- | tools/regression/bin/sh/builtins/case17.0 | 3 | ||||
-rw-r--r-- | tools/regression/bin/sh/builtins/case18.0 | 7 | ||||
-rw-r--r-- | tools/regression/bin/sh/builtins/case19.0 | 7 |
4 files changed, 41 insertions, 9 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 07b0d64..ea23a9d 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -89,7 +89,7 @@ int oexitstatus; /* saved exit status */ static void evalloop(union node *, int); static void evalfor(union node *, int); -static union node *evalcase(union node *, int); +static union node *evalcase(union node *); static void evalsubshell(union node *, int); static void evalredir(union node *, int); static void expredir(union node *); @@ -256,7 +256,18 @@ evaltree(union node *n, int flags) evalfor(n, flags & ~EV_EXIT); break; case NCASE: - next = evalcase(n, flags); + next = evalcase(n); + break; + case NCLIST: + next = n->nclist.body; + break; + case NCLISTFALLTHRU: + if (n->nclist.body) { + evaltree(n->nclist.body, flags & ~EV_EXIT); + if (evalskip) + goto out; + } + next = n->nclist.next; break; case NDEFUN: defun(n->narg.text, n->narg.next); @@ -366,9 +377,14 @@ evalfor(union node *n, int flags) } +/* + * Evaluate a case statement, returning the selected tree. + * + * The exit status needs care to get right. + */ static union node * -evalcase(union node *n, int flags) +evalcase(union node *n) { union node *cp; union node *patp; @@ -384,13 +400,12 @@ evalcase(union node *n, int flags) if (casematch(patp, arglist.list->text)) { popstackmark(&smark); while (cp->nclist.next && - cp->type == NCLISTFALLTHRU) { - evaltree(cp->nclist.body, - flags & ~EV_EXIT); - if (evalskip != 0) - return (NULL); + cp->type == NCLISTFALLTHRU && + cp->nclist.body == NULL) cp = cp->nclist.next; - } + if (cp->nclist.next && + cp->type == NCLISTFALLTHRU) + return (cp); if (cp->nclist.body == NULL) exitstatus = 0; return (cp->nclist.body); diff --git a/tools/regression/bin/sh/builtins/case17.0 b/tools/regression/bin/sh/builtins/case17.0 new file mode 100644 index 0000000..ed1d25f --- /dev/null +++ b/tools/regression/bin/sh/builtins/case17.0 @@ -0,0 +1,3 @@ +# $FreeBSD$ + +! case x in x) false ;& y) esac diff --git a/tools/regression/bin/sh/builtins/case18.0 b/tools/regression/bin/sh/builtins/case18.0 new file mode 100644 index 0000000..470253f --- /dev/null +++ b/tools/regression/bin/sh/builtins/case18.0 @@ -0,0 +1,7 @@ +# $FreeBSD$ + +case x$(false) in +x) ;& +y) [ $? != 0 ] ;; +z) false ;; +esac diff --git a/tools/regression/bin/sh/builtins/case19.0 b/tools/regression/bin/sh/builtins/case19.0 new file mode 100644 index 0000000..215066a --- /dev/null +++ b/tools/regression/bin/sh/builtins/case19.0 @@ -0,0 +1,7 @@ +# $FreeBSD$ + +[ "`case x in +x) false ;& +y) ;& +z) echo $? ;; +esac`" != 0 ] |