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