$ ); echo $? echoed 0,all other shells echo 2.
[unix-history] / usr / src / bin / sh / eval.c
index 3dfb61b..e4d81d6 100644 (file)
@@ -9,9 +9,12 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)eval.c     8.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)eval.c     8.8 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
+#include <signal.h>
+#include <unistd.h>
+
 /*
  * Evaluate a command.
  */
 /*
  * Evaluate a command.
  */
@@ -33,9 +36,11 @@ static char sccsid[] = "@(#)eval.c   8.2 (Berkeley) %G%";
 #include "var.h"
 #include "memalloc.h"
 #include "error.h"
 #include "var.h"
 #include "memalloc.h"
 #include "error.h"
+#include "show.h"
 #include "mystring.h"
 #include "mystring.h"
+#ifndef NO_HISTORY
 #include "myhistedit.h"
 #include "myhistedit.h"
-#include <signal.h>
+#endif
 
 
 /* flags in argument to evaltree */
 
 
 /* flags in argument to evaltree */
@@ -58,28 +63,17 @@ int funcnest;                       /* depth of function calls */
 char *commandname;
 struct strlist *cmdenviron;
 int exitstatus;                        /* exit status of last command */
 char *commandname;
 struct strlist *cmdenviron;
 int exitstatus;                        /* exit status of last command */
+int oexitstatus;               /* saved exit status */
 
 
 
 
-#ifdef __STDC__
-STATIC void evalloop(union node *);
-STATIC void evalfor(union node *);
-STATIC void evalcase(union node *, int);
-STATIC void evalsubshell(union node *, int);
-STATIC void expredir(union node *);
-STATIC void evalpipe(union node *);
-STATIC void evalcommand(union node *, int, struct backcmd *);
-STATIC void prehash(union node *);
-#else
-STATIC void evalloop();
-STATIC void evalfor();
-STATIC void evalcase();
-STATIC void evalsubshell();
-STATIC void expredir();
-STATIC void evalpipe();
-STATIC void evalcommand();
-STATIC void prehash();
-#endif
-
+STATIC void evalloop __P((union node *));
+STATIC void evalfor __P((union node *));
+STATIC void evalcase __P((union node *, int));
+STATIC void evalsubshell __P((union node *, int));
+STATIC void expredir __P((union node *));
+STATIC void evalpipe __P((union node *));
+STATIC void evalcommand __P((union node *, int, struct backcmd *));
+STATIC void prehash __P((union node *));
 
 
 /*
 
 
 /*
@@ -106,7 +100,9 @@ SHELLPROC {
  * The eval commmand.
  */
 
  * The eval commmand.
  */
 
+int
 evalcmd(argc, argv)  
 evalcmd(argc, argv)  
