1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.lex.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ 2: /* 3: * sh.lex.c: Lexical analysis into tokens 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: #if !defined(lint) && !defined(pdp11) 39: static char *rcsid() 40: { return "$Id: sh.lex.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } 41: #endif 42: 43: #include "sh.h" 44: #include "ed.h" 45: 46: /* 47: * C shell 48: */ 49: 50: /* 51: * These lexical routines read input and form lists of words. 52: * There is some involved processing here, because of the complications 53: * of input buffering, and especially because of history substitution. 54: */ 55: static Char *word __P((void)); 56: static int getC1 __P((int)); 57: static void getdol __P((void)); 58: static void getexcl __P((int)); 59: static struct Hist *findev __P((Char *, bool)); 60: static void setexclp __P((Char *)); 61: static int bgetc __P((void)); 62: static void bfree __P((void)); 63: static struct wordent *gethent __P((int)); 64: static int matchs __P((Char *, Char *)); 65: static int getsel __P((int *, int *, int)); 66: static struct wordent *getsub __P((struct wordent *)); 67: static Char *subword __P((Char *, int, bool *)); 68: static struct wordent *dosub __P((int, struct wordent *, bool)); 69: 70: /* 71: * Peekc is a peek character for getC, peekread for readc. 72: * There is a subtlety here in many places... history routines 73: * will read ahead and then insert stuff into the input stream. 74: * If they push back a character then they must push it behind 75: * the text substituted by the history substitution. On the other 76: * hand in several places we need 2 peek characters. To make this 77: * all work, the history routines read with getC, and make use both 78: * of ungetC and unreadc. The key observation is that the state 79: * of getC at the call of a history reference is such that calls 80: * to getC from the history routines will always yield calls of 81: * readc, unless this peeking is involved. That is to say that during 82: * getexcl the variables lap, exclp, and exclnxt are all zero. 83: * 84: * Getdol invokes history substitution, hence the extra peek, peekd, 85: * which it can ungetD to be before history substitutions. 86: */ 87: static Char peekc = 0, peekd = 0; 88: static Char peekread = 0; 89: 90: /* (Tail of) current word from ! subst */ 91: static Char *exclp = NULL; 92: 93: /* The rest of the ! subst words */ 94: static struct wordent *exclnxt = NULL; 95: 96: /* Count of remaining words in ! subst */ 97: static int exclc = 0; 98: 99: /* "Globp" for alias resubstitution */ 100: static Char *alvecp = NULL; 101: 102: /* 103: * Labuf implements a general buffer for lookahead during lexical operations. 104: * Text which is to be placed in the input stream can be stuck here. 105: * We stick parsed ahead $ constructs during initial input, 106: * process id's from `$$', and modified variable values (from qualifiers 107: * during expansion in sh.dol.c) here. 108: */ 109: static Char labuf[BUFSIZ]; 110: 111: /* 112: * Lex returns to its caller not only a wordlist (as a "var" parameter) 113: * but also whether a history substitution occurred. This is used in 114: * the main (process) routine to determine whether to echo, and also 115: * when called by the alias routine to determine whether to keep the 116: * argument list. 117: */ 118: static bool hadhist = 0; 119: 120: /* 121: * Avoid alias expansion recursion via \!# 122: */ 123: int hleft; 124: 125: Char histline[BUFSIZ + 2]; /* last line input */ 126: 127: /* The +2 is to fool hp's optimizer */ 128: bool histvalid = 0; /* is histline valid */ 129: static Char *hist_p_line = NULL; /* current pointer into histline */ 130: 131: static Char getCtmp; 132: 133: #define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f)) 134: #define ungetC(c) peekc = c 135: #define ungetD(c) peekd = c 136: 137: int 138: lex(hp) 139: register struct wordent *hp; 140: { 141: register struct wordent *wdp; 142: int c; 143: 144: histvalid = 0; 145: hist_p_line = histline; 146: *hist_p_line = '\0'; 147: 148: lineloc = btell(); 149: hp->next = hp->prev = hp; 150: hp->word = STRNULL; 151: alvecp = 0, hadhist = 0; 152: do 153: c = readc(0); 154: while (c == ' ' || c == '\t'); 155: if (c == HISTSUB && intty) 156: /* ^lef^rit from tty is short !:s^lef^rit */ 157: getexcl(c); 158: else 159: unreadc(c); 160: wdp = hp; 161: /* 162: * The following loop is written so that the links needed by freelex will 163: * be ready and rarin to go even if it is interrupted. 164: */ 165: do { 166: register struct wordent *new; 167: 168: new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 169: new->word = 0; 170: new->prev = wdp; 171: new->next = hp; 172: wdp->next = new; 173: wdp = new; 174: wdp->word = word(); 175: } while (wdp->word[0] != '\n'); 176: hp->prev = wdp; 177: if (hist_p_line < histline + BUFSIZ) { 178: *hist_p_line = '\0'; 179: if (hist_p_line > histline && hist_p_line[-1] == '\n') 180: hist_p_line[-1] = '\0'; 181: histvalid = 1; 182: } 183: else { 184: histline[BUFSIZ - 1] = '\0'; 185: } 186: return (hadhist); 187: } 188: 189: void 190: prlex(sp0) 191: struct wordent *sp0; 192: { 193: register struct wordent *sp = sp0->next; 194: 195: for (;;) { 196: xprintf("%s", short2str(sp->word)); 197: sp = sp->next; 198: if (sp == sp0) 199: break; 200: if (sp->word[0] != '\n') 201: xputchar(' '); 202: } 203: } 204: 205: void 206: copylex(hp, fp) 207: register struct wordent *hp; 208: register struct wordent *fp; 209: { 210: register struct wordent *wdp; 211: 212: wdp = hp; 213: fp = fp->next; 214: do { 215: register struct wordent *new; 216: 217: new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 218: new->prev = wdp; 219: new->next = hp; 220: wdp->next = new; 221: wdp = new; 222: wdp->word = Strsave(fp->word); 223: fp = fp->next; 224: } while (wdp->word[0] != '\n'); 225: hp->prev = wdp; 226: } 227: 228: void 229: freelex(vp) 230: register struct wordent *vp; 231: { 232: register struct wordent *fp; 233: 234: while (vp->next != vp) { 235: fp = vp->next; 236: vp->next = fp->next; 237: xfree((ptr_t) fp->word); 238: xfree((ptr_t) fp); 239: } 240: vp->prev = vp; 241: } 242: 243: static Char * 244: word() 245: { 246: register Char c, c1; 247: register Char *wp; 248: Char wbuf[BUFSIZ]; 249: register bool dolflg; 250: register int i; 251: 252: wp = wbuf; 253: i = BUFSIZ - 4; 254: loop: 255: while ((c = getC(DOALL)) == ' ' || c == '\t'); 256: if (cmap(c, _META | _ESC)) 257: switch (c) { 258: case '&': 259: case '|': 260: case '<': 261: case '>': 262: *wp++ = c; 263: c1 = getC(DOALL); 264: if (c1 == c) 265: *wp++ = c1; 266: else 267: ungetC(c1); 268: goto ret; 269: 270: case '#': 271: if (intty) 272: break; 273: c = 0; 274: do { 275: c1 = c; 276: c = getC(0); 277: } while (c != '\n'); 278: if (c1 == '\\') 279: goto loop; 280: /* fall into ... */ 281: 282: case ';': 283: case '(': 284: case ')': 285: case '\n': 286: *wp++ = c; 287: goto ret; 288: 289: case '\\': 290: c = getC(0); 291: if (c == '\n') { 292: if (onelflg == 1) 293: onelflg = 2; 294: goto loop; 295: } 296: if (c != HIST) 297: *wp++ = '\\', --i; 298: c |= QUOTE; 299: } 300: c1 = 0; 301: dolflg = DOALL; 302: for (;;) { 303: if (c1) { 304: if (c == c1) { 305: c1 = 0; 306: dolflg = DOALL; 307: } 308: else if (c == '\\') { 309: c = getC(0); 310: /* 311: * PWP: this is dumb, but how all of the other shells work. If \ quotes 312: * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 313: * following character INSIDE a set of ''s. 314: * 315: * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 316: */ 317: if (c == HIST) 318: c |= QUOTE; 319: else { 320: if (bslash_quote && 321: ((c == '\'') || (c == '"') || 322: (c == '\\'))) { 323: c |= QUOTE; 324: } 325: else { 326: if (c == '\n') 327: /* 328: * if (c1 == '`') c = ' '; else 329: */ 330: c |= QUOTE; 331: ungetC(c); 332: c = '\\'; 333: } 334: } 335: } 336: else if (c == '\n') { 337: seterror(ERR_UNMATCHED, c1); 338: ungetC(c); 339: break; 340: } 341: } 342: else if (cmap(c, _META | _Q | _Q1 | _ESC)) { 343: if (c == '\\') { 344: c = getC(0); 345: if (c == '\n') { 346: if (onelflg == 1) 347: onelflg = 2; 348: break; 349: } 350: if (c != HIST) 351: *wp++ = '\\', --i; 352: c |= QUOTE; 353: } 354: else if (cmap(c, _Q | _Q1)) { /* '"` */ 355: c1 = c; 356: dolflg = c == '"' ? DOALL : DOEXCL; 357: } 358: else if (c != '#' || !intty) { 359: ungetC(c); 360: break; 361: } 362: } 363: if (--i > 0) { 364: *wp++ = c; 365: c = getC(dolflg); 366: } 367: else { 368: seterror(ERR_WTOOLONG); 369: wp = &wbuf[1]; 370: break; 371: } 372: } 373: ret: 374: *wp = 0; 375: return (Strsave(wbuf)); 376: } 377: 378: static int 379: getC1(flag) 380: register int flag; 381: { 382: register Char c; 383: 384: while (1) { 385: if (c = peekc) { 386: peekc = 0; 387: return (c); 388: } 389: if (lap) { 390: if ((c = *lap++) == 0) 391: lap = 0; 392: else { 393: if (cmap(c, _META | _Q | _Q1)) 394: c |= QUOTE; 395: return (c); 396: } 397: } 398: if (c = peekd) { 399: peekd = 0; 400: return (c); 401: } 402: if (exclp) { 403: if (c = *exclp++) 404: return (c); 405: if (exclnxt && --exclc >= 0) { 406: exclnxt = exclnxt->next; 407: setexclp(exclnxt->word); 408: return (' '); 409: } 410: exclp = 0; 411: exclnxt = 0; 412: } 413: if (exclnxt) { 414: exclnxt = exclnxt->next; 415: if (--exclc < 0) 416: exclnxt = 0; 417: else 418: setexclp(exclnxt->word); 419: continue; 420: } 421: c = readc(0); 422: if (c == '$' && (flag & DODOL)) { 423: getdol(); 424: continue; 425: } 426: if (c == HIST && (flag & DOEXCL)) { 427: getexcl(0); 428: continue; 429: } 430: break; 431: } 432: return (c); 433: } 434: 435: static void 436: getdol() 437: { 438: register Char *np, *ep; 439: Char name[4 * MAXVARLEN + 1]; 440: register int c; 441: int sc; 442: bool special = 0, toolong; 443: 444: np = name, *np++ = '$'; 445: c = sc = getC(DOEXCL); 446: if (any("\t \n", c)) { 447: ungetD(c); 448: ungetC('$' | QUOTE); 449: return; 450: } 451: if (c == '{') 452: *np++ = c, c = getC(DOEXCL); 453: if (c == '#' || c == '?') 454: special++, *np++ = c, c = getC(DOEXCL); 455: *np++ = c; 456: switch (c) { 457: 458: case '<': 459: case '$': 460: if (special) 461: seterror(ERR_SPDOLLT); 462: *np = 0; 463: addla(name); 464: return; 465: 466: case '\n': 467: ungetD(c); 468: np--; 469: seterror(ERR_NEWLINE); 470: *np = 0; 471: addla(name); 472: return; 473: 474: case '*': 475: if (special) 476: seterror(ERR_SPSTAR); 477: *np = 0; 478: addla(name); 479: return; 480: 481: default: 482: toolong = 0; 483: if (Isdigit(c)) { 484: #ifdef notdef 485: /* let $?0 pass for now */ 486: if (special) { 487: seterror(ERR_DIGIT); 488: *np = 0; 489: addla(name); 490: return; 491: } 492: #endif 493: /* we know that np < &name[4] */ 494: ep = &np[MAXVARLEN]; 495: while (c = getC(DOEXCL)) { 496: if (!Isdigit(c)) 497: break; 498: if (np < ep) 499: *np++ = c; 500: else 501: toolong = 1; 502: } 503: } 504: else if (letter(c)) { 505: /* we know that np < &name[4] */ 506: ep = &np[MAXVARLEN]; 507: toolong = 0; 508: while (c = getC(DOEXCL)) { 509: /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 510: if (!letter(c) && !Isdigit(c)) 511: break; 512: if (np < ep) 513: *np++ = c; 514: else 515: toolong = 1; 516: } 517: } 518: else { 519: *np = 0; 520: seterror(ERR_VARILL); 521: addla(name); 522: return; 523: } 524: if (toolong) { 525: seterror(ERR_VARTOOLONG); 526: *np = 0; 527: addla(name); 528: return; 529: } 530: break; 531: } 532: if (c == '[') { 533: *np++ = c; 534: /* 535: * Name up to here is a max of MAXVARLEN + 8. 536: */ 537: ep = &np[2 * MAXVARLEN + 8]; 538: do { 539: /* 540: * Michael Greim: Allow $ expansion to take place in selector 541: * expressions. (limits the number of characters returned) 542: */ 543: c = getC(DOEXCL | DODOL); 544: if (c == '\n') { 545: ungetD(c); 546: np--; 547: seterror(ERR_NLINDEX); 548: *np = 0; 549: addla(name); 550: return; 551: } 552: if (np < ep) 553: *np++ = c; 554: } while (c != ']'); 555: *np = '\0'; 556: if (np >= ep) { 557: seterror(ERR_SELOVFL); 558: addla(name); 559: return; 560: } 561: c = getC(DOEXCL); 562: } 563: /* 564: * Name up to here is a max of 2 * MAXVARLEN + 8. 565: */ 566: if (c == ':') { 567: /* 568: * if the :g modifier is followed by a newline, then error right away! 569: * -strike 570: */ 571: 572: int gmodflag = 0; 573: 574: *np++ = c, c = getC(DOEXCL); 575: if (c == 'g') 576: gmodflag++, *np++ = c, c = getC(DOEXCL); 577: *np++ = c; 578: if (!any("htrqxe", c)) { 579: if (gmodflag && c == '\n') 580: stderror(ERR_VARSYN); /* strike */ 581: seterror(ERR_VARMOD, c); 582: *np = 0; 583: addla(name); 584: return; 585: } 586: } 587: else 588: ungetD(c); 589: if (sc == '{') { 590: c = getC(DOEXCL); 591: if (c != '}') { 592: ungetD(c); 593: seterror(ERR_MISSING, '}'); 594: *np = 0; 595: addla(name); 596: return; 597: } 598: *np++ = c; 599: } 600: *np = 0; 601: addla(name); 602: return; 603: } 604: 605: void 606: addla(cp) 607: Char *cp; 608: { 609: Char buf[BUFSIZ]; 610: 611: if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= 612: (sizeof(labuf) - 4) / sizeof(Char)) { 613: seterror(ERR_EXPOVFL); 614: return; 615: } 616: if (lap) 617: (void) Strcpy(buf, lap); 618: (void) Strcpy(labuf, cp); 619: if (lap) 620: (void) Strcat(labuf, buf); 621: lap = labuf; 622: } 623: 624: static Char lhsb[32]; 625: static Char slhs[32]; 626: static Char rhsb[64]; 627: static int quesarg; 628: 629: static void 630: getexcl(sc) 631: Char sc; 632: { 633: register struct wordent *hp, *ip; 634: int left, right, dol; 635: register int c; 636: 637: if (sc == 0) { 638: sc = getC(0); 639: if (sc != '{') { 640: ungetC(sc); 641: sc = 0; 642: } 643: } 644: quesarg = -1; 645: lastev = eventno; 646: hp = gethent(sc); 647: if (hp == 0) 648: return; 649: hadhist = 1; 650: dol = 0; 651: if (hp == alhistp) 652: for (ip = hp->next->next; ip != alhistt; ip = ip->next) 653: dol++; 654: else 655: for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 656: dol++; 657: left = 0, right = dol; 658: if (sc == HISTSUB) { 659: ungetC('s'), unreadc(HISTSUB), c = ':'; 660: goto subst; 661: } 662: c = getC(0); 663: if (!any(":^$*-%", c)) 664: goto subst; 665: left = right = -1; 666: if (c == ':') { 667: c = getC(0); 668: unreadc(c); 669: if (letter(c) || c == '&') { 670: c = ':'; 671: left = 0, right = dol; 672: goto subst; 673: } 674: } 675: else 676: ungetC(c); 677: if (!getsel(&left, &right, dol)) 678: return; 679: c = getC(0); 680: if (c == '*') 681: ungetC(c), c = '-'; 682: if (c == '-') { 683: if (!getsel(&left, &right, dol)) 684: return; 685: c = getC(0); 686: } 687: subst: 688: exclc = right - left + 1; 689: while (--left >= 0) 690: hp = hp->next; 691: if (sc == HISTSUB || c == ':') { 692: do { 693: hp = getsub(hp); 694: c = getC(0); 695: } while (c == ':'); 696: } 697: unreadc(c); 698: if (sc == '{') { 699: c = getC(0); 700: if (c != '}') 701: seterror(ERR_BADBANG); 702: } 703: exclnxt = hp; 704: } 705: 706: static struct wordent * 707: getsub(en) 708: struct wordent *en; 709: { 710: register Char *cp; 711: int delim; 712: register int c; 713: int sc; 714: bool global = 0; 715: Char orhsb[sizeof(rhsb) / sizeof(Char)]; 716: 717: exclnxt = 0; 718: sc = c = getC(0); 719: if (c == 'g') 720: global++, sc = c = getC(0); 721: 722: switch (c) { 723: case 'p': 724: justpr++; 725: return (en); 726: 727: case 'x': 728: case 'q': 729: global++; 730: 731: /* fall into ... */ 732: 733: case 'h': 734: case 'r': 735: case 't': 736: case 'e': 737: break; 738: 739: case '&': 740: if (slhs[0] == 0) { 741: seterror(ERR_NOSUBST); 742: return (en); 743: } 744: (void) Strcpy(lhsb, slhs); 745: break; 746: 747: #ifdef notdef 748: case '~': 749: if (lhsb[0] == 0) 750: goto badlhs; 751: break; 752: #endif 753: 754: case 's': 755: delim = getC(0); 756: if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 757: unreadc(delim); 758: lhsb[0] = 0; 759: seterror(ERR_BADSUBST); 760: return (en); 761: } 762: cp = lhsb; 763: for (;;) { 764: c = getC(0); 765: if (c == '\n') { 766: unreadc(c); 767: break; 768: } 769: if (c == delim) 770: break; 771: if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { 772: lhsb[0] = 0; 773: seterror(ERR_BADSUBST); 774: return (en); 775: } 776: if (c == '\\') { 777: c = getC(0); 778: if (c != delim && c != '\\') 779: *cp++ = '\\'; 780: } 781: *cp++ = c; 782: } 783: if (cp != lhsb) 784: *cp++ = 0; 785: else if (lhsb[0] == 0) { 786: seterror(ERR_LHS); 787: return (en); 788: } 789: cp = rhsb; 790: (void) Strcpy(orhsb, cp); 791: for (;;) { 792: c = getC(0); 793: if (c == '\n') { 794: unreadc(c); 795: break; 796: } 797: if (c == delim) 798: break; 799: #ifdef notdef 800: if (c == '~') { 801: if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) / 802: sizeof(Char) - 2]) 803: goto toorhs; 804: (void) Strcpy(cp, orhsb); 805: cp = Strend(cp); 806: continue; 807: } 808: #endif 809: if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { 810: seterror(ERR_RHSLONG); 811: return (en); 812: } 813: if (c == '\\') { 814: c = getC(0); 815: if (c != delim /* && c != '~' */ ) 816: *cp++ = '\\'; 817: } 818: *cp++ = c; 819: } 820: *cp++ = 0; 821: break; 822: 823: default: 824: if (c == '\n') 825: unreadc(c); 826: seterror(ERR_BADBANGMOD, c); 827: return (en); 828: } 829: (void) Strcpy(slhs, lhsb); 830: if (exclc) 831: en = dosub(sc, en, global); 832: return (en); 833: } 834: 835: static struct wordent * 836: dosub(sc, en, global) 837: int sc; 838: struct wordent *en; 839: bool global; 840: { 841: struct wordent lexi; 842: bool didsub = 0; 843: struct wordent *hp = &lexi; 844: register struct wordent *wdp; 845: register int i = exclc; 846: 847: wdp = hp; 848: while (--i >= 0) { 849: register struct wordent *new = (struct wordent *) 850: xcalloc(1, sizeof *wdp); 851: 852: new->word = 0; 853: new->prev = wdp; 854: new->next = hp; 855: wdp->next = new; 856: wdp = new; 857: en = en->next; 858: wdp->word = (en->word && (global ||didsub == 0)) ? 859: subword(en->word, sc, &didsub) : Strsave(en->word); 860: } 861: if (didsub == 0) 862: seterror(ERR_MODFAIL); 863: hp->prev = wdp; 864: return (&enthist(-1000, &lexi, 0)->Hlex); 865: } 866: 867: static Char * 868: subword(cp, type, adid) 869: Char *cp; 870: int type; 871: bool *adid; 872: { 873: Char wbuf[BUFSIZ]; 874: register Char *wp, *mp, *np; 875: register int i; 876: 877: switch (type) { 878: 879: case 'r': 880: case 'e': 881: case 'h': 882: case 't': 883: case 'q': 884: case 'x': 885: wp = domod(cp, type); 886: if (wp == 0) 887: return (Strsave(cp)); 888: *adid = 1; 889: return (wp); 890: 891: default: 892: wp = wbuf; 893: i = BUFSIZ - 4; 894: for (mp = cp; *mp; mp++) 895: if (matchs(mp, lhsb)) { 896: for (np = cp; np < mp;) 897: *wp++ = *np++, --i; 898: for (np = rhsb; *np; np++) 899: switch (*np) { 900: 901: case '\\': 902: if (np[1] == '&') 903: np++; 904: /* fall into ... */ 905: 906: default: 907: if (--i < 0) { 908: seterror(ERR_SUBOVFL); 909: return (STRNULL); 910: } 911: *wp++ = *np; 912: continue; 913: 914: case '&': 915: i -= Strlen(lhsb); 916: if (i < 0) { 917: seterror(ERR_SUBOVFL); 918: return (STRNULL); 919: } 920: *wp = 0; 921: (void) Strcat(wp, lhsb); 922: wp = Strend(wp); 923: continue; 924: } 925: mp += Strlen(lhsb); 926: i -= Strlen(mp); 927: if (i < 0) { 928: seterror(ERR_SUBOVFL); 929: return (STRNULL); 930: } 931: *wp = 0; 932: (void) Strcat(wp, mp); 933: *adid = 1; 934: return (Strsave(wbuf)); 935: } 936: return (Strsave(cp)); 937: } 938: } 939: 940: Char * 941: domod(cp, type) 942: Char *cp; 943: int type; 944: { 945: register Char *wp, *xp; 946: register int c; 947: 948: switch (type) { 949: 950: case 'x': 951: case 'q': 952: wp = Strsave(cp); 953: for (xp = wp; c = *xp; xp++) 954: if ((c != ' ' && c != '\t') || type == 'q') 955: *xp |= QUOTE; 956: return (wp); 957: 958: case 'h': 959: case 't': 960: if (!any(short2str(cp), '/')) 961: return (type == 't' ? Strsave(cp) : 0); 962: wp = Strend(cp); 963: while (*--wp != '/') 964: continue; 965: if (type == 'h') 966: xp = Strsave(cp), xp[wp - cp] = 0; 967: else 968: xp = Strsave(wp + 1); 969: return (xp); 970: 971: case 'e': 972: case 'r': 973: wp = Strend(cp); 974: for (wp--; wp >= cp && *wp != '/'; wp--) 975: if (*wp == '.') { 976: if (type == 'e') 977: xp = Strsave(wp + 1); 978: else 979: xp = Strsave(cp), xp[wp - cp] = 0; 980: return (xp); 981: } 982: return (Strsave(type == 'e' ? STRNULL : cp)); 983: } 984: return (0); 985: } 986: 987: static int 988: matchs(str, pat) 989: register Char *str, *pat; 990: { 991: while (*str && *pat && *str == *pat) 992: str++, pat++; 993: return (*pat == 0); 994: } 995: 996: static int 997: getsel(al, ar, dol) 998: register int *al, *ar; 999: int dol; 1000: { 1001: register int c = getC(0); 1002: register int i; 1003: bool first = *al < 0; 1004: 1005: switch (c) { 1006: 1007: case '%': 1008: if (quesarg == -1) { 1009: seterror(ERR_BADBANGARG); 1010: return (0); 1011: } 1012: if (*al < 0) 1013: *al = quesarg; 1014: *ar = quesarg; 1015: break; 1016: 1017: case '-': 1018: if (*al < 0) { 1019: *al = 0; 1020: *ar = dol - 1; 1021: unreadc(c); 1022: } 1023: return (1); 1024: 1025: case '^': 1026: if (*al < 0) 1027: *al = 1; 1028: *ar = 1; 1029: break; 1030: 1031: case '$': 1032: if (*al < 0) 1033: *al = dol; 1034: *ar = dol; 1035: break; 1036: 1037: case '*': 1038: if (*al < 0) 1039: *al = 1; 1040: *ar = dol; 1041: if (*ar < *al) { 1042: *ar = 0; 1043: *al = 1; 1044: return (1); 1045: } 1046: break; 1047: 1048: default: 1049: if (Isdigit(c)) { 1050: i = 0; 1051: while (Isdigit(c)) { 1052: i = i * 10 + c - '0'; 1053: c = getC(0); 1054: } 1055: if (i < 0) 1056: i = dol + 1; 1057: if (*al < 0) 1058: *al = i; 1059: *ar = i; 1060: } 1061: else if (*al < 0) 1062: *al = 0, *ar = dol; 1063: else 1064: *ar = dol - 1; 1065: unreadc(c); 1066: break; 1067: } 1068: if (first) { 1069: c = getC(0); 1070: unreadc(c); 1071: if (any("-$*", c)) 1072: return (1); 1073: } 1074: if (*al > *ar || *ar > dol) { 1075: seterror(ERR_BADBANGARG); 1076: return (0); 1077: } 1078: return (1); 1079: 1080: } 1081: 1082: static struct wordent * 1083: gethent(sc) 1084: int sc; 1085: { 1086: register struct Hist *hp; 1087: register Char *np; 1088: register int c; 1089: int event; 1090: bool back = 0; 1091: 1092: c = sc == HISTSUB ? HIST : getC(0); 1093: if (c == HIST) { 1094: if (alhistp) 1095: return (alhistp); 1096: event = eventno; 1097: } 1098: else 1099: switch (c) { 1100: 1101: case ':': 1102: case '^': 1103: case '$': 1104: case '*': 1105: case '%': 1106: ungetC(c); 1107: if (lastev == eventno && alhistp) 1108: return (alhistp); 1109: event = lastev; 1110: break; 1111: 1112: case '#': /* !# is command being typed in (mrh) */ 1113: if (--hleft == 0) { 1114: seterror(ERR_HISTLOOP); 1115: return (0); 1116: } 1117: else 1118: return (¶ml); 1119: /* NOTREACHED */ 1120: 1121: case '-': 1122: back = 1; 1123: c = getC(0); 1124: /* FALLSTHROUGH */ 1125: 1126: default: 1127: if (any("(=~", c)) { 1128: unreadc(c); 1129: ungetC(HIST); 1130: return (0); 1131: } 1132: np = lhsb; 1133: event = 0; 1134: while (!any(": \t\\\n}", c)) { 1135: if (event != -1 && Isdigit(c)) 1136: event = event * 10 + c - '0'; 1137: else 1138: event = -1; 1139: if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1140: *np++ = c; 1141: c = getC(0); 1142: } 1143: unreadc(c); 1144: if (np == lhsb) { 1145: ungetC(HIST); 1146: return (0); 1147: } 1148: *np++ = 0; 1149: if (event != -1) { 1150: /* 1151: * History had only digits 1152: */ 1153: if (back) 1154: event = eventno + (alhistp == 0) - (event ? event : 0); 1155: break; 1156: } 1157: hp = findev(lhsb, 0); 1158: if (hp) 1159: lastev = hp->Hnum; 1160: return (&hp->Hlex); 1161: 1162: case '?': 1163: np = lhsb; 1164: for (;;) { 1165: c = getC(0); 1166: if (c == '\n') { 1167: unreadc(c); 1168: break; 1169: } 1170: if (c == '?') 1171: break; 1172: if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1173: *np++ = c; 1174: } 1175: if (np == lhsb) { 1176: if (lhsb[0] == 0) { 1177: seterror(ERR_NOSEARCH); 1178: return (0); 1179: } 1180: } 1181: else 1182: *np++ = 0; 1183: hp = findev(lhsb, 1); 1184: if (hp) 1185: lastev = hp->Hnum; 1186: return (&hp->Hlex); 1187: } 1188: 1189: for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 1190: if (hp->Hnum == event) { 1191: hp->Href = eventno; 1192: lastev = hp->Hnum; 1193: return (&hp->Hlex); 1194: } 1195: np = putn(event); 1196: seterror(ERR_NOEVENT, short2str(np)); 1197: return (0); 1198: } 1199: 1200: static struct Hist * 1201: findev(cp, anyarg) 1202: Char *cp; 1203: bool anyarg; 1204: { 1205: register struct Hist *hp; 1206: 1207: for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 1208: Char *dp; 1209: register Char *p, *q; 1210: register struct wordent *lp = hp->Hlex.next; 1211: int argno = 0; 1212: 1213: /* 1214: * The entries added by alias substitution don't have a newline but do 1215: * have a negative event number. Savehist() trims off these entries, 1216: * but it happens before alias expansion, too early to delete those 1217: * from the previous command. 1218: */ 1219: if (hp->Hnum < 0) 1220: continue; 1221: if (lp->word[0] == '\n') 1222: continue; 1223: if (!anyarg) { 1224: p = cp; 1225: q = lp->word; 1226: do 1227: if (!*p) 1228: return (hp); 1229: while (*p++ == *q++); 1230: continue; 1231: } 1232: do { 1233: for (dp = lp->word; *dp; dp++) { 1234: p = cp; 1235: q = dp; 1236: do 1237: if (!*p) { 1238: quesarg = argno; 1239: return (hp); 1240: } 1241: while (*p++ == *q++); 1242: } 1243: lp = lp->next; 1244: argno++; 1245: } while (lp->word[0] != '\n'); 1246: } 1247: seterror(ERR_NOEVENT, short2str(cp)); 1248: return (0); 1249: } 1250: 1251: 1252: static void 1253: setexclp(cp) 1254: register Char *cp; 1255: { 1256: if (cp && cp[0] == '\n') 1257: return; 1258: exclp = cp; 1259: } 1260: 1261: void 1262: unreadc(c) 1263: Char c; 1264: { 1265: peekread = c; 1266: } 1267: 1268: int 1269: readc(wanteof) 1270: bool wanteof; 1271: { 1272: register int c; 1273: static sincereal; 1274: 1275: if (c = peekread) { 1276: peekread = 0; 1277: return (c); 1278: } 1279: top: 1280: if (alvecp) { 1281: if (c = *alvecp++) 1282: return (c); 1283: if (*alvec) { 1284: alvecp = *alvec++; 1285: return (' '); 1286: } 1287: } 1288: if (alvec) { 1289: if (alvecp = *alvec) { 1290: alvec++; 1291: goto top; 1292: } 1293: /* Infinite source! */ 1294: return ('\n'); 1295: } 1296: if (evalp) { 1297: if (c = *evalp++) 1298: return (c); 1299: if (*evalvec) { 1300: evalp = *evalvec++; 1301: return (' '); 1302: } 1303: evalp = 0; 1304: } 1305: if (evalvec) { 1306: if (evalvec == (Char **) 1) { 1307: doneinp = 1; 1308: reset(); 1309: } 1310: if (evalp = *evalvec) { 1311: evalvec++; 1312: goto top; 1313: } 1314: evalvec = (Char **) 1; 1315: return ('\n'); 1316: } 1317: do { 1318: if (arginp == (Char *) 1 || onelflg == 1) { 1319: if (wanteof) 1320: return (-1); 1321: exitstat(); 1322: } 1323: if (arginp) { 1324: if ((c = *arginp++) == 0) { 1325: arginp = (Char *) 1; 1326: return ('\n'); 1327: } 1328: return (c); 1329: } 1330: reread: 1331: c = bgetc(); 1332: if (c < 0) { 1333: #ifndef POSIX 1334: #ifdef TERMIO 1335: #include <termio.h> 1336: struct termio tty; 1337: 1338: #else /* SGTTYB */ 1339: #include <sys/ioctl.h> 1340: struct sgttyb tty; 1341: 1342: #endif /* TERMIO */ 1343: #else /* POSIX */ 1344: #include <termios.h> 1345: struct termios tty; 1346: 1347: #endif /* POSIX */ 1348: if (wanteof) 1349: return (-1); 1350: /* was isatty but raw with ignoreeof yields problems */ 1351: #ifndef POSIX 1352: #ifdef TERMIO 1353: if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 1354: (tty.c_lflag & ICANON)) 1355: #else /* GSTTYB */ 1356: if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 1357: (tty.sg_flags & RAW) == 0) 1358: #endif /* TERMIO */ 1359: #else /* POSIX */ 1360: if (tcgetattr(SHIN, &tty) == 0 && 1361: (tty.c_lflag & ICANON)) 1362: #endif /* POSIX */ 1363: { 1364: /* was 'short' for FILEC */ 1365: int ctpgrp; 1366: 1367: if (++sincereal > 25) 1368: goto oops; 1369: #ifdef BSDJOBS 1370: if (tpgrp != -1 && 1371: (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 1372: tpgrp != ctpgrp) { 1373: (void) tcsetpgrp(FSHTTY, tpgrp); 1374: (void) killpg((pid_t) ctpgrp, SIGHUP); 1375: xprintf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp); 1376: goto reread; 1377: } 1378: #endif /* BSDJOBS */ 1379: if (adrof(STRig_eof)) { 1380: if (loginsh) 1381: xprintf("\nUse \"logout\" to logout.\n"); 1382: else 1383: xprintf("\nUse \"exit\" to leave tcsh.\n"); 1384: reset(); 1385: } 1386: if (chkstop == 0) 1387: panystop(1); 1388: } 1389: oops: 1390: doneinp = 1; 1391: reset(); 1392: } 1393: sincereal = 0; 1394: if (c == '\n' && onelflg) 1395: onelflg--; 1396: } while (c == 0); 1397: if (hist_p_line < histline + BUFSIZ) 1398: *hist_p_line++ = c; 1399: return (c); 1400: } 1401: 1402: static int 1403: bgetc() 1404: { 1405: register int buf, off, c; 1406: register int numleft = 0, roomleft; 1407: extern Char InputBuf[]; 1408: char tbuf[BUFSIZ + 1]; 1409: 1410: if (cantell) { 1411: if (fseekp < fbobp || fseekp > feobp) { 1412: fbobp = feobp = fseekp; 1413: (void) lseek(SHIN, fseekp, L_SET); 1414: } 1415: if (fseekp == feobp) { 1416: int i; 1417: 1418: fbobp = feobp; 1419: do 1420: c = read(SHIN, tbuf, BUFSIZ); 1421: while (c < 0 && errno == EINTR); 1422: if (c <= 0) 1423: return (-1); 1424: for (i = 0; i < c; i++) 1425: fbuf[0][i] = (unsigned char) tbuf[i]; 1426: feobp += c; 1427: } 1428: c = fbuf[0][fseekp - fbobp]; 1429: fseekp++; 1430: return (c); 1431: } 1432: again: 1433: buf = (int) fseekp / BUFSIZ; 1434: if (buf >= fblocks) { 1435: register Char **nfbuf = 1436: (Char **) xcalloc((size_t) (fblocks + 2), 1437: sizeof(Char **)); 1438: 1439: if (fbuf) { 1440: (void) blkcpy(nfbuf, fbuf); 1441: xfree((ptr_t) fbuf); 1442: } 1443: fbuf = nfbuf; 1444: fbuf[fblocks] = (Char *) xcalloc(BUFSIZ, sizeof(Char)); 1445: fblocks++; 1446: if (!intty) 1447: goto again; 1448: } 1449: if (fseekp >= feobp) { 1450: buf = (int) feobp / BUFSIZ; 1451: off = (int) feobp % BUFSIZ; 1452: roomleft = BUFSIZ - off; 1453: for (;;) { 1454: if (editing && intty) { /* then use twenex routine */ 1455: c = numleft ? numleft : Inputl(); /* PWP: get a line */ 1456: if (c > roomleft) { /* No room in this buffer? */ 1457: /* start with fresh buffer */ 1458: feobp = fseekp = fblocks * BUFSIZ; 1459: numleft = c; 1460: goto again; 1461: } 1462: if (c > 0) 1463: copy((char *) (fbuf[buf] + off), 1464: (char *) InputBuf, (int) (c * sizeof(Char))); 1465: /* copy (fbuf[buf] + off, ttyline, c); */ 1466: numleft = 0; 1467: } 1468: else { 1469: c = read(SHIN, tbuf, (size_t) roomleft); 1470: if (c > 0) { 1471: int i; 1472: Char *ptr = fbuf[buf] + off; 1473: 1474: for (i = 0; i < c; i++) 1475: ptr[i] = (unsigned char) tbuf[i]; 1476: } 1477: } 1478: if (c >= 0) 1479: break; 1480: switch (errno) { 1481: #ifdef FIONBIO 1482: static int zero = 0; 1483: 1484: #endif /* FIONBIO */ 1485: #ifdef EWOULDBLOCK 1486: case EWOULDBLOCK: 1487: #endif /* EWOULDBLOCK */ 1488: #if defined(POSIX) && defined(EAGAIN) 1489: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 1490: case EAGAIN: 1491: #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ 1492: #endif /* POSIX && EAGAIN */ 1493: #if defined(F_SETFL) && defined(O_NDELAY) 1494: (void) fcntl(SHIN, F_SETFL, 1495: fcntl(SHIN, F_GETFL, 0) & ~O_NDELAY); 1496: #endif /* F_SETFL && O_NDELAY */ 1497: #ifdef FIONBIO 1498: (void) ioctl(SHIN, FIONBIO, (ioctl_t) & zero); 1499: #endif /* FIONBIO */ 1500: #if (defined(F_SETFL) && defined(O_NDELAY)) || defined(FIONBIO) 1501: c = 0; 1502: #endif /* (F_SETFL && O_NDELAY) || FIONBIO */ 1503: break; 1504: #ifdef _SEQUENT_ 1505: case EBADF: 1506: #endif /* _SEQUENT_ */ 1507: case EINTR: 1508: c = 0; 1509: break; 1510: default: 1511: c = -1; 1512: break; 1513: } 1514: if (c == -1) 1515: break; 1516: } 1517: if (c <= 0) 1518: return (-1); 1519: feobp += c; 1520: if (editing && !intty) 1521: goto again; 1522: } 1523: c = fbuf[buf][(int) fseekp % BUFSIZ]; 1524: fseekp++; 1525: return (c); 1526: } 1527: 1528: static void 1529: bfree() 1530: { 1531: register int sb, i; 1532: 1533: if (cantell) 1534: return; 1535: if (whyles) 1536: return; 1537: sb = (int) (fseekp - 1) / BUFSIZ; 1538: if (sb > 0) { 1539: for (i = 0; i < sb; i++) 1540: xfree((ptr_t) fbuf[i]); 1541: (void) blkcpy(fbuf, &fbuf[sb]); 1542: fseekp -= BUFSIZ * sb; 1543: feobp -= BUFSIZ * sb; 1544: fblocks -= sb; 1545: } 1546: } 1547: 1548: void 1549: bseek(l) 1550: off_t l; 1551: { 1552: 1553: fseekp = l; 1554: if (!cantell) { 1555: #ifdef notdef 1556: register struct whyle *wp; 1557: #endif 1558: if (!whyles) 1559: return; 1560: #ifdef notdef 1561: /* 1562: * Christos: I don't understand this? both wp and l are local. What is 1563: * this used for? I suspect the author meant fseek = wp->w_start 1564: */ 1565: for (wp = whyles; wp->w_next; wp = wp->w_next) 1566: continue; 1567: if (wp->w_start > l) 1568: l = wp->w_start; 1569: #endif 1570: } 1571: } 1572: 1573: /* any similarity to bell telephone is purely accidental */ 1574: #ifndef btell 1575: off_t 1576: btell() 1577: { 1578: return (fseekp); 1579: } 1580: 1581: #endif 1582: 1583: void 1584: btoeof() 1585: { 1586: (void) lseek(SHIN, (off_t) 0, L_XTND); 1587: fseekp = feobp; 1588: wfree(); 1589: bfree(); 1590: } 1591: 1592: void 1593: settell() 1594: { 1595: cantell = 0; 1596: if (arginp || onelflg || intty) 1597: return; 1598: if (lseek(SHIN, (off_t) 0, L_INCR) < 0 || errno == ESPIPE) 1599: return; 1600: fbuf = (Char **) xcalloc(2, sizeof(Char **)); 1601: fblocks = 1; 1602: fbuf[0] = (Char *) xcalloc(BUFSIZ, sizeof(Char)); 1603: fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, L_INCR); 1604: cantell = 1; 1605: }