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