1#define Extern extern 2#include <sys/types.h> 3#include <signal.h> 4#define _NSIG NSIG 5#include <errno.h> 6#include <setjmp.h> 7#include <stddef.h> 8#include <time.h> 9#include <sys/times.h> 10#include <sys/stat.h> 11#include <sys/wait.h> 12#undef NULL 13#include "sh.h" 14 15/* -------- exec.c -------- */ 16/* #include "sh.h" */ 17 18/* 19 * execute tree 20 */ 21 22static char *signame[] = { 23 "Signal 0", 24 "Hangup", 25 (char *)NULL, /* interrupt */ 26 "Quit", 27 "Illegal instruction", 28 "Trace/BPT trap", 29 "Abort", 30 "EMT trap", 31 "Floating exception", 32 "Killed", 33 "Bus error", 34 "Memory fault", 35 "Bad system call", 36 (char *)NULL, /* broken pipe */ 37 "Alarm clock", 38 "Terminated", 39}; 40#define NSIGNAL (sizeof(signame)/sizeof(signame[0])) 41 42 43_PROTOTYPE(static int forkexec, (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked )); 44_PROTOTYPE(static int parent, (void)); 45_PROTOTYPE(int iosetup, (struct ioword *iop, int pipein, int pipeout )); 46_PROTOTYPE(static void echo, (char **wp )); 47_PROTOTYPE(static struct op **find1case, (struct op *t, char *w )); 48_PROTOTYPE(static struct op *findcase, (struct op *t, char *w )); 49_PROTOTYPE(static void brkset, (struct brkcon *bc )); 50_PROTOTYPE(int dolabel, (void)); 51_PROTOTYPE(int dochdir, (struct op *t )); 52_PROTOTYPE(int doshift, (struct op *t )); 53_PROTOTYPE(int dologin, (struct op *t )); 54_PROTOTYPE(int doumask, (struct op *t )); 55_PROTOTYPE(int doexec, (struct op *t )); 56_PROTOTYPE(int dodot, (struct op *t )); 57_PROTOTYPE(int dowait, (struct op *t )); 58_PROTOTYPE(int doread, (struct op *t )); 59_PROTOTYPE(int doeval, (struct op *t )); 60_PROTOTYPE(int dotrap, (struct op *t )); 61_PROTOTYPE(int getsig, (char *s )); 62_PROTOTYPE(void setsig, (int n, void (*f)())); 63_PROTOTYPE(int getn, (char *as )); 64_PROTOTYPE(int dobreak, (struct op *t )); 65_PROTOTYPE(int docontinue, (struct op *t )); 66_PROTOTYPE(static int brkcontin, (char *cp, int val )); 67_PROTOTYPE(int doexit, (struct op *t )); 68_PROTOTYPE(int doexport, (struct op *t )); 69_PROTOTYPE(int doreadonly, (struct op *t )); 70_PROTOTYPE(static void rdexp, (char **wp, void (*f)(), int key)); 71_PROTOTYPE(static void badid, (char *s )); 72_PROTOTYPE(int doset, (struct op *t )); 73_PROTOTYPE(void varput, (char *s, int out )); 74_PROTOTYPE(int dotimes, (void)); 75 76int 77execute(t, pin, pout, act) 78register struct op *t; 79int *pin, *pout; 80int act; 81{ 82 register struct op *t1; 83 int i, pv[2], rv, child, a; 84 char *cp, **wp, **wp2; 85 struct var *vp; 86 struct brkcon bc; 87 88 if (t == NULL) 89 return(0); 90 rv = 0; 91 a = areanum++; 92 wp = (wp2 = t->words) != NULL 93 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) 94 : NULL; 95 96 switch(t->type) { 97 case TPAREN: 98 case TCOM: 99 rv = forkexec(t, pin, pout, act, wp, &child); 100 if (child) { 101 exstat = rv; 102 leave(); 103 } 104 break; 105 106 case TPIPE: 107 if ((rv = openpipe(pv)) < 0) 108 break; 109 pv[0] = remap(pv[0]); 110 pv[1] = remap(pv[1]); 111 (void) execute(t->left, pin, pv, 0); 112 rv = execute(t->right, pv, pout, 0); 113 break; 114 115 case TLIST: 116 (void) execute(t->left, pin, pout, 0); 117 rv = execute(t->right, pin, pout, 0); 118 break; 119 120 case TASYNC: 121 i = parent(); 122 if (i != 0) { 123 if (i != -1) { 124 setval(lookup("!"), putn(i)); 125 if (pin != NULL) 126 closepipe(pin); 127 if (talking) { 128 prs(putn(i)); 129 prs("\n"); 130 } 131 } else 132 rv = -1; 133 setstatus(rv); 134 } else { 135 signal(SIGINT, SIG_IGN); 136 signal(SIGQUIT, SIG_IGN); 137 if (talking) 138 signal(SIGTERM, SIG_DFL); 139 talking = 0; 140 if (pin == NULL) { 141 close(0); 142 open("/dev/null", 0); 143 } 144 exit(execute(t->left, pin, pout, FEXEC)); 145 } 146 break; 147 148 case TOR: 149 case TAND: 150 rv = execute(t->left, pin, pout, 0); 151 if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND)) 152 rv = execute(t1, pin, pout, 0); 153 break; 154 155 case TFOR: 156 if (wp == NULL) { 157 wp = dolv+1; 158 if ((i = dolc) < 0) 159 i = 0; 160 } else { 161 i = -1; 162 while (*wp++ != NULL) 163 ; 164 } 165 vp = lookup(t->str); 166 while (setjmp(bc.brkpt)) 167 if (isbreak) 168 goto broken; 169 brkset(&bc); 170 for (t1 = t->left; i-- && *wp != NULL;) { 171 setval(vp, *wp++); 172 rv = execute(t1, pin, pout, 0); 173 } 174 brklist = brklist->nextlev; 175 break; 176 177 case TWHILE: 178 case TUNTIL: 179 while (setjmp(bc.brkpt)) 180 if (isbreak) 181 goto broken; 182 brkset(&bc); 183 t1 = t->left; 184 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) 185 rv = execute(t->right, pin, pout, 0); 186 brklist = brklist->nextlev; 187 break; 188 189 case TIF: 190 case TELIF: 191 if (t->right != NULL) { 192 rv = !execute(t->left, pin, pout, 0) ? 193 execute(t->right->left, pin, pout, 0): 194 execute(t->right->right, pin, pout, 0); 195 } 196 break; 197 198 case TCASE: 199 if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0) 200 cp = ""; 201 if ((t1 = findcase(t->left, cp)) != NULL) 202 rv = execute(t1, pin, pout, 0); 203 break; 204 205 case TBRACE: 206/* 207 if (iopp = t->ioact) 208 while (*iopp) 209 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) { 210 rv = -1; 211 break; 212 } 213*/ 214 if (rv >= 0 && (t1 = t->left)) 215 rv = execute(t1, pin, pout, 0); 216 break; 217 } 218 219broken: 220 t->words = wp2; 221 isbreak = 0; 222 freehere(areanum); 223 freearea(areanum); 224 areanum = a; 225 if (talking && intr) { 226 closeall(); 227 fail(); 228 } 229 if ((i = trapset) != 0) { 230 trapset = 0; 231 runtrap(i); 232 } 233 return(rv); 234} 235 236static int 237forkexec(t, pin, pout, act, wp, pforked) 238register struct op *t; 239int *pin, *pout; 240int act; 241char **wp; 242int *pforked; 243{ 244 int i, rv, (*shcom)(); 245 register int f; 246 char *cp; 247 struct ioword **iopp; 248 int resetsig; 249 char **owp; 250 251 owp = wp; 252 resetsig = 0; 253 *pforked = 0; 254 shcom = NULL; 255 rv = -1; /* system-detected error */ 256 if (t->type == TCOM) { 257 while ((cp = *wp++) != NULL) 258 ; 259 cp = *wp; 260 261 /* strip all initial assignments */ 262 /* not correct wrt PATH=yyy command etc */ 263 if (flag['x']) 264 echo (cp ? wp: owp); 265 if (cp == NULL && t->ioact == NULL) { 266 while ((cp = *owp++) != NULL && assign(cp, COPYV)) 267 ; 268 return(setstatus(0)); 269 } 270 else if (cp != NULL) 271 shcom = inbuilt(cp); 272 } 273 t->words = wp; 274 f = act; 275 if (shcom == NULL && (f & FEXEC) == 0) { 276 i = parent(); 277 if (i != 0) { 278 if (i == -1) 279 return(rv); 280 if (pin != NULL) 281 closepipe(pin); 282 return(pout==NULL? setstatus(waitfor(i,0)): 0); 283 } 284 if (talking) { 285 signal(SIGINT, SIG_IGN); 286 signal(SIGQUIT, SIG_IGN); 287 resetsig = 1; 288 } 289 talking = 0; 290 intr = 0; 291 (*pforked)++; 292 brklist = 0; 293 execflg = 0; 294 } 295 if (owp != NULL) 296 while ((cp = *owp++) != NULL && assign(cp, COPYV)) 297 if (shcom == NULL) 298 export(lookup(cp)); 299#ifdef COMPIPE 300 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) { 301 err("piping to/from shell builtins not yet done"); 302 return(-1); 303 } 304#endif 305 if (pin != NULL) { 306 dup2(pin[0], 0); 307 closepipe(pin); 308 } 309 if (pout != NULL) { 310 dup2(pout[1], 1); 311 closepipe(pout); 312 } 313 if ((iopp = t->ioact) != NULL) { 314 if (shcom != NULL && shcom != doexec) { 315 prs(cp); 316 err(": cannot redirect shell command"); 317 return(-1); 318 } 319 while (*iopp) 320 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) 321 return(rv); 322 } 323 if (shcom) 324 return(setstatus((*shcom)(t))); 325 /* should use FIOCEXCL */ 326 for (i=FDBASE; i<NOFILE; i++) 327 close(i); 328 if (resetsig) { 329 signal(SIGINT, SIG_DFL); 330 signal(SIGQUIT, SIG_DFL); 331 } 332 if (t->type == TPAREN) 333 exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); 334 if (wp[0] == NULL) 335 exit(0); 336 cp = rexecve(wp[0], wp, makenv()); 337 prs(wp[0]); prs(": "); warn(cp); 338 if (!execflg) 339 trap[0] = NULL; 340 leave(); 341 /* NOTREACHED */ 342} 343 344/* 345 * common actions when creating a new child 346 */ 347static int 348parent() 349{ 350 register int i; 351 352 i = fork(); 353 if (i != 0) { 354 if (i == -1) 355 warn("try again"); 356 } 357 return(i); 358} 359 360/* 361 * 0< 1> are ignored as required 362 * within pipelines. 363 */ 364int 365iosetup(iop, pipein, pipeout) 366register struct ioword *iop; 367int pipein, pipeout; 368{ 369 register u; 370 char *cp, *msg; 371 372 if (iop->io_unit == IODEFAULT) /* take default */ 373 iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1; 374 if (pipein && iop->io_unit == 0) 375 return(0); 376 if (pipeout && iop->io_unit == 1) 377 return(0); 378 msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create"; 379 if ((iop->io_flag & IOHERE) == 0) { 380 cp = iop->io_name; 381 if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL) 382 return(1); 383 } 384 if (iop->io_flag & IODUP) { 385 if (cp[1] || (!digit(*cp) && *cp != '-')) { 386 prs(cp); 387 err(": illegal >& argument"); 388 return(1); 389 } 390 if (*cp == '-') 391 iop->io_flag = IOCLOSE; 392 iop->io_flag &= ~(IOREAD|IOWRITE); 393 } 394 switch (iop->io_flag) { 395 case IOREAD: 396 u = open(cp, 0); 397 break; 398 399 case IOHERE: 400 case IOHERE|IOXHERE: 401 u = herein(iop->io_name, iop->io_flag&IOXHERE); 402 cp = "here file"; 403 break; 404 405 case IOWRITE|IOCAT: 406 if ((u = open(cp, 1)) >= 0) { 407 lseek(u, (long)0, 2); 408 break; 409 } 410 case IOWRITE: 411 u = creat(cp, 0666); 412 break; 413 414 case IODUP: 415 u = dup2(*cp-'0', iop->io_unit); 416 break; 417 418 case IOCLOSE: 419 close(iop->io_unit); 420 return(0); 421 } 422 if (u < 0) { 423 prs(cp); 424 prs(": cannot "); 425 warn(msg); 426 return(1); 427 } else { 428 if (u != iop->io_unit) { 429 dup2(u, iop->io_unit); 430 close(u); 431 } 432 } 433 return(0); 434} 435 436static void 437echo(wp) 438register char **wp; 439{ 440 register i; 441 442 prs("+"); 443 for (i=0; wp[i]; i++) { 444 if (i) 445 prs(" "); 446 prs(wp[i]); 447 } 448 prs("\n"); 449} 450 451static struct op ** 452find1case(t, w) 453struct op *t; 454char *w; 455{ 456 register struct op *t1; 457 struct op **tp; 458 register char **wp, *cp; 459 460 if (t == NULL) 461 return((struct op **)NULL); 462 if (t->type == TLIST) { 463 if ((tp = find1case(t->left, w)) != NULL) 464 return(tp); 465 t1 = t->right; /* TPAT */ 466 } else 467 t1 = t; 468 for (wp = t1->words; *wp;) 469 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) 470 return(&t1->left); 471 return((struct op **)NULL); 472} 473 474static struct op * 475findcase(t, w) 476struct op *t; 477char *w; 478{ 479 register struct op **tp; 480 481 return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL); 482} 483 484/* 485 * Enter a new loop level (marked for break/continue). 486 */ 487static void 488brkset(bc) 489struct brkcon *bc; 490{ 491 bc->nextlev = brklist; 492 brklist = bc; 493} 494 495/* 496 * Wait for the last process created. 497 * Print a message for each process found 498 * that was killed by a signal. 499 * Ignore interrupt signals while waiting 500 * unless `canintr' is true. 501 */ 502int 503waitfor(lastpid, canintr) 504register int lastpid; 505int canintr; 506{ 507 register int pid, rv; 508 int s; 509 int oheedint = heedint; 510 511 heedint = 0; 512 rv = 0; 513 do { 514 pid = wait(&s); 515 if (pid == -1) { 516 if (errno != EINTR || canintr) 517 break; 518 } else { 519 if ((rv = WAITSIG(s)) != 0) { 520 if (rv < NSIGNAL) { 521 if (signame[rv] != NULL) { 522 if (pid != lastpid) { 523 prn(pid); 524 prs(": "); 525 } 526 prs(signame[rv]); 527 } 528 } else { 529 if (pid != lastpid) { 530 prn(pid); 531 prs(": "); 532 } 533 prs("Signal "); prn(rv); prs(" "); 534 } 535 if (WAITCORE(s)) 536 prs(" - core dumped"); 537 if (rv >= NSIGNAL || signame[rv]) 538 prs("\n"); 539 rv = -1; 540 } else 541 rv = WAITVAL(s); 542 } 543 } while (pid != lastpid); 544 heedint = oheedint; 545 if (intr) 546 if (talking) { 547 if (canintr) 548 intr = 0; 549 } else { 550 if (exstat == 0) exstat = rv; 551 onintr(0); 552 } 553 return(rv); 554} 555 556int 557setstatus(s) 558register int s; 559{ 560 exstat = s; 561 setval(lookup("?"), putn(s)); 562 return(s); 563} 564 565/* 566 * PATH-searching interface to execve. 567 * If getenv("PATH") were kept up-to-date, 568 * execvp might be used. 569 */ 570char * 571rexecve(c, v, envp) 572char *c, **v, **envp; 573{ 574 register int i; 575 register char *sp, *tp; 576 int eacces = 0, asis = 0; 577 578 sp = any('/', c)? "": path->value; 579 asis = *sp == '\0'; 580 while (asis || *sp != '\0') { 581 asis = 0; 582 tp = e.linep; 583 for (; *sp != '\0'; tp++) 584 if ((*tp = *sp++) == ':') { 585 asis = *sp == '\0'; 586 break; 587 } 588 if (tp != e.linep) 589 *tp++ = '/'; 590 for (i = 0; (*tp++ = c[i++]) != '\0';) 591 ; 592 execve(e.linep, v, envp); 593 switch (errno) { 594 case ENOEXEC: 595 *v = e.linep; 596 tp = *--v; 597 *v = e.linep; 598 execve("/bin/sh", v, envp); 599 *v = tp; 600 return("no Shell"); 601 602 case ENOMEM: 603 return("program too big"); 604 605 case E2BIG: 606 return("argument list too long"); 607 608 case EACCES: 609 eacces++; 610 break; 611 } 612 } 613 return(errno==ENOENT ? "not found" : "cannot execute"); 614} 615 616/* 617 * Run the command produced by generator `f' 618 * applied to stream `arg'. 619 */ 620int 621run(argp, f) 622struct ioarg *argp; 623int (*f)(); 624{ 625 struct op *otree; 626 struct wdblock *swdlist; 627 struct wdblock *siolist; 628 jmp_buf ev, rt; 629 xint *ofail; 630 int rv; 631 632 areanum++; 633 swdlist = wdlist; 634 siolist = iolist; 635 otree = outtree; 636 ofail = failpt; 637 rv = -1; 638 if (newenv(setjmp(errpt = ev)) == 0) { 639 wdlist = 0; 640 iolist = 0; 641 pushio(argp, f); 642 e.iobase = e.iop; 643 yynerrs = 0; 644 if (setjmp(failpt = rt) == 0 && yyparse() == 0) 645 rv = execute(outtree, NOPIPE, NOPIPE, 0); 646 quitenv(); 647 } 648 wdlist = swdlist; 649 iolist = siolist; 650 failpt = ofail; 651 outtree = otree; 652 freearea(areanum--); 653 return(rv); 654} 655 656/* -------- do.c -------- */ 657/* #include "sh.h" */ 658 659/* 660 * built-in commands: doX 661 */ 662 663int 664dolabel() 665{ 666 return(0); 667} 668 669int 670dochdir(t) 671register struct op *t; 672{ 673 register char *cp, *er; 674 675 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) 676 er = ": no home directory"; 677 else if(chdir(cp) < 0) 678 er = ": bad directory"; 679 else 680 return(0); 681 prs(cp != NULL? cp: "cd"); 682 err(er); 683 return(1); 684} 685 686int 687doshift(t) 688register struct op *t; 689{ 690 register n; 691 692 n = t->words[1]? getn(t->words[1]): 1; 693 if(dolc < n) { 694 err("nothing to shift"); 695 return(1); 696 } 697 dolv[n] = dolv[0]; 698 dolv += n; 699 dolc -= n; 700 setval(lookup("#"), putn(dolc)); 701 return(0); 702} 703 704/* 705 * execute login and newgrp directly 706 */ 707int 708dologin(t) 709struct op *t; 710{ 711 register char *cp; 712 713 if (talking) { 714 signal(SIGINT, SIG_DFL); 715 signal(SIGQUIT, SIG_DFL); 716 } 717 cp = rexecve(t->words[0], t->words, makenv()); 718 prs(t->words[0]); prs(": "); err(cp); 719 return(1); 720} 721 722int 723doumask(t) 724register struct op *t; 725{ 726 register int i, n; 727 register char *cp; 728 729 if ((cp = t->words[1]) == NULL) { 730 i = umask(0); 731 umask(i); 732 for (n=3*4; (n-=3) >= 0;) 733 putc('0'+((i>>n)&07)); 734 putc('\n'); 735 } else { 736 for (n=0; *cp>='0' && *cp<='9'; cp++) 737 n = n*8 + (*cp-'0'); 738 umask(n); 739 } 740 return(0); 741} 742 743int 744doexec(t) 745register struct op *t; 746{ 747 register i; 748 jmp_buf ex; 749 xint *ofail; 750 751 t->ioact = NULL; 752 for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++) 753 ; 754 if (i == 0) 755 return(1); 756 execflg = 1; 757 ofail = failpt; 758 if (setjmp(failpt = ex) == 0) 759 execute(t, NOPIPE, NOPIPE, FEXEC); 760 failpt = ofail; 761 execflg = 0; 762 return(1); 763} 764 765int 766dodot(t) 767struct op *t; 768{ 769 register i; 770 register char *sp, *tp; 771 char *cp; 772 773 if ((cp = t->words[1]) == NULL) 774 return(0); 775 sp = any('/', cp)? ":": path->value; 776 while (*sp) { 777 tp = e.linep; 778 while (*sp && (*tp = *sp++) != ':') 779 tp++; 780 if (tp != e.linep) 781 *tp++ = '/'; 782 for (i = 0; (*tp++ = cp[i++]) != '\0';) 783 ; 784 if ((i = open(e.linep, 0)) >= 0) { 785 exstat = 0; 786 next(remap(i)); 787 return(exstat); 788 } 789 } 790 prs(cp); 791 err(": not found"); 792 return(-1); 793} 794 795int 796dowait(t) 797struct op *t; 798{ 799 register i; 800 register char *cp; 801 802 if ((cp = t->words[1]) != NULL) { 803 i = getn(cp); 804 if (i == 0) 805 return(0); 806 } else 807 i = -1; 808 setstatus(waitfor(i, 1)); 809 return(0); 810} 811 812int 813doread(t) 814struct op *t; 815{ 816 register char *cp, **wp; 817 register nb; 818 register int nl = 0; 819 820 if (t->words[1] == NULL) { 821 err("usage: read name ..."); 822 return(1); 823 } 824 for (wp = t->words+1; *wp; wp++) { 825 for (cp = e.linep; !nl && cp < elinep-1; cp++) 826 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) || 827 (nl = (*cp == '\n')) || 828 (wp[1] && any(*cp, ifs->value))) 829 break; 830 *cp = 0; 831 if (nb <= 0) 832 break; 833 setval(lookup(*wp), e.linep); 834 } 835 return(nb <= 0); 836} 837 838int 839doeval(t) 840register struct op *t; 841{ 842 return(RUN(awordlist, t->words+1, wdchar)); 843} 844 845int 846dotrap(t) 847register struct op *t; 848{ 849 register int n, i; 850 register int resetsig; 851 852 if (t->words[1] == NULL) { 853 for (i=0; i<=_NSIG; i++) 854 if (trap[i]) { 855 prn(i); 856 prs(": "); 857 prs(trap[i]); 858 prs("\n"); 859 } 860 return(0); 861 } 862 resetsig = digit(*t->words[1]); 863 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { 864 n = getsig(t->words[i]); 865 xfree(trap[n]); 866 trap[n] = 0; 867 if (!resetsig) { 868 if (*t->words[1] != '\0') { 869 trap[n] = strsave(t->words[1], 0); 870 setsig(n, sig); 871 } else 872 setsig(n, SIG_IGN); 873 } else { 874 if (talking) 875 if (n == SIGINT) 876 setsig(n, onintr); 877 else 878 setsig(n, n == SIGQUIT ? SIG_IGN 879 : SIG_DFL); 880 else 881 setsig(n, SIG_DFL); 882 } 883 } 884 return(0); 885} 886 887int 888getsig(s) 889char *s; 890{ 891 register int n; 892 893 if ((n = getn(s)) < 0 || n > _NSIG) { 894 err("trap: bad signal number"); 895 n = 0; 896 } 897 return(n); 898} 899 900void 901setsig(n, f) 902register n; 903_PROTOTYPE(void (*f), (int)); 904{ 905 if (n == 0) 906 return; 907 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) { 908 ourtrap[n] = 1; 909 signal(n, f); 910 } 911} 912 913int 914getn(as) 915char *as; 916{ 917 register char *s; 918 register n, m; 919 920 s = as; 921 m = 1; 922 if (*s == '-') { 923 m = -1; 924 s++; 925 } 926 for (n = 0; digit(*s); s++) 927 n = (n*10) + (*s-'0'); 928 if (*s) { 929 prs(as); 930 err(": bad number"); 931 } 932 return(n*m); 933} 934 935int 936dobreak(t) 937struct op *t; 938{ 939 return(brkcontin(t->words[1], 1)); 940} 941 942int 943docontinue(t) 944struct op *t; 945{ 946 return(brkcontin(t->words[1], 0)); 947} 948 949static int 950brkcontin(cp, val) 951register char *cp; 952int val; 953{ 954 register struct brkcon *bc; 955 register nl; 956 957 nl = cp == NULL? 1: getn(cp); 958 if (nl <= 0) 959 nl = 999; 960 do { 961 if ((bc = brklist) == NULL) 962 break; 963 brklist = bc->nextlev; 964 } while (--nl); 965 if (nl) { 966 err("bad break/continue level"); 967 return(1); 968 } 969 isbreak = val; 970 longjmp(bc->brkpt, 1); 971 /* NOTREACHED */ 972} 973 974int 975doexit(t) 976struct op *t; 977{ 978 register char *cp; 979 980 execflg = 0; 981 if ((cp = t->words[1]) != NULL) 982 setstatus(getn(cp)); 983 leave(); 984 /* NOTREACHED */ 985} 986 987int 988doexport(t) 989struct op *t; 990{ 991 rdexp(t->words+1, export, EXPORT); 992 return(0); 993} 994 995int 996doreadonly(t) 997struct op *t; 998{ 999 rdexp(t->words+1, ronly, RONLY); 1000 return(0); 1001} 1002 1003static void 1004rdexp(wp, f, key) 1005register char **wp; 1006void (*f)(); 1007int key; 1008{ 1009 if (*wp != NULL) { 1010 for (; *wp != NULL; wp++) 1011 if (checkname(*wp)) 1012 (*f)(lookup(*wp)); 1013 else 1014 badid(*wp); 1015 } else 1016 putvlist(key, 1); 1017} 1018 1019static void 1020badid(s) 1021register char *s; 1022{ 1023 prs(s); 1024 err(": bad identifier"); 1025} 1026 1027int 1028doset(t) 1029register struct op *t; 1030{ 1031 register struct var *vp; 1032 register char *cp; 1033 register n; 1034 1035 if ((cp = t->words[1]) == NULL) { 1036 for (vp = vlist; vp; vp = vp->next) 1037 varput(vp->name, 1); 1038 return(0); 1039 } 1040 if (*cp == '-') { 1041 /* bad: t->words++; */ 1042 for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++) 1043 ; 1044 if (*++cp == 0) 1045 flag['x'] = flag['v'] = 0; 1046 else 1047 for (; *cp; cp++) 1048 switch (*cp) { 1049 case 'e': 1050 if (!talking) 1051 flag['e']++; 1052 break; 1053 1054 default: 1055 if (*cp>='a' && *cp<='z') 1056 flag[*cp]++; 1057 break; 1058 } 1059 setdash(); 1060 } 1061 if (t->words[1]) { 1062 t->words[0] = dolv[0]; 1063 for (n=1; t->words[n]; n++) 1064 setarea((char *)t->words[n], 0); 1065 dolc = n-1; 1066 dolv = t->words; 1067 setval(lookup("#"), putn(dolc)); 1068 setarea((char *)(dolv-1), 0); 1069 } 1070 return(0); 1071} 1072 1073void 1074varput(s, out) 1075register char *s; 1076int out; 1077{ 1078 if (letnum(*s)) { 1079 write(out, s, strlen(s)); 1080 write(out, "\n", 1); 1081 } 1082} 1083 1084 1085#define SECS 60L 1086#define MINS 3600L 1087 1088int 1089dotimes() 1090{ 1091 struct tms tbuf; 1092 1093 times(&tbuf); 1094 1095 prn((int)(tbuf.tms_cutime / MINS)); 1096 prs("m"); 1097 prn((int)((tbuf.tms_cutime % MINS) / SECS)); 1098 prs("s "); 1099 prn((int)(tbuf.tms_cstime / MINS)); 1100 prs("m"); 1101 prn((int)((tbuf.tms_cstime % MINS) / SECS)); 1102 prs("s\n"); 1103 return(0); 1104} 1105 1106struct builtin { 1107 char *command; 1108 int (*fn)(); 1109}; 1110static struct builtin builtin[] = { 1111 ":", dolabel, 1112 "cd", dochdir, 1113 "shift", doshift, 1114 "exec", doexec, 1115 "wait", dowait, 1116 "read", doread, 1117 "eval", doeval, 1118 "trap", dotrap, 1119 "break", dobreak, 1120 "continue", docontinue, 1121 "exit", doexit, 1122 "export", doexport, 1123 "readonly", doreadonly, 1124 "set", doset, 1125 ".", dodot, 1126 "umask", doumask, 1127 "login", dologin, 1128 "newgrp", dologin, 1129 "times", dotimes, 1130 0, 1131}; 1132 1133int (*inbuilt(s))() 1134register char *s; 1135{ 1136 register struct builtin *bp; 1137 1138 for (bp = builtin; bp->command != NULL; bp++) 1139 if (strcmp(bp->command, s) == 0) 1140 return(bp->fn); 1141 return((int(*)())NULL); 1142} 1143 1144