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