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