1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley Software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if !defined(lint) && defined(DOSCCS) 8: static char *sccsid = "@(#)sh.lex.c 5.4 (Berkeley) 3/29/86"; 9: #endif 10: 11: #include "sh.h" 12: #include <sgtty.h> 13: 14: /* 15: * C shell 16: */ 17: 18: /* 19: * These lexical routines read input and form lists of words. 20: * There is some involved processing here, because of the complications 21: * of input buffering, and especially because of history substitution. 22: */ 23: 24: char *word(); 25: 26: /* 27: * Peekc is a peek characer for getC, peekread for readc. 28: * There is a subtlety here in many places... history routines 29: * will read ahead and then insert stuff into the input stream. 30: * If they push back a character then they must push it behind 31: * the text substituted by the history substitution. On the other 32: * hand in several places we need 2 peek characters. To make this 33: * all work, the history routines read with getC, and make use both 34: * of ungetC and unreadc. The key observation is that the state 35: * of getC at the call of a history reference is such that calls 36: * to getC from the history routines will always yield calls of 37: * readc, unless this peeking is involved. That is to say that during 38: * getexcl the variables lap, exclp, and exclnxt are all zero. 39: * 40: * Getdol invokes history substitution, hence the extra peek, peekd, 41: * which it can ungetD to be before history substitutions. 42: */ 43: char peekc, peekd; 44: char peekread; 45: 46: char *exclp; /* (Tail of) current word from ! subst */ 47: struct wordent *exclnxt; /* The rest of the ! subst words */ 48: int exclc; /* Count of remainig words in ! subst */ 49: char *alvecp; /* "Globp" for alias resubstitution */ 50: 51: /* 52: * Lex returns to its caller not only a wordlist (as a "var" parameter) 53: * but also whether a history substitution occurred. This is used in 54: * the main (process) routine to determine whether to echo, and also 55: * when called by the alias routine to determine whether to keep the 56: * argument list. 57: */ 58: bool hadhist; 59: 60: char getCtmp; 61: #define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f)) 62: #define ungetC(c) peekc = c 63: #define ungetD(c) peekd = c 64: 65: lex(hp) 66: register struct wordent *hp; 67: { 68: register struct wordent *wdp; 69: int c; 70: 71: lineloc = btell(); 72: hp->next = hp->prev = hp; 73: hp->word = ""; 74: alvecp = 0, hadhist = 0; 75: do 76: c = readc(0); 77: while (c == ' ' || c == '\t'); 78: if (c == HISTSUB && intty) 79: /* ^lef^rit from tty is short !:s^lef^rit */ 80: getexcl(c); 81: else 82: unreadc(c); 83: wdp = hp; 84: /* 85: * The following loop is written so that the links needed 86: * by freelex will be ready and rarin to go even if it is 87: * interrupted. 88: */ 89: do { 90: register struct wordent *new = (struct wordent *) xalloc(sizeof *wdp); 91: 92: new->word = 0; 93: new->prev = wdp; 94: new->next = hp; 95: wdp->next = new; 96: wdp = new; 97: wdp->word = word(); 98: } while (wdp->word[0] != '\n'); 99: hp->prev = wdp; 100: return (hadhist); 101: } 102: 103: prlex(sp0) 104: struct wordent *sp0; 105: { 106: register struct wordent *sp = sp0->next; 107: 108: for (;;) { 109: printf("%s", sp->word); 110: sp = sp->next; 111: if (sp == sp0) 112: break; 113: if (sp->word[0] != '\n') 114: putchar(' '); 115: } 116: } 117: 118: copylex(hp, fp) 119: register struct wordent *hp; 120: register struct wordent *fp; 121: { 122: register struct wordent *wdp; 123: 124: wdp = hp; 125: fp = fp->next; 126: do { 127: register struct wordent *new = (struct wordent *) xalloc(sizeof *wdp); 128: 129: new->prev = wdp; 130: new->next = hp; 131: wdp->next = new; 132: wdp = new; 133: wdp->word = savestr(fp->word); 134: fp = fp->next; 135: } while (wdp->word[0] != '\n'); 136: hp->prev = wdp; 137: } 138: 139: freelex(vp) 140: register struct wordent *vp; 141: { 142: register struct wordent *fp; 143: 144: while (vp->next != vp) { 145: fp = vp->next; 146: vp->next = fp->next; 147: XFREE(fp->word) 148: XFREE((char *)fp) 149: } 150: vp->prev = vp; 151: } 152: 153: char * 154: word() 155: { 156: register char c, c1; 157: register char *wp; 158: char wbuf[BUFSIZ]; 159: register bool dolflg; 160: register int i; 161: 162: wp = wbuf; 163: i = BUFSIZ - 4; 164: loop: 165: while ((c = getC(DOALL)) == ' ' || c == '\t') 166: ; 167: if (cmap(c, _META|_ESC)) 168: switch (c) { 169: case '&': 170: case '|': 171: case '<': 172: case '>': 173: *wp++ = c; 174: c1 = getC(DOALL); 175: if (c1 == c) 176: *wp++ = c1; 177: else 178: ungetC(c1); 179: goto ret; 180: 181: case '#': 182: if (intty) 183: break; 184: c = 0; 185: do { 186: c1 = c; 187: c = getC(0); 188: } while (c != '\n'); 189: if (c1 == '\\') 190: goto loop; 191: /* fall into ... */ 192: 193: case ';': 194: case '(': 195: case ')': 196: case '\n': 197: *wp++ = c; 198: goto ret; 199: 200: case '\\': 201: c = getC(0); 202: if (c == '\n') { 203: if (onelflg == 1) 204: onelflg = 2; 205: goto loop; 206: } 207: if (c != HIST) 208: *wp++ = '\\', --i; 209: c |= QUOTE; 210: } 211: c1 = 0; 212: dolflg = DOALL; 213: for (;;) { 214: if (c1) { 215: if (c == c1) { 216: c1 = 0; 217: dolflg = DOALL; 218: } else if (c == '\\') { 219: c = getC(0); 220: if (c == HIST) 221: c |= QUOTE; 222: else { 223: if (c == '\n') 224: /* 225: if (c1 == '`') 226: c = ' '; 227: else 228: */ 229: c |= QUOTE; 230: ungetC(c); 231: c = '\\'; 232: } 233: } else if (c == '\n') { 234: seterrc("Unmatched ", c1); 235: ungetC(c); 236: break; 237: } 238: } else if (cmap(c, _META|_Q|_Q1|_ESC)) { 239: if (c == '\\') { 240: c = getC(0); 241: if (c == '\n') { 242: if (onelflg == 1) 243: onelflg = 2; 244: break; 245: } 246: if (c != HIST) 247: *wp++ = '\\', --i; 248: c |= QUOTE; 249: } else if (cmap(c, _Q|_Q1)) { /* '"` */ 250: c1 = c; 251: dolflg = c == '"' ? DOALL : DOEXCL; 252: } else if (c != '#' || !intty) { 253: ungetC(c); 254: break; 255: } 256: } 257: if (--i > 0) { 258: *wp++ = c; 259: c = getC(dolflg); 260: } else { 261: seterr("Word too long"); 262: wp = &wbuf[1]; 263: break; 264: } 265: } 266: ret: 267: *wp = 0; 268: return (savestr(wbuf)); 269: } 270: 271: getC1(flag) 272: register int flag; 273: { 274: register char c; 275: 276: top: 277: if (c = peekc) { 278: peekc = 0; 279: return (c); 280: } 281: if (lap) { 282: if ((c = *lap++) == 0) 283: lap = 0; 284: else { 285: if (cmap(c, _META|_Q|_Q1)) 286: c |= QUOTE; 287: return (c); 288: } 289: } 290: if (c = peekd) { 291: peekd = 0; 292: return (c); 293: } 294: if (exclp) { 295: if (c = *exclp++) 296: return (c); 297: if (exclnxt && --exclc >= 0) { 298: exclnxt = exclnxt->next; 299: setexclp(exclnxt->word); 300: return (' '); 301: } 302: exclp = 0; 303: exclnxt = 0; 304: } 305: if (exclnxt) { 306: exclnxt = exclnxt->next; 307: if (--exclc < 0) 308: exclnxt = 0; 309: else 310: setexclp(exclnxt->word); 311: goto top; 312: } 313: c = readc(0); 314: if (c == '$' && (flag & DODOL)) { 315: getdol(); 316: goto top; 317: } 318: if (c == HIST && (flag & DOEXCL)) { 319: getexcl(0); 320: goto top; 321: } 322: return (c); 323: } 324: 325: getdol() 326: { 327: register char *np; 328: char name[40]; 329: register int c; 330: int sc; 331: bool special = 0; 332: 333: np = name, *np++ = '$'; 334: c = sc = getC(DOEXCL); 335: if (any(c, "\t \n")) { 336: ungetD(c); 337: ungetC('$' | QUOTE); 338: return; 339: } 340: if (c == '{') 341: *np++ = c, c = getC(DOEXCL); 342: if (c == '#' || c == '?') 343: special++, *np++ = c, c = getC(DOEXCL); 344: *np++ = c; 345: switch (c) { 346: 347: case '<': 348: case '$': 349: if (special) 350: goto vsyn; 351: goto ret; 352: 353: case '\n': 354: ungetD(c); 355: np--; 356: goto vsyn; 357: 358: case '*': 359: if (special) 360: goto vsyn; 361: goto ret; 362: 363: default: 364: if (digit(c)) { 365: /* 366: * let $?0 pass for now 367: if (special) 368: goto vsyn; 369: */ 370: while (digit(c = getC(DOEXCL))) { 371: if (np < &name[sizeof name / 2]) 372: *np++ = c; 373: } 374: } else if (letter(c)) 375: while (letter(c = getC(DOEXCL))) { 376: if (np < &name[sizeof name / 2]) 377: *np++ = c; 378: } 379: else 380: goto vsyn; 381: } 382: if (c == '[') { 383: *np++ = c; 384: do { 385: c = getC(DOEXCL); 386: if (c == '\n') { 387: ungetD(c); 388: np--; 389: goto vsyn; 390: } 391: if (np >= &name[sizeof name - 8]) 392: goto vsyn; 393: *np++ = c; 394: } while (c != ']'); 395: c = getC(DOEXCL); 396: } 397: if (c == ':') { 398: *np++ = c, c = getC(DOEXCL); 399: if (c == 'g') 400: *np++ = c, c = getC(DOEXCL); 401: *np++ = c; 402: if (!any(c, "htrqxe")) 403: goto vsyn; 404: } else 405: ungetD(c); 406: if (sc == '{') { 407: c = getC(DOEXCL); 408: if (c != '}') { 409: ungetC(c); 410: goto vsyn; 411: } 412: *np++ = c; 413: } 414: ret: 415: *np = 0; 416: addla(name); 417: return; 418: 419: vsyn: 420: seterr("Variable syntax"); 421: goto ret; 422: } 423: 424: addla(cp) 425: char *cp; 426: { 427: char buf[BUFSIZ]; 428: 429: if (lap != 0 && strlen(cp) + strlen(lap) >= sizeof (labuf) - 4) { 430: seterr("Expansion buf ovflo"); 431: return; 432: } 433: if (lap) 434: (void) strcpy(buf, lap); 435: (void) strcpy(labuf, cp); 436: if (lap) 437: (void) strcat(labuf, buf); 438: lap = labuf; 439: } 440: 441: char lhsb[32]; 442: char slhs[32]; 443: char rhsb[64]; 444: int quesarg; 445: 446: getexcl(sc) 447: char sc; 448: { 449: register struct wordent *hp, *ip; 450: int left, right, dol; 451: register int c; 452: 453: if (sc == 0) { 454: sc = getC(0); 455: if (sc != '{') { 456: ungetC(sc); 457: sc = 0; 458: } 459: } 460: quesarg = -1; 461: lastev = eventno; 462: hp = gethent(sc); 463: if (hp == 0) 464: return; 465: hadhist = 1; 466: dol = 0; 467: if (hp == alhistp) 468: for (ip = hp->next->next; ip != alhistt; ip = ip->next) 469: dol++; 470: else 471: for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 472: dol++; 473: left = 0, right = dol; 474: if (sc == HISTSUB) { 475: ungetC('s'), unreadc(HISTSUB), c = ':'; 476: goto subst; 477: } 478: c = getC(0); 479: if (!any(c, ":^$*-%")) 480: goto subst; 481: left = right = -1; 482: if (c == ':') { 483: c = getC(0); 484: unreadc(c); 485: if (letter(c) || c == '&') { 486: c = ':'; 487: left = 0, right = dol; 488: goto subst; 489: } 490: } else 491: ungetC(c); 492: if (!getsel(&left, &right, dol)) 493: return; 494: c = getC(0); 495: if (c == '*') 496: ungetC(c), c = '-'; 497: if (c == '-') { 498: if (!getsel(&left, &right, dol)) 499: return; 500: c = getC(0); 501: } 502: subst: 503: exclc = right - left + 1; 504: while (--left >= 0) 505: hp = hp->next; 506: if (sc == HISTSUB || c == ':') { 507: do { 508: hp = getsub(hp); 509: c = getC(0); 510: } while (c == ':'); 511: } 512: unreadc(c); 513: if (sc == '{') { 514: c = getC(0); 515: if (c != '}') 516: seterr("Bad ! form"); 517: } 518: exclnxt = hp; 519: } 520: 521: struct wordent * 522: getsub(en) 523: struct wordent *en; 524: { 525: register char *cp; 526: int delim; 527: register int c; 528: int sc; 529: bool global = 0; 530: char orhsb[sizeof rhsb]; 531: 532: exclnxt = 0; 533: sc = c = getC(0); 534: if (c == 'g') 535: global++, c = getC(0); 536: switch (c) { 537: 538: case 'p': 539: justpr++; 540: goto ret; 541: 542: case 'x': 543: case 'q': 544: global++; 545: /* fall into ... */ 546: 547: case 'h': 548: case 'r': 549: case 't': 550: case 'e': 551: break; 552: 553: case '&': 554: if (slhs[0] == 0) { 555: seterr("No prev sub"); 556: goto ret; 557: } 558: (void) strcpy(lhsb, slhs); 559: break; 560: 561: /* 562: case '~': 563: if (lhsb[0] == 0) 564: goto badlhs; 565: break; 566: */ 567: 568: case 's': 569: delim = getC(0); 570: if (letter(delim) || digit(delim) || any(delim, " \t\n")) { 571: unreadc(delim); 572: bads: 573: lhsb[0] = 0; 574: seterr("Bad substitute"); 575: goto ret; 576: } 577: cp = lhsb; 578: for (;;) { 579: c = getC(0); 580: if (c == '\n') { 581: unreadc(c); 582: break; 583: } 584: if (c == delim) 585: break; 586: if (cp > &lhsb[sizeof lhsb - 2]) 587: goto bads; 588: if (c == '\\') { 589: c = getC(0); 590: if (c != delim && c != '\\') 591: *cp++ = '\\'; 592: } 593: *cp++ = c; 594: } 595: if (cp != lhsb) 596: *cp++ = 0; 597: else if (lhsb[0] == 0) { 598: /*badlhs:*/ 599: seterr("No prev lhs"); 600: goto ret; 601: } 602: cp = rhsb; 603: (void) strcpy(orhsb, cp); 604: for (;;) { 605: c = getC(0); 606: if (c == '\n') { 607: unreadc(c); 608: break; 609: } 610: if (c == delim) 611: break; 612: /* 613: if (c == '~') { 614: if (&cp[strlen(orhsb)] > &rhsb[sizeof rhsb - 2]) 615: goto toorhs; 616: (void) strcpy(cp, orhsb); 617: cp = strend(cp); 618: continue; 619: } 620: */ 621: if (cp > &rhsb[sizeof rhsb - 2]) { 622: /*toorhs:*/ 623: seterr("Rhs too long"); 624: goto ret; 625: } 626: if (c == '\\') { 627: c = getC(0); 628: if (c != delim /* && c != '~' */) 629: *cp++ = '\\'; 630: } 631: *cp++ = c; 632: } 633: *cp++ = 0; 634: break; 635: 636: default: 637: if (c == '\n') 638: unreadc(c); 639: seterrc("Bad ! modifier: ", c); 640: goto ret; 641: } 642: (void) strcpy(slhs, lhsb); 643: if (exclc) 644: en = dosub(sc, en, global); 645: ret: 646: return (en); 647: } 648: 649: struct wordent * 650: dosub(sc, en, global) 651: int sc; 652: struct wordent *en; 653: bool global; 654: { 655: struct wordent lex; 656: bool didsub = 0; 657: struct wordent *hp = &lex; 658: register struct wordent *wdp; 659: register int i = exclc; 660: 661: wdp = hp; 662: while (--i >= 0) { 663: register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp); 664: 665: new->prev = wdp; 666: new->next = hp; 667: wdp->next = new; 668: wdp = new; 669: en = en->next; 670: wdp->word = global || didsub == 0 ? 671: subword(en->word, sc, &didsub) : savestr(en->word); 672: } 673: if (didsub == 0) 674: seterr("Modifier failed"); 675: hp->prev = wdp; 676: return (&enthist(-1000, &lex, 0)->Hlex); 677: } 678: 679: char * 680: subword(cp, type, adid) 681: char *cp; 682: int type; 683: bool *adid; 684: { 685: char wbuf[BUFSIZ]; 686: register char *wp, *mp, *np; 687: register int i; 688: 689: switch (type) { 690: 691: case 'r': 692: case 'e': 693: case 'h': 694: case 't': 695: case 'q': 696: case 'x': 697: wp = domod(cp, type); 698: if (wp == 0) 699: return (savestr(cp)); 700: *adid = 1; 701: return (wp); 702: 703: default: 704: wp = wbuf; 705: i = BUFSIZ - 4; 706: for (mp = cp; *mp; mp++) 707: if (matchs(mp, lhsb)) { 708: for (np = cp; np < mp;) 709: *wp++ = *np++, --i; 710: for (np = rhsb; *np; np++) switch (*np) { 711: 712: case '\\': 713: if (np[1] == '&') 714: np++; 715: /* fall into ... */ 716: 717: default: 718: if (--i < 0) 719: goto ovflo; 720: *wp++ = *np; 721: continue; 722: 723: case '&': 724: i -= strlen(lhsb); 725: if (i < 0) 726: goto ovflo; 727: *wp = 0; 728: (void) strcat(wp, lhsb); 729: wp = strend(wp); 730: continue; 731: } 732: mp += strlen(lhsb); 733: i -= strlen(mp); 734: if (i < 0) { 735: ovflo: 736: seterr("Subst buf ovflo"); 737: return (""); 738: } 739: *wp = 0; 740: (void) strcat(wp, mp); 741: *adid = 1; 742: return (savestr(wbuf)); 743: } 744: return (savestr(cp)); 745: } 746: } 747: 748: char * 749: domod(cp, type) 750: char *cp; 751: int type; 752: { 753: register char *wp, *xp; 754: register int c; 755: 756: switch (type) { 757: 758: case 'x': 759: case 'q': 760: wp = savestr(cp); 761: for (xp = wp; c = *xp; xp++) 762: if ((c != ' ' && c != '\t') || type == 'q') 763: *xp |= QUOTE; 764: return (wp); 765: 766: case 'h': 767: case 't': 768: if (!any('/', cp)) 769: return (type == 't' ? savestr(cp) : 0); 770: wp = strend(cp); 771: while (*--wp != '/') 772: continue; 773: if (type == 'h') 774: xp = savestr(cp), xp[wp - cp] = 0; 775: else 776: xp = savestr(wp + 1); 777: return (xp); 778: 779: case 'e': 780: case 'r': 781: wp = strend(cp); 782: for (wp--; wp >= cp && *wp != '/'; wp--) 783: if (*wp == '.') { 784: if (type == 'e') 785: xp = savestr(wp + 1); 786: else 787: xp = savestr(cp), xp[wp - cp] = 0; 788: return (xp); 789: } 790: return (savestr(type == 'e' ? "" : cp)); 791: } 792: return (0); 793: } 794: 795: matchs(str, pat) 796: register char *str, *pat; 797: { 798: 799: while (*str && *pat && *str == *pat) 800: str++, pat++; 801: return (*pat == 0); 802: } 803: 804: getsel(al, ar, dol) 805: register int *al, *ar; 806: int dol; 807: { 808: register int c = getC(0); 809: register int i; 810: bool first = *al < 0; 811: 812: switch (c) { 813: 814: case '%': 815: if (quesarg == -1) 816: goto bad; 817: if (*al < 0) 818: *al = quesarg; 819: *ar = quesarg; 820: break; 821: 822: case '-': 823: if (*al < 0) { 824: *al = 0; 825: *ar = dol - 1; 826: unreadc(c); 827: } 828: return (1); 829: 830: case '^': 831: if (*al < 0) 832: *al = 1; 833: *ar = 1; 834: break; 835: 836: case '$': 837: if (*al < 0) 838: *al = dol; 839: *ar = dol; 840: break; 841: 842: case '*': 843: if (*al < 0) 844: *al = 1; 845: *ar = dol; 846: if (*ar < *al) { 847: *ar = 0; 848: *al = 1; 849: return (1); 850: } 851: break; 852: 853: default: 854: if (digit(c)) { 855: i = 0; 856: while (digit(c)) { 857: i = i * 10 + c - '0'; 858: c = getC(0); 859: } 860: if (i < 0) 861: i = dol + 1; 862: if (*al < 0) 863: *al = i; 864: *ar = i; 865: } else 866: if (*al < 0) 867: *al = 0, *ar = dol; 868: else 869: *ar = dol - 1; 870: unreadc(c); 871: break; 872: } 873: if (first) { 874: c = getC(0); 875: unreadc(c); 876: if (any(c, "-$*")) 877: return (1); 878: } 879: if (*al > *ar || *ar > dol) { 880: bad: 881: seterr("Bad ! arg selector"); 882: return (0); 883: } 884: return (1); 885: 886: } 887: 888: struct wordent * 889: gethent(sc) 890: int sc; 891: { 892: register struct Hist *hp; 893: register char *np; 894: register int c; 895: int event; 896: bool back = 0; 897: 898: c = sc == HISTSUB ? HIST : getC(0); 899: if (c == HIST) { 900: if (alhistp) 901: return (alhistp); 902: event = eventno; 903: goto skip; 904: } 905: switch (c) { 906: 907: case ':': 908: case '^': 909: case '$': 910: case '*': 911: case '%': 912: ungetC(c); 913: if (lastev == eventno && alhistp) 914: return (alhistp); 915: event = lastev; 916: break; 917: 918: case '-': 919: back = 1; 920: c = getC(0); 921: goto number; 922: 923: case '#': /* !# is command being typed in (mrh) */ 924: return(¶ml); 925: 926: default: 927: if (any(c, "(=~")) { 928: unreadc(c); 929: ungetC(HIST); 930: return (0); 931: } 932: if (digit(c)) 933: goto number; 934: np = lhsb; 935: while (!any(c, ": \t\\\n}")) { 936: if (np < &lhsb[sizeof lhsb - 2]) 937: *np++ = c; 938: c = getC(0); 939: } 940: unreadc(c); 941: if (np == lhsb) { 942: ungetC(HIST); 943: return (0); 944: } 945: *np++ = 0; 946: hp = findev(lhsb, 0); 947: if (hp) 948: lastev = hp->Hnum; 949: return (&hp->Hlex); 950: 951: case '?': 952: np = lhsb; 953: for (;;) { 954: c = getC(0); 955: if (c == '\n') { 956: unreadc(c); 957: break; 958: } 959: if (c == '?') 960: break; 961: if (np < &lhsb[sizeof lhsb - 2]) 962: *np++ = c; 963: } 964: if (np == lhsb) { 965: if (lhsb[0] == 0) { 966: seterr("No prev search"); 967: return (0); 968: } 969: } else 970: *np++ = 0; 971: hp = findev(lhsb, 1); 972: if (hp) 973: lastev = hp->Hnum; 974: return (&hp->Hlex); 975: 976: number: 977: event = 0; 978: while (digit(c)) { 979: event = event * 10 + c - '0'; 980: c = getC(0); 981: } 982: if (back) 983: event = eventno + (alhistp == 0) - (event ? event : 0); 984: unreadc(c); 985: break; 986: } 987: skip: 988: for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 989: if (hp->Hnum == event) { 990: hp->Href = eventno; 991: lastev = hp->Hnum; 992: return (&hp->Hlex); 993: } 994: np = putn(event); 995: noev(np); 996: return (0); 997: } 998: 999: struct Hist * 1000: findev(cp, anyarg) 1001: char *cp; 1002: bool anyarg; 1003: { 1004: register struct Hist *hp; 1005: 1006: for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 1007: char *dp; 1008: register char *p, *q; 1009: register struct wordent *lp = hp->Hlex.next; 1010: int argno = 0; 1011: 1012: if (lp->word[0] == '\n') 1013: continue; 1014: if (!anyarg) { 1015: p = cp; 1016: q = lp->word; 1017: do 1018: if (!*p) 1019: return (hp); 1020: while (*p++ == *q++); 1021: continue; 1022: } 1023: do { 1024: for (dp = lp->word; *dp; dp++) { 1025: p = cp; 1026: q = dp; 1027: do 1028: if (!*p) { 1029: quesarg = argno; 1030: return (hp); 1031: } 1032: while (*p++ == *q++); 1033: } 1034: lp = lp->next; 1035: argno++; 1036: } while (lp->word[0] != '\n'); 1037: } 1038: noev(cp); 1039: return (0); 1040: } 1041: 1042: noev(cp) 1043: char *cp; 1044: { 1045: 1046: seterr2(cp, ": Event not found"); 1047: } 1048: 1049: setexclp(cp) 1050: register char *cp; 1051: { 1052: 1053: if (cp && cp[0] == '\n') 1054: return; 1055: exclp = cp; 1056: } 1057: 1058: unreadc(c) 1059: char c; 1060: { 1061: 1062: peekread = c; 1063: } 1064: 1065: readc(wanteof) 1066: bool wanteof; 1067: { 1068: register int c; 1069: static sincereal; 1070: 1071: if (c = peekread) { 1072: peekread = 0; 1073: return (c); 1074: } 1075: top: 1076: if (alvecp) { 1077: if (c = *alvecp++) 1078: return (c); 1079: if (*alvec) { 1080: alvecp = *alvec++; 1081: return (' '); 1082: } 1083: } 1084: if (alvec) { 1085: if (alvecp = *alvec) { 1086: alvec++; 1087: goto top; 1088: } 1089: /* Infinite source! */ 1090: return ('\n'); 1091: } 1092: if (evalp) { 1093: if (c = *evalp++) 1094: return (c); 1095: if (*evalvec) { 1096: evalp = *evalvec++; 1097: return (' '); 1098: } 1099: evalp = 0; 1100: } 1101: if (evalvec) { 1102: if (evalvec == (char **)1) { 1103: doneinp = 1; 1104: reset(); 1105: } 1106: if (evalp = *evalvec) { 1107: evalvec++; 1108: goto top; 1109: } 1110: evalvec = (char **)1; 1111: return ('\n'); 1112: } 1113: do { 1114: if (arginp == (char *) 1 || onelflg == 1) { 1115: if (wanteof) 1116: return (-1); 1117: exitstat(); 1118: } 1119: if (arginp) { 1120: if ((c = *arginp++) == 0) { 1121: arginp = (char *) 1; 1122: return ('\n'); 1123: } 1124: return (c); 1125: } 1126: reread: 1127: c = bgetc(); 1128: if (c < 0) { 1129: struct sgttyb tty; 1130: 1131: if (wanteof) 1132: return (-1); 1133: /* was isatty but raw with ignoreeof yields problems */ 1134: if (ioctl(SHIN, TIOCGETP, (char *)&tty) == 0 && 1135: (tty.sg_flags & RAW) == 0) { 1136: /* was 'short' for FILEC */ 1137: int ctpgrp; 1138: 1139: if (++sincereal > 25) 1140: goto oops; 1141: if (tpgrp != -1 && 1142: ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp) == 0 && 1143: tpgrp != ctpgrp) { 1144: (void) ioctl(FSHTTY, TIOCSPGRP, 1145: (char *)&tpgrp); 1146: (void) killpg(ctpgrp, SIGHUP); 1147: printf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp); 1148: goto reread; 1149: } 1150: if (adrof("ignoreeof")) { 1151: if (loginsh) 1152: printf("\nUse \"logout\" to logout.\n"); 1153: else 1154: printf("\nUse \"exit\" to leave csh.\n"); 1155: reset(); 1156: } 1157: if (chkstop == 0) 1158: panystop(1); 1159: } 1160: oops: 1161: doneinp = 1; 1162: reset(); 1163: } 1164: sincereal = 0; 1165: if (c == '\n' && onelflg) 1166: onelflg--; 1167: } while (c == 0); 1168: return (c); 1169: } 1170: 1171: bgetc() 1172: { 1173: register int buf, off, c; 1174: #ifdef FILEC 1175: char ttyline[BUFSIZ]; 1176: register int numleft = 0, roomleft; 1177: #endif 1178: 1179: #ifdef TELL 1180: if (cantell) { 1181: if (fseekp < fbobp || fseekp > feobp) { 1182: fbobp = feobp = fseekp; 1183: (void) lseek(SHIN, fseekp, 0); 1184: } 1185: if (fseekp == feobp) { 1186: fbobp = feobp; 1187: do 1188: c = read(SHIN, fbuf[0], BUFSIZ); 1189: while (c < 0 && errno == EINTR); 1190: if (c <= 0) 1191: return (-1); 1192: feobp += c; 1193: } 1194: c = fbuf[0][fseekp - fbobp]; 1195: fseekp++; 1196: return (c & 0377); 1197: } 1198: #endif 1199: again: 1200: buf = (int) fseekp / BUFSIZ; 1201: if (buf >= fblocks) { 1202: register char **nfbuf = 1203: (char **) calloc((unsigned) (fblocks + 2), 1204: sizeof (char **)); 1205: 1206: if (fbuf) { 1207: (void) blkcpy(nfbuf, fbuf); 1208: xfree((char *)fbuf); 1209: } 1210: fbuf = nfbuf; 1211: fbuf[fblocks] = calloc(BUFSIZ, sizeof (char)); 1212: fblocks++; 1213: goto again; 1214: } 1215: if (fseekp >= feobp) { 1216: buf = (int) feobp / BUFSIZ; 1217: off = (int) feobp % BUFSIZ; 1218: #ifndef FILEC 1219: for (;;) { 1220: c = read(SHIN, fbuf[buf] + off, BUFSIZ - off); 1221: #else 1222: roomleft = BUFSIZ - off; 1223: for (;;) { 1224: if (filec && intty) { 1225: c = numleft ? numleft : tenex(ttyline, BUFSIZ); 1226: if (c > roomleft) { 1227: /* start with fresh buffer */ 1228: feobp = fseekp = fblocks * BUFSIZ; 1229: numleft = c; 1230: goto again; 1231: } 1232: if (c > 0) 1233: copy(fbuf[buf] + off, ttyline, c); 1234: numleft = 0; 1235: } else 1236: c = read(SHIN, fbuf[buf] + off, roomleft); 1237: #endif 1238: if (c >= 0) 1239: break; 1240: if (errno == EWOULDBLOCK) { 1241: int off = 0; 1242: 1243: (void) ioctl(SHIN, FIONBIO, (char *)&off); 1244: } else if (errno != EINTR) 1245: break; 1246: } 1247: if (c <= 0) 1248: return (-1); 1249: feobp += c; 1250: #ifndef FILEC 1251: goto again; 1252: #else 1253: if (filec && !intty) 1254: goto again; 1255: #endif 1256: } 1257: c = fbuf[buf][(int) fseekp % BUFSIZ]; 1258: fseekp++; 1259: return (c & 0377); 1260: } 1261: 1262: bfree() 1263: { 1264: register int sb, i; 1265: 1266: #ifdef TELL 1267: if (cantell) 1268: return; 1269: #endif 1270: if (whyles) 1271: return; 1272: sb = (int) (fseekp - 1) / BUFSIZ; 1273: if (sb > 0) { 1274: for (i = 0; i < sb; i++) 1275: xfree(fbuf[i]); 1276: (void) blkcpy(fbuf, &fbuf[sb]); 1277: fseekp -= BUFSIZ * sb; 1278: feobp -= BUFSIZ * sb; 1279: fblocks -= sb; 1280: } 1281: } 1282: 1283: bseek(l) 1284: off_t l; 1285: { 1286: register struct whyle *wp; 1287: 1288: fseekp = l; 1289: #ifdef TELL 1290: if (!cantell) { 1291: #endif 1292: if (!whyles) 1293: return; 1294: for (wp = whyles; wp->w_next; wp = wp->w_next) 1295: continue; 1296: if (wp->w_start > l) 1297: l = wp->w_start; 1298: #ifdef TELL 1299: } 1300: #endif 1301: } 1302: 1303: /* any similarity to bell telephone is purely accidental */ 1304: #ifndef btell 1305: off_t 1306: btell() 1307: { 1308: 1309: return (fseekp); 1310: } 1311: #endif 1312: 1313: btoeof() 1314: { 1315: 1316: (void) lseek(SHIN, (off_t)0, 2); 1317: fseekp = feobp; 1318: wfree(); 1319: bfree(); 1320: } 1321: 1322: #ifdef TELL 1323: settell() 1324: { 1325: 1326: cantell = 0; 1327: if (arginp || onelflg || intty) 1328: return; 1329: if (lseek(SHIN, (off_t)0, 1) < 0 || errno == ESPIPE) 1330: return; 1331: fbuf = (char **) calloc(2, sizeof (char **)); 1332: fblocks = 1; 1333: fbuf[0] = calloc(BUFSIZ, sizeof (char)); 1334: fseekp = fbobp = feobp = lseek(SHIN, (off_t)0, 1); 1335: cantell = 1; 1336: } 1337: #endif