+       int argc;
        char **argv; 
 {
         char *p;
        char **argv; 
 {
         char *p;
@@ -165,14 +161,17 @@ evalstring(s)
 void
 evaltree(n, flags)
        union node *n;
 void
 evaltree(n, flags)
        union node *n;
-       {
+       int flags;
+{
        if (n == NULL) {
                TRACE(("evaltree(NULL) called\n"));
                exitstatus = 0;
                goto out;
        }
        if (n == NULL) {
                TRACE(("evaltree(NULL) called\n"));
                exitstatus = 0;
                goto out;
        }
+#ifndef NO_HISTORY
        displayhist = 1;        /* show history substitutions done with fc */
        displayhist = 1;        /* show history substitutions done with fc */
-       TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type));
+#endif
+       TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
        switch (n->type) {
        case NSEMI:
                evaltree(n->nbinary.ch1, 0);
        switch (n->type) {
        case NSEMI:
                evaltree(n->nbinary.ch1, 0);
@@ -205,19 +204,17 @@ evaltree(n, flags)
                evalsubshell(n, flags);
                break;
        case NIF: {
                evalsubshell(n, flags);
                break;
        case NIF: {
-               int status = 0
+               int status; 
 
                evaltree(n->nif.test, EV_TESTED);
 
                evaltree(n->nif.test, EV_TESTED);
+               status = exitstatus;
+               exitstatus = 0;
                if (evalskip)
                        goto out;
                if (evalskip)
                        goto out;
-               if (exitstatus == 0) {
+               if (status == 0)
                        evaltree(n->nif.ifpart, flags);
                        evaltree(n->nif.ifpart, flags);
-                       status = exitstatus;
-               } else if (n->nif.elsepart) {
+               else if (n->nif.elsepart)
                        evaltree(n->nif.elsepart, flags);
                        evaltree(n->nif.elsepart, flags);
-                       status = exitstatus;
-               }
-               exitstatus = status;
                break;
        }
        case NWHILE:
                break;
        }
        case NWHILE:
@@ -261,7 +258,7 @@ out:
 STATIC void
 evalloop(n)
        union node *n;
 STATIC void
 evalloop(n)
        union node *n;
-       {
+{
        int status;
 
        loopnest++;
        int status;
 
        loopnest++;
@@ -297,8 +294,8 @@ skipping:     if (evalskip == SKIPCONT && --skipcount <= 0) {
 
 STATIC void
 evalfor(n)
 
 STATIC void
 evalfor(n)
-       union node *n;
-       {
+    union node *n;
+{
        struct arglist arglist;
        union node *argp;
        struct strlist *sp;
        struct arglist arglist;
        union node *argp;
        struct strlist *sp;
@@ -307,6 +304,7 @@ evalfor(n)
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
        for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
        for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
+               oexitstatus = exitstatus;
                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
                if (evalskip)
                        goto out;
                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
                if (evalskip)
                        goto out;
@@ -338,7 +336,8 @@ out:
 STATIC void
 evalcase(n, flags)
        union node *n;
 STATIC void
 evalcase(n, flags)
        union node *n;
-       {
+       int flags;
+{
        union node *cp;
        union node *patp;
        struct arglist arglist;
        union node *cp;
        union node *patp;
        struct arglist arglist;
@@ -346,6 +345,7 @@ evalcase(n, flags)
 
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
 
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
+       oexitstatus = exitstatus;
        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) {
        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) {
@@ -370,7 +370,8 @@ out:
 STATIC void
 evalsubshell(n, flags)
        union node *n;
 STATIC void
 evalsubshell(n, flags)
        union node *n;
-       {
+       int flags;
+{
        struct job *jp;
        int backgnd = (n->type == NBACKGND);
 
        struct job *jp;
        int backgnd = (n->type == NBACKGND);
 
@@ -398,17 +399,27 @@ evalsubshell(n, flags)
 STATIC void
 expredir(n)
        union node *n;
 STATIC void
 expredir(n)
        union node *n;
-       {
+{
        register union node *redir;
 
        for (redir = n ; redir ; redir = redir->nfile.next) {
        register union node *redir;
 
        for (redir = n ; redir ; redir = redir->nfile.next) {
-               if (redir->type == NFROM
-                || redir->type == NTO
-                || redir->type == NAPPEND) {
-                       struct arglist fn;
-                       fn.lastp = &fn.list;
+               struct arglist fn;
+               fn.lastp = &fn.list;
+               oexitstatus = exitstatus;
+               switch (redir->type) {
+               case NFROM:
+               case NTO:
+               case NAPPEND:
                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
                        redir->nfile.expfname = fn.list->text;
                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
                        redir->nfile.expfname = fn.list->text;
+                       break;
+               case NFROMFD:
+               case NTOFD:
+                       if (redir->ndup.vname) {
+                               expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
+                               fixredir(redir, fn.list->text, 1);
+                       }
+                       break;
                }
        }
 }
                }
        }
 }
@@ -425,14 +436,14 @@ expredir(n)
 STATIC void
 evalpipe(n)
        union node *n;
 STATIC void
 evalpipe(n)
        union node *n;
-       {
+{
        struct job *jp;
        struct nodelist *lp;
        int pipelen;
        int prevfd;
        int pip[2];
 
        struct job *jp;
        struct nodelist *lp;
        int pipelen;
        int prevfd;
        int pip[2];
 
-       TRACE(("evalpipe(0x%x) called\n", (int)n));
+       TRACE(("evalpipe(0x%lx) called\n", (long)n));
        pipelen = 0;
        for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
                pipelen++;
        pipelen = 0;
        for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
                pipelen++;
@@ -492,7 +503,7 @@ void
 evalbackcmd(n, result)
        union node *n;
        struct backcmd *result;
 evalbackcmd(n, result)
        union node *n;
        struct backcmd *result;
-       {
+{
        int pip[2];
        struct job *jp;
        struct stackmark smark;         /* unnecessary */
        int pip[2];
        struct job *jp;
        struct stackmark smark;         /* unnecessary */
@@ -502,12 +513,15 @@ evalbackcmd(n, result)
        result->buf = NULL;
        result->nleft = 0;
        result->jp = NULL;
        result->buf = NULL;
        result->nleft = 0;
        result->jp = NULL;
-       exitstatus = 0;
-       if (n == NULL)
+       if (n == NULL) {
+               exitstatus = 0;
                goto out;
                goto out;
+       }
        if (n->type == NCMD) {
        if (n->type == NCMD) {
+               exitstatus = oexitstatus;
                evalcommand(n, EV_BACKCMD, result);
        } else {
                evalcommand(n, EV_BACKCMD, result);
        } else {
+               exitstatus = 0;
                if (pipe(pip) < 0)
                        error("Pipe call failed");
                jp = makejob(n, 1);
                if (pipe(pip) < 0)
                        error("Pipe call failed");
                jp = makejob(n, 1);
@@ -540,8 +554,9 @@ out:
 STATIC void
 evalcommand(cmd, flags, backcmd)
        union node *cmd;
 STATIC void
 evalcommand(cmd, flags, backcmd)
        union node *cmd;
+       int flags;
        struct backcmd *backcmd;
        struct backcmd *backcmd;
-       {
+{
        struct stackmark smark;
        union node *argp;
        struct arglist arglist;
        struct stackmark smark;
        union node *argp;
        struct arglist arglist;
@@ -551,7 +566,6 @@ evalcommand(cmd, flags, backcmd)
        char **envp;
        int varflag;
        struct strlist *sp;
        char **envp;
        int varflag;
        struct strlist *sp;
-       register char *p;
        int mode;
        int pip[2];
        struct cmdentry cmdentry;
        int mode;
        int pip[2];
        struct cmdentry cmdentry;
@@ -563,15 +577,24 @@ evalcommand(cmd, flags, backcmd)
        struct localvar *volatile savelocalvars;
        volatile int e;
        char *lastarg;
        struct localvar *volatile savelocalvars;
        volatile int e;
        char *lastarg;
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &argv;
+       (void) &argc;
+       (void) &lastarg;
+       (void) &flags;
+#endif
 
        /* First expand the arguments. */
 
        /* First expand the arguments. */
-       TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags));
+       TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
        varlist.lastp = &varlist.list;
        varflag = 1;
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
        varlist.lastp = &varlist.list;
        varflag = 1;
+       oexitstatus = exitstatus;
+       exitstatus = 0;
        for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
        for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
-               p = argp->narg.text;
+               char *p = argp->narg.text;
                if (varflag && is_name(*p)) {
                        do {
                                p++;
                if (varflag && is_name(*p)) {
                        do {
                                p++;
@@ -624,7 +647,7 @@ evalcommand(cmd, flags, backcmd)
        } else {
                find_command(argv[0], &cmdentry, 1);
                if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
        } else {
                find_command(argv[0], &cmdentry, 1);
                if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
-                       exitstatus = 2;
+                       exitstatus = 1;
                        flushout(&errout);
                        return;
                }
                        flushout(&errout);
                        return;
                }
@@ -636,7 +659,7 @@ evalcommand(cmd, flags, backcmd)
                                        break;
                                if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
                                        outfmt(&errout, "%s: not found\n", *argv);
                                        break;
                                if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
                                        outfmt(&errout, "%s: not found\n", *argv);
-                                       exitstatus = 2;
+                                       exitstatus = 1;
                                        flushout(&errout);
                                        return;
                                }
                                        flushout(&errout);
                                        return;
                                }
@@ -648,11 +671,11 @@ evalcommand(cmd, flags, backcmd)
 
        /* Fork off a child process if necessary. */
        if (cmd->ncmd.backgnd
 
        /* Fork off a child process if necessary. */
        if (cmd->ncmd.backgnd
-        || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0
-        || (flags & EV_BACKCMD) != 0
+        || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
+        || ((flags & EV_BACKCMD) != 0
            && (cmdentry.cmdtype != CMDBUILTIN
                 || cmdentry.u.index == DOTCMD
            && (cmdentry.cmdtype != CMDBUILTIN
                 || cmdentry.u.index == DOTCMD
-                || cmdentry.u.index == EVALCMD)) {
+                || cmdentry.u.index == EVALCMD))) {
                jp = makejob(cmd, 1);
                mode = cmd->ncmd.backgnd;
                if (flags & EV_BACKCMD) {
                jp = makejob(cmd, 1);
                mode = cmd->ncmd.backgnd;
                if (flags & EV_BACKCMD) {
@@ -761,7 +784,9 @@ cmddone:
                        if (e != EXERROR || cmdentry.u.index == BLTINCMD
                                               || cmdentry.u.index == DOTCMD
                                               || cmdentry.u.index == EVALCMD
                        if (e != EXERROR || cmdentry.u.index == BLTINCMD
                                               || cmdentry.u.index == DOTCMD
                                               || cmdentry.u.index == EVALCMD
+#ifndef NO_HISTORY
                                               || cmdentry.u.index == HISTCMD
                                               || cmdentry.u.index == HISTCMD
+#endif
                                               || cmdentry.u.index == EXECCMD)
                                exraise(e);
                        FORCEINTON;
                                               || cmdentry.u.index == EXECCMD)
                                exraise(e);
                        FORCEINTON;
@@ -777,16 +802,10 @@ cmddone:
                trputs("normal command:  ");  trargs(argv);
                clearredir();
                redirect(cmd->ncmd.redirect, 0);
                trputs("normal command:  ");  trargs(argv);
                clearredir();
                redirect(cmd->ncmd.redirect, 0);
-               if (varlist.list) {
-                       p = stalloc(strlen(pathval()) + 1);
-                       scopy(pathval(), p);
-               } else {
-                       p = pathval();
-               }
                for (sp = varlist.list ; sp ; sp = sp->next)
                        setvareq(sp->text, VEXPORT|VSTACK);
                envp = environment();
                for (sp = varlist.list ; sp ; sp = sp->next)
                        setvareq(sp->text, VEXPORT|VSTACK);
                envp = environment();
-               shellexec(argv, envp, p, cmdentry.u.index);
+               shellexec(argv, envp, pathval(), cmdentry.u.index);
                /*NOTREACHED*/
        }
        goto out;
                /*NOTREACHED*/
        }
        goto out;
@@ -820,11 +839,12 @@ out:
 STATIC void
 prehash(n)
        union node *n;
 STATIC void
 prehash(n)
        union node *n;
-       {
+{
        struct cmdentry entry;
 
        struct cmdentry entry;
 
-       if (n->type == NCMD && goodname(n->ncmd.args->narg.text))
-               find_command(n->ncmd.args->narg.text, &entry, 0);
+       if (n->type == NCMD && n->ncmd.args)
+               if (goodname(n->ncmd.args->narg.text))
+                       find_command(n->ncmd.args->narg.text, &entry, 0);
 }
 
 
 }
 
 
@@ -839,8 +859,16 @@ prehash(n)
  * specified variables.
  */
 
  * specified variables.
  */
 
-bltincmd(argc, argv)  char **argv; {
+int
+bltincmd(argc, argv)
+       int argc;
+       char **argv; 
+{
        listsetvar(cmdenviron);
        listsetvar(cmdenviron);
+       /* 
+        * Preserve exitstatus of a previous possible redirection
+        * as POSIX mandates 
+        */
        return exitstatus;
 }
 
        return exitstatus;
 }
 
@@ -856,7 +884,11 @@ bltincmd(argc, argv)  char **argv; {
  * in the standard shell so we don't make it one here.
  */
 
  * in the standard shell so we don't make it one here.
  */
 
-breakcmd(argc, argv)  char **argv; {
+int
+breakcmd(argc, argv)
+       int argc;
+       char **argv; 
+{
        int n;
 
        n = 1;
        int n;
 
        n = 1;
@@ -876,7 +908,11 @@ breakcmd(argc, argv)  char **argv; {
  * The return command.
  */
 
  * The return command.
  */
 
-returncmd(argc, argv)  char **argv; {
+int
+returncmd(argc, argv) 
+       int argc;
+       char **argv; 
+{
        int ret;
 
        ret = exitstatus;
        int ret;
 
        ret = exitstatus;
@@ -890,21 +926,37 @@ returncmd(argc, argv)  char **argv; {
 }
 
 
 }
 
 
-falsecmd(argc, argv) char **argv; {
+int
+falsecmd(argc, argv) 
+       int argc;
+       char **argv; 
+{
        return 1;
 }
 
 
        return 1;
 }
 
 
-truecmd(argc, argv)  char **argv; {
+int
+truecmd(argc, argv)  
+       int argc;
+       char **argv; 
+{
        return 0;
 }
 
 
        return 0;
 }
 
 
-execcmd(argc, argv)  char **argv; {
+int
+execcmd(argc, argv) 
+       int argc;
+       char **argv; 
+{
        if (argc > 1) {
        if (argc > 1) {
+               struct strlist *sp;
+
                iflag = 0;              /* exit on error */
                mflag = 0;
                optschanged();
                iflag = 0;              /* exit on error */
                mflag = 0;
                optschanged();
+               for (sp = cmdenviron; sp ; sp = sp->next)
+                       setvareq(sp->text, VEXPORT|VSTACK);
                shellexec(argv + 1, environment(), pathval(), 0);
 
        }
                shellexec(argv + 1, environment(), pathval(), 0);
 
        }