00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef lint
00038 static char sccsid[] = "@(#)eval.c 5.3 (Berkeley) 4/12/91";
00039 #endif
00040
00041
00042
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
00068 #define EV_EXIT 01
00069 #define EV_TESTED 02
00070 #define EV_BACKCMD 04
00071
00072
00073
00074 #define SKIPBREAK 1
00075 #define SKIPCONT 2
00076 #define SKIPFUNC 3
00077
00078 MKINIT int evalskip;
00079 STATIC int skipcount;
00080 MKINIT int loopnest;
00081 int funcnest;
00082
00083
00084 char *commandname;
00085 struct strlist *cmdenviron;
00086 int exitstatus;
00087 int oexitstatus;
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
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
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
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
00189
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
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);
00409 }
00410 if (! backgnd) {
00411 INTOFF;
00412 exitstatus = waitforjob(jp);
00413 INTON;
00414 }
00415 }
00416
00417
00418
00419
00420
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
00446
00447
00448
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
00512
00513
00514
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;
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
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
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
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
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) {
00652 exitstatus = 2;
00653 flushout(&errout);
00654 popstackmark(&smark);
00655 return;
00656 }
00657
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
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;
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
00705
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;
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
00820 }
00821 goto out;
00822
00823 parent:
00824 if (mode == 0) {
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
00844
00845
00846
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
00863
00864
00865
00866
00867
00868
00869
00870
00871 bltincmd(argc, argv) char **argv; {
00872 listsetvar(cmdenviron);
00873 return exitstatus;
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
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
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;
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 }