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