1 /* $OpenBSD: lex.c,v 1.14 2009/10/27 23:59:21 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 <sys/ioctl.h> 35 #include <termios.h> 36 #include <errno.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 = (struct wordent *) 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 = (struct wordent *) 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 xfree((ptr_t) fp->word); 215 xfree((ptr_t) 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 #ifdef notdef 449 /* let $?0 pass for now */ 450 if (special) { 451 seterror(ERR_DIGIT); 452 *np = 0; 453 addla(name); 454 return; 455 } 456 #endif 457 /* we know that np < &name[4] */ 458 ep = &np[MAXVARLEN]; 459 while ((c = getC(DOEXCL)) != '\0'){ 460 if (!Isdigit(c)) 461 break; 462 if (np < ep) 463 *np++ = c; 464 else 465 toolong = 1; 466 } 467 } 468 else if (letter(c)) { 469 /* we know that np < &name[4] */ 470 ep = &np[MAXVARLEN]; 471 toolong = 0; 472 while ((c = getC(DOEXCL)) != '\0') { 473 /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 474 if (!letter(c) && !Isdigit(c)) 475 break; 476 if (np < ep) 477 *np++ = c; 478 else 479 toolong = 1; 480 } 481 } 482 else { 483 *np = 0; 484 seterror(ERR_VARILL); 485 addla(name); 486 return; 487 } 488 if (toolong) { 489 seterror(ERR_VARTOOLONG); 490 *np = 0; 491 addla(name); 492 return; 493 } 494 break; 495 } 496 if (c == '[') { 497 *np++ = c; 498 /* 499 * Name up to here is a max of MAXVARLEN + 8. 500 */ 501 ep = &np[2 * MAXVARLEN + 8]; 502 do { 503 /* 504 * Michael Greim: Allow $ expansion to take place in selector 505 * expressions. (limits the number of characters returned) 506 */ 507 c = getC(DOEXCL | DODOL); 508 if (c == '\n') { 509 ungetD(c); 510 np--; 511 seterror(ERR_NLINDEX); 512 *np = 0; 513 addla(name); 514 return; 515 } 516 if (np < ep) 517 *np++ = c; 518 } while (c != ']'); 519 *np = '\0'; 520 if (np >= ep) { 521 seterror(ERR_SELOVFL); 522 addla(name); 523 return; 524 } 525 c = getC(DOEXCL); 526 } 527 /* 528 * Name up to here is a max of 2 * MAXVARLEN + 8. 529 */ 530 if (c == ':') { 531 /* 532 * if the :g modifier is followed by a newline, then error right away! 533 * -strike 534 */ 535 536 int gmodflag = 0, amodflag = 0; 537 538 do { 539 *np++ = c, c = getC(DOEXCL); 540 if (c == 'g' || c == 'a') { 541 if (c == 'g') 542 gmodflag++; 543 else 544 amodflag++; 545 *np++ = c; c = getC(DOEXCL); 546 } 547 if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 548 if (c == 'g') 549 gmodflag++; 550 else 551 amodflag++; 552 *np++ = c; c = getC(DOEXCL); 553 } 554 *np++ = c; 555 /* scan s// [eichin:19910926.0512EST] */ 556 if (c == 's') { 557 int delimcnt = 2; 558 int delim = getC(0); 559 *np++ = delim; 560 561 if (!delim || letter(delim) 562 || Isdigit(delim) || any(" \t\n", delim)) { 563 seterror(ERR_BADSUBST); 564 break; 565 } 566 while ((c = getC(0)) != (-1)) { 567 *np++ = c; 568 if(c == delim) delimcnt--; 569 if(!delimcnt) break; 570 } 571 if(delimcnt) { 572 seterror(ERR_BADSUBST); 573 break; 574 } 575 c = 's'; 576 } 577 if (!any("htrqxes", c)) { 578 if ((amodflag || gmodflag) && c == '\n') 579 stderror(ERR_VARSYN); /* strike */ 580 seterror(ERR_VARMOD, c); 581 *np = 0; 582 addla(name); 583 return; 584 } 585 } 586 while ((c = getC(DOEXCL)) == ':'); 587 ungetD(c); 588 } 589 else 590 ungetD(c); 591 if (sc == '{') { 592 c = getC(DOEXCL); 593 if (c != '}') { 594 ungetD(c); 595 seterror(ERR_MISSING, '}'); 596 *np = 0; 597 addla(name); 598 return; 599 } 600 *np++ = c; 601 } 602 *np = 0; 603 addla(name); 604 return; 605 } 606 607 void 608 addla(Char *cp) 609 { 610 Char buf[BUFSIZ]; 611 612 if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= 613 (sizeof(labuf) - 4) / sizeof(Char)) { 614 seterror(ERR_EXPOVFL); 615 return; 616 } 617 if (lap) 618 (void) Strlcpy(buf, lap, sizeof buf/sizeof(Char)); 619 (void) Strlcpy(labuf, cp, sizeof labuf/sizeof(Char)); 620 if (lap) 621 (void) Strlcat(labuf, buf, sizeof labuf/sizeof(Char)); 622 lap = labuf; 623 } 624 625 static Char lhsb[32]; 626 static Char slhs[32]; 627 static Char rhsb[64]; 628 static int quesarg; 629 630 static void 631 getexcl(int sc) 632 { 633 struct wordent *hp, *ip; 634 int left, right, dol; 635 int c; 636 637 if (sc == 0) { 638 sc = getC(0); 639 if (sc != '{') { 640 ungetC(sc); 641 sc = 0; 642 } 643 } 644 quesarg = -1; 645 lastev = eventno; 646 hp = gethent(sc); 647 if (hp == 0) 648 return; 649 hadhist = 1; 650 dol = 0; 651 if (hp == alhistp) 652 for (ip = hp->next->next; ip != alhistt; ip = ip->next) 653 dol++; 654 else 655 for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 656 dol++; 657 left = 0, right = dol; 658 if (sc == HISTSUB) { 659 ungetC('s'), unreadc(HISTSUB), c = ':'; 660 goto subst; 661 } 662 c = getC(0); 663 if (!any(":^$*-%", c)) 664 goto subst; 665 left = right = -1; 666 if (c == ':') { 667 c = getC(0); 668 unreadc(c); 669 if (letter(c) || c == '&') { 670 c = ':'; 671 left = 0, right = dol; 672 goto subst; 673 } 674 } 675 else 676 ungetC(c); 677 if (!getsel(&left, &right, dol)) 678 return; 679 c = getC(0); 680 if (c == '*') 681 ungetC(c), c = '-'; 682 if (c == '-') { 683 if (!getsel(&left, &right, dol)) 684 return; 685 c = getC(0); 686 } 687 subst: 688 exclc = right - left + 1; 689 while (--left >= 0) 690 hp = hp->next; 691 if (sc == HISTSUB || c == ':') { 692 do { 693 hp = getsub(hp); 694 c = getC(0); 695 } while (c == ':'); 696 } 697 unreadc(c); 698 if (sc == '{') { 699 c = getC(0); 700 if (c != '}') 701 seterror(ERR_BADBANG); 702 } 703 exclnxt = hp; 704 } 705 706 static struct wordent * 707 getsub(struct wordent *en) 708 { 709 Char *cp; 710 int delim; 711 int c; 712 int sc; 713 bool global; 714 Char orhsb[sizeof(rhsb) / sizeof(Char)]; 715 716 do { 717 exclnxt = 0; 718 global = 0; 719 sc = c = getC(0); 720 if (c == 'g' || c == 'a') { 721 global |= (c == 'g') ? 1 : 2; 722 sc = c = getC(0); 723 } 724 if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) { 725 global |= (c == 'g') ? 1 : 2; 726 sc = c = getC(0); 727 } 728 729 switch (c) { 730 case 'p': 731 justpr++; 732 return (en); 733 734 case 'x': 735 case 'q': 736 global |= 1; 737 738 /* fall into ... */ 739 740 case 'h': 741 case 'r': 742 case 't': 743 case 'e': 744 break; 745 746 case '&': 747 if (slhs[0] == 0) { 748 seterror(ERR_NOSUBST); 749 return (en); 750 } 751 (void) Strlcpy(lhsb, slhs, sizeof(lhsb)/sizeof(Char)); 752 break; 753 754 #ifdef notdef 755 case '~': 756 if (lhsb[0] == 0) 757 goto badlhs; 758 break; 759 #endif 760 761 case 's': 762 delim = getC(0); 763 if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 764 unreadc(delim); 765 lhsb[0] = 0; 766 seterror(ERR_BADSUBST); 767 return (en); 768 } 769 cp = lhsb; 770 for (;;) { 771 c = getC(0); 772 if (c == '\n') { 773 unreadc(c); 774 break; 775 } 776 if (c == delim) 777 break; 778 if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { 779 lhsb[0] = 0; 780 seterror(ERR_BADSUBST); 781 return (en); 782 } 783 if (c == '\\') { 784 c = getC(0); 785 if (c != delim && c != '\\') 786 *cp++ = '\\'; 787 } 788 *cp++ = c; 789 } 790 if (cp != lhsb) 791 *cp++ = 0; 792 else if (lhsb[0] == 0) { 793 seterror(ERR_LHS); 794 return (en); 795 } 796 cp = rhsb; 797 (void) Strlcpy(orhsb, cp, sizeof(orhsb)/sizeof(Char)); 798 for (;;) { 799 c = getC(0); 800 if (c == '\n') { 801 unreadc(c); 802 break; 803 } 804 if (c == delim) 805 break; 806 if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { 807 seterror(ERR_RHSLONG); 808 return (en); 809 } 810 if (c == '\\') { 811 c = getC(0); 812 if (c != delim /* && c != '~' */ ) 813 *cp++ = '\\'; 814 } 815 *cp++ = c; 816 } 817 *cp++ = 0; 818 break; 819 820 default: 821 if (c == '\n') 822 unreadc(c); 823 seterror(ERR_BADBANGMOD, c); 824 return (en); 825 } 826 (void) Strlcpy(slhs, lhsb, sizeof(slhs)/sizeof(Char)); 827 if (exclc) 828 en = dosub(sc, en, global); 829 } 830 while ((c = getC(0)) == ':'); 831 unreadc(c); 832 return (en); 833 } 834 835 static struct wordent * 836 dosub(int sc, struct wordent *en, bool global) 837 { 838 struct wordent lexi; 839 bool didsub = 0, didone = 0; 840 struct wordent *hp = &lexi; 841 struct wordent *wdp; 842 int i = exclc; 843 844 wdp = hp; 845 while (--i >= 0) { 846 struct wordent *new = 847 (struct wordent *) xcalloc(1, sizeof *wdp); 848 849 new->word = 0; 850 new->prev = wdp; 851 new->next = hp; 852 wdp->next = new; 853 wdp = new; 854 en = en->next; 855 if (en->word) { 856 Char *tword, *otword; 857 858 if ((global & 1) || didsub == 0) { 859 tword = subword(en->word, sc, &didone); 860 if (didone) 861 didsub = 1; 862 if (global & 2) { 863 while (didone && tword != STRNULL) { 864 otword = tword; 865 tword = subword(otword, sc, &didone); 866 if (Strcmp(tword, otword) == 0) { 867 xfree((ptr_t) otword); 868 break; 869 } 870 else 871 xfree((ptr_t) otword); 872 } 873 } 874 } 875 else 876 tword = Strsave(en->word); 877 wdp->word = tword; 878 } 879 } 880 if (didsub == 0) 881 seterror(ERR_MODFAIL); 882 hp->prev = wdp; 883 return (&enthist(-1000, &lexi, 0)->Hlex); 884 } 885 886 static Char * 887 subword(Char *cp, int type, bool *adid) 888 { 889 Char wbuf[BUFSIZ]; 890 Char *wp, *mp, *np; 891 int i; 892 893 *adid = 0; 894 switch (type) { 895 896 case 'r': 897 case 'e': 898 case 'h': 899 case 't': 900 case 'q': 901 case 'x': 902 wp = domod(cp, type); 903 if (wp == 0) 904 return (Strsave(cp)); 905 *adid = 1; 906 return (wp); 907 908 default: 909 wp = wbuf; 910 i = BUFSIZ - 4; 911 for (mp = cp; *mp; mp++) 912 if (matchs(mp, lhsb)) { 913 for (np = cp; np < mp;) 914 *wp++ = *np++, --i; 915 for (np = rhsb; *np; np++) 916 switch (*np) { 917 918 case '\\': 919 if (np[1] == '&') 920 np++; 921 /* fall into ... */ 922 923 default: 924 if (--i < 0) { 925 seterror(ERR_SUBOVFL); 926 return (STRNULL); 927 } 928 *wp++ = *np; 929 continue; 930 931 case '&': 932 i -= Strlen(lhsb); 933 if (i < 0) { 934 seterror(ERR_SUBOVFL); 935 return (STRNULL); 936 } 937 *wp = 0; 938 (void)Strlcat(wp, lhsb, 939 sizeof(wbuf)/sizeof(Char) - (wp - wbuf)); 940 wp = Strend(wp); 941 continue; 942 } 943 mp += Strlen(lhsb); 944 i -= Strlen(mp); 945 if (i < 0) { 946 seterror(ERR_SUBOVFL); 947 return (STRNULL); 948 } 949 *wp = 0; 950 (void)Strlcat(wp, mp, 951 sizeof(wbuf)/sizeof(Char) - (wp - wbuf)); 952 *adid = 1; 953 return (Strsave(wbuf)); 954 } 955 return (Strsave(cp)); 956 } 957 } 958 959 Char * 960 domod(Char *cp, int type) 961 { 962 Char *wp, *xp; 963 int c; 964 965 switch (type) { 966 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 975 case 'h': 976 case 't': 977 if (!any(short2str(cp), '/')) 978 return (type == 't' ? Strsave(cp) : 0); 979 wp = Strend(cp); 980 while (*--wp != '/') 981 continue; 982 if (type == 'h') 983 xp = Strsave(cp), xp[wp - cp] = 0; 984 else 985 xp = Strsave(wp + 1); 986 return (xp); 987 988 case 'e': 989 case 'r': 990 wp = Strend(cp); 991 for (wp--; wp >= cp && *wp != '/'; wp--) 992 if (*wp == '.') { 993 if (type == 'e') 994 xp = Strsave(wp + 1); 995 else 996 xp = Strsave(cp), xp[wp - cp] = 0; 997 return (xp); 998 } 999 return (Strsave(type == 'e' ? STRNULL : cp)); 1000 default: 1001 break; 1002 } 1003 return (0); 1004 } 1005 1006 static int 1007 matchs(Char *str, Char *pat) 1008 { 1009 while (*str && *pat && *str == *pat) 1010 str++, pat++; 1011 return (*pat == 0); 1012 } 1013 1014 static int 1015 getsel(int *al, int *ar, int dol) 1016 { 1017 int c = getC(0); 1018 int i; 1019 bool first = *al < 0; 1020 1021 switch (c) { 1022 1023 case '%': 1024 if (quesarg == -1) { 1025 seterror(ERR_BADBANGARG); 1026 return (0); 1027 } 1028 if (*al < 0) 1029 *al = quesarg; 1030 *ar = quesarg; 1031 break; 1032 1033 case '-': 1034 if (*al < 0) { 1035 *al = 0; 1036 *ar = dol - 1; 1037 unreadc(c); 1038 } 1039 return (1); 1040 1041 case '^': 1042 if (*al < 0) 1043 *al = 1; 1044 *ar = 1; 1045 break; 1046 1047 case '$': 1048 if (*al < 0) 1049 *al = dol; 1050 *ar = dol; 1051 break; 1052 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 1064 default: 1065 if (Isdigit(c)) { 1066 i = 0; 1067 while (Isdigit(c)) { 1068 i = i * 10 + c - '0'; 1069 c = getC(0); 1070 } 1071 if (i < 0) 1072 i = dol + 1; 1073 if (*al < 0) 1074 *al = i; 1075 *ar = i; 1076 } 1077 else if (*al < 0) 1078 *al = 0, *ar = dol; 1079 else 1080 *ar = dol - 1; 1081 unreadc(c); 1082 break; 1083 } 1084 if (first) { 1085 c = getC(0); 1086 unreadc(c); 1087 if (any("-$*", c)) 1088 return (1); 1089 } 1090 if (*al > *ar || *ar > dol) { 1091 seterror(ERR_BADBANGARG); 1092 return (0); 1093 } 1094 return (1); 1095 1096 } 1097 1098 static struct wordent * 1099 gethent(int sc) 1100 { 1101 struct Hist *hp; 1102 Char *np; 1103 int c; 1104 int event; 1105 bool back = 0; 1106 1107 c = sc == HISTSUB ? HIST : getC(0); 1108 if (c == HIST) { 1109 if (alhistp) 1110 return (alhistp); 1111 event = eventno; 1112 } 1113 else 1114 switch (c) { 1115 1116 case ':': 1117 case '^': 1118 case '$': 1119 case '*': 1120 case '%': 1121 ungetC(c); 1122 if (lastev == eventno && alhistp) 1123 return (alhistp); 1124 event = lastev; 1125 break; 1126 1127 case '#': /* !# is command being typed in (mrh) */ 1128 if (--hleft == 0) { 1129 seterror(ERR_HISTLOOP); 1130 return (0); 1131 } 1132 else 1133 return (¶ml); 1134 /* NOTREACHED */ 1135 1136 case '-': 1137 back = 1; 1138 c = getC(0); 1139 /* FALLSTHROUGH */ 1140 1141 default: 1142 if (any("(=~", c)) { 1143 unreadc(c); 1144 ungetC(HIST); 1145 return (0); 1146 } 1147 np = lhsb; 1148 event = 0; 1149 while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) { 1150 if (event != -1 && Isdigit(c)) 1151 event = event * 10 + c - '0'; 1152 else 1153 event = -1; 1154 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1155 *np++ = c; 1156 c = getC(0); 1157 } 1158 unreadc(c); 1159 if (np == lhsb) { 1160 ungetC(HIST); 1161 return (0); 1162 } 1163 *np++ = 0; 1164 if (event != -1) { 1165 /* 1166 * History had only digits 1167 */ 1168 if (back) 1169 event = eventno + (alhistp == 0) - (event ? event : 0); 1170 break; 1171 } 1172 hp = findev(lhsb, 0); 1173 if (hp) 1174 lastev = hp->Hnum; 1175 return (&hp->Hlex); 1176 1177 case '?': 1178 np = lhsb; 1179 for (;;) { 1180 c = getC(0); 1181 if (c == '\n') { 1182 unreadc(c); 1183 break; 1184 } 1185 if (c == '?') 1186 break; 1187 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1188 *np++ = c; 1189 } 1190 if (np == lhsb) { 1191 if (lhsb[0] == 0) { 1192 seterror(ERR_NOSEARCH); 1193 return (0); 1194 } 1195 } 1196 else 1197 *np++ = 0; 1198 hp = findev(lhsb, 1); 1199 if (hp) 1200 lastev = hp->Hnum; 1201 return (&hp->Hlex); 1202 } 1203 1204 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 1205 if (hp->Hnum == event) { 1206 hp->Href = eventno; 1207 lastev = hp->Hnum; 1208 return (&hp->Hlex); 1209 } 1210 np = putn(event); 1211 seterror(ERR_NOEVENT, vis_str(np)); 1212 return (0); 1213 } 1214 1215 static struct Hist * 1216 findev(Char *cp, bool anyarg) 1217 { 1218 struct Hist *hp; 1219 1220 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 1221 Char *dp; 1222 Char *p, *q; 1223 struct wordent *lp = hp->Hlex.next; 1224 int argno = 0; 1225 1226 /* 1227 * The entries added by alias substitution don't have a newline but do 1228 * have a negative event number. Savehist() trims off these entries, 1229 * but it happens before alias expansion, too early to delete those 1230 * from the previous command. 1231 */ 1232 if (hp->Hnum < 0) 1233 continue; 1234 if (lp->word[0] == '\n') 1235 continue; 1236 if (!anyarg) { 1237 p = cp; 1238 q = lp->word; 1239 do 1240 if (!*p) 1241 return (hp); 1242 while (*p++ == *q++); 1243 continue; 1244 } 1245 do { 1246 for (dp = lp->word; *dp; dp++) { 1247 p = cp; 1248 q = dp; 1249 do 1250 if (!*p) { 1251 quesarg = argno; 1252 return (hp); 1253 } 1254 while (*p++ == *q++); 1255 } 1256 lp = lp->next; 1257 argno++; 1258 } while (lp->word[0] != '\n'); 1259 } 1260 seterror(ERR_NOEVENT, vis_str(cp)); 1261 return (0); 1262 } 1263 1264 1265 static void 1266 setexclp(Char *cp) 1267 { 1268 if (cp && cp[0] == '\n') 1269 return; 1270 exclp = cp; 1271 } 1272 1273 void 1274 unreadc(int c) 1275 { 1276 peekread = c; 1277 } 1278 1279 int 1280 readc(bool wanteof) 1281 { 1282 int c; 1283 static int sincereal; 1284 1285 aret = F_SEEK; 1286 if ((c = peekread) != '\0') { 1287 peekread = 0; 1288 return (c); 1289 } 1290 top: 1291 aret = F_SEEK; 1292 if (alvecp) { 1293 aret = A_SEEK; 1294 if ((c = *alvecp++) != '\0') 1295 return (c); 1296 if (alvec && *alvec) { 1297 alvecp = *alvec++; 1298 return (' '); 1299 } 1300 else { 1301 aret = F_SEEK; 1302 alvecp = NULL; 1303 return('\n'); 1304 } 1305 } 1306 if (alvec) { 1307 if ((alvecp = *alvec) != '\0') { 1308 alvec++; 1309 goto top; 1310 } 1311 /* Infinite source! */ 1312 return ('\n'); 1313 } 1314 if (evalp) { 1315 aret = E_SEEK; 1316 if ((c = *evalp++) != '\0') 1317 return (c); 1318 if (evalvec && *evalvec) { 1319 evalp = *evalvec++; 1320 return (' '); 1321 } 1322 aret = F_SEEK; 1323 evalp = 0; 1324 } 1325 if (evalvec) { 1326 if (evalvec == (Char **) 1) { 1327 doneinp = 1; 1328 reset(); 1329 } 1330 if ((evalp = *evalvec) != '\0') { 1331 evalvec++; 1332 goto top; 1333 } 1334 evalvec = (Char **) 1; 1335 return ('\n'); 1336 } 1337 do { 1338 if (arginp == (Char *) 1 || onelflg == 1) { 1339 if (wanteof) 1340 return (-1); 1341 exitstat(); 1342 } 1343 if (arginp) { 1344 if ((c = *arginp++) == 0) { 1345 arginp = (Char *) 1; 1346 return ('\n'); 1347 } 1348 return (c); 1349 } 1350 reread: 1351 c = bgetc(); 1352 if (c < 0) { 1353 struct termios tty; 1354 if (wanteof) 1355 return (-1); 1356 /* was isatty but raw with ignoreeof yields problems */ 1357 if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON)) 1358 { 1359 /* was 'short' for FILEC */ 1360 pid_t ctpgrp; 1361 1362 if (++sincereal > 25) 1363 goto oops; 1364 if (tpgrp != -1 && 1365 (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 1366 tpgrp != ctpgrp) { 1367 (void) tcsetpgrp(FSHTTY, tpgrp); 1368 (void) kill(-ctpgrp, SIGHUP); 1369 (void) fprintf(csherr, "Reset tty pgrp from %d to %d\n", 1370 ctpgrp, tpgrp); 1371 goto reread; 1372 } 1373 if (adrof(STRignoreeof)) { 1374 if (loginsh) 1375 (void) fprintf(csherr,"\nUse \"logout\" to logout.\n"); 1376 else 1377 (void) fprintf(csherr,"\nUse \"exit\" to leave csh.\n"); 1378 reset(); 1379 } 1380 if (chkstop == 0) 1381 panystop(1); 1382 } 1383 oops: 1384 doneinp = 1; 1385 reset(); 1386 } 1387 sincereal = 0; 1388 if (c == '\n' && onelflg) 1389 onelflg--; 1390 } while (c == 0); 1391 return (c); 1392 } 1393 1394 static int 1395 bgetc(void) 1396 { 1397 int buf, off, c; 1398 1399 #ifdef FILEC 1400 int numleft = 0, roomleft; 1401 Char ttyline[BUFSIZ]; 1402 #endif 1403 char tbuf[BUFSIZ + 1]; 1404 1405 if (cantell) { 1406 if (fseekp < fbobp || fseekp > feobp) { 1407 fbobp = feobp = fseekp; 1408 (void) lseek(SHIN, fseekp, SEEK_SET); 1409 } 1410 if (fseekp == feobp) { 1411 int i; 1412 1413 fbobp = feobp; 1414 do 1415 c = read(SHIN, tbuf, BUFSIZ); 1416 while (c < 0 && errno == EINTR); 1417 if (c <= 0) 1418 return (-1); 1419 for (i = 0; i < c; i++) 1420 fbuf[0][i] = (unsigned char) tbuf[i]; 1421 feobp += c; 1422 } 1423 c = fbuf[0][fseekp - fbobp]; 1424 fseekp++; 1425 return (c); 1426 } 1427 1428 again: 1429 buf = (int) fseekp / BUFSIZ; 1430 if (buf >= fblocks) { 1431 Char **nfbuf = 1432 (Char **) xcalloc((size_t) (fblocks + 2), 1433 sizeof(Char **)); 1434 1435 if (fbuf) { 1436 (void) blkcpy(nfbuf, fbuf); 1437 xfree((ptr_t) fbuf); 1438 } 1439 fbuf = nfbuf; 1440 fbuf[fblocks] = (Char *) xcalloc(BUFSIZ, sizeof(Char)); 1441 fblocks++; 1442 if (!intty) 1443 goto again; 1444 } 1445 if (fseekp >= feobp) { 1446 buf = (int) feobp / BUFSIZ; 1447 off = (int) feobp % BUFSIZ; 1448 roomleft = BUFSIZ - off; 1449 1450 #ifdef FILEC 1451 roomleft = BUFSIZ - off; 1452 for (;;) { 1453 if (filec && intty) { 1454 c = numleft ? numleft : tenex(ttyline, BUFSIZ); 1455 if (c > roomleft) { 1456 /* start with fresh buffer */ 1457 feobp = fseekp = fblocks * BUFSIZ; 1458 numleft = c; 1459 goto again; 1460 } 1461 if (c > 0) 1462 memcpy(fbuf[buf] + off, ttyline, c * sizeof(Char)); 1463 numleft = 0; 1464 } 1465 else { 1466 #endif 1467 c = read(SHIN, tbuf, roomleft); 1468 if (c > 0) { 1469 int i; 1470 Char *ptr = fbuf[buf] + off; 1471 1472 for (i = 0; i < c; i++) 1473 ptr[i] = (unsigned char) tbuf[i]; 1474 } 1475 #ifdef FILEC 1476 } 1477 #endif 1478 if (c >= 0) 1479 break; 1480 if (errno == EWOULDBLOCK) { 1481 int off = 0; 1482 1483 (void) ioctl(SHIN, FIONBIO, (ioctl_t) & off); 1484 } 1485 else if (errno != EINTR) 1486 break; 1487 } 1488 if (c <= 0) 1489 return (-1); 1490 feobp += c; 1491 #ifndef FILEC 1492 goto again; 1493 #else 1494 if (filec && !intty) 1495 goto again; 1496 #endif 1497 } 1498 c = fbuf[buf][(int) fseekp % BUFSIZ]; 1499 fseekp++; 1500 return (c); 1501 } 1502 1503 static void 1504 bfree(void) 1505 { 1506 int sb, i; 1507 1508 if (cantell) 1509 return; 1510 if (whyles) 1511 return; 1512 sb = (int) (fseekp - 1) / BUFSIZ; 1513 if (sb > 0) { 1514 for (i = 0; i < sb; i++) 1515 xfree((ptr_t) fbuf[i]); 1516 (void) blkcpy(fbuf, &fbuf[sb]); 1517 fseekp -= BUFSIZ * sb; 1518 feobp -= BUFSIZ * sb; 1519 fblocks -= sb; 1520 } 1521 } 1522 1523 void 1524 bseek(struct Ain *l) 1525 { 1526 switch (aret = l->type) { 1527 case E_SEEK: 1528 evalvec = l->a_seek; 1529 evalp = l->c_seek; 1530 return; 1531 case A_SEEK: 1532 alvec = l->a_seek; 1533 alvecp = l->c_seek; 1534 return; 1535 case F_SEEK: 1536 fseekp = l->f_seek; 1537 return; 1538 default: 1539 (void) fprintf(csherr, "Bad seek type %d\n", aret); 1540 abort(); 1541 } 1542 } 1543 1544 void 1545 btell(struct Ain *l) 1546 { 1547 switch (l->type = aret) { 1548 case E_SEEK: 1549 l->a_seek = evalvec; 1550 l->c_seek = evalp; 1551 return; 1552 case A_SEEK: 1553 l->a_seek = alvec; 1554 l->c_seek = alvecp; 1555 return; 1556 case F_SEEK: 1557 l->f_seek = fseekp; 1558 l->a_seek = NULL; 1559 return; 1560 default: 1561 (void) fprintf(csherr, "Bad seek type %d\n", aret); 1562 abort(); 1563 } 1564 } 1565 1566 void 1567 btoeof(void) 1568 { 1569 (void) lseek(SHIN, (off_t) 0, SEEK_END); 1570 aret = F_SEEK; 1571 fseekp = feobp; 1572 alvec = NULL; 1573 alvecp = NULL; 1574 evalvec = NULL; 1575 evalp = NULL; 1576 wfree(); 1577 bfree(); 1578 } 1579 1580 void 1581 settell(void) 1582 { 1583 cantell = 0; 1584 if (arginp || onelflg || intty) 1585 return; 1586 if (lseek(SHIN, (off_t) 0, SEEK_CUR) < 0 || errno == ESPIPE) 1587 return; 1588 fbuf = (Char **) xcalloc(2, sizeof(Char **)); 1589 fblocks = 1; 1590 fbuf[0] = (Char *) xcalloc(BUFSIZ, sizeof(Char)); 1591 fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, SEEK_CUR); 1592 cantell = 1; 1593 } 1594