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