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