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