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