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