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 #ifndef lint 8 static char *sccsid = "@(#)lex.c 5.8 (Berkeley) 03/14/91"; 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 cshputchar(' '); 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 (index("\t \n", c)) { 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 (!index("htrqxe", c)) 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 (strlen(cp) + (lap ? strlen(lap) : 0) >= sizeof (labuf) - 4) { 430 seterr("Expansion buffer overflow"); 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 (!index(":^$*-%", 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) || index(" \t\n", delim)) { 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 (!index(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 (index("-$*", 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 (index("(=~", c)) { 928 unreadc(c); 929 ungetC(HIST); 930 return (0); 931 } 932 if (digit(c)) 933 goto number; 934 np = lhsb; 935 while (!index(": \t\\\n}", c)) { 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 /* 1013 * The entries added by alias substitution don't 1014 * have a newline but do have a negative event number. 1015 * Savehist() trims off these entries, but it happens 1016 * before alias expansion, too early to delete those 1017 * from the previous command. 1018 */ 1019 if (hp->Hnum < 0) 1020 continue; 1021 if (lp->word[0] == '\n') 1022 continue; 1023 if (!anyarg) { 1024 p = cp; 1025 q = lp->word; 1026 do 1027 if (!*p) 1028 return (hp); 1029 while (*p++ == *q++); 1030 continue; 1031 } 1032 do { 1033 for (dp = lp->word; *dp; dp++) { 1034 p = cp; 1035 q = dp; 1036 do 1037 if (!*p) { 1038 quesarg = argno; 1039 return (hp); 1040 } 1041 while (*p++ == *q++); 1042 } 1043 lp = lp->next; 1044 argno++; 1045 } while (lp->word[0] != '\n'); 1046 } 1047 noev(cp); 1048 return (0); 1049 } 1050 1051 noev(cp) 1052 char *cp; 1053 { 1054 1055 seterr2(cp, ": Event not found"); 1056 } 1057 1058 setexclp(cp) 1059 register char *cp; 1060 { 1061 1062 if (cp && cp[0] == '\n') 1063 return; 1064 exclp = cp; 1065 } 1066 1067 unreadc(c) 1068 char c; 1069 { 1070 1071 peekread = c; 1072 } 1073 1074 readc(wanteof) 1075 bool wanteof; 1076 { 1077 register int c; 1078 static sincereal; 1079 1080 if (c = peekread) { 1081 peekread = 0; 1082 return (c); 1083 } 1084 top: 1085 if (alvecp) { 1086 if (c = *alvecp++) 1087 return (c); 1088 if (*alvec) { 1089 alvecp = *alvec++; 1090 return (' '); 1091 } 1092 } 1093 if (alvec) { 1094 if (alvecp = *alvec) { 1095 alvec++; 1096 goto top; 1097 } 1098 /* Infinite source! */ 1099 return ('\n'); 1100 } 1101 if (evalp) { 1102 if (c = *evalp++) 1103 return (c); 1104 if (*evalvec) { 1105 evalp = *evalvec++; 1106 return (' '); 1107 } 1108 evalp = 0; 1109 } 1110 if (evalvec) { 1111 if (evalvec == (char **)1) { 1112 doneinp = 1; 1113 reset(); 1114 } 1115 if (evalp = *evalvec) { 1116 evalvec++; 1117 goto top; 1118 } 1119 evalvec = (char **)1; 1120 return ('\n'); 1121 } 1122 do { 1123 if (arginp == (char *) 1 || onelflg == 1) { 1124 if (wanteof) 1125 return (-1); 1126 exitstat(); 1127 } 1128 if (arginp) { 1129 if ((c = *arginp++) == 0) { 1130 arginp = (char *) 1; 1131 return ('\n'); 1132 } 1133 return (c); 1134 } 1135 reread: 1136 c = bgetc(); 1137 if (c < 0) { 1138 struct sgttyb tty; 1139 1140 if (wanteof) 1141 return (-1); 1142 /* was isatty but raw with ignoreeof yields problems */ 1143 if (ioctl(SHIN, TIOCGETP, (char *)&tty) == 0 && 1144 (tty.sg_flags & RAW) == 0) { 1145 /* was 'short' for FILEC */ 1146 int ctpgrp; 1147 1148 if (++sincereal > 25) 1149 goto oops; 1150 if (tpgrp != -1 && 1151 ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp) == 0 && 1152 tpgrp != ctpgrp) { 1153 (void) ioctl(FSHTTY, TIOCSPGRP, 1154 (char *)&tpgrp); 1155 (void) killpg(ctpgrp, SIGHUP); 1156 printf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp); 1157 goto reread; 1158 } 1159 if (adrof("ignoreeof")) { 1160 if (loginsh) 1161 printf("\nUse \"logout\" to logout.\n"); 1162 else 1163 printf("\nUse \"exit\" to leave csh.\n"); 1164 reset(); 1165 } 1166 if (chkstop == 0) 1167 panystop(1); 1168 } 1169 oops: 1170 doneinp = 1; 1171 reset(); 1172 } 1173 sincereal = 0; 1174 if (c == '\n' && onelflg) 1175 onelflg--; 1176 } while (c == 0); 1177 return (c); 1178 } 1179 1180 bgetc() 1181 { 1182 register int buf, off, c; 1183 #ifdef FILEC 1184 char ttyline[BUFSIZ]; 1185 register int numleft = 0, roomleft; 1186 #endif 1187 1188 #ifdef TELL 1189 if (cantell) { 1190 if (fseekp < fbobp || fseekp > feobp) { 1191 fbobp = feobp = fseekp; 1192 (void) lseek(SHIN, fseekp, 0); 1193 } 1194 if (fseekp == feobp) { 1195 fbobp = feobp; 1196 do 1197 c = read(SHIN, fbuf[0], BUFSIZ); 1198 while (c < 0 && errno == EINTR); 1199 if (c <= 0) 1200 return (-1); 1201 feobp += c; 1202 } 1203 c = fbuf[0][fseekp - fbobp]; 1204 fseekp++; 1205 return (c); 1206 } 1207 #endif 1208 again: 1209 buf = (int) fseekp / BUFSIZ; 1210 if (buf >= fblocks) { 1211 register char **nfbuf = 1212 (char **) calloc((unsigned) (fblocks + 2), 1213 sizeof (char **)); 1214 1215 if (fbuf) { 1216 (void) blkcpy(nfbuf, fbuf); 1217 xfree((char *)fbuf); 1218 } 1219 fbuf = nfbuf; 1220 fbuf[fblocks] = calloc(BUFSIZ, sizeof (char)); 1221 fblocks++; 1222 goto again; 1223 } 1224 if (fseekp >= feobp) { 1225 buf = (int) feobp / BUFSIZ; 1226 off = (int) feobp % BUFSIZ; 1227 #ifndef FILEC 1228 for (;;) { 1229 c = read(SHIN, fbuf[buf] + off, BUFSIZ - off); 1230 #else 1231 roomleft = BUFSIZ - off; 1232 for (;;) { 1233 if (filec && intty) { 1234 c = numleft ? numleft : tenex(ttyline, BUFSIZ); 1235 if (c > roomleft) { 1236 /* start with fresh buffer */ 1237 feobp = fseekp = fblocks * BUFSIZ; 1238 numleft = c; 1239 goto again; 1240 } 1241 if (c > 0) 1242 bcopy(ttyline, fbuf[buf] + off, c); 1243 numleft = 0; 1244 } else 1245 c = read(SHIN, fbuf[buf] + off, roomleft); 1246 #endif 1247 if (c >= 0) 1248 break; 1249 if (errno == EWOULDBLOCK) { 1250 int off = 0; 1251 1252 (void) ioctl(SHIN, FIONBIO, (char *)&off); 1253 } else if (errno != EINTR) 1254 break; 1255 } 1256 if (c <= 0) 1257 return (-1); 1258 feobp += c; 1259 #ifndef FILEC 1260 goto again; 1261 #else 1262 if (filec && !intty) 1263 goto again; 1264 #endif 1265 } 1266 c = fbuf[buf][(int) fseekp % BUFSIZ]; 1267 fseekp++; 1268 return (c); 1269 } 1270 1271 bfree() 1272 { 1273 register int sb, i; 1274 1275 #ifdef TELL 1276 if (cantell) 1277 return; 1278 #endif 1279 if (whyles) 1280 return; 1281 sb = (int) (fseekp - 1) / BUFSIZ; 1282 if (sb > 0) { 1283 for (i = 0; i < sb; i++) 1284 xfree(fbuf[i]); 1285 (void) blkcpy(fbuf, &fbuf[sb]); 1286 fseekp -= BUFSIZ * sb; 1287 feobp -= BUFSIZ * sb; 1288 fblocks -= sb; 1289 } 1290 } 1291 1292 bseek(l) 1293 off_t l; 1294 { 1295 register struct whyle *wp; 1296 1297 fseekp = l; 1298 #ifdef TELL 1299 if (!cantell) { 1300 #endif 1301 if (!whyles) 1302 return; 1303 for (wp = whyles; wp->w_next; wp = wp->w_next) 1304 continue; 1305 if (wp->w_start > l) 1306 l = wp->w_start; 1307 #ifdef TELL 1308 } 1309 #endif 1310 } 1311 1312 /* any similarity to bell telephone is purely accidental */ 1313 #ifndef btell 1314 off_t 1315 btell() 1316 { 1317 1318 return (fseekp); 1319 } 1320 #endif 1321 1322 btoeof() 1323 { 1324 1325 (void) lseek(SHIN, (off_t)0, 2); 1326 fseekp = feobp; 1327 wfree(); 1328 bfree(); 1329 } 1330 1331 #ifdef TELL 1332 settell() 1333 { 1334 1335 cantell = 0; 1336 if (arginp || onelflg || intty) 1337 return; 1338 if (lseek(SHIN, (off_t)0, 1) < 0 || errno == ESPIPE) 1339 return; 1340 fbuf = (char **) calloc(2, sizeof (char **)); 1341 fblocks = 1; 1342 fbuf[0] = calloc(BUFSIZ, sizeof (char)); 1343 fseekp = fbobp = feobp = lseek(SHIN, (off_t)0, 1); 1344 cantell = 1; 1345 } 1346 #endif 1347