/* These forward decls are needed to use "eval" code for backticks handling: */
static uint8_t back_exitstatus; /* exit status of backquoted command */
#define EV_EXIT 01 /* exit after evaluating tree */
-static void evaltree(union node *, int);
+static int evaltree(union node *, int);
static void FAST_FUNC
evalbackcmd(union node *n, struct backcmd *result)
}
/* forward declarations - evaluation is fairly recursive business... */
-static void evalloop(union node *, int);
-static void evalfor(union node *, int);
-static void evalcase(union node *, int);
-static void evalsubshell(union node *, int);
+static int evalloop(union node *, int);
+static int evalfor(union node *, int);
+static int evalcase(union node *, int);
+static int evalsubshell(union node *, int);
static void expredir(union node *);
-static void evalpipe(union node *, int);
-static void evalcommand(union node *, int);
+static int evalpipe(union node *, int);
+static int evalcommand(union node *, int);
static int evalbltin(const struct builtincmd *, int, char **);
static void prehash(union node *);
* Evaluate a parse tree. The value is left in the global variable
* exitstatus.
*/
-static void
+static int
evaltree(union node *n, int flags)
{
struct jmploc *volatile savehandler = exception_handler;
struct jmploc jmploc;
int checkexit = 0;
- void (*evalfn)(union node *, int);
- int status;
+ int (*evalfn)(union node *, int);
+ int status = 0;
int int_level;
SAVE_INT(int_level);
break;
#endif
case NNOT:
- evaltree(n->nnot.com, EV_TESTED);
- status = !exitstatus;
+ status = !evaltree(n->nnot.com, EV_TESTED);
goto setstatus;
case NREDIR:
expredir(n->nredir.redirect);
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
if (!status) {
- evaltree(n->nredir.n, flags & EV_TESTED);
- status = exitstatus;
+ status = evaltree(n->nredir.n, flags & EV_TESTED);
}
popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
goto setstatus;
#error NOR + 1 != NSEMI
#endif
unsigned is_or = n->type - NAND;
- evaltree(
+ status = evaltree(
n->nbinary.ch1,
(flags | ((is_or >> 1) - 1)) & EV_TESTED
);
- if ((!exitstatus) == is_or)
+ if (!status == is_or || evalskip)
break;
- if (!evalskip) {
- n = n->nbinary.ch2;
+ n = n->nbinary.ch2;
evaln:
- evalfn = evaltree;
+ evalfn = evaltree;
calleval:
- evalfn(n, flags);
- break;
- }
- break;
+ status = evalfn(n, flags);
+ goto setstatus;
}
case NIF:
- evaltree(n->nif.test, EV_TESTED);
+ status = evaltree(n->nif.test, EV_TESTED);
if (evalskip)
break;
- if (exitstatus == 0) {
+ if (!status) {
n = n->nif.ifpart;
goto evaln;
}
n = n->nif.elsepart;
goto evaln;
}
- goto success;
+ status = 0;
+ goto setstatus;
case NDEFUN:
defun(n->narg.text, n->narg.next);
- success:
- status = 0;
+ /* Not necessary. To test it:
+ * "false; f() { qwerty; }; echo $?" should print 0.
+ */
+ /* status = 0; */
setstatus:
exitstatus = status;
break;
*/
if (pending_sig && dotrap())
goto exexit;
- if (checkexit & exitstatus)
+ if (checkexit & status)
evalskip |= SKIPEVAL;
if (flags & EV_EXIT) {
RESTORE_INT(int_level);
TRACE(("leaving evaltree (no interrupts)\n"));
+
+ return exitstatus;
}
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
static
#endif
-void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
+int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
-static void
+static int
evalloop(union node *n, int flags)
{
int status;
for (;;) {
int i;
- evaltree(n->nbinary.ch1, EV_TESTED);
+ i = evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip) {
skipping:
if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
break;
}
- i = exitstatus;
if (n->type != NWHILE)
i = !i;
if (i != 0)
break;
- evaltree(n->nbinary.ch2, flags);
- status = exitstatus;
+ status = evaltree(n->nbinary.ch2, flags);
if (evalskip)
goto skipping;
}
- loopnest--;
exitstatus = status;
+ loopnest--;
+
+ return status;
}
-static void
+static int
evalfor(union node *n, int flags)
{
struct arglist arglist;
union node *argp;
struct strlist *sp;
struct stackmark smark;
+ int status = 0;
setstackmark(&smark);
arglist.list = NULL;
}
*arglist.lastp = NULL;
- exitstatus = 0;
loopnest++;
flags &= EV_TESTED;
for (sp = arglist.list; sp; sp = sp->next) {
setvar0(n->nfor.var, sp->text);
- evaltree(n->nfor.body, flags);
+ status = evaltree(n->nfor.body, flags);
if (evalskip) {
if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
loopnest--;
out:
popstackmark(&smark);
+
+ return status;
}
-static void
+static int
evalcase(union node *n, int flags)
{
union node *cp;
union node *patp;
struct arglist arglist;
struct stackmark smark;
+ int status = 0;
setstackmark(&smark);
arglist.list = NULL;
arglist.lastp = &arglist.list;
expandarg(n->ncase.expr, &arglist, EXP_TILDE);
- exitstatus = 0;
for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
if (casematch(patp, arglist.list->text)) {
- if (evalskip == 0) {
- evaltree(cp->nclist.body, flags);
+ /* Ensure body is non-empty as otherwise
+ * EV_EXIT may prevent us from setting the
+ * exit status.
+ */
+ if (evalskip == 0 && cp->nclist.body) {
+ status = evaltree(cp->nclist.body, flags);
}
goto out;
}
}
out:
popstackmark(&smark);
+
+ return status;
}
/*
* Kick off a subshell to evaluate a tree.
*/
-static void
+static int
evalsubshell(union node *n, int flags)
{
struct job *jp;
status = 0;
if (!backgnd)
status = waitforjob(jp);
- exitstatus = status;
INT_ON;
+ return status;
}
/*
* of the shell, which make the last process in a pipeline the parent
* of all the rest.)
*/
-static void
+static int
evalpipe(union node *n, int flags)
{
struct job *jp;
int pipelen;
int prevfd;
int pip[2];
+ int status = 0;
TRACE(("evalpipe(0x%lx) called\n", (long)n));
pipelen = 0;
close(pip[1]);
}
if (n->npipe.pipe_backgnd == 0) {
- exitstatus = waitforjob(jp);
- TRACE(("evalpipe: job done exit status %d\n", exitstatus));
+ status = waitforjob(jp);
+ TRACE(("evalpipe: job done exit status %d\n", status));
}
INT_ON;
+
+ return status;
}
/*
* as POSIX mandates */
return back_exitstatus;
}
-static void
+static int
evalcommand(union node *cmd, int flags)
{
static const struct builtincmd null_bltin = {
jp = makejob(/*cmd,*/ 1);
if (forkshell(jp, cmd, FORK_FG) != 0) {
/* parent */
- exitstatus = waitforjob(jp);
+ status = waitforjob(jp);
INT_ON;
- TRACE(("forked child exited with %d\n", exitstatus));
+ TRACE(("forked child exited with %d\n", status));
break;
}
/* child */
}
FORCE_INT_ON;
}
- break;
+ goto readstatus;
case CMDFUNCTION:
listsetvar(varlist.list, 0);
dowait(DOWAIT_NONBLOCK, NULL);
if (evalfun(cmdentry.u.func, argc, argv, flags))
goto raise;
+ readstatus:
+ status = exitstatus;
break;
} /* switch */
setvar0("_", lastarg);
}
popstackmark(&smark);
+
+ return status;
}
static int
union node *n;
struct stackmark smark;
int skip;
+// int status;
setinputstring(s);
setstackmark(&smark);
skip = 0;
while ((n = parsecmd(0)) != NODE_EOF) {
- evaltree(n, 0);
+ int i;
+
+ i = evaltree(n, 0);
+// if (n)
+// status = i;
popstackmark(&smark);
skip = evalskip;
if (skip)
skip &= mask;
evalskip = skip;
return skip;
+// return status;
}
/*
union node *n;
struct stackmark smark;
int inter;
+ int status = 0;
int numeof = 0;
TRACE(("cmdloop(%d) called\n", top));
}
numeof++;
} else if (nflag == 0) {
+ int i;
+
/* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
job_warning >>= 1;
numeof = 0;
- evaltree(n, 0);
+ i = evaltree(n, 0);
+ if (n)
+ status = i;
}
popstackmark(&smark);
skip = evalskip;
return skip & SKIPEVAL;
}
}
- return 0;
+ return status;
}
/*