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