1 /* $NetBSD: lex.c,v 1.38 2020/10/02 17:33:13 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.38 2020/10/02 17:33:13 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 free(fp->word); 251 free(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 = xcalloc(1, sizeof *new); 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 free(otword); 901 break; 902 } 903 else 904 free(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 1000 case 'h': 1001 case 't': 1002 wp = Strrchr(cp, '/'); 1003 if (wp == NULL) 1004 return Strsave(type == 't' ? cp : STRNULL); 1005 if (type == 't') 1006 xp = Strsave(wp + 1); 1007 else 1008 xp = Strsave(cp), xp[wp - cp] = 0; 1009 return (xp); 1010 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 1024 default: 1025 break; 1026 } 1027 return (0); 1028 } 1029 1030 static int 1031 matchs(Char *str, Char *pat) 1032 { 1033 while (*str && *pat && *str == *pat) 1034 str++, pat++; 1035 return (*pat == 0); 1036 } 1037 1038 static int 1039 getsel(int *al, int *ar, int dol) 1040 { 1041 int c, i; 1042 int first; 1043 1044 c = getC(0); 1045 first = *al < 0; 1046 1047 switch (c) { 1048 case '%': 1049 if (quesarg == -1) { 1050 seterror(ERR_BADBANGARG); 1051 return (0); 1052 } 1053 if (*al < 0) 1054 *al = quesarg; 1055 *ar = quesarg; 1056 break; 1057 case '-': 1058 if (*al < 0) { 1059 *al = 0; 1060 *ar = dol - 1; 1061 unreadc(c); 1062 } 1063 return (1); 1064 case '^': 1065 if (*al < 0) 1066 *al = 1; 1067 *ar = 1; 1068 break; 1069 case '$': 1070 if (*al < 0) 1071 *al = dol; 1072 *ar = dol; 1073 break; 1074 case '*': 1075 if (*al < 0) 1076 *al = 1; 1077 *ar = dol; 1078 if (*ar < *al) { 1079 *ar = 0; 1080 *al = 1; 1081 return (1); 1082 } 1083 break; 1084 default: 1085 if (Isdigit(c)) { 1086 i = 0; 1087 while (Isdigit(c)) { 1088 i = i * 10 + c - '0'; 1089 c = getC(0); 1090 } 1091 if (i < 0) 1092 i = dol + 1; 1093 if (*al < 0) 1094 *al = i; 1095 *ar = i; 1096 } 1097 else if (*al < 0) 1098 *al = 0, *ar = dol; 1099 else 1100 *ar = dol - 1; 1101 unreadc(c); 1102 break; 1103 } 1104 if (first) { 1105 c = getC(0); 1106 unreadc(c); 1107 if (any("-$*", c)) 1108 return (1); 1109 } 1110 if (*al > *ar || *ar > dol) { 1111 seterror(ERR_BADBANGARG); 1112 return (0); 1113 } 1114 return (1); 1115 1116 } 1117 1118 static struct wordent * 1119 gethent(int sc) 1120 { 1121 struct Hist *hp; 1122 Char *np; 1123 char *str; 1124 int c, event; 1125 int back; 1126 1127 back = 0; 1128 c = sc == HISTSUB ? HIST : getC(0); 1129 if (c == HIST) { 1130 if (alhistp) 1131 return (alhistp); 1132 event = eventno; 1133 } 1134 else 1135 switch (c) { 1136 case ':': 1137 case '^': 1138 case '$': 1139 case '*': 1140 case '%': 1141 ungetC(c); 1142 if (lastev == eventno && alhistp) 1143 return (alhistp); 1144 event = lastev; 1145 break; 1146 case '#': /* !# is command being typed in (mrh) */ 1147 if (--hleft == 0) { 1148 seterror(ERR_HISTLOOP); 1149 return (0); 1150 } 1151 else 1152 return (¶ml); 1153 /* NOTREACHED */ 1154 case '-': 1155 back = 1; 1156 c = getC(0); 1157 /* FALLTHROUGH */ 1158 default: 1159 if (any("(=~", c)) { 1160 unreadc(c); 1161 ungetC(HIST); 1162 return (0); 1163 } 1164 np = lhsb; 1165 event = 0; 1166 while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) { 1167 if (event != -1 && Isdigit(c)) 1168 event = event * 10 + c - '0'; 1169 else 1170 event = -1; 1171 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1172 *np++ = (Char)c; 1173 c = getC(0); 1174 } 1175 unreadc(c); 1176 if (np == lhsb) { 1177 ungetC(HIST); 1178 return (0); 1179 } 1180 *np++ = 0; 1181 if (event != -1) { 1182 /* 1183 * History had only digits 1184 */ 1185 if (back) 1186 event = eventno + (alhistp == 0) - (event ? event : 0); 1187 break; 1188 } 1189 hp = findev(lhsb, 0); 1190 if (hp) 1191 lastev = hp->Hnum; 1192 return (&hp->Hlex); 1193 case '?': 1194 np = lhsb; 1195 for (;;) { 1196 c = getC(0); 1197 if (c == '\n') { 1198 unreadc(c); 1199 break; 1200 } 1201 if (c == '?') 1202 break; 1203 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1204 *np++ = (Char)c; 1205 } 1206 if (np == lhsb) { 1207 if (lhsb[0] == 0) { 1208 seterror(ERR_NOSEARCH); 1209 return (0); 1210 } 1211 } 1212 else 1213 *np++ = 0; 1214 hp = findev(lhsb, 1); 1215 if (hp) 1216 lastev = hp->Hnum; 1217 return (&hp->Hlex); 1218 } 1219 1220 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 1221 if (hp->Hnum == event) { 1222 hp->Href = eventno; 1223 lastev = hp->Hnum; 1224 return (&hp->Hlex); 1225 } 1226 np = putn(event); 1227 str = vis_str(np); 1228 free(np); 1229 seterror(ERR_NOEVENT, str); 1230 return (0); 1231 } 1232 1233 static struct Hist * 1234 findev(Char *cp, int anyarg) 1235 { 1236 struct Hist *hp; 1237 1238 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 1239 Char *dp, *p, *q; 1240 struct wordent *lp; 1241 int argno; 1242 1243 lp = hp->Hlex.next; 1244 argno = 0; 1245 1246 /* 1247 * The entries added by alias substitution don't have a newline but do 1248 * have a negative event number. Savehist() trims off these entries, 1249 * but it happens before alias expansion, too early to delete those 1250 * from the previous command. 1251 */ 1252 if (hp->Hnum < 0) 1253 continue; 1254 if (lp->word[0] == '\n') 1255 continue; 1256 if (!anyarg) { 1257 p = cp; 1258 q = lp->word; 1259 do 1260 if (!*p) 1261 return (hp); 1262 while (*p++ == *q++); 1263 continue; 1264 } 1265 do { 1266 for (dp = lp->word; *dp; dp++) { 1267 p = cp; 1268 q = dp; 1269 do 1270 if (!*p) { 1271 quesarg = argno; 1272 return (hp); 1273 } 1274 while (*p++ == *q++); 1275 } 1276 lp = lp->next; 1277 argno++; 1278 } while (lp->word[0] != '\n'); 1279 } 1280 seterror(ERR_NOEVENT, vis_str(cp)); 1281 return (0); 1282 } 1283 1284 1285 static void 1286 setexclp(Char *cp) 1287 { 1288 if (cp && cp[0] == '\n') 1289 return; 1290 exclp = cp; 1291 } 1292 1293 void 1294 unreadc(int c) 1295 { 1296 peekread = c; 1297 } 1298 1299 int 1300 readc(int wanteof) 1301 { 1302 static int sincereal; 1303 int c; 1304 1305 aret = F_SEEK; 1306 if ((c = peekread) != '\0') { 1307 peekread = 0; 1308 return (c); 1309 } 1310 top: 1311 aret = F_SEEK; 1312 if (alvecp) { 1313 aret = A_SEEK; 1314 if ((c = *alvecp++) != '\0') 1315 return (c); 1316 if (alvec && *alvec) { 1317 alvecp = *alvec++; 1318 return (' '); 1319 } 1320 else { 1321 aret = F_SEEK; 1322 alvecp = NULL; 1323 return('\n'); 1324 } 1325 } 1326 if (alvec) { 1327 if ((alvecp = *alvec) != NULL) { 1328 alvec++; 1329 goto top; 1330 } 1331 /* Infinite source! */ 1332 return ('\n'); 1333 } 1334 if (evalp) { 1335 aret = E_SEEK; 1336 if ((c = *evalp++) != '\0') 1337 return (c); 1338 if (evalvec && *evalvec) { 1339 evalp = *evalvec++; 1340 return (' '); 1341 } 1342 aret = F_SEEK; 1343 evalp = 0; 1344 } 1345 if (evalvec) { 1346 if (evalvec == (Char **) 1) { 1347 doneinp = 1; 1348 reset(); 1349 } 1350 if ((evalp = *evalvec) != NULL) { 1351 evalvec++; 1352 goto top; 1353 } 1354 evalvec = (Char **) 1; 1355 return ('\n'); 1356 } 1357 do { 1358 if (arginp == (Char *) 1 || onelflg == 1) { 1359 if (wanteof) 1360 return (-1); 1361 exitstat(); 1362 } 1363 if (arginp) { 1364 if ((c = *arginp++) == 0) { 1365 arginp = (Char *) 1; 1366 return ('\n'); 1367 } 1368 return (c); 1369 } 1370 reread: 1371 c = bgetc(); 1372 if (c < 0) { 1373 struct termios tty; 1374 if (wanteof) 1375 return (-1); 1376 /* was isatty but raw with ignoreeof yields problems */ 1377 if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON)) 1378 { 1379 /* was 'short' for FILEC */ 1380 pid_t ctpgrp; 1381 1382 if (++sincereal > 25) 1383 goto oops; 1384 if (tpgrp != -1 && 1385 (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 1386 tpgrp != ctpgrp) { 1387 (void)tcsetpgrp(FSHTTY, tpgrp); 1388 (void)kill(-ctpgrp, SIGHUP); 1389 (void)fprintf(csherr, "Reset tty pgrp from %ld to %ld\n", 1390 (long)ctpgrp, (long)tpgrp); 1391 goto reread; 1392 } 1393 if (adrof(STRignoreeof)) { 1394 if (loginsh) 1395 (void)fprintf(csherr,"\nUse \"logout\" to logout.\n"); 1396 else 1397 (void)fprintf(csherr,"\nUse \"exit\" to leave csh.\n"); 1398 reset(); 1399 } 1400 if (chkstop == 0) 1401 panystop(1); 1402 } 1403 oops: 1404 doneinp = 1; 1405 reset(); 1406 } 1407 sincereal = 0; 1408 if (c == '\n' && onelflg) 1409 onelflg--; 1410 } while (c == 0); 1411 return (c); 1412 } 1413 1414 static int 1415 bgetc(void) 1416 { 1417 #ifdef FILEC 1418 char tbuf[BUFSIZE + 1]; 1419 Char ttyline[BUFSIZE]; 1420 int buf, off; 1421 ssize_t c, numleft, roomleft; 1422 1423 numleft = 0; 1424 #else /* FILEC */ 1425 char tbuf[BUFSIZE + 1]; 1426 int c, buf, off; 1427 #endif /* !FILEC */ 1428 1429 if (cantell) { 1430 if (fseekp < fbobp || fseekp > feobp) { 1431 fbobp = feobp = fseekp; 1432 (void)lseek(SHIN, fseekp, SEEK_SET); 1433 } 1434 if (fseekp == feobp) { 1435 int i; 1436 1437 fbobp = feobp; 1438 do 1439 c = read(SHIN, tbuf, BUFSIZE); 1440 while (c < 0 && errno == EINTR); 1441 if (c <= 0) 1442 return (-1); 1443 for (i = 0; i < c; i++) 1444 fbuf[0][i] = (unsigned char) tbuf[i]; 1445 feobp += c; 1446 } 1447 c = fbuf[0][fseekp - fbobp]; 1448 fseekp++; 1449 return (int)(c); 1450 } 1451 1452 again: 1453 buf = (int) fseekp / BUFSIZE; 1454 if (buf >= fblocks) { 1455 Char **nfbuf; 1456 1457 /* XXX the cast is needed because fblocks is signed */ 1458 nfbuf = xcalloc((size_t)(fblocks + 2), sizeof(*nfbuf)); 1459 if (fbuf) { 1460 (void)blkcpy(nfbuf, fbuf); 1461 free(fbuf); 1462 } 1463 fbuf = nfbuf; 1464 fbuf[fblocks] = xcalloc(BUFSIZE, sizeof(Char)); 1465 fblocks++; 1466 if (!intty) 1467 goto again; 1468 } 1469 if (fseekp >= feobp) { 1470 buf = (int) feobp / BUFSIZE; 1471 off = (int) feobp % BUFSIZE; 1472 roomleft = BUFSIZE - off; 1473 1474 #ifdef FILEC 1475 for (;;) { 1476 if ((editing || filec) && intty) { 1477 #ifdef EDIT 1478 if (editing) { 1479 const char *p; 1480 int d; 1481 if ((p = el_gets(el, &d)) != NULL) { 1482 size_t i; 1483 /* XXX: Truncation */ 1484 numleft = d > BUFSIZE ? BUFSIZE : d; 1485 for (i = 0; *p && i < BUFSIZE; i++, p++) 1486 ttyline[i] = *p; 1487 ttyline[i - (i == BUFSIZE)] = '\0'; 1488 } 1489 } 1490 #endif 1491 c = numleft ? numleft : tenex(ttyline, BUFSIZE); 1492 if (c > roomleft) { 1493 /* start with fresh buffer */ 1494 feobp = fseekp = fblocks * BUFSIZE; 1495 numleft = c; 1496 goto again; 1497 } 1498 if (c > 0) 1499 (void)memcpy(fbuf[buf] + off, ttyline, 1500 (size_t)c * sizeof(**fbuf)); 1501 numleft = 0; 1502 } 1503 else { 1504 #endif 1505 c = read(SHIN, tbuf, (size_t)roomleft); 1506 if (c > 0) { 1507 int i; 1508 Char *ptr = fbuf[buf] + off; 1509 1510 for (i = 0; i < c; i++) 1511 ptr[i] = (unsigned char) tbuf[i]; 1512 } 1513 #ifdef FILEC 1514 } 1515 #endif 1516 if (c >= 0) 1517 break; 1518 if (errno == EWOULDBLOCK) { 1519 int iooff = 0; 1520 1521 (void)ioctl(SHIN, FIONBIO, (ioctl_t) & iooff); 1522 } 1523 else if (errno != EINTR) 1524 break; 1525 #ifdef FILEC 1526 } 1527 #endif 1528 if (c <= 0) 1529 return (-1); 1530 feobp += c; 1531 #ifndef FILEC 1532 goto again; 1533 #else 1534 if (filec && !intty) 1535 goto again; 1536 #endif 1537 } 1538 c = fbuf[buf][(int)fseekp % BUFSIZE]; 1539 fseekp++; 1540 return (int)(c); 1541 } 1542 1543 static void 1544 bfree(void) 1545 { 1546 int i, sb; 1547 1548 if (cantell) 1549 return; 1550 if (whyles) 1551 return; 1552 sb = (int)(fseekp - 1) / BUFSIZE; 1553 if (sb > 0) { 1554 for (i = 0; i < sb; i++) 1555 free(fbuf[i]); 1556 (void)blkcpy(fbuf, &fbuf[sb]); 1557 fseekp -= BUFSIZE * sb; 1558 feobp -= BUFSIZE * sb; 1559 fblocks -= sb; 1560 } 1561 } 1562 1563 void 1564 bseek(struct Ain *l) 1565 { 1566 switch (aret = l->type) { 1567 case A_SEEK: 1568 alvec = l->a_seek; 1569 alvecp = l->c_seek; 1570 return; 1571 case E_SEEK: 1572 evalvec = l->a_seek; 1573 evalp = l->c_seek; 1574 return; 1575 case F_SEEK: 1576 fseekp = l->f_seek; 1577 return; 1578 default: 1579 (void)fprintf(csherr, "Bad seek type %d\n", aret); 1580 abort(); 1581 } 1582 } 1583 1584 void 1585 btell(struct Ain *l) 1586 { 1587 switch (l->type = aret) { 1588 case A_SEEK: 1589 l->a_seek = alvec; 1590 l->c_seek = alvecp; 1591 return; 1592 case E_SEEK: 1593 l->a_seek = evalvec; 1594 l->c_seek = evalp; 1595 return; 1596 case F_SEEK: 1597 l->f_seek = fseekp; 1598 l->a_seek = NULL; 1599 return; 1600 default: 1601 (void)fprintf(csherr, "Bad seek type %d\n", aret); 1602 abort(); 1603 } 1604 } 1605 1606 void 1607 btoeof(void) 1608 { 1609 (void)lseek(SHIN, (off_t) 0, SEEK_END); 1610 aret = F_SEEK; 1611 fseekp = feobp; 1612 alvec = NULL; 1613 alvecp = NULL; 1614 evalvec = NULL; 1615 evalp = NULL; 1616 wfree(); 1617 bfree(); 1618 } 1619 1620 void 1621 settell(void) 1622 { 1623 cantell = 0; 1624 if (arginp || onelflg || intty) 1625 return; 1626 if (lseek(SHIN, (off_t) 0, SEEK_CUR) < 0 || errno == ESPIPE) 1627 return; 1628 fbuf = xcalloc(2, sizeof(*fbuf)); 1629 fblocks = 1; 1630 fbuf[0] = xcalloc(BUFSIZE, sizeof(Char)); 1631 fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, SEEK_CUR); 1632 cantell = 1; 1633 } 1634