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.4 (Berkeley) 05/04/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 = 0; 207 208 evaltree(n->nif.test, EV_TESTED); 209 if (evalskip) 210 goto out; 211 if (exitstatus == 0) { 212 evaltree(n->nif.ifpart, flags); 213 status = exitstatus; 214 } else if (n->nif.elsepart) { 215 evaltree(n->nif.elsepart, flags); 216 status = exitstatus; 217 } 218 exitstatus = status; 219 break; 220 } 221 case NWHILE: 222 case NUNTIL: 223 evalloop(n); 224 break; 225 case NFOR: 226 evalfor(n); 227 break; 228 case NCASE: 229 evalcase(n, flags); 230 break; 231 case NDEFUN: 232 defun(n->narg.text, n->narg.next); 233 exitstatus = 0; 234 break; 235 case NNOT: 236 evaltree(n->nnot.com, EV_TESTED); 237 exitstatus = !exitstatus; 238 break; 239 240 case NPIPE: 241 evalpipe(n); 242 break; 243 case NCMD: 244 evalcommand(n, flags, (struct backcmd *)NULL); 245 break; 246 default: 247 out1fmt("Node type = %d\n", n->type); 248 flushout(&output); 249 break; 250 } 251 out: 252 if (pendingsigs) 253 dotrap(); 254 if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) 255 exitshell(exitstatus); 256 } 257 258 259 STATIC void 260 evalloop(n) 261 union node *n; 262 { 263 int status; 264 265 loopnest++; 266 status = 0; 267 for (;;) { 268 evaltree(n->nbinary.ch1, EV_TESTED); 269 if (evalskip) { 270 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 271 evalskip = 0; 272 continue; 273 } 274 if (evalskip == SKIPBREAK && --skipcount <= 0) 275 evalskip = 0; 276 break; 277 } 278 if (n->type == NWHILE) { 279 if (exitstatus != 0) 280 break; 281 } else { 282 if (exitstatus == 0) 283 break; 284 } 285 evaltree(n->nbinary.ch2, 0); 286 status = exitstatus; 287 if (evalskip) 288 goto skipping; 289 } 290 loopnest--; 291 exitstatus = status; 292 } 293 294 295 296 STATIC void 297 evalfor(n) 298 union node *n; 299 { 300 struct arglist arglist; 301 union node *argp; 302 struct strlist *sp; 303 struct stackmark smark; 304 305 setstackmark(&smark); 306 arglist.lastp = &arglist.list; 307 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 308 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 309 if (evalskip) 310 goto out; 311 } 312 *arglist.lastp = NULL; 313 314 exitstatus = 0; 315 loopnest++; 316 for (sp = arglist.list ; sp ; sp = sp->next) { 317 setvar(n->nfor.var, sp->text, 0); 318 evaltree(n->nfor.body, 0); 319 if (evalskip) { 320 if (evalskip == SKIPCONT && --skipcount <= 0) { 321 evalskip = 0; 322 continue; 323 } 324 if (evalskip == SKIPBREAK && --skipcount <= 0) 325 evalskip = 0; 326 break; 327 } 328 } 329 loopnest--; 330 out: 331 popstackmark(&smark); 332 } 333 334 335 336 STATIC void 337 evalcase(n, flags) 338 union node *n; 339 int flags; 340 { 341 union node *cp; 342 union node *patp; 343 struct arglist arglist; 344 struct stackmark smark; 345 346 setstackmark(&smark); 347 arglist.lastp = &arglist.list; 348 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 349 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 350 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 351 if (casematch(patp, arglist.list->text)) { 352 if (evalskip == 0) { 353 evaltree(cp->nclist.body, flags); 354 } 355 goto out; 356 } 357 } 358 } 359 out: 360 popstackmark(&smark); 361 } 362 363 364 365 /* 366 * Kick off a subshell to evaluate a tree. 367 */ 368 369 STATIC void 370 evalsubshell(n, flags) 371 union node *n; 372 int flags; 373 { 374 struct job *jp; 375 int backgnd = (n->type == NBACKGND); 376 377 expredir(n->nredir.redirect); 378 jp = makejob(n, 1); 379 if (forkshell(jp, n, backgnd) == 0) { 380 if (backgnd) 381 flags &=~ EV_TESTED; 382 redirect(n->nredir.redirect, 0); 383 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ 384 } 385 if (! backgnd) { 386 INTOFF; 387 exitstatus = waitforjob(jp); 388 INTON; 389 } 390 } 391 392 393 394 /* 395 * Compute the names of the files in a redirection list. 396 */ 397 398 STATIC void 399 expredir(n) 400 union node *n; 401 { 402 register union node *redir; 403 404 for (redir = n ; redir ; redir = redir->nfile.next) { 405 struct arglist fn; 406 fn.lastp = &fn.list; 407 switch (redir->type) { 408 case NFROM: 409 case NTO: 410 case NAPPEND: 411 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 412 redir->nfile.expfname = fn.list->text; 413 break; 414 case NFROMFD: 415 case NTOFD: 416 if (redir->ndup.vname) { 417 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 418 fixredir(redir, fn.list->text, 1); 419 } 420 break; 421 } 422 } 423 } 424 425 426 427 /* 428 * Evaluate a pipeline. All the processes in the pipeline are children 429 * of the process creating the pipeline. (This differs from some versions 430 * of the shell, which make the last process in a pipeline the parent 431 * of all the rest.) 432 */ 433 434 STATIC void 435 evalpipe(n) 436 union node *n; 437 { 438 struct job *jp; 439 struct nodelist *lp; 440 int pipelen; 441 int prevfd; 442 int pip[2]; 443 444 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 445 pipelen = 0; 446 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 447 pipelen++; 448 INTOFF; 449 jp = makejob(n, pipelen); 450 prevfd = -1; 451 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 452 prehash(lp->n); 453 pip[1] = -1; 454 if (lp->next) { 455 if (pipe(pip) < 0) { 456 close(prevfd); 457 error("Pipe call failed"); 458 } 459 } 460 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 461 INTON; 462 if (prevfd > 0) { 463 close(0); 464 copyfd(prevfd, 0); 465 close(prevfd); 466 } 467 if (pip[1] >= 0) { 468 close(pip[0]); 469 if (pip[1] != 1) { 470 close(1); 471 copyfd(pip[1], 1); 472 close(pip[1]); 473 } 474 } 475 evaltree(lp->n, EV_EXIT); 476 } 477 if (prevfd >= 0) 478 close(prevfd); 479 prevfd = pip[0]; 480 close(pip[1]); 481 } 482 INTON; 483 if (n->npipe.backgnd == 0) { 484 INTOFF; 485 exitstatus = waitforjob(jp); 486 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 487 INTON; 488 } 489 } 490 491 492 493 /* 494 * Execute a command inside back quotes. If it's a builtin command, we 495 * want to save its output in a block obtained from malloc. Otherwise 496 * we fork off a subprocess and get the output of the command via a pipe. 497 * Should be called with interrupts off. 498 */ 499 500 void 501 evalbackcmd(n, result) 502 union node *n; 503 struct backcmd *result; 504 { 505 int pip[2]; 506 struct job *jp; 507 struct stackmark smark; /* unnecessary */ 508 509 setstackmark(&smark); 510 result->fd = -1; 511 result->buf = NULL; 512 result->nleft = 0; 513 result->jp = NULL; 514 exitstatus = 0; 515 if (n == NULL) 516 goto out; 517 if (n->type == NCMD) { 518 evalcommand(n, EV_BACKCMD, result); 519 } else { 520 if (pipe(pip) < 0) 521 error("Pipe call failed"); 522 jp = makejob(n, 1); 523 if (forkshell(jp, n, FORK_NOJOB) == 0) { 524 FORCEINTON; 525 close(pip[0]); 526 if (pip[1] != 1) { 527 close(1); 528 copyfd(pip[1], 1); 529 close(pip[1]); 530 } 531 evaltree(n, EV_EXIT); 532 } 533 close(pip[1]); 534 result->fd = pip[0]; 535 result->jp = jp; 536 } 537 out: 538 popstackmark(&smark); 539 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 540 result->fd, result->buf, result->nleft, result->jp)); 541 } 542 543 544 545 /* 546 * Execute a simple command. 547 */ 548 549 STATIC void 550 evalcommand(cmd, flags, backcmd) 551 union node *cmd; 552 int flags; 553 struct backcmd *backcmd; 554 { 555 struct stackmark smark; 556 union node *argp; 557 struct arglist arglist; 558 struct arglist varlist; 559 char **argv; 560 int argc; 561 char **envp; 562 int varflag; 563 struct strlist *sp; 564 int mode; 565 int pip[2]; 566 struct cmdentry cmdentry; 567 struct job *jp; 568 struct jmploc jmploc; 569 struct jmploc *volatile savehandler; 570 char *volatile savecmdname; 571 volatile struct shparam saveparam; 572 struct localvar *volatile savelocalvars; 573 volatile int e; 574 char *lastarg; 575 #if __GNUC__ 576 /* Avoid longjmp clobbering */ 577 (void) &argv; 578 (void) &argc; 579 (void) &lastarg; 580 (void) &flags; 581 #endif 582 583 /* First expand the arguments. */ 584 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 585 setstackmark(&smark); 586 arglist.lastp = &arglist.list; 587 varlist.lastp = &varlist.list; 588 varflag = 1; 589 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { 590 char *p = argp->narg.text; 591 if (varflag && is_name(*p)) { 592 do { 593 p++; 594 } while (is_in_name(*p)); 595 if (*p == '=') { 596 expandarg(argp, &varlist, EXP_VARTILDE); 597 continue; 598 } 599 } 600 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 601 varflag = 0; 602 } 603 *arglist.lastp = NULL; 604 *varlist.lastp = NULL; 605 expredir(cmd->ncmd.redirect); 606 argc = 0; 607 for (sp = arglist.list ; sp ; sp = sp->next) 608 argc++; 609 argv = stalloc(sizeof (char *) * (argc + 1)); 610 611 for (sp = arglist.list ; sp ; sp = sp->next) { 612 TRACE(("evalcommand arg: %s\n", sp->text)); 613 *argv++ = sp->text; 614 } 615 *argv = NULL; 616 lastarg = NULL; 617 if (iflag && funcnest == 0 && argc > 0) 618 lastarg = argv[-1]; 619 argv -= argc; 620 621 /* Print the command if xflag is set. */ 622 if (xflag) { 623 outc('+', &errout); 624 for (sp = varlist.list ; sp ; sp = sp->next) { 625 outc(' ', &errout); 626 out2str(sp->text); 627 } 628 for (sp = arglist.list ; sp ; sp = sp->next) { 629 outc(' ', &errout); 630 out2str(sp->text); 631 } 632 outc('\n', &errout); 633 flushout(&errout); 634 } 635 636 /* Now locate the command. */ 637 if (argc == 0) { 638 cmdentry.cmdtype = CMDBUILTIN; 639 cmdentry.u.index = BLTINCMD; 640 } else { 641 find_command(argv[0], &cmdentry, 1); 642 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ 643 exitstatus = 2; 644 flushout(&errout); 645 return; 646 } 647 /* implement the bltin builtin here */ 648 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { 649 for (;;) { 650 argv++; 651 if (--argc == 0) 652 break; 653 if ((cmdentry.u.index = find_builtin(*argv)) < 0) { 654 outfmt(&errout, "%s: not found\n", *argv); 655 exitstatus = 2; 656 flushout(&errout); 657 return; 658 } 659 if (cmdentry.u.index != BLTINCMD) 660 break; 661 } 662 } 663 } 664 665 /* Fork off a child process if necessary. */ 666 if (cmd->ncmd.backgnd 667 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) 668 || ((flags & EV_BACKCMD) != 0 669 && (cmdentry.cmdtype != CMDBUILTIN 670 || cmdentry.u.index == DOTCMD 671 || cmdentry.u.index == EVALCMD))) { 672 jp = makejob(cmd, 1); 673 mode = cmd->ncmd.backgnd; 674 if (flags & EV_BACKCMD) { 675 mode = FORK_NOJOB; 676 if (pipe(pip) < 0) 677 error("Pipe call failed"); 678 } 679 if (forkshell(jp, cmd, mode) != 0) 680 goto parent; /* at end of routine */ 681 if (flags & EV_BACKCMD) { 682 FORCEINTON; 683 close(pip[0]); 684 if (pip[1] != 1) { 685 close(1); 686 copyfd(pip[1], 1); 687 close(pip[1]); 688 } 689 } 690 flags |= EV_EXIT; 691 } 692 693 /* This is the child process if a fork occurred. */ 694 /* Execute the command. */ 695 if (cmdentry.cmdtype == CMDFUNCTION) { 696 trputs("Shell function: "); trargs(argv); 697 redirect(cmd->ncmd.redirect, REDIR_PUSH); 698 saveparam = shellparam; 699 shellparam.malloc = 0; 700 shellparam.nparam = argc - 1; 701 shellparam.p = argv + 1; 702 shellparam.optnext = NULL; 703 INTOFF; 704 savelocalvars = localvars; 705 localvars = NULL; 706 INTON; 707 if (setjmp(jmploc.loc)) { 708 if (exception == EXSHELLPROC) 709 freeparam((struct shparam *)&saveparam); 710 else { 711 freeparam(&shellparam); 712 shellparam = saveparam; 713 } 714 poplocalvars(); 715 localvars = savelocalvars; 716 handler = savehandler; 717 longjmp(handler->loc, 1); 718 } 719 savehandler = handler; 720 handler = &jmploc; 721 for (sp = varlist.list ; sp ; sp = sp->next) 722 mklocal(sp->text); 723 funcnest++; 724 evaltree(cmdentry.u.func, 0); 725 funcnest--; 726 INTOFF; 727 poplocalvars(); 728 localvars = savelocalvars; 729 freeparam(&shellparam); 730 shellparam = saveparam; 731 handler = savehandler; 732 popredir(); 733 INTON; 734 if (evalskip == SKIPFUNC) { 735 evalskip = 0; 736 skipcount = 0; 737 } 738 if (flags & EV_EXIT) 739 exitshell(exitstatus); 740 } else if (cmdentry.cmdtype == CMDBUILTIN) { 741 trputs("builtin command: "); trargs(argv); 742 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; 743 if (flags == EV_BACKCMD) { 744 memout.nleft = 0; 745 memout.nextc = memout.buf; 746 memout.bufsize = 64; 747 mode |= REDIR_BACKQ; 748 } 749 redirect(cmd->ncmd.redirect, mode); 750 savecmdname = commandname; 751 cmdenviron = varlist.list; 752 e = -1; 753 if (setjmp(jmploc.loc)) { 754 e = exception; 755 exitstatus = (e == EXINT)? SIGINT+128 : 2; 756 goto cmddone; 757 } 758 savehandler = handler; 759 handler = &jmploc; 760 commandname = argv[0]; 761 argptr = argv + 1; 762 optptr = NULL; /* initialize nextopt */ 763 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); 764 flushall(); 765 cmddone: 766 out1 = &output; 767 out2 = &errout; 768 freestdout(); 769 if (e != EXSHELLPROC) { 770 commandname = savecmdname; 771 if (flags & EV_EXIT) { 772 exitshell(exitstatus); 773 } 774 } 775 handler = savehandler; 776 if (e != -1) { 777 if (e != EXERROR || cmdentry.u.index == BLTINCMD 778 || cmdentry.u.index == DOTCMD 779 || cmdentry.u.index == EVALCMD 780 #ifndef NO_HISTORY 781 || cmdentry.u.index == HISTCMD 782 #endif 783 || cmdentry.u.index == EXECCMD) 784 exraise(e); 785 FORCEINTON; 786 } 787 if (cmdentry.u.index != EXECCMD) 788 popredir(); 789 if (flags == EV_BACKCMD) { 790 backcmd->buf = memout.buf; 791 backcmd->nleft = memout.nextc - memout.buf; 792 memout.buf = NULL; 793 } 794 } else { 795 trputs("normal command: "); trargs(argv); 796 clearredir(); 797 redirect(cmd->ncmd.redirect, 0); 798 for (sp = varlist.list ; sp ; sp = sp->next) 799 setvareq(sp->text, VEXPORT|VSTACK); 800 envp = environment(); 801 shellexec(argv, envp, pathval(), cmdentry.u.index); 802 /*NOTREACHED*/ 803 } 804 goto out; 805 806 parent: /* parent process gets here (if we forked) */ 807 if (mode == 0) { /* argument to fork */ 808 INTOFF; 809 exitstatus = waitforjob(jp); 810 INTON; 811 } else if (mode == 2) { 812 backcmd->fd = pip[0]; 813 close(pip[1]); 814 backcmd->jp = jp; 815 } 816 817 out: 818 if (lastarg) 819 setvar("_", lastarg, 0); 820 popstackmark(&smark); 821 } 822 823 824 825 /* 826 * Search for a command. This is called before we fork so that the 827 * location of the command will be available in the parent as well as 828 * the child. The check for "goodname" is an overly conservative 829 * check that the name will not be subject to expansion. 830 */ 831 832 STATIC void 833 prehash(n) 834 union node *n; 835 { 836 struct cmdentry entry; 837 838 if (n->type == NCMD && n->ncmd.args) 839 if (goodname(n->ncmd.args->narg.text)) 840 find_command(n->ncmd.args->narg.text, &entry, 0); 841 } 842 843 844 845 /* 846 * Builtin commands. Builtin commands whose functions are closely 847 * tied to evaluation are implemented here. 848 */ 849 850 /* 851 * No command given, or a bltin command with no arguments. Set the 852 * specified variables. 853 */ 854 855 int 856 bltincmd(argc, argv) 857 int argc; 858 char **argv; 859 { 860 listsetvar(cmdenviron); 861 return 0; 862 } 863 864 865 /* 866 * Handle break and continue commands. Break, continue, and return are 867 * all handled by setting the evalskip flag. The evaluation routines 868 * above all check this flag, and if it is set they start skipping 869 * commands rather than executing them. The variable skipcount is 870 * the number of loops to break/continue, or the number of function 871 * levels to return. (The latter is always 1.) It should probably 872 * be an error to break out of more loops than exist, but it isn't 873 * in the standard shell so we don't make it one here. 874 */ 875 876 int 877 breakcmd(argc, argv) 878 int argc; 879 char **argv; 880 { 881 int n; 882 883 n = 1; 884 if (argc > 1) 885 n = number(argv[1]); 886 if (n > loopnest) 887 n = loopnest; 888 if (n > 0) { 889 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 890 skipcount = n; 891 } 892 return 0; 893 } 894 895 896 /* 897 * The return command. 898 */ 899 900 int 901 returncmd(argc, argv) 902 int argc; 903 char **argv; 904 { 905 int ret; 906 907 ret = exitstatus; 908 if (argc > 1) 909 ret = number(argv[1]); 910 if (funcnest) { 911 evalskip = SKIPFUNC; 912 skipcount = 1; 913 } 914 return ret; 915 } 916 917 918 int 919 falsecmd(argc, argv) 920 int argc; 921 char **argv; 922 { 923 return 1; 924 } 925 926 927 int 928 truecmd(argc, argv) 929 int argc; 930 char **argv; 931 { 932 return 0; 933 } 934 935 936 int 937 execcmd(argc, argv) 938 int argc; 939 char **argv; 940 { 941 if (argc > 1) { 942 struct strlist *sp; 943 944 iflag = 0; /* exit on error */ 945 mflag = 0; 946 optschanged(); 947 for (sp = cmdenviron; sp ; sp = sp->next) 948 setvareq(sp->text, VEXPORT|VSTACK); 949 shellexec(argv + 1, environment(), pathval(), 0); 950 951 } 952 return 0; 953 } 954