home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / sh / eval.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-15  |  19.7 KB  |  921 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)eval.c    5.3 (Berkeley) 4/12/91";
  39. #endif /* not lint */
  40.  
  41. /*
  42.  * Evaluate a command.
  43.  */
  44.  
  45. #include "shell.h"
  46. #include "nodes.h"
  47. #include "syntax.h"
  48. #include "expand.h"
  49. #include "parser.h"
  50. #include "jobs.h"
  51. #include "eval.h"
  52. #include "builtins.h"
  53. #include "options.h"
  54. #include "exec.h"
  55. #include "redir.h"
  56. #include "input.h"
  57. #include "output.h"
  58. #include "trap.h"
  59. #include "var.h"
  60. #include "memalloc.h"
  61. #include "error.h"
  62. #include "mystring.h"
  63. #include <signal.h>
  64.  
  65.  
  66. /* flags in argument to evaltree */
  67. #define EV_EXIT 01        /* exit after evaluating tree */
  68. #define EV_TESTED 02        /* exit status is checked; ignore -e flag */
  69. #define EV_BACKCMD 04        /* command executing within back quotes */
  70.  
  71.  
  72. /* reasons for skipping commands (see comment on breakcmd routine) */
  73. #define SKIPBREAK 1
  74. #define SKIPCONT 2
  75. #define SKIPFUNC 3
  76.  
  77. MKINIT int evalskip;        /* set if we are skipping commands */
  78. STATIC int skipcount;        /* number of levels to skip */
  79. MKINIT int loopnest;        /* current loop nesting level */
  80. int funcnest;            /* depth of function calls */
  81.  
  82.  
  83. char *commandname;
  84. struct strlist *cmdenviron;
  85. int exitstatus;            /* exit status of last command */
  86.  
  87.  
  88. #ifdef __STDC__
  89. STATIC void evalloop(union node *);
  90. STATIC void evalfor(union node *);
  91. STATIC void evalcase(union node *, int);
  92. STATIC void evalsubshell(union node *, int);
  93. STATIC void expredir(union node *);
  94. STATIC void evalpipe(union node *);
  95. STATIC void evalcommand(union node *, int, struct backcmd *);
  96. STATIC void prehash(union node *);
  97. #else
  98. STATIC void evalloop();
  99. STATIC void evalfor();
  100. STATIC void evalcase();
  101. STATIC void evalsubshell();
  102. STATIC void expredir();
  103. STATIC void evalpipe();
  104. STATIC void evalcommand();
  105. STATIC void prehash();
  106. #endif
  107.  
  108.  
  109.  
  110. /*
  111.  * Called to reset things after an exception.
  112.  */
  113.  
  114. #ifdef mkinit
  115. INCLUDE "eval.h"
  116.  
  117. RESET {
  118.     evalskip = 0;
  119.     loopnest = 0;
  120.     funcnest = 0;
  121. }
  122.  
  123. SHELLPROC {
  124.     exitstatus = 0;
  125. }
  126. #endif
  127.  
  128.  
  129.  
  130. /*
  131.  * The eval commmand.
  132.  */
  133.  
  134. evalcmd(argc, argv)  
  135.     char **argv; 
  136. {
  137.         char *p;
  138.         char *concat;
  139.         char **ap;
  140.  
  141.         if (argc > 1) {
  142.                 p = argv[1];
  143.                 if (argc > 2) {
  144.                         STARTSTACKSTR(concat);
  145.                         ap = argv + 2;
  146.                         for (;;) {
  147.                                 while (*p)
  148.                                         STPUTC(*p++, concat);
  149.                                 if ((p = *ap++) == NULL)
  150.                                         break;
  151.                                 STPUTC(' ', concat);
  152.                         }
  153.                         STPUTC('\0', concat);
  154.                         p = grabstackstr(concat);
  155.                 }
  156.                 evalstring(p);
  157.         }
  158.         return exitstatus;
  159. }
  160.  
  161.  
  162. /*
  163.  * Execute a command or commands contained in a string.
  164.  */
  165.  
  166. void
  167. evalstring(s)
  168.     char *s;
  169.     {
  170.     union node *n;
  171.     struct stackmark smark;
  172.  
  173.     setstackmark(&smark);
  174.     setinputstring(s, 1);
  175.     while ((n = parsecmd(0)) != NEOF) {
  176.         evaltree(n, 0);
  177.         popstackmark(&smark);
  178.     }
  179.     popfile();
  180.     popstackmark(&smark);
  181. }
  182.  
  183.  
  184.  
  185. /*
  186.  * Evaluate a parse tree.  The value is left in the global variable
  187.  * exitstatus.
  188.  */
  189.  
  190. void
  191. evaltree(n, flags)
  192.     union node *n;
  193.     {
  194.     if (n == NULL) {
  195.         TRACE(("evaltree(NULL) called\n"));
  196.         return;
  197.     }
  198.     TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type));
  199.     switch (n->type) {
  200.     case NSEMI:
  201.         evaltree(n->nbinary.ch1, 0);
  202.         if (evalskip)
  203.             goto out;
  204.         evaltree(n->nbinary.ch2, flags);
  205.         break;
  206.     case NAND:
  207.         evaltree(n->nbinary.ch1, EV_TESTED);
  208.         if (evalskip || exitstatus != 0)
  209.             goto out;
  210.         evaltree(n->nbinary.ch2, flags);
  211.         break;
  212.     case NOR:
  213.         evaltree(n->nbinary.ch1, EV_TESTED);
  214.         if (evalskip || exitstatus == 0)
  215.             goto out;
  216.         evaltree(n->nbinary.ch2, flags);
  217.         break;
  218.     case NREDIR:
  219.         expredir(n->nredir.redirect);
  220.         redirect(n->nredir.redirect, REDIR_PUSH);
  221.         evaltree(n->nredir.n, flags);
  222.         popredir();
  223.         break;
  224.     case NSUBSHELL:
  225.         evalsubshell(n, flags);
  226.         break;
  227.     case NBACKGND:
  228.         evalsubshell(n, flags);
  229.         break;
  230.     case NIF: {
  231.         int status = 0; 
  232.  
  233.         evaltree(n->nif.test, EV_TESTED);
  234.         if (evalskip)
  235.             goto out;
  236.         if (exitstatus == 0) {
  237.             evaltree(n->nif.ifpart, flags);
  238.             status = exitstatus;
  239.         } else if (n->nif.elsepart) {
  240.             evaltree(n->nif.elsepart, flags);
  241.             status = exitstatus;
  242.         }
  243.         exitstatus = status;
  244.         break;
  245.     }
  246.     case NWHILE:
  247.     case NUNTIL:
  248.         evalloop(n);
  249.         break;
  250.     case NFOR:
  251.         evalfor(n);
  252.         break;
  253.     case NCASE:
  254.         evalcase(n, flags);
  255.         break;
  256.     case NDEFUN:
  257.         defun(n->narg.text, n->narg.next);
  258.         exitstatus = 0;
  259.         break;
  260.     case NPIPE:
  261.         evalpipe(n);
  262.         break;
  263.     case NCMD:
  264.         evalcommand(n, flags, (struct backcmd *)NULL);
  265.         break;
  266.     default:
  267.         out1fmt("Node type = %d\n", n->type);
  268.         flushout(&output);
  269.         break;
  270.     }
  271. out:
  272.     if (pendingsigs)
  273.         dotrap();
  274.     if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
  275.         exitshell(exitstatus);
  276. }
  277.  
  278.  
  279. STATIC void
  280. evalloop(n)
  281.     union node *n;
  282.     {
  283.     int status;
  284.  
  285.     loopnest++;
  286.     status = 0;
  287.     for (;;) {
  288.         evaltree(n->nbinary.ch1, EV_TESTED);
  289.         if (evalskip) {
  290. skipping:      if (evalskip == SKIPCONT && --skipcount <= 0) {
  291.                 evalskip = 0;
  292.                 continue;
  293.             }
  294.             if (evalskip == SKIPBREAK && --skipcount <= 0)
  295.                 evalskip = 0;
  296.             break;
  297.         }
  298.         if (n->type == NWHILE) {
  299.             if (exitstatus != 0)
  300.                 break;
  301.         } else {
  302.             if (exitstatus == 0)
  303.                 break;
  304.         }
  305.         evaltree(n->nbinary.ch2, 0);
  306.         status = exitstatus;
  307.         if (evalskip)
  308.             goto skipping;
  309.     }
  310.     loopnest--;
  311.     exitstatus = status;
  312. }
  313.  
  314.  
  315.  
  316. STATIC void
  317. evalfor(n)
  318.     union node *n;
  319.     {
  320.     struct arglist arglist;
  321.     union node *argp;
  322.     struct strlist *sp;
  323.     struct stackmark smark;
  324.  
  325.     setstackmark(&smark);
  326.     arglist.lastp = &arglist.list;
  327.     for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
  328.         expandarg(argp, &arglist, 1);
  329.         if (evalskip)
  330.             goto out;
  331.     }
  332.     *arglist.lastp = NULL;
  333.  
  334.     exitstatus = 0;
  335.     loopnest++;
  336.     for (sp = arglist.list ; sp ; sp = sp->next) {
  337.         setvar(n->nfor.var, sp->text, 0);
  338.         evaltree(n->nfor.body, 0);
  339.         if (evalskip) {
  340.             if (evalskip == SKIPCONT && --skipcount <= 0) {
  341.                 evalskip = 0;
  342.                 continue;
  343.             }
  344.             if (evalskip == SKIPBREAK && --skipcount <= 0)
  345.                 evalskip = 0;
  346.             break;
  347.         }
  348.     }
  349.     loopnest--;
  350. out:
  351.     popstackmark(&smark);
  352. }
  353.  
  354.  
  355.  
  356. STATIC void
  357. evalcase(n, flags)
  358.     union node *n;
  359.     {
  360.     union node *cp;
  361.     union node *patp;
  362.     struct arglist arglist;
  363.     struct stackmark smark;
  364.  
  365.     setstackmark(&smark);
  366.     arglist.lastp = &arglist.list;
  367.     expandarg(n->ncase.expr, &arglist, 0);
  368.     for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
  369.         for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
  370.             if (casematch(patp, arglist.list->text)) {
  371.                 if (evalskip == 0) {
  372.                     evaltree(cp->nclist.body, flags);
  373.                 }
  374.                 goto out;
  375.             }
  376.         }
  377.     }
  378. out:
  379.     popstackmark(&smark);
  380. }
  381.  
  382.  
  383.  
  384. /*
  385.  * Kick off a subshell to evaluate a tree.
  386.  */
  387.  
  388. STATIC void
  389. evalsubshell(n, flags)
  390.     union node *n;
  391.     {
  392.     struct job *jp;
  393.     int backgnd = (n->type == NBACKGND);
  394.  
  395.     expredir(n->nredir.redirect);
  396.     jp = makejob(n, 1);
  397.     if (forkshell(jp, n, backgnd) == 0) {
  398.         if (backgnd)
  399.             flags &=~ EV_TESTED;
  400.         redirect(n->nredir.redirect, 0);
  401.         evaltree(n->nredir.n, flags | EV_EXIT);    /* never returns */
  402.     }
  403.     if (! backgnd) {
  404.         INTOFF;
  405.         exitstatus = waitforjob(jp);
  406.         INTON;
  407.     }
  408. }
  409.  
  410.  
  411.  
  412. /*
  413.  * Compute the names of the files in a redirection list.
  414.  */
  415.  
  416. STATIC void
  417. expredir(n)
  418.     union node *n;
  419.     {
  420.     register union node *redir;
  421.  
  422.     for (redir = n ; redir ; redir = redir->nfile.next) {
  423.         if (redir->type == NFROM
  424.          || redir->type == NTO
  425.          || redir->type == NAPPEND) {
  426.             struct arglist fn;
  427.             fn.lastp = &fn.list;
  428.             expandarg(redir->nfile.fname, &fn, 0);
  429.             redir->nfile.expfname = fn.list->text;
  430.         }
  431.     }
  432. }
  433.  
  434.  
  435.  
  436. /*
  437.  * Evaluate a pipeline.  All the processes in the pipeline are children
  438.  * of the process creating the pipeline.  (This differs from some versions
  439.  * of the shell, which make the last process in a pipeline the parent
  440.  * of all the rest.)
  441.  */
  442.  
  443. STATIC void
  444. evalpipe(n)
  445.     union node *n;
  446.     {
  447.     struct job *jp;
  448.     struct nodelist *lp;
  449.     int pipelen;
  450.     int prevfd;
  451.     int pip[2];
  452.  
  453.     TRACE(("evalpipe(0x%x) called\n", (int)n));
  454.     pipelen = 0;
  455.     for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
  456.         pipelen++;
  457.     INTOFF;
  458.     jp = makejob(n, pipelen);
  459.     prevfd = -1;
  460.     for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
  461.         prehash(lp->n);
  462.         pip[1] = -1;
  463.         if (lp->next) {
  464.             if (pipe(pip) < 0) {
  465.                 close(prevfd);
  466.                 error("Pipe call failed");
  467.             }
  468.         }
  469.         if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
  470.             INTON;
  471.             if (prevfd > 0) {
  472.                 close(0);
  473.                 copyfd(prevfd, 0);
  474.                 close(prevfd);
  475.             }
  476.             if (pip[1] >= 0) {
  477.                 close(pip[0]);
  478.                 if (pip[1] != 1) {
  479.                     close(1);
  480.                     copyfd(pip[1], 1);
  481.                     close(pip[1]);
  482.                 }
  483.             }
  484.             evaltree(lp->n, EV_EXIT);
  485.         }
  486.         if (prevfd >= 0)
  487.             close(prevfd);
  488.         prevfd = pip[0];
  489.         close(pip[1]);
  490.     }
  491.     INTON;
  492.     if (n->npipe.backgnd == 0) {
  493.         INTOFF;
  494.         exitstatus = waitforjob(jp);
  495.         TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
  496.         INTON;
  497.     }
  498. }
  499.  
  500.  
  501.  
  502. /*
  503.  * Execute a command inside back quotes.  If it's a builtin command, we
  504.  * want to save its output in a block obtained from malloc.  Otherwise
  505.  * we fork off a subprocess and get the output of the command via a pipe.
  506.  * Should be called with interrupts off.
  507.  */
  508.  
  509. void
  510. evalbackcmd(n, result)
  511.     union node *n;
  512.     struct backcmd *result;
  513.     {
  514.     int pip[2];
  515.     struct job *jp;
  516.     struct stackmark smark;        /* unnecessary */
  517.  
  518.     setstackmark(&smark);
  519.     result->fd = -1;
  520.     result->buf = NULL;
  521.     result->nleft = 0;
  522.     result->jp = NULL;
  523.     if (n->type == NCMD) {
  524.         evalcommand(n, EV_BACKCMD, result);
  525.     } else {
  526.         if (pipe(pip) < 0)
  527.             error("Pipe call failed");
  528.         jp = makejob(n, 1);
  529.         if (forkshell(jp, n, FORK_NOJOB) == 0) {
  530.             FORCEINTON;
  531.             close(pip[0]);
  532.             if (pip[1] != 1) {
  533.                 close(1);
  534.                 copyfd(pip[1], 1);
  535.                 close(pip[1]);
  536.             }
  537.             evaltree(n, EV_EXIT);
  538.         }
  539.         close(pip[1]);
  540.         result->fd = pip[0];
  541.         result->jp = jp;
  542.     }
  543.     popstackmark(&smark);
  544.     TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
  545.         result->fd, result->buf, result->nleft, result->jp));
  546. }
  547.  
  548.  
  549.  
  550. /*
  551.  * Execute a simple command.
  552.  */
  553.  
  554. STATIC void
  555. evalcommand(cmd, flags, backcmd)
  556.     union node *cmd;
  557.     struct backcmd *backcmd;
  558.     {
  559.     struct stackmark smark;
  560.     union node *argp;
  561.     struct arglist arglist;
  562.     struct arglist varlist;
  563.     char **argv;
  564.     int argc;
  565.     char **envp;
  566.     int varflag;
  567.     struct strlist *sp;
  568.     register char *p;
  569.     int mode;
  570.     int pip[2];
  571.     struct cmdentry cmdentry;
  572.     struct job *jp;
  573.     struct jmploc jmploc;
  574.     struct jmploc *volatile savehandler;
  575.     char *volatile savecmdname;
  576.     volatile struct shparam saveparam;
  577.     struct localvar *volatile savelocalvars;
  578.     volatile int e;
  579.     char *lastarg;
  580.  
  581.     /* First expand the arguments. */
  582.     TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags));
  583.     setstackmark(&smark);
  584.     arglist.lastp = &arglist.list;
  585.     varlist.lastp = &varlist.list;
  586.     varflag = 1;
  587.     for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
  588.         p = argp->narg.text;
  589.         if (varflag && is_name(*p)) {
  590.             do {
  591.                 p++;
  592.             } while (is_in_name(*p));
  593.             if (*p == '=') {
  594.                 expandarg(argp, &varlist, 0);
  595.                 continue;
  596.             }
  597.         }
  598.         expandarg(argp, &arglist, 1);
  599.         varflag = 0;
  600.     }
  601.     *arglist.lastp = NULL;
  602.     *varlist.lastp = NULL;
  603.     expredir(cmd->ncmd.redirect);
  604.     argc = 0;
  605.     for (sp = arglist.list ; sp ; sp = sp->next)
  606.         argc++;
  607.     argv = stalloc(sizeof (char *) * (argc + 1));
  608.     for (sp = arglist.list ; sp ; sp = sp->next)
  609.         *argv++ = sp->text;
  610.     *argv = NULL;
  611.     lastarg = NULL;
  612.     if (iflag && funcnest == 0 && argc > 0)
  613.         lastarg = argv[-1];
  614.     argv -= argc;
  615.  
  616.     /* Print the command if xflag is set. */
  617.     if (xflag) {
  618.         outc('+', &errout);
  619.         for (sp = varlist.list ; sp ; sp = sp->next) {
  620.             outc(' ', &errout);
  621.             out2str(sp->text);
  622.         }
  623.         for (sp = arglist.list ; sp ; sp = sp->next) {
  624.             outc(' ', &errout);
  625.             out2str(sp->text);
  626.         }
  627.         outc('\n', &errout);
  628.         flushout(&errout);
  629.     }
  630.  
  631.     /* Now locate the command. */
  632.     if (argc == 0) {
  633.         cmdentry.cmdtype = CMDBUILTIN;
  634.         cmdentry.u.index = BLTINCMD;
  635.     } else {
  636.         find_command(argv[0], &cmdentry, 1);
  637.         if (cmdentry.cmdtype == CMDUNKNOWN) {    /* command not found */
  638.             exitstatus = 2;
  639.             flushout(&errout);
  640.             return;
  641.         }
  642.         /* implement the bltin builtin here */
  643.         if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
  644.             for (;;) {
  645.                 argv++;
  646.                 if (--argc == 0)
  647.                     break;
  648.                 if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
  649.                     outfmt(&errout, "%s: not found\n", *argv);
  650.                     exitstatus = 2;
  651.                     flushout(&errout);
  652.                     return;
  653.                 }
  654.                 if (cmdentry.u.index != BLTINCMD)
  655.                     break;
  656.             }
  657.         }
  658.     }
  659.  
  660.     /* Fork off a child process if necessary. */
  661.     if (cmd->ncmd.backgnd
  662.      || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0
  663.      || (flags & EV_BACKCMD) != 0
  664.         && (cmdentry.cmdtype != CMDBUILTIN
  665.          || cmdentry.u.index == DOTCMD
  666.          || cmdentry.u.index == EVALCMD)) {
  667.         jp = makejob(cmd, 1);
  668.         mode = cmd->ncmd.backgnd;
  669.         if (flags & EV_BACKCMD) {
  670.             mode = FORK_NOJOB;
  671.             if (pipe(pip) < 0)
  672.                 error("Pipe call failed");
  673.         }
  674.         if (forkshell(jp, cmd, mode) != 0)
  675.             goto parent;    /* at end of routine */
  676.         if (flags & EV_BACKCMD) {
  677.             FORCEINTON;
  678.             close(pip[0]);
  679.             if (pip[1] != 1) {
  680.                 close(1);
  681.                 copyfd(pip[1], 1);
  682.                 close(pip[1]);
  683.             }
  684.         }
  685.         flags |= EV_EXIT;
  686.     }
  687.  
  688.     /* This is the child process if a fork occurred. */
  689.     /* Execute the command. */
  690.     if (cmdentry.cmdtype == CMDFUNCTION) {
  691.         trputs("Shell function:  ");  trargs(argv);
  692.         redirect(cmd->ncmd.redirect, REDIR_PUSH);
  693.         saveparam = shellparam;
  694.         shellparam.malloc = 0;
  695.         shellparam.nparam = argc - 1;
  696.         shellparam.p = argv + 1;
  697.         shellparam.optnext = NULL;
  698.         INTOFF;
  699.         savelocalvars = localvars;
  700.         localvars = NULL;
  701.         INTON;
  702.         if (setjmp(jmploc.loc)) {
  703.             if (exception == EXSHELLPROC)
  704.                 freeparam((struct shparam *)&saveparam);
  705.             else {
  706.                 freeparam(&shellparam);
  707.                 shellparam = saveparam;
  708.             }
  709.             poplocalvars();
  710.             localvars = savelocalvars;
  711.             handler = savehandler;
  712.             longjmp(handler->loc, 1);
  713.         }
  714.         savehandler = handler;
  715.         handler = &jmploc;
  716.         for (sp = varlist.list ; sp ; sp = sp->next)
  717.             mklocal(sp->text);
  718.         funcnest++;
  719.         evaltree(cmdentry.u.func, 0);
  720.         funcnest--;
  721.         INTOFF;
  722.         poplocalvars();
  723.         localvars = savelocalvars;
  724.         freeparam(&shellparam);
  725.         shellparam = saveparam;
  726.         handler = savehandler;
  727.         popredir();
  728.         INTON;
  729.         if (evalskip == SKIPFUNC) {
  730.             evalskip = 0;
  731.             skipcount = 0;
  732.         }
  733.         if (flags & EV_EXIT)
  734.             exitshell(exitstatus);
  735.     } else if (cmdentry.cmdtype == CMDBUILTIN) {
  736.         trputs("builtin command:  ");  trargs(argv);
  737.         mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
  738.         if (flags == EV_BACKCMD) {
  739.             memout.nleft = 0;
  740.             memout.nextc = memout.buf;
  741.             memout.bufsize = 64;
  742.             mode |= REDIR_BACKQ;
  743.         }
  744.         redirect(cmd->ncmd.redirect, mode);
  745.         savecmdname = commandname;
  746.         cmdenviron = varlist.list;
  747.         e = -1;
  748.         if (setjmp(jmploc.loc)) {
  749.             e = exception;
  750.             exitstatus = (e == EXINT)? SIGINT+128 : 2;
  751.             goto cmddone;
  752.         }
  753.         savehandler = handler;
  754.         handler = &jmploc;
  755.         commandname = argv[0];
  756.         argptr = argv + 1;
  757.         optptr = NULL;            /* initialize nextopt */
  758.         exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
  759.         flushall();
  760. cmddone:
  761.         out1 = &output;
  762.         out2 = &errout;
  763.         freestdout();
  764.         if (e != EXSHELLPROC) {
  765.             commandname = savecmdname;
  766.             if (flags & EV_EXIT) {
  767.                 exitshell(exitstatus);
  768.             }
  769.         }
  770.         handler = savehandler;
  771.         if (e != -1) {
  772.             if (e != EXERROR || cmdentry.u.index == BLTINCMD
  773.                            || cmdentry.u.index == DOTCMD
  774.                            || cmdentry.u.index == EVALCMD
  775.                            || cmdentry.u.index == EXECCMD)
  776.                 exraise(e);
  777.             FORCEINTON;
  778.         }
  779.         if (cmdentry.u.index != EXECCMD)
  780.             popredir();
  781.         if (flags == EV_BACKCMD) {
  782.             backcmd->buf = memout.buf;
  783.             backcmd->nleft = memout.nextc - memout.buf;
  784.             memout.buf = NULL;
  785.         }
  786.     } else {
  787.         trputs("normal command:  ");  trargs(argv);
  788.         clearredir();
  789.         redirect(cmd->ncmd.redirect, 0);
  790.         if (varlist.list) {
  791.             p = stalloc(strlen(pathval()) + 1);
  792.             scopy(pathval(), p);
  793.         } else {
  794.             p = pathval();
  795.         }
  796.         for (sp = varlist.list ; sp ; sp = sp->next)
  797.             setvareq(sp->text, VEXPORT|VSTACK);
  798.         envp = environment();
  799.         shellexec(argv, envp, p, cmdentry.u.index);
  800.         /*NOTREACHED*/
  801.     }
  802.     goto out;
  803.  
  804. parent:    /* parent process gets here (if we forked) */
  805.     if (mode == 0) {    /* argument to fork */
  806.         INTOFF;
  807.         exitstatus = waitforjob(jp);
  808.         INTON;
  809.     } else if (mode == 2) {
  810.         backcmd->fd = pip[0];
  811.         close(pip[1]);
  812.         backcmd->jp = jp;
  813.     }
  814.  
  815. out:
  816.     if (lastarg)
  817.         setvar("_", lastarg, 0);
  818.     popstackmark(&smark);
  819. }
  820.  
  821.  
  822.  
  823. /*
  824.  * Search for a command.  This is called before we fork so that the
  825.  * location of the command will be available in the parent as well as
  826.  * the child.  The check for "goodname" is an overly conservative
  827.  * check that the name will not be subject to expansion.
  828.  */
  829.  
  830. STATIC void
  831. prehash(n)
  832.     union node *n;
  833.     {
  834.     struct cmdentry entry;
  835.  
  836.     if (n->type == NCMD && goodname(n->ncmd.args->narg.text))
  837.         find_command(n->ncmd.args->narg.text, &entry, 0);
  838. }
  839.  
  840.  
  841.  
  842. /*
  843.  * Builtin commands.  Builtin commands whose functions are closely
  844.  * tied to evaluation are implemented here.
  845.  */
  846.  
  847. /*
  848.  * No command given, or a bltin command with no arguments.  Set the
  849.  * specified variables.
  850.  */
  851.  
  852. bltincmd(argc, argv)  char **argv; {
  853.     listsetvar(cmdenviron);
  854.     return exitstatus;
  855. }
  856.  
  857.  
  858. /*
  859.  * Handle break and continue commands.  Break, continue, and return are
  860.  * all handled by setting the evalskip flag.  The evaluation routines
  861.  * above all check this flag, and if it is set they start skipping
  862.  * commands rather than executing them.  The variable skipcount is
  863.  * the number of loops to break/continue, or the number of function
  864.  * levels to return.  (The latter is always 1.)  It should probably
  865.  * be an error to break out of more loops than exist, but it isn't
  866.  * in the standard shell so we don't make it one here.
  867.  */
  868.  
  869. breakcmd(argc, argv)  char **argv; {
  870.     int n;
  871.  
  872.     n = 1;
  873.     if (argc > 1)
  874.         n = number(argv[1]);
  875.     if (n > loopnest)
  876.         n = loopnest;
  877.     if (n > 0) {
  878.         evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
  879.         skipcount = n;
  880.     }
  881.     return 0;
  882. }
  883.  
  884.  
  885. /*
  886.  * The return command.
  887.  */
  888.  
  889. returncmd(argc, argv)  char **argv; {
  890.     int ret;
  891.  
  892.     ret = exitstatus;
  893.     if (argc > 1)
  894.         ret = number(argv[1]);
  895.     if (funcnest) {
  896.         evalskip = SKIPFUNC;
  897.         skipcount = 1;
  898.     }
  899.     return ret;
  900. }
  901.  
  902.  
  903. truecmd(argc, argv)  char **argv; {
  904.     return 0;
  905. }
  906.  
  907.  
  908. execcmd(argc, argv)  char **argv; {
  909.     if (argc > 1) {
  910.         iflag = 0;        /* exit on error */
  911.         setinteractive(0);
  912. #if JOBS
  913.         jflag = 0;
  914.         setjobctl(0);
  915. #endif
  916.         shellexec(argv + 1, environment(), pathval(), 0);
  917.  
  918.     }
  919.     return 0;
  920. }
  921.