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