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 /bin/sh | |
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 $?.
Diffstat (limited to 'bin/sh')
-rw-r--r-- | bin/sh/eval.c | 33 |
1 files changed, 24 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); |