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