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