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