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