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