1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.func.c,v 3.1 1991/07/05 19:07:02 christos Exp $ */ 2: /* 3: * sh.func.c: csh builtin functions 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: 39: #if !defined(lint) && !defined(pdp11) 40: static char *rcsid() 41: { return "$Id: sh.func.c,v 3.1 1991/07/05 19:07:02 christos Exp $"; } 42: #endif 43: 44: #include "sh.h" 45: #include "ed.h" 46: #include "tw.h" 47: 48: /* 49: * C shell 50: */ 51: 52: extern int just_signaled; 53: extern char **environ; 54: 55: extern bool MapsAreInited; 56: extern bool NLSMapsAreInited; 57: extern bool NoNLSRebind; 58: 59: static int zlast = -1; 60: 61: static void islogin __P((void)); 62: static void reexecute __P((struct command *)); 63: static void preread __P((void)); 64: static void doagain __P((void)); 65: static int getword __P((Char *)); 66: static int keyword __P((Char *)); 67: static void Unsetenv __P((Char *)); 68: static void toend __P((void)); 69: static void xecho __P((int, Char **)); 70: 71: struct biltins * 72: isbfunc(t) 73: struct command *t; 74: { 75: register Char *cp = t->t_dcom[0]; 76: register struct biltins *bp, *bp1, *bp2; 77: static struct biltins label = {"", dozip, 0, 0}; 78: static struct biltins foregnd = {"%job", dofg1, 0, 0}; 79: static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 80: 81: if (lastchr(cp) == ':') { 82: label.bname = short2str(cp); 83: return (&label); 84: } 85: if (*cp == '%') { 86: if (t->t_dflg & F_AMPERSAND) { 87: t->t_dflg &= ~F_AMPERSAND; 88: backgnd.bname = short2str(cp); 89: return (&backgnd); 90: } 91: foregnd.bname = short2str(cp); 92: return (&foregnd); 93: } 94: #ifdef WARP 95: /* 96: * This is a perhaps kludgy way to determine if the warp builtin is to be 97: * acknowledged or not. If checkwarp() fails, then we are to assume that 98: * the warp command is invalid, and carry on as we would handle any other 99: * non-builtin command. -- JDK 2/4/88 100: */ 101: if (eq(STRwarp, cp) && !checkwarp()) { 102: return (0); /* this builtin disabled */ 103: } 104: #endif 105: /* 106: * Binary search Bp1 is the beginning of the current search range. Bp2 is 107: * one past the end. 108: */ 109: for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 110: register i; 111: 112: bp = bp1 + ((bp2 - bp1) >> 1); 113: if ((i = *cp - *bp->bname) == 0 && 114: (i = Strcmp(cp, str2short(bp->bname))) == 0) 115: return bp; 116: if (i < 0) 117: bp2 = bp; 118: else 119: bp1 = bp + 1; 120: } 121: return (0); 122: } 123: 124: void 125: func(t, bp) 126: register struct command *t; 127: register struct biltins *bp; 128: { 129: int i; 130: 131: xechoit(t->t_dcom); 132: setname(bp->bname); 133: i = blklen(t->t_dcom) - 1; 134: if (i < bp->minargs) 135: stderror(ERR_NAME | ERR_TOOFEW); 136: if (i > bp->maxargs) 137: stderror(ERR_NAME | ERR_TOOMANY); 138: (*bp->bfunct) (t->t_dcom, t); 139: } 140: 141: void 142: doonintr(v) 143: Char **v; 144: { 145: register Char *cp; 146: register Char *vv = v[1]; 147: 148: if (parintr == SIG_IGN) 149: return; 150: if (setintr && intty) 151: stderror(ERR_NAME | ERR_TERMINAL); 152: cp = gointr; 153: gointr = 0; 154: xfree((ptr_t) cp); 155: if (vv == 0) { 156: #ifdef BSDSIGS 157: if (setintr) 158: (void) sigblock(sigmask(SIGINT)); 159: else 160: (void) signal(SIGINT, SIG_DFL); 161: #else 162: if (setintr) 163: (void) sighold(SIGINT); 164: else 165: (void) sigset(SIGINT, SIG_DFL); 166: #endif 167: gointr = 0; 168: } 169: else if (eq((vv = strip(vv)), STRminus)) { 170: #ifdef BSDSIGS 171: (void) signal(SIGINT, SIG_IGN); 172: #else 173: (void) sigset(SIGINT, SIG_IGN); 174: #endif 175: gointr = Strsave(STRminus); 176: } 177: else { 178: gointr = Strsave(vv); 179: #ifdef BSDSIGS 180: (void) signal(SIGINT, pintr); 181: #else 182: (void) sigset(SIGINT, pintr); 183: #endif 184: } 185: } 186: 187: void 188: donohup() 189: { 190: if (intty) 191: stderror(ERR_NAME | ERR_TERMINAL); 192: if (setintr == 0) { 193: (void) signal(SIGHUP, SIG_IGN); 194: #ifdef CC 195: submit(getpid()); 196: #endif 197: } 198: } 199: 200: void 201: dozip() 202: { 203: ; 204: } 205: 206: void 207: prvars() 208: { 209: plist(&shvhed); 210: } 211: 212: void 213: doalias(v) 214: register Char **v; 215: { 216: register struct varent *vp; 217: register Char *p; 218: 219: v++; 220: p = *v++; 221: if (p == 0) 222: plist(&aliases); 223: else if (*v == 0) { 224: vp = adrof1(strip(p), &aliases); 225: if (vp) 226: blkpr(vp->vec), xprintf("\n"); 227: } 228: else { 229: if (eq(p, STRalias) || eq(p, STRunalias)) { 230: setname(short2str(p)); 231: stderror(ERR_NAME | ERR_DANGER); 232: } 233: set1(strip(p), saveblk(v), &aliases); 234: tw_clear_comm_list(); 235: } 236: } 237: 238: void 239: unalias(v) 240: Char **v; 241: { 242: unset1(v, &aliases); 243: tw_clear_comm_list(); 244: } 245: 246: void 247: dologout() 248: { 249: islogin(); 250: goodbye(); 251: } 252: 253: void 254: dologin(v) 255: Char **v; 256: { 257: islogin(); 258: rechist(); 259: (void) signal(SIGTERM, parterm); 260: (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL); 261: untty(); 262: xexit(1); 263: } 264: 265: 266: #ifdef NEWGRP 267: void 268: donewgrp(v) 269: Char **v; 270: { 271: if (chkstop == 0 && setintr) 272: panystop(0); 273: (void) signal(SIGTERM, parterm); 274: (void) execl(_PATH_BIN_NEWGRP, "newgrp", short2str(v[1]), NULL); 275: (void) execl(_PATH_USRBIN_NEWGRP, "newgrp", short2str(v[1]), NULL); 276: untty(); 277: xexit(1); 278: } 279: #endif 280: 281: static void 282: islogin() 283: { 284: if (chkstop == 0 && setintr) 285: panystop(0); 286: if (loginsh) 287: return; 288: stderror(ERR_NOTLOGIN); 289: } 290: 291: void 292: doif(v, kp) 293: Char **v; 294: struct command *kp; 295: { 296: register int i; 297: register Char **vv; 298: 299: v++; 300: i = exp(&v); 301: vv = v; 302: if (*vv == NOSTR) 303: stderror(ERR_NAME | ERR_EMPTYIF); 304: if (eq(*vv, STRthen)) { 305: if (*++vv) 306: stderror(ERR_NAME | ERR_IMPRTHEN); 307: setname(short2str(STRthen)); 308: /* 309: * If expression was zero, then scan to else, otherwise just fall into 310: * following code. 311: */ 312: if (!i) 313: search(T_IF, 0, NOSTR); 314: return; 315: } 316: /* 317: * Simple command attached to this if. Left shift the node in this tree, 318: * munging it so we can reexecute it. 319: */ 320: if (i) { 321: lshift(kp->t_dcom, vv - kp->t_dcom); 322: reexecute(kp); 323: donefds(); 324: } 325: } 326: 327: /* 328: * Reexecute a command, being careful not 329: * to redo i/o redirection, which is already set up. 330: */ 331: static void 332: reexecute(kp) 333: register struct command *kp; 334: { 335: kp->t_dflg &= F_SAVE; 336: kp->t_dflg |= F_REPEAT; 337: /* 338: * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 339: * pgrp's as the jobs would then have no way to get the tty (we can't give 340: * it to them, and our parent wouldn't know their pgrp, etc. 341: */ 342: execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); 343: } 344: 345: void 346: doelse() 347: { 348: search(T_ELSE, 0, NOSTR); 349: } 350: 351: void 352: dogoto(v) 353: Char **v; 354: { 355: register struct whyle *wp; 356: Char *lp; 357: 358: /* 359: * While we still can, locate any unknown ends of existing loops. This 360: * obscure code is the WORST result of the fact that we don't really parse. 361: */ 362: zlast = T_GOTO; 363: for (wp = whyles; wp; wp = wp->w_next) 364: if (wp->w_end == 0) { 365: search(T_BREAK, 0, NOSTR); 366: wp->w_end = btell(); 367: } 368: else 369: bseek(wp->w_end); 370: search(T_GOTO, 0, lp = globone(v[1], G_ERROR)); 371: xfree((ptr_t) lp); 372: /* 373: * Eliminate loops which were exited. 374: */ 375: wfree(); 376: } 377: 378: void 379: doswitch(v) 380: register Char **v; 381: { 382: register Char *cp, *lp; 383: 384: v++; 385: if (!*v || *(*v++) != '(') 386: stderror(ERR_SYNTAX); 387: cp = **v == ')' ? STRNULL : *v++; 388: if (*(*v++) != ')') 389: v--; 390: if (*v) 391: stderror(ERR_SYNTAX); 392: search(T_SWITCH, 0, lp = globone(cp, G_ERROR)); 393: xfree((ptr_t) lp); 394: } 395: 396: void 397: dobreak() 398: { 399: if (whyles) 400: toend(); 401: else 402: stderror(ERR_NAME | ERR_NOTWHILE); 403: } 404: 405: void 406: doexit(v) 407: Char **v; 408: { 409: if (chkstop == 0 && (intty || intact) && evalvec == 0) 410: panystop(0); 411: /* 412: * Don't DEMAND parentheses here either. 413: */ 414: v++; 415: if (*v) { 416: set(STRstatus, putn(exp(&v))); 417: if (*v) 418: stderror(ERR_NAME | ERR_EXPRESSION); 419: } 420: btoeof(); 421: if (intty) 422: (void) close(SHIN); 423: } 424: 425: void 426: doforeach(v) 427: register Char **v; 428: { 429: register Char *cp, *sp; 430: register struct whyle *nwp; 431: 432: v++; 433: sp = cp = strip(*v); 434: if (!letter(*sp)) 435: stderror(ERR_NAME | ERR_VARBEGIN); 436: while (*cp && alnum(*cp)) 437: cp++; 438: if (*cp) 439: stderror(ERR_NAME | ERR_VARALNUM); 440: if ((cp - sp) > MAXVARLEN) 441: stderror(ERR_NAME | ERR_VARTOOLONG); 442: cp = *v++; 443: if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 444: stderror(ERR_NAME | ERR_NOPAREN); 445: v++; 446: gflag = 0, tglob(v); 447: v = globall(v); 448: if (v == 0) 449: stderror(ERR_NAME | ERR_NOMATCH); 450: nwp = (struct whyle *) xcalloc(1, sizeof *nwp); 451: nwp->w_fe = nwp->w_fe0 = v; 452: gargv = 0; 453: nwp->w_start = btell(); 454: nwp->w_fename = Strsave(cp); 455: nwp->w_next = whyles; 456: whyles = nwp; 457: /* 458: * Pre-read the loop so as to be more comprehensible to a terminal user. 459: */ 460: zlast = T_FOREACH; 461: if (intty) 462: preread(); 463: doagain(); 464: } 465: 466: void 467: dowhile(v) 468: Char **v; 469: { 470: register int status; 471: register bool again = whyles != 0 && whyles->w_start == lineloc && 472: whyles->w_fename == 0; 473: 474: v++; 475: /* 476: * Implement prereading here also, taking care not to evaluate the 477: * expression before the loop has been read up from a terminal. 478: */ 479: if (intty && !again) 480: status = !exp0(&v, 1); 481: else 482: status = !exp(&v); 483: if (*v) 484: stderror(ERR_NAME | ERR_EXPRESSION); 485: if (!again) { 486: register struct whyle *nwp = 487: (struct whyle *) xcalloc(1, sizeof(*nwp)); 488: 489: nwp->w_start = lineloc; 490: nwp->w_end = 0; 491: nwp->w_next = whyles; 492: whyles = nwp; 493: zlast = T_WHILE; 494: if (intty) { 495: /* 496: * The tty preread 497: */ 498: preread(); 499: doagain(); 500: return; 501: } 502: } 503: if (status) 504: /* We ain't gonna loop no more, no more! */ 505: toend(); 506: } 507: 508: static void 509: preread() 510: { 511: whyles->w_end = -1; 512: if (setintr) 513: #ifdef BSDSIGS 514: (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 515: #else 516: (void) sigrelse(SIGINT); 517: #endif 518: search(T_BREAK, 0, NOSTR); /* read the expression in */ 519: if (setintr) 520: #ifdef BSDSIGS 521: (void) sigblock(sigmask(SIGINT)); 522: #else 523: (void) sighold(SIGINT); 524: #endif 525: whyles->w_end = btell(); 526: } 527: 528: void 529: doend() 530: { 531: if (!whyles) 532: stderror(ERR_NAME | ERR_NOTWHILE); 533: whyles->w_end = btell(); 534: doagain(); 535: } 536: 537: void 538: docontin() 539: { 540: if (!whyles) 541: stderror(ERR_NAME | ERR_NOTWHILE); 542: doagain(); 543: } 544: 545: static void 546: doagain() 547: { 548: /* Repeating a while is simple */ 549: if (whyles->w_fename == 0) { 550: bseek(whyles->w_start); 551: return; 552: } 553: /* 554: * The foreach variable list actually has a spurious word ")" at the end of 555: * the w_fe list. Thus we are at the of the list if one word beyond this 556: * is 0. 557: */ 558: if (!whyles->w_fe[1]) { 559: dobreak(); 560: return; 561: } 562: set(whyles->w_fename, Strsave(*whyles->w_fe++)); 563: bseek(whyles->w_start); 564: } 565: 566: void 567: dorepeat(v, kp) 568: Char **v; 569: struct command *kp; 570: { 571: register int i; 572: 573: #ifdef BSDSIGS 574: sigmask_t omask = 0; 575: 576: #endif 577: 578: i = getn(v[1]); 579: if (setintr) 580: #ifdef BSDSIGS 581: omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); 582: #else 583: (void) sighold(SIGINT); 584: #endif 585: lshift(v, 2); 586: while (i > 0) { 587: if (setintr) 588: #ifdef BSDSIGS 589: (void) sigsetmask(omask); 590: #else 591: (void) sigrelse(SIGINT); 592: #endif 593: reexecute(kp); 594: --i; 595: } 596: donefds(); 597: if (setintr) 598: #ifdef BSDSIGS 599: (void) sigsetmask(omask); 600: #else 601: (void) sigrelse(SIGINT); 602: #endif 603: } 604: 605: void 606: doswbrk() 607: { 608: search(T_BRKSW, 0, NOSTR); 609: } 610: 611: int 612: srchx(cp) 613: register Char *cp; 614: { 615: register struct srch *sp, *sp1, *sp2; 616: register i; 617: 618: /* 619: * Binary search Sp1 is the beginning of the current search range. Sp2 is 620: * one past the end. 621: */ 622: for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 623: sp = sp1 + ((sp2 - sp1) >> 1); 624: if ((i = *cp - *sp->s_name) == 0 && 625: (i = Strcmp(cp, str2short(sp->s_name))) == 0) 626: return sp->s_value; 627: if (i < 0) 628: sp2 = sp; 629: else 630: sp1 = sp + 1; 631: } 632: return (-1); 633: } 634: 635: static char * 636: isrchx(n) 637: register int n; 638: { 639: register struct srch *sp, *sp2; 640: 641: for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++) 642: if (sp->s_value == n) 643: return (sp->s_name); 644: return (""); 645: } 646: 647: 648: static Char Stype; 649: static Char *Sgoal; 650: 651: /*VARARGS2*/ 652: void 653: search(type, level, goal) 654: int type; 655: register int level; 656: Char *goal; 657: { 658: Char wordbuf[BUFSIZ]; 659: register Char *aword = wordbuf; 660: register Char *cp; 661: 662: Stype = type; 663: Sgoal = goal; 664: if (type == T_GOTO) 665: bseek((off_t) 0); 666: do { 667: if (intty && fseekp == feobp) 668: printprompt(1, str2short(isrchx(type == T_BREAK ? 669: zlast : type))); 670: /* xprintf("? "), flush(); */ 671: aword[0] = 0; 672: (void) getword(aword); 673: switch (srchx(aword)) { 674: 675: case T_ELSE: 676: if (level == 0 && type == T_IF) 677: return; 678: break; 679: 680: case T_IF: 681: while (getword(aword)) 682: continue; 683: if ((type == T_IF || type == T_ELSE) && 684: eq(aword, STRthen)) 685: level++; 686: break; 687: 688: case T_ENDIF: 689: if (type == T_IF || type == T_ELSE) 690: level--; 691: break; 692: 693: case T_FOREACH: 694: case T_WHILE: 695: if (type == T_BREAK) 696: level++; 697: break; 698: 699: case T_END: 700: if (type == T_BREAK) 701: level--; 702: break; 703: 704: case T_SWITCH: 705: if (type == T_SWITCH || type == T_BRKSW) 706: level++; 707: break; 708: 709: case T_ENDSW: 710: if (type == T_SWITCH || type == T_BRKSW) 711: level--; 712: break; 713: 714: case T_LABEL: 715: if (type == T_GOTO && getword(aword) && eq(aword, goal)) 716: level = -1; 717: break; 718: 719: default: 720: if (type != T_GOTO && (type != T_SWITCH || level != 0)) 721: break; 722: if (lastchr(aword) != ':') 723: break; 724: aword[Strlen(aword) - 1] = 0; 725: if (type == T_GOTO && eq(aword, goal) || 726: type == T_SWITCH && eq(aword, STRdefault)) 727: level = -1; 728: break; 729: 730: case T_CASE: 731: if (type != T_SWITCH || level != 0) 732: break; 733: (void) getword(aword); 734: if (lastchr(aword) == ':') 735: aword[Strlen(aword) - 1] = 0; 736: cp = strip(Dfix1(aword)); 737: if (Gmatch(goal, cp)) 738: level = -1; 739: xfree((ptr_t) cp); 740: break; 741: 742: case T_DEFAULT: 743: if (type == T_SWITCH && level == 0) 744: level = -1; 745: break; 746: } 747: (void) getword(NOSTR); 748: } while (level >= 0); 749: } 750: 751: static int 752: getword(wp) 753: register Char *wp; 754: { 755: register int found = 0; 756: register int c, d; 757: int kwd = 0; 758: Char *owp = wp; 759: 760: c = readc(1); 761: d = 0; 762: do { 763: while (c == ' ' || c == '\t') 764: c = readc(1); 765: if (c == '#') 766: do 767: c = readc(1); 768: while (c >= 0 && c != '\n'); 769: if (c < 0) 770: goto past; 771: if (c == '\n') { 772: if (wp) 773: break; 774: return (0); 775: } 776: unreadc(c); 777: found = 1; 778: do { 779: c = readc(1); 780: if (c == '\\' && (c = readc(1)) == '\n') 781: c = ' '; 782: if (c == '\'' || c == '"') 783: if (d == 0) 784: d = c; 785: else if (d == c) 786: d = 0; 787: if (c < 0) 788: goto past; 789: if (wp) { 790: *wp++ = c; 791: *wp = 0; /* end the string b4 test */ 792: } 793: } while ((d || !(kwd = keyword(owp)) && c != ' ' 794: && c != '\t') && c != '\n'); 795: } while (wp == 0); 796: 797: /* 798: * if we have read a keyword ( "if", "switch" or "while" ) then we do not 799: * need to unreadc the look-ahead char 800: */ 801: if (!kwd) { 802: unreadc(c); 803: if (found) 804: *--wp = 0; 805: } 806: 807: return (found); 808: 809: past: 810: switch (Stype) { 811: 812: case T_IF: 813: stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 814: 815: case T_ELSE: 816: stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 817: 818: case T_BRKSW: 819: case T_SWITCH: 820: stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 821: 822: case T_BREAK: 823: stderror(ERR_NAME | ERR_NOTFOUND, "end"); 824: 825: case T_GOTO: 826: setname(short2str(Sgoal)); 827: stderror(ERR_NAME | ERR_NOTFOUND, "label"); 828: } 829: /* NOTREACHED */ 830: return (0); 831: } 832: 833: /* 834: * keyword(wp) determines if wp is one of the built-n functions if, 835: * switch or while. It seems that when an if statement looks like 836: * "if(" then getword above sucks in the '(' and so the search routine 837: * never finds what it is scanning for. Rather than rewrite doword, I hack 838: * in a test to see if the string forms a keyword. Then doword stops 839: * and returns the word "if" -strike 840: */ 841: 842: static int 843: keyword(wp) 844: Char *wp; 845: { 846: static Char STRif[] = {'i', 'f', '\0'}; 847: static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'}; 848: static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'}; 849: 850: if (!wp) 851: return (0); 852: 853: if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0) 854: || (Strcmp(wp, STRswitch) == 0)) 855: return (1); 856: 857: return (0); 858: } 859: 860: static void 861: toend() 862: { 863: if (whyles->w_end == 0) { 864: search(T_BREAK, 0, NOSTR); 865: whyles->w_end = btell() - 1; 866: } 867: else 868: bseek(whyles->w_end); 869: wfree(); 870: } 871: 872: void 873: wfree() 874: { 875: long o = btell(); 876: 877: while (whyles) { 878: register struct whyle *wp = whyles; 879: register struct whyle *nwp = wp->w_next; 880: 881: if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) 882: break; 883: if (wp->w_fe0) 884: blkfree(wp->w_fe0); 885: if (wp->w_fename) 886: xfree((ptr_t) wp->w_fename); 887: xfree((ptr_t) wp); 888: whyles = nwp; 889: } 890: } 891: 892: void 893: doecho(v) 894: Char **v; 895: { 896: xecho(' ', v); 897: } 898: 899: void 900: doglob(v) 901: Char **v; 902: { 903: xecho(0, v); 904: flush(); 905: } 906: 907: static void 908: xecho(sep, v) 909: Char sep; 910: register Char **v; 911: { 912: register Char *cp; 913: int nonl = 0; 914: 915: if (setintr) 916: #ifdef BSDSIGS 917: (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 918: #else 919: (void) sigrelse(SIGINT); 920: #endif 921: v++; 922: if (*v == 0) 923: return; 924: gflag = 0, tglob(v); 925: if (gflag) { 926: v = globall(v); 927: if (v == 0) 928: stderror(ERR_NAME | ERR_NOMATCH); 929: } 930: else { 931: v = gargv = saveblk(v); 932: trim(v); 933: } 934: if (sep == ' ' && *v && eq(*v, STRmn)) 935: nonl++, v++; 936: while (cp = *v++) { 937: register int c; 938: 939: while (c = *cp++) { 940: #if SVID > 0 941: #ifndef OREO 942: if (c == '\\') { 943: switch (c = *cp++) { 944: case 'b': 945: c = '\b'; 946: break; 947: case 'c': 948: nonl = 1; 949: goto done; 950: case 'f': 951: c = '\f'; 952: break; 953: case 'n': 954: c = '\n'; 955: break; 956: case 'r': 957: c = '\r'; 958: break; 959: case 't': 960: c = '\t'; 961: break; 962: case 'v': 963: c = '\v'; 964: break; 965: case '\\': 966: c = '\\'; 967: break; 968: case '0': 969: c = 0; 970: if (*cp >= '0' && *cp < '8') 971: c = c * 8 + *cp++ - '0'; 972: if (*cp >= '0' && *cp < '8') 973: c = c * 8 + *cp++ - '0'; 974: if (*cp >= '0' && *cp < '8') 975: c = c * 8 + *cp++ - '0'; 976: break; 977: case '\0': 978: c = *--cp; 979: break; 980: default: 981: xputchar('\\' | QUOTE); 982: break; 983: } 984: } 985: #endif /* OREO */ 986: #endif /* SVID > 0 */ 987: xputchar(c | QUOTE); 988: 989: } 990: if (*v) 991: xputchar(sep | QUOTE); 992: } 993: #if SVID > 0 994: #ifndef OREO 995: done: 996: #endif /* OREO */ 997: #endif /* SVID > 0 */ 998: if (sep && nonl == 0) 999: xputchar('\n'); 1000: else 1001: flush(); 1002: if (setintr) 1003: #ifdef BSDSIGS 1004: (void) sigblock(sigmask(SIGINT)); 1005: #else 1006: (void) sighold(SIGINT); 1007: #endif 1008: if (gargv) 1009: blkfree(gargv), gargv = 0; 1010: } 1011: 1012: /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things 1013: (and anything else with a modern comp_r) */ 1014: 1015: void 1016: dosetenv(v) 1017: register Char **v; 1018: { 1019: Char *vp, *lp; 1020: 1021: v++; 1022: if ((vp = *v++) == 0) { 1023: register Char **ep; 1024: 1025: if (setintr) 1026: #ifdef BSDSIGS 1027: (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 1028: #else 1029: (void) sigrelse(SIGINT); 1030: #endif 1031: for (ep = STR_environ; *ep; ep++) 1032: xprintf("%s\n", short2str(*ep)); 1033: return; 1034: } 1035: if ((lp = *v++) == 0) 1036: lp = STRNULL; 1037: Setenv(vp, lp = globone(lp, G_ERROR)); 1038: if (eq(vp, STRPATH)) { 1039: importpath(lp); 1040: dohash(); 1041: } 1042: #ifdef apollo 1043: else if (eq(vp, STRSYSTYPE)) 1044: dohash(); 1045: #endif /* apollo */ 1046: else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) { 1047: #ifdef NLS 1048: int k; 1049: 1050: (void) setlocale(LC_ALL, ""); 1051: for (k = 0200; k <= 0377 && !Isprint(k); k++); 1052: AsciiOnly = k > 0377; 1053: #else 1054: AsciiOnly = 0; 1055: #endif /* NLS */ 1056: NLSMapsAreInited = 0; 1057: ed_I(); 1058: if (MapsAreInited && !NLSMapsAreInited) 1059: (void) ed_INLSMaps(); 1060: } 1061: else if (eq(vp, STRNOREBIND)) { 1062: NoNLSRebind = 1; 1063: } 1064: #ifdef SIG_WINDOW 1065: else if ((eq(lp, STRNULL) && 1066: (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) || 1067: eq(vp, STRTRMCAP)) { 1068: check_window_size(1); 1069: } 1070: #endif /* SIG_WINDOW */ 1071: xfree((ptr_t) lp); 1072: } 1073: 1074: void 1075: dounsetenv(v) 1076: register Char **v; 1077: { 1078: Char **ep, *p, *n; 1079: int i, maxi; 1080: static Char *name = NULL; 1081: 1082: if (name) 1083: xfree((ptr_t) name); 1084: /* 1085: * Find the longest environment variable 1086: */ 1087: for (maxi = 0, ep = STR_environ; *ep; ep++) { 1088: for (i = 0, p = *ep; *p && *p != '='; p++, i++); 1089: if (i > maxi) 1090: maxi = i; 1091: } 1092: 1093: name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char)); 1094: 1095: while (++v && *v) 1096: for (maxi = 1; maxi;) 1097: for (maxi = 0, ep = STR_environ; *ep; ep++) { 1098: for (n = name, p = *ep; *p && *p != '='; *n++ = *p++); 1099: *n = '\0'; 1100: if (!Gmatch(name, *v)) 1101: continue; 1102: maxi = 1; 1103: if (eq(name, STRNOREBIND)) 1104: NoNLSRebind = 0; 1105: #ifdef apollo 1106: else if (eq(name, STRSYSTYPE)) 1107: dohash(); 1108: #endif /* apollo */ 1109: else if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) { 1110: #ifdef NLS 1111: int k; 1112: 1113: (void) setlocale(LC_ALL, ""); 1114: for (k = 0200; k <= 0377 && !Isprint(k); k++); 1115: AsciiOnly = k > 0377; 1116: #else 1117: AsciiOnly = getenv("LANG") == NULL && 1118: getenv("LC_CTYPE") == NULL; 1119: #endif /* NLS */ 1120: NLSMapsAreInited = 0; 1121: ed_I(); 1122: if (MapsAreInited && !NLSMapsAreInited) 1123: (void) ed_INLSMaps(); 1124: 1125: } 1126: /* 1127: * Delete name, and start again cause the environment changes 1128: */ 1129: Unsetenv(name); 1130: break; 1131: } 1132: xfree((ptr_t) name), name = NULL; 1133: } 1134: 1135: void 1136: Setenv(name, val) 1137: Char *name, *val; 1138: { 1139: #ifdef SETENV_IN_LIB 1140: #undef setenv 1141: char nameBuf[BUFSIZ]; 1142: char *cname = short2str(name); 1143: 1144: if (cname == NULL) 1145: return; 1146: (void) strcpy(nameBuf, cname); 1147: setenv(nameBuf, short2str(val), 1); 1148: #else 1149: register Char **ep = STR_environ; 1150: register Char *cp, *dp; 1151: Char *blk[2]; 1152: Char **oep = ep; 1153: 1154: 1155: for (; *ep; ep++) { 1156: for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1157: continue; 1158: if (*cp != 0 || *dp != '=') 1159: continue; 1160: cp = Strspl(STRequal, val); 1161: xfree((ptr_t) * ep); 1162: *ep = strip(Strspl(name, cp)); 1163: xfree((ptr_t) cp); 1164: blkfree((Char **) environ); 1165: environ = short2blk(STR_environ); 1166: return; 1167: } 1168: cp = Strspl(name, STRequal); 1169: blk[0] = strip(Strspl(cp, val)); 1170: xfree((ptr_t) cp); 1171: blk[1] = 0; 1172: STR_environ = blkspl(STR_environ, blk); 1173: blkfree((Char **) environ); 1174: environ = short2blk(STR_environ); 1175: xfree((ptr_t) oep); 1176: #endif /* SETENV_IN_LIB */ 1177: } 1178: 1179: static void 1180: Unsetenv(name) 1181: Char *name; 1182: { 1183: register Char **ep = STR_environ; 1184: register Char *cp, *dp; 1185: Char **oep = ep; 1186: 1187: for (; *ep; ep++) { 1188: for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1189: continue; 1190: if (*cp != 0 || *dp != '=') 1191: continue; 1192: cp = *ep; 1193: *ep = 0; 1194: STR_environ = blkspl(STR_environ, ep + 1); 1195: environ = short2blk(STR_environ); 1196: *ep = cp; 1197: xfree((ptr_t) cp); 1198: xfree((ptr_t) oep); 1199: return; 1200: } 1201: } 1202: 1203: void 1204: doumask(v) 1205: register Char **v; 1206: { 1207: register Char *cp = v[1]; 1208: register int i; 1209: 1210: if (cp == 0) { 1211: i = umask(0); 1212: (void) umask(i); 1213: xprintf("%o\n", i); 1214: return; 1215: } 1216: i = 0; 1217: while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1218: i = i * 8 + *cp++ - '0'; 1219: if (*cp || i < 0 || i > 0777) 1220: stderror(ERR_NAME | ERR_MASK); 1221: (void) umask(i); 1222: } 1223: 1224: #ifndef BSDTIMES 1225: typedef long RLIM_TYPE; 1226: 1227: #ifndef RLIM_INFINITY 1228: extern RLIM_TYPE ulimit(); 1229: 1230: #define RLIM_INFINITY 0x003fffff 1231: #define RLIMIT_FSIZE 1 1232: #endif /* RLIM_INFINITY */ 1233: #ifdef aiws 1234: #define toset(a) (((a) == 3) ? 1004 : (a) + 1) 1235: #define RLIMIT_STACK 1005 1236: #else /* aiws */ 1237: #define toset(a) ((a) + 1) 1238: #endif /* aiws */ 1239: #else /* BSDTIMES */ 1240: typedef int RLIM_TYPE; 1241: 1242: #endif /* BSDTIMES */ 1243: 1244: 1245: static struct limits { 1246: int limconst; 1247: char *limname; 1248: int limdiv; 1249: char *limscale; 1250: } limits[] = { 1251: 1252: #ifdef RLIMIT_CPU 1253: RLIMIT_CPU, "cputime", 1, "seconds", 1254: #endif /* RLIMIT_CPU */ 1255: 1256: #ifdef RLIMIT_FSIZE 1257: RLIMIT_FSIZE, "filesize", 1024, "kbytes", 1258: #endif /* RLIMIT_FSIZE */ 1259: 1260: #ifdef RLIMIT_DATA 1261: RLIMIT_DATA, "datasize", 1024, "kbytes", 1262: #endif /* RLIMIT_DATA */ 1263: 1264: #ifdef RLIMIT_STACK 1265: RLIMIT_STACK, "stacksize", 1024, "kbytes", 1266: #endif /* RLIMIT_STACK */ 1267: 1268: #ifdef RLIMIT_CORE 1269: RLIMIT_CORE, "coredumpsize", 1024, "kbytes", 1270: #endif /* RLIMIT_CORE */ 1271: 1272: #ifdef RLIMIT_RSS 1273: RLIMIT_RSS, "memoryuse", 1024, "kbytes", 1274: #endif /* RLIMIT_RSS */ 1275: 1276: #ifdef RLIMIT_NOFILE 1277: RLIMIT_NOFILE, "descriptors", 1, "", 1278: #endif 1279: 1280: #ifdef RLIMIT_CONCUR 1281: RLIMIT_CONCUR, "concurrency", 1, "thread(s)", 1282: #endif 1283: 1284: #ifdef RLIMIT_MEMLOCK 1285: RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes", 1286: #endif 1287: 1288: #ifdef RLIMIT_NPROC 1289: RLIMIT_NPROC, "maxproc", 1, "", 1290: #endif 1291: 1292: #ifdef RLIMIT_OFILE 1293: RLIMIT_OFILE, "openfiles", 1, "", 1294: #endif 1295: 1296: -1, NULL, 0, NULL 1297: }; 1298: 1299: static struct limits *findlim(); 1300: static RLIM_TYPE getval(); 1301: static void limtail(); 1302: static void plim(); 1303: static int setlim(); 1304: 1305: #if defined(convex) || defined(__convex__) 1306: static RLIM_TYPE 1307: restrict_limit(value) 1308: double value; 1309: { 1310: /* 1311: * is f too large to cope with? return the maximum or minimum int 1312: */ 1313: if (value > (double) INT_MAX) 1314: return (INT_MAX); 1315: else if (value < (double) INT_MIN) 1316: return (INT_MIN); 1317: else 1318: return ((int) value); 1319: } 1320: #endif /* convex */ 1321: 1322: 1323: static struct limits * 1324: findlim(cp) 1325: Char *cp; 1326: { 1327: register struct limits *lp, *res; 1328: 1329: res = (struct limits *) NULL; 1330: for (lp = limits; lp->limconst >= 0; lp++) 1331: if (prefix(cp, str2short(lp->limname))) { 1332: if (res) 1333: stderror(ERR_NAME | ERR_AMBIG); 1334: res = lp; 1335: } 1336: if (res) 1337: return (res); 1338: stderror(ERR_NAME | ERR_LIMIT); 1339: /* NOTREACHED */ 1340: return (0); 1341: } 1342: 1343: void 1344: dolimit(v) 1345: register Char **v; 1346: { 1347: register struct limits *lp; 1348: register RLIM_TYPE limit; 1349: char hard = 0; 1350: 1351: v++; 1352: if (*v && eq(*v, STRmh)) { 1353: hard = 1; 1354: v++; 1355: } 1356: if (*v == 0) { 1357: for (lp = limits; lp->limconst >= 0; lp++) 1358: plim(lp, hard); 1359: return; 1360: } 1361: lp = findlim(v[0]); 1362: if (v[1] == 0) { 1363: plim(lp, hard); 1364: return; 1365: } 1366: limit = getval(lp, v + 1); 1367: if (setlim(lp, hard, limit) < 0) 1368: stderror(ERR_SILENT); 1369: } 1370: 1371: static RLIM_TYPE 1372: getval(lp, v) 1373: register struct limits *lp; 1374: Char **v; 1375: { 1376: #if defined(convex) || defined(__convex__) 1377: RLIM_TYPE restrict_limit(); 1378: #endif /* convex */ 1379: 1380: register float f; 1381: double atof(); 1382: Char *cp = *v++; 1383: 1384: f = atof(short2str(cp)); 1385: 1386: #if defined(convex)||defined(__convex__) 1387: /* 1388: * is f too large to cope with. limit f to minint, maxint - X-6768 by 1389: * strike 1390: */ 1391: if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) { 1392: stderror(ERR_NAME | ERR_TOOLARGE); 1393: } 1394: #endif /* convex */ 1395: 1396: while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 1397: cp++; 1398: if (*cp == 0) { 1399: if (*v == 0) 1400: #if defined(convex) || defined(__convex__) 1401: return ((RLIM_TYPE) restrict_limit((f + 0.5) * lp->limdiv)); 1402: #else /* convex */ 1403: return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv)); 1404: #endif /* convex */ 1405: cp = *v; 1406: } 1407: switch (*cp) { 1408: #ifdef RLIMIT_CPU 1409: case ':': 1410: if (lp->limconst != RLIMIT_CPU) 1411: goto badscal; 1412: #if defined(convex) || defined(__convex__) 1413: return ((RLIM_TYPE) 1414: restrict_limit((f * 60.0 + atof(short2str(cp + 1))))); 1415: #else /* convex */ 1416: return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1)))); 1417: #endif /* convex */ 1418: case 'h': 1419: if (lp->limconst != RLIMIT_CPU) 1420: goto badscal; 1421: limtail(cp, "hours"); 1422: f *= 3600.0; 1423: break; 1424: case 'm': 1425: if (lp->limconst == RLIMIT_CPU) { 1426: limtail(cp, "minutes"); 1427: f *= 60.0; 1428: break; 1429: } 1430: *cp = 'm'; 1431: limtail(cp, "megabytes"); 1432: f *= 1024.0 * 1024.0; 1433: break; 1434: case 's': 1435: if (lp->limconst != RLIMIT_CPU) 1436: goto badscal; 1437: limtail(cp, "seconds"); 1438: break; 1439: #endif /* RLIMIT_CPU */ 1440: case 'M': 1441: #ifdef RLIMIT_CPU 1442: if (lp->limconst == RLIMIT_CPU) 1443: goto badscal; 1444: #endif /* RLIMIT_CPU */ 1445: *cp = 'm'; 1446: limtail(cp, "megabytes"); 1447: f *= 1024.0 * 1024.0; 1448: break; 1449: case 'k': 1450: #ifdef RLIMIT_CPU 1451: if (lp->limconst == RLIMIT_CPU) 1452: goto badscal; 1453: #endif /* RLIMIT_CPU */ 1454: limtail(cp, "kbytes"); 1455: f *= 1024.0; 1456: break; 1457: case 'u': 1458: limtail(cp, "unlimited"); 1459: return (RLIM_INFINITY); 1460: default: 1461: #ifdef RLIMIT_CPU 1462: badscal: 1463: #endif /* RLIMIT_CPU */ 1464: stderror(ERR_NAME | ERR_SCALEF); 1465: } 1466: #if defined(convex) || defined(__convex__) 1467: return ((RLIM_TYPE) restrict_limit((f + 0.5))); 1468: #else 1469: return ((RLIM_TYPE) (f + 0.5)); 1470: #endif 1471: } 1472: 1473: static void 1474: limtail(cp, str) 1475: Char *cp; 1476: char *str; 1477: { 1478: while (*cp && *cp == *str) 1479: cp++, str++; 1480: if (*cp) 1481: stderror(ERR_BADSCALE, str); 1482: } 1483: 1484: 1485: /*ARGSUSED*/ 1486: static void 1487: plim(lp, hard) 1488: register struct limits *lp; 1489: Char hard; 1490: { 1491: #ifdef BSDTIMES 1492: struct rlimit rlim; 1493: 1494: #endif /* BSDTIMES */ 1495: RLIM_TYPE limit; 1496: 1497: xprintf("%s \t", lp->limname); 1498: 1499: #ifndef BSDTIMES 1500: limit = ulimit(lp->limconst, 0); 1501: #else /* BSDTIMES */ 1502: (void) getrlimit(lp->limconst, &rlim); 1503: limit = hard ? rlim.rlim_max : rlim.rlim_cur; 1504: #endif /* BSDTIMES */ 1505: 1506: if (limit == RLIM_INFINITY) 1507: xprintf("unlimited"); 1508: #ifdef RLIMIT_CPU 1509: else if (lp->limconst == RLIMIT_CPU) 1510: psecs((long) limit); 1511: #endif /* RLIMIT_CPU */ 1512: else 1513: #ifndef BSDTIMES 1514: if (lp->limconst == RLIMIT_FSIZE) 1515: /* 1516: * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024 1517: * blocks. Note we cannot pre-multiply cause we might overflow (A/UX) 1518: */ 1519: xprintf("%ld %s", (long) (limit / 2), lp->limscale); 1520: else 1521: #endif /* BSDTIMES */ 1522: xprintf("%ld %s", (long) (limit / lp->limdiv), lp->limscale); 1523: xprintf("\n"); 1524: } 1525: 1526: void 1527: dounlimit(v) 1528: register Char **v; 1529: { 1530: register struct limits *lp; 1531: int lerr = 0; 1532: Char hard = 0; 1533: 1534: v++; 1535: if (*v && eq(*v, STRmh)) { 1536: hard = 1; 1537: v++; 1538: } 1539: if (*v == 0) { 1540: for (lp = limits; lp->limconst >= 0; lp++) 1541: if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 1542: lerr++; 1543: if (lerr) 1544: stderror(ERR_SILENT); 1545: return; 1546: } 1547: while (*v) { 1548: lp = findlim(*v++); 1549: if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 1550: stderror(ERR_SILENT); 1551: } 1552: } 1553: 1554: static int 1555: setlim(lp, hard, limit) 1556: register struct limits *lp; 1557: Char hard; 1558: RLIM_TYPE limit; 1559: { 1560: #ifdef BSDTIMES 1561: struct rlimit rlim; 1562: 1563: (void) getrlimit(lp->limconst, &rlim); 1564: 1565: if (hard) 1566: rlim.rlim_max = limit; 1567: else if (limit == RLIM_INFINITY && geteuid() != 0) 1568: rlim.rlim_cur = rlim.rlim_max; 1569: else 1570: rlim.rlim_cur = limit; 1571: 1572: if (setrlimit(lp->limconst, &rlim) < 0) { 1573: #else /* BSDTIMES */ 1574: if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE) 1575: limit /= 512; 1576: if (ulimit(toset(lp->limconst), limit) < 0) { 1577: #endif /* BSDTIMES */ 1578: xprintf("%s: %s: Can't %s%s limit\n", bname, lp->limname, 1579: limit == RLIM_INFINITY ? "remove" : "set", 1580: hard ? " hard" : ""); 1581: return (-1); 1582: } 1583: return (0); 1584: } 1585: 1586: void 1587: dosuspend() 1588: { 1589: int ctpgrp; 1590: sigmask_t omask; 1591: 1592: sigret_t(*old) (); 1593: 1594: if (loginsh) 1595: stderror(ERR_SUSPLOG); 1596: untty(); 1597: 1598: #ifdef BSDJOBS 1599: old = signal(SIGTSTP, SIG_DFL); 1600: #ifndef pdp11 1601: (void) kill(0, SIGTSTP); 1602: #else 1603: (void) kill(0, SIGSTOP); /* jpn: TSTP doesn't do anything. why? */ 1604: #endif 1605: /* the shell stops here */ 1606: (void) signal(SIGTSTP, old); 1607: #else 1608: stderror(ERR_JOBCONTROL); 1609: #endif /* BSDJOBS */ 1610: 1611: #ifdef BSDJOBS 1612: if (tpgrp != -1) { 1613: retry: 1614: ctpgrp = tcgetpgrp(FSHTTY); 1615: if (ctpgrp != opgrp) { 1616: old = signal(SIGTTIN, SIG_DFL); 1617: (void) kill(0, SIGTTIN); 1618: (void) signal(SIGTTIN, old); 1619: goto retry; 1620: } 1621: (void) setpgid(0, shpgrp); 1622: (void) tcsetpgrp(FSHTTY, shpgrp); 1623: } 1624: #endif /* BSDJOBS */ 1625: (void) setdisc(FSHTTY); 1626: } 1627: 1628: /* This is the dreaded EVAL built-in. 1629: * If you don't fiddle with file descriptors, and reset didfds, 1630: * this command will either ignore redirection inside or outside 1631: * its aguments, e.g. eval "date >x" vs. eval "date" >x 1632: * The stuff here seems to work, but I did it by trial and error rather 1633: * than really knowing what was going on. If tpgrp is zero, we are 1634: * probably a background eval, e.g. "eval date &", and we want to 1635: * make sure that any processes we start stay in our pgrp. 1636: * This is also the case for "time eval date" -- stay in same pgrp. 1637: * Otherwise, under stty tostop, processes will stop in the wrong 1638: * pgrp, with no way for the shell to get them going again. -IAN! 1639: */ 1640: static Char **gv = NULL; 1641: void 1642: doeval(v) 1643: Char **v; 1644: { 1645: Char **oevalvec; 1646: Char *oevalp; 1647: int odidfds; 1648: 1649: #ifndef FIOCLEX 1650: int odidcch; 1651: 1652: #endif /* FIOCLEX */ 1653: jmp_buf osetexit; 1654: int my_reenter; 1655: Char **savegv; 1656: int saveIN; 1657: int saveOUT; 1658: int saveDIAG; 1659: int oSHIN; 1660: int oSHOUT; 1661: int oSHDIAG; 1662: 1663: oevalvec = evalvec; 1664: oevalp = evalp; 1665: odidfds = didfds; 1666: #ifndef FIOCLEX 1667: odidcch = didcch; 1668: #endif /* FIOCLEX */ 1669: oSHIN = SHIN; 1670: oSHOUT = SHOUT; 1671: oSHDIAG = SHDIAG; 1672: 1673: savegv = gv; 1674: 1675: v++; 1676: if (*v == 0) 1677: return; 1678: gflag = 0, tglob(v); 1679: if (gflag) { 1680: gv = v = globall(v); 1681: gargv = 0; 1682: if (v == 0) 1683: stderror(ERR_NOMATCH); 1684: v = copyblk(v); 1685: } 1686: else { 1687: gv = NULL; 1688: v = copyblk(v); 1689: trim(v); 1690: } 1691: 1692: saveIN = dcopy(SHIN, -1); 1693: saveOUT = dcopy(SHOUT, -1); 1694: saveDIAG = dcopy(SHDIAG, -1); 1695: 1696: getexit(osetexit); 1697: 1698: /* PWP: setjmp/longjmp bugfix for optimizing comp_rs */ 1699: if ((my_reenter = setexit()) == 0) { 1700: evalvec = v; 1701: evalp = 0; 1702: SHIN = dcopy(0, -1); 1703: SHOUT = dcopy(1, -1); 1704: SHDIAG = dcopy(2, -1); 1705: #ifndef FIOCLEX 1706: didcch = 0; 1707: #endif /* FIOCLEX */ 1708: didfds = 0; 1709: process(0); 1710: } 1711: 1712: evalvec = oevalvec; 1713: evalp = oevalp; 1714: doneinp = 0; 1715: #ifndef FIOCLEX 1716: didcch = odidcch; 1717: #endif /* FIOCLEX */ 1718: didfds = odidfds; 1719: (void) close(SHIN); 1720: (void) close(SHOUT); 1721: (void) close(SHDIAG); 1722: SHIN = dmove(saveIN, oSHIN); 1723: SHOUT = dmove(saveOUT, oSHOUT); 1724: SHDIAG = dmove(saveDIAG, oSHDIAG); 1725: 1726: if (gv) 1727: blkfree(gv); 1728: 1729: gv = savegv; 1730: resexit(osetexit); 1731: if (my_reenter) 1732: stderror(ERR_SILENT); 1733: }