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