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