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