eval.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 static char sccsid[] = "@(#)eval.c      5.3 (Berkeley) 4/12/91";
00039 #endif /* not lint */
00040 
00041 /*
00042  * Evaluate a command.
00043  */
00044 
00045 #include "shell.h"
00046 #include "nodes.h"
00047 #include "syntax.h"
00048 #include "expand.h"
00049 #include "parser.h"
00050 #include "jobs.h"
00051 #include "eval.h"
00052 #include "builtins.h"
00053 #include "options.h"
00054 #include "exec.h"
00055 #include "redir.h"
00056 #include "input.h"
00057 #include "output.h"
00058 #include "trap.h"
00059 #include "var.h"
00060 #include "memalloc.h"
00061 #include "error.h"
00062 #include "mystring.h"
00063 #include <sys/types.h>
00064 #include <signal.h>
00065 
00066 
00067 /* flags in argument to evaltree */
00068 #define EV_EXIT 01              /* exit after evaluating tree */
00069 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
00070 #define EV_BACKCMD 04           /* command executing within back quotes */
00071 
00072 
00073 /* reasons for skipping commands (see comment on breakcmd routine) */
00074 #define SKIPBREAK 1
00075 #define SKIPCONT 2
00076 #define SKIPFUNC 3
00077 
00078 MKINIT int evalskip;            /* set if we are skipping commands */
00079 STATIC int skipcount;           /* number of levels to skip */
00080 MKINIT int loopnest;            /* current loop nesting level */
00081 int funcnest;                   /* depth of function calls */
00082 
00083 
00084 char *commandname;
00085 struct strlist *cmdenviron;
00086 int exitstatus;                 /* exit status of last command */
00087 int oexitstatus;                /* saved exit status */
00088 
00089 
00090 #ifdef __STDC__
00091 STATIC void evalloop(union node *);
00092 STATIC void evalfor(union node *);
00093 STATIC void evalcase(union node *, int);
00094 STATIC void evalsubshell(union node *, int);
00095 STATIC void expredir(union node *);
00096 STATIC void evalpipe(union node *);
00097 STATIC void evalcommand(union node *, int, struct backcmd *);
00098 STATIC void prehash(union node *);
00099 #else
00100 STATIC void evalloop();
00101 STATIC void evalfor();
00102 STATIC void evalcase();
00103 STATIC void evalsubshell();
00104 STATIC void expredir();
00105 STATIC void evalpipe();
00106 STATIC void evalcommand();
00107 STATIC void prehash();
00108 #endif
00109 
00110 
00111 
00112 /*
00113  * Called to reset things after an exception.
00114  */
00115 
00116 #ifdef mkinit
00117 INCLUDE "eval.h"
00118 
00119 RESET {
00120         evalskip = 0;
00121         loopnest = 0;
00122         funcnest = 0;
00123 }
00124 
00125 SHELLPROC {
00126         exitstatus = 0;
00127 }
00128 #endif
00129 
00130 
00131 
00132 /*
00133  * The eval commmand.
00134  */
00135 
00136 evalcmd(argc, argv)  
00137         char **argv; 
00138 {
00139         char *p;
00140         char *concat;
00141         char **ap;
00142 
00143         if (argc > 1) {
00144                 p = argv[1];
00145                 if (argc > 2) {
00146                         STARTSTACKSTR(concat);
00147                         ap = argv + 2;
00148                         for (;;) {
00149                                 while (*p)
00150                                         STPUTC(*p++, concat);
00151                                 if ((p = *ap++) == NULL)
00152                                         break;
00153                                 STPUTC(' ', concat);
00154                         }
00155                         STPUTC('\0', concat);
00156                         p = grabstackstr(concat);
00157                 }
00158                 evalstring(p);
00159         }
00160         return exitstatus;
00161 }
00162 
00163 
00164 /*
00165  * Execute a command or commands contained in a string.
00166  */
00167 
00168 void
00169 evalstring(s)
00170         char *s;
00171         {
00172         union node *n;
00173         struct stackmark smark;
00174 
00175         setstackmark(&smark);
00176         setinputstring(s, 1);
00177         while ((n = parsecmd(0)) != NEOF) {
00178                 evaltree(n, 0);
00179                 popstackmark(&smark);
00180         }
00181         popfile();
00182         popstackmark(&smark);
00183 }
00184 
00185 
00186 
00187 /*
00188  * Evaluate a parse tree.  The value is left in the global variable
00189  * exitstatus.
00190  */
00191 
00192 void
00193 evaltree(n, flags)
00194         union node *n;
00195         {
00196         if (n == NULL) {
00197                 TRACE(("evaltree(NULL) called\n"));
00198                 return;
00199         }
00200         TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type));
00201         switch (n->type) {
00202         case NSEMI:
00203                 evaltree(n->nbinary.ch1, 0);
00204                 if (evalskip)
00205                         goto out;
00206                 evaltree(n->nbinary.ch2, flags);
00207                 break;
00208         case NAND:
00209                 evaltree(n->nbinary.ch1, EV_TESTED);
00210                 if (evalskip || exitstatus != 0)
00211                         goto out;
00212                 evaltree(n->nbinary.ch2, flags);
00213                 break;
00214         case NOR:
00215                 evaltree(n->nbinary.ch1, EV_TESTED);
00216                 if (evalskip || exitstatus == 0)
00217                         goto out;
00218                 evaltree(n->nbinary.ch2, flags);
00219                 break;
00220         case NREDIR:
00221                 expredir(n->nredir.redirect);
00222                 redirect(n->nredir.redirect, REDIR_PUSH);
00223                 evaltree(n->nredir.n, flags);
00224                 popredir();
00225                 break;
00226         case NSUBSHELL:
00227                 evalsubshell(n, flags);
00228                 break;
00229         case NBACKGND:
00230                 evalsubshell(n, flags);
00231                 break;
00232         case NIF: {
00233                 int status = 0; 
00234 
00235                 evaltree(n->nif.test, EV_TESTED);
00236                 if (evalskip)
00237                         goto out;
00238                 if (exitstatus == 0) {
00239                         evaltree(n->nif.ifpart, flags);
00240                         status = exitstatus;
00241                 } else if (n->nif.elsepart) {
00242                         evaltree(n->nif.elsepart, flags);
00243                         status = exitstatus;
00244                 }
00245                 exitstatus = status;
00246                 break;
00247         }
00248         case NWHILE:
00249         case NUNTIL:
00250                 evalloop(n);
00251                 break;
00252         case NFOR:
00253                 evalfor(n);
00254                 break;
00255         case NCASE:
00256                 evalcase(n, flags);
00257                 break;
00258         case NDEFUN:
00259                 defun(n->narg.text, n->narg.next);
00260                 exitstatus = 0;
00261                 break;
00262         case NPIPE:
00263                 evalpipe(n);
00264                 break;
00265         case NCMD:
00266                 evalcommand(n, flags, (struct backcmd *)NULL);
00267                 break;
00268         default:
00269                 out1fmt("Node type = %d\n", n->type);
00270                 flushout(&output);
00271                 break;
00272         }
00273 out:
00274         if (pendingsigs)
00275                 dotrap();
00276         if ((flags & EV_EXIT) || (eflag && exitstatus
00277           && !(flags & EV_TESTED) && (n->type == NCMD ||
00278           n->type == NSUBSHELL))) {
00279                 exitshell(exitstatus);
00280         }
00281 }
00282 
00283 
00284 STATIC void
00285 evalloop(n)
00286         union node *n;
00287         {
00288         int status;
00289 
00290         loopnest++;
00291         status = 0;
00292         for (;;) {
00293                 evaltree(n->nbinary.ch1, EV_TESTED);
00294                 if (evalskip) {
00295 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
00296                                 evalskip = 0;
00297                                 continue;
00298                         }
00299                         if (evalskip == SKIPBREAK && --skipcount <= 0)
00300                                 evalskip = 0;
00301                         break;
00302                 }
00303                 if (n->type == NWHILE) {
00304                         if (exitstatus != 0)
00305                                 break;
00306                 } else {
00307                         if (exitstatus == 0)
00308                                 break;
00309                 }
00310                 evaltree(n->nbinary.ch2, 0);
00311                 status = exitstatus;
00312                 if (evalskip)
00313                         goto skipping;
00314         }
00315         loopnest--;
00316         exitstatus = status;
00317 }
00318 
00319 
00320 
00321 STATIC void
00322 evalfor(n)
00323         union node *n;
00324         {
00325         struct arglist arglist;
00326         union node *argp;
00327         struct strlist *sp;
00328         struct stackmark smark;
00329 
00330         setstackmark(&smark);
00331         arglist.lastp = &arglist.list;
00332         for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
00333                 oexitstatus = exitstatus;
00334                 expandarg(argp, &arglist, 1);
00335                 if (evalskip)
00336                         goto out;
00337         }
00338         *arglist.lastp = NULL;
00339 
00340         exitstatus = 0;
00341         loopnest++;
00342         for (sp = arglist.list ; sp ; sp = sp->next) {
00343                 setvar(n->nfor.var, sp->text, 0);
00344                 evaltree(n->nfor.body, 0);
00345                 if (evalskip) {
00346                         if (evalskip == SKIPCONT && --skipcount <= 0) {
00347                                 evalskip = 0;
00348                                 continue;
00349                         }
00350                         if (evalskip == SKIPBREAK && --skipcount <= 0)
00351                                 evalskip = 0;
00352                         break;
00353                 }
00354         }
00355         loopnest--;
00356 out:
00357         popstackmark(&smark);
00358 }
00359 
00360 
00361 
00362 STATIC void
00363 evalcase(n, flags)
00364         union node *n;
00365         {
00366         union node *cp;
00367         union node *patp;
00368         struct arglist arglist;
00369         struct stackmark smark;
00370 
00371         setstackmark(&smark);
00372         arglist.lastp = &arglist.list;
00373         oexitstatus = exitstatus;
00374         expandarg(n->ncase.expr, &arglist, 0);
00375         for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
00376                 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
00377                         if (casematch(patp, arglist.list->text)) {
00378                                 if (evalskip == 0) {
00379                                         evaltree(cp->nclist.body, flags);
00380                                 }
00381                                 goto out;
00382                         }
00383                 }
00384         }
00385 out:
00386         popstackmark(&smark);
00387 }
00388 
00389 
00390 
00391 /*
00392  * Kick off a subshell to evaluate a tree.
00393  */
00394 
00395 STATIC void
00396 evalsubshell(n, flags)
00397         union node *n;
00398         {
00399         struct job *jp;
00400         int backgnd = (n->type == NBACKGND);
00401 
00402         expredir(n->nredir.redirect);
00403         jp = makejob(n, 1);
00404         if (forkshell(jp, n, backgnd) == 0) {
00405                 if (backgnd)
00406                         flags &=~ EV_TESTED;
00407                 redirect(n->nredir.redirect, 0);
00408                 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
00409         }
00410         if (! backgnd) {
00411                 INTOFF;
00412                 exitstatus = waitforjob(jp);
00413                 INTON;
00414         }
00415 }
00416 
00417 
00418 
00419 /*
00420  * Compute the names of the files in a redirection list.
00421  */
00422 
00423 STATIC void
00424 expredir(n)
00425         union node *n;
00426         {
00427         register union node *redir;
00428 
00429         for (redir = n ; redir ; redir = redir->nfile.next) {
00430                 oexitstatus = exitstatus;
00431                 if (redir->type == NFROM
00432                  || redir->type == NTO
00433                  || redir->type == NAPPEND) {
00434                         struct arglist fn;
00435                         fn.lastp = &fn.list;
00436                         expandarg(redir->nfile.fname, &fn, 0);
00437                         redir->nfile.expfname = fn.list->text;
00438                 }
00439         }
00440 }
00441 
00442 
00443 
00444 /*
00445  * Evaluate a pipeline.  All the processes in the pipeline are children
00446  * of the process creating the pipeline.  (This differs from some versions
00447  * of the shell, which make the last process in a pipeline the parent
00448  * of all the rest.)
00449  */
00450 
00451 STATIC void
00452 evalpipe(n)
00453         union node *n;
00454         {
00455         struct job *jp;
00456         struct nodelist *lp;
00457         int pipelen;
00458         int prevfd;
00459         int pip[2];
00460 
00461         TRACE(("evalpipe(0x%x) called\n", (int)n));
00462         pipelen = 0;
00463         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
00464                 pipelen++;
00465         INTOFF;
00466         jp = makejob(n, pipelen);
00467         prevfd = -1;
00468         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
00469                 prehash(lp->n);
00470                 pip[1] = -1;
00471                 if (lp->next) {
00472                         if (pipe(pip) < 0) {
00473                                 close(prevfd);
00474                                 error("Pipe call failed");
00475                         }
00476                 }
00477                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
00478                         INTON;
00479                         if (prevfd > 0) {
00480                                 close(0);
00481                                 copyfd(prevfd, 0);
00482                                 close(prevfd);
00483                         }
00484                         if (pip[1] >= 0) {
00485                                 close(pip[0]);
00486                                 if (pip[1] != 1) {
00487                                         close(1);
00488                                         copyfd(pip[1], 1);
00489                                         close(pip[1]);
00490                                 }
00491                         }
00492                         evaltree(lp->n, EV_EXIT);
00493                 }
00494                 if (prevfd >= 0)
00495                         close(prevfd);
00496                 prevfd = pip[0];
00497                 close(pip[1]);
00498         }
00499         INTON;
00500         if (n->npipe.backgnd == 0) {
00501                 INTOFF;
00502                 exitstatus = waitforjob(jp);
00503                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
00504                 INTON;
00505         }
00506 }
00507 
00508 
00509 
00510 /*
00511  * Execute a command inside back quotes.  If it's a builtin command, we
00512  * want to save its output in a block obtained from malloc.  Otherwise
00513  * we fork off a subprocess and get the output of the command via a pipe.
00514  * Should be called with interrupts off.
00515  */
00516 
00517 void
00518 evalbackcmd(n, result)
00519         union node *n;
00520         struct backcmd *result;
00521         {
00522         int pip[2];
00523         struct job *jp;
00524         struct stackmark smark;         /* unnecessary */
00525 
00526         setstackmark(&smark);
00527         result->fd = -1;
00528         result->buf = NULL;
00529         result->nleft = 0;
00530         result->jp = NULL;
00531         if (n == NULL) {
00532                 /* `` */
00533         } else
00534         if (n->type == NCMD) {
00535                 exitstatus = oexitstatus;
00536                 evalcommand(n, EV_BACKCMD, result);
00537         } else {
00538                 if (pipe(pip) < 0)
00539                         error("Pipe call failed");
00540                 jp = makejob(n, 1);
00541                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
00542                         FORCEINTON;
00543                         close(pip[0]);
00544                         if (pip[1] != 1) {
00545                                 close(1);
00546                                 copyfd(pip[1], 1);
00547                                 close(pip[1]);
00548                         }
00549                         evaltree(n, EV_EXIT);
00550                 }
00551                 close(pip[1]);
00552                 result->fd = pip[0];
00553                 result->jp = jp;
00554         }
00555         popstackmark(&smark);
00556         TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
00557                 result->fd, result->buf, result->nleft, result->jp));
00558 }
00559 
00560 
00561 
00562 /*
00563  * Execute a simple command.
00564  */
00565 
00566 STATIC void
00567 evalcommand(cmd, flags, backcmd)
00568         union node *cmd;
00569         struct backcmd *backcmd;
00570         {
00571         struct stackmark smark;
00572         union node *argp;
00573         struct arglist arglist;
00574         struct arglist varlist;
00575         char **argv;
00576         int argc;
00577         char **envp;
00578         int varflag;
00579         struct strlist *sp;
00580         register char *p;
00581         int mode;
00582         int pip[2];
00583         struct cmdentry cmdentry;
00584         struct job *jp;
00585         struct jmploc jmploc;
00586         struct jmploc *volatile savehandler;
00587         char *volatile savecmdname;
00588         volatile struct shparam saveparam;
00589         struct localvar *volatile savelocalvars;
00590         volatile int e;
00591         char *lastarg;
00592 
00593         /* First expand the arguments. */
00594         TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags));
00595         setstackmark(&smark);
00596         arglist.lastp = &arglist.list;
00597         varlist.lastp = &varlist.list;
00598         varflag = 1;
00599         oexitstatus = exitstatus;
00600         exitstatus = 0;
00601         for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
00602                 p = argp->narg.text;
00603                 if (varflag && is_name(*p)) {
00604                         do {
00605                                 p++;
00606                         } while (is_in_name(*p));
00607                         if (*p == '=') {
00608                                 expandarg(argp, &varlist, 0);
00609                                 continue;
00610                         }
00611                 }
00612                 expandarg(argp, &arglist, 1);
00613                 varflag = 0;
00614         }
00615         *arglist.lastp = NULL;
00616         *varlist.lastp = NULL;
00617         expredir(cmd->ncmd.redirect);
00618         argc = 0;
00619         for (sp = arglist.list ; sp ; sp = sp->next)
00620                 argc++;
00621         argv = stalloc(sizeof (char *) * (argc + 1));
00622         for (sp = arglist.list ; sp ; sp = sp->next)
00623                 *argv++ = sp->text;
00624         *argv = NULL;
00625         lastarg = NULL;
00626         if (iflag && funcnest == 0 && argc > 0)
00627                 lastarg = argv[-1];
00628         argv -= argc;
00629 
00630         /* Print the command if xflag is set. */
00631         if (xflag == 1) {
00632                 outc('+', &errout);
00633                 for (sp = varlist.list ; sp ; sp = sp->next) {
00634                         outc(' ', &errout);
00635                         out2str(sp->text);
00636                 }
00637                 for (sp = arglist.list ; sp ; sp = sp->next) {
00638                         outc(' ', &errout);
00639                         out2str(sp->text);
00640                 }
00641                 outc('\n', &errout);
00642                 flushout(&errout);
00643         }
00644 
00645         /* Now locate the command. */
00646         if (argc == 0) {
00647                 cmdentry.cmdtype = CMDBUILTIN;
00648                 cmdentry.u.index = BLTINCMD;
00649         } else {
00650                 find_command(argv[0], &cmdentry, 1);
00651                 if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
00652                         exitstatus = 2;
00653                         flushout(&errout);
00654                         popstackmark(&smark);
00655                         return;
00656                 }
00657                 /* implement the bltin builtin here */
00658                 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
00659                         for (;;) {
00660                                 argv++;
00661                                 if (--argc == 0)
00662                                         break;
00663                                 if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
00664                                         outfmt(&errout, "%s: not found\n", *argv);
00665                                         exitstatus = 2;
00666                                         flushout(&errout);
00667                                         popstackmark(&smark);
00668                                         return;
00669                                 }
00670                                 if (cmdentry.u.index != BLTINCMD)
00671                                         break;
00672                         }
00673                 }
00674         }
00675 
00676         /* Fork off a child process if necessary. */
00677         if (cmd->ncmd.backgnd
00678          || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0
00679          || (flags & EV_BACKCMD) != 0
00680             && (cmdentry.cmdtype != CMDBUILTIN
00681                  || cmdentry.u.index == DOTCMD
00682                  || cmdentry.u.index == EVALCMD)) {
00683                 jp = makejob(cmd, 1);
00684                 mode = cmd->ncmd.backgnd;
00685                 if (flags & EV_BACKCMD) {
00686                         mode = FORK_NOJOB;
00687                         if (pipe(pip) < 0)
00688                                 error("Pipe call failed");
00689                 }
00690                 if (forkshell(jp, cmd, mode) != 0)
00691                         goto parent;    /* at end of routine */
00692                 if (flags & EV_BACKCMD) {
00693                         FORCEINTON;
00694                         close(pip[0]);
00695                         if (pip[1] != 1) {
00696                                 close(1);
00697                                 copyfd(pip[1], 1);
00698                                 close(pip[1]);
00699                         }
00700                 }
00701                 flags |= EV_EXIT;
00702         }
00703 
00704         /* This is the child process if a fork occurred. */
00705         /* Execute the command. */
00706         if (cmdentry.cmdtype == CMDFUNCTION) {
00707                 trputs("Shell function:  ");  trargs(argv);
00708                 redirect(cmd->ncmd.redirect, REDIR_PUSH);
00709                 saveparam = shellparam;
00710                 shellparam.malloc = 0;
00711                 shellparam.nparam = argc - 1;
00712                 shellparam.p = argv + 1;
00713                 shellparam.optnext = NULL;
00714                 INTOFF;
00715                 savelocalvars = localvars;
00716                 localvars = NULL;
00717                 INTON;
00718                 if (setjmp(jmploc.loc)) {
00719                         if (exception == EXSHELLPROC)
00720                                 freeparam((struct shparam *)&saveparam);
00721                         else {
00722                                 freeparam(&shellparam);
00723                                 shellparam = saveparam;
00724                         }
00725                         poplocalvars();
00726                         localvars = savelocalvars;
00727                         handler = savehandler;
00728                         longjmp(handler->loc, 1);
00729                 }
00730                 savehandler = handler;
00731                 handler = &jmploc;
00732                 for (sp = varlist.list ; sp ; sp = sp->next)
00733                         mklocal(sp->text);
00734                 funcnest++;
00735                 if (flags & EV_TESTED)
00736                         evaltree(cmdentry.u.func, EV_TESTED);
00737                 else
00738                         evaltree(cmdentry.u.func, 0);
00739                 funcnest--;
00740                 INTOFF;
00741                 poplocalvars();
00742                 localvars = savelocalvars;
00743                 freeparam(&shellparam);
00744                 shellparam = saveparam;
00745                 handler = savehandler;
00746                 popredir();
00747                 INTON;
00748                 if (evalskip == SKIPFUNC) {
00749                         evalskip = 0;
00750                         skipcount = 0;
00751                 }
00752                 if (flags & EV_EXIT)
00753                         exitshell(exitstatus);
00754         } else if (cmdentry.cmdtype == CMDBUILTIN) {
00755                 trputs("builtin command:  ");  trargs(argv);
00756                 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
00757                 if (flags == EV_BACKCMD) {
00758                         memout.nleft = 0;
00759                         memout.nextc = memout.buf;
00760                         memout.bufsize = 64;
00761                         mode |= REDIR_BACKQ;
00762                 }
00763                 redirect(cmd->ncmd.redirect, mode);
00764                 savecmdname = commandname;
00765                 cmdenviron = varlist.list;
00766                 e = -1;
00767                 if (setjmp(jmploc.loc)) {
00768                         e = exception;
00769                         exitstatus = (e == EXINT)? SIGINT+128 : 2;
00770                         goto cmddone;
00771                 }
00772                 savehandler = handler;
00773                 handler = &jmploc;
00774                 commandname = argv[0];
00775                 argptr = argv + 1;
00776                 optptr = NULL;                  /* initialize nextopt */
00777                 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
00778                 flushall();
00779 cmddone:
00780                 out1 = &output;
00781                 out2 = &errout;
00782                 freestdout();
00783                 if (e != EXSHELLPROC) {
00784                         commandname = savecmdname;
00785                         if (flags & EV_EXIT) {
00786                                 exitshell(exitstatus);
00787                         }
00788                 }
00789                 handler = savehandler;
00790                 if (e != -1) {
00791                         if (e != EXERROR || cmdentry.u.index == BLTINCMD
00792                                                || cmdentry.u.index == DOTCMD
00793                                                || cmdentry.u.index == EVALCMD
00794                                                || cmdentry.u.index == EXECCMD)
00795                                 exraise(e);
00796                         FORCEINTON;
00797                 }
00798                 if (cmdentry.u.index != EXECCMD)
00799                         popredir();
00800                 if (flags == EV_BACKCMD) {
00801                         backcmd->buf = memout.buf;
00802                         backcmd->nleft = memout.nextc - memout.buf;
00803                         memout.buf = NULL;
00804                 }
00805         } else {
00806                 trputs("normal command:  ");  trargs(argv);
00807                 clearredir();
00808                 redirect(cmd->ncmd.redirect, 0);
00809                 if (varlist.list) {
00810                         p = stalloc(strlen(pathval()) + 1);
00811                         scopy(pathval(), p);
00812                 } else {
00813                         p = pathval();
00814                 }
00815                 for (sp = varlist.list ; sp ; sp = sp->next)
00816                         setvareq(sp->text, VEXPORT|VSTACK);
00817                 envp = environment();
00818                 shellexec(argv, envp, p, cmdentry.u.index);
00819                 /*NOTREACHED*/
00820         }
00821         goto out;
00822 
00823 parent: /* parent process gets here (if we forked) */
00824         if (mode == 0) {        /* argument to fork */
00825                 INTOFF;
00826                 exitstatus = waitforjob(jp);
00827                 INTON;
00828         } else if (mode == 2) {
00829                 backcmd->fd = pip[0];
00830                 close(pip[1]);
00831                 backcmd->jp = jp;
00832         }
00833 
00834 out:
00835         if (lastarg)
00836                 setvar("_", lastarg, 0);
00837         popstackmark(&smark);
00838 }
00839 
00840 
00841 
00842 /*
00843  * Search for a command.  This is called before we fork so that the
00844  * location of the command will be available in the parent as well as
00845  * the child.  The check for "goodname" is an overly conservative
00846  * check that the name will not be subject to expansion.
00847  */
00848 
00849 STATIC void
00850 prehash(n)
00851         union node *n;
00852         {
00853         struct cmdentry entry;
00854 
00855         if (n->type == NCMD && goodname(n->ncmd.args->narg.text))
00856                 find_command(n->ncmd.args->narg.text, &entry, 0);
00857 }
00858 
00859 
00860 
00861 /*
00862  * Builtin commands.  Builtin commands whose functions are closely
00863  * tied to evaluation are implemented here.
00864  */
00865 
00866 /*
00867  * No command given, or a bltin command with no arguments.  Set the
00868  * specified variables.
00869  */
00870 
00871 bltincmd(argc, argv)  char **argv; {
00872         listsetvar(cmdenviron);
00873         return exitstatus;
00874 }
00875 
00876 
00877 /*
00878  * Handle break and continue commands.  Break, continue, and return are
00879  * all handled by setting the evalskip flag.  The evaluation routines
00880  * above all check this flag, and if it is set they start skipping
00881  * commands rather than executing them.  The variable skipcount is
00882  * the number of loops to break/continue, or the number of function
00883  * levels to return.  (The latter is always 1.)  It should probably
00884  * be an error to break out of more loops than exist, but it isn't
00885  * in the standard shell so we don't make it one here.
00886  */
00887 
00888 breakcmd(argc, argv)  char **argv; {
00889         int n;
00890 
00891         n = 1;
00892         if (argc > 1)
00893                 n = number(argv[1]);
00894         if (n > loopnest)
00895                 n = loopnest;
00896         if (n > 0) {
00897                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
00898                 skipcount = n;
00899         }
00900         return 0;
00901 }
00902 
00903 
00904 /*
00905  * The return command.
00906  */
00907 
00908 returncmd(argc, argv)  char **argv; {
00909         int ret;
00910 
00911         ret = oexitstatus;
00912         if (argc > 1)
00913                 ret = number(argv[1]);
00914         if (funcnest) {
00915                 evalskip = SKIPFUNC;
00916                 skipcount = 1;
00917         }
00918         return ret;
00919 }
00920 
00921 
00922 truecmd(argc, argv)  char **argv; {
00923         return strcmp(argv[0], "false") == 0 ? 1 : 0;
00924 }
00925 
00926 
00927 execcmd(argc, argv)  char **argv; {
00928         if (argc > 1) {
00929                 iflag = 0;              /* exit on error */
00930                 setinteractive(0);
00931 #if JOBS
00932                 jflag = 0;
00933                 setjobctl(0);
00934 #endif
00935                 shellexec(argv + 1, environment(), pathval(), 0);
00936 
00937         }
00938         return 0;
00939 }

Generated on Fri Apr 14 22:56:40 2006 for minix by  doxygen 1.4.6