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