1 /* $Header: /src/pub/tcsh/sh.lex.c,v 3.56 2002/07/08 20:57:32 christos Exp $ */ 2 /* 3 * sh.lex.c: Lexical analysis into tokens 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. 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 #include "sh.h" 34 35 RCSID("$Id: sh.lex.c,v 3.56 2002/07/08 20:57:32 christos Exp $") 36 37 #include "ed.h" 38 /* #define DEBUG_INP */ 39 /* #define DEBUG_SEEK */ 40 41 /* 42 * C shell 43 */ 44 45 /* 46 * These lexical routines read input and form lists of words. 47 * There is some involved processing here, because of the complications 48 * of input buffering, and especially because of history substitution. 49 */ 50 static Char *word __P((void)); 51 static int getC1 __P((int)); 52 static void getdol __P((void)); 53 static void getexcl __P((int)); 54 static struct Hist *findev __P((Char *, bool)); 55 static void setexclp __P((Char *)); 56 static int bgetc __P((void)); 57 static void balloc __P((int)); 58 static void bfree __P((void)); 59 static struct wordent *gethent __P((int)); 60 static int matchs __P((Char *, Char *)); 61 static int getsel __P((int *, int *, int)); 62 static struct wordent *getsub __P((struct wordent *)); 63 static Char *subword __P((Char *, int, bool *)); 64 static struct wordent *dosub __P((int, struct wordent *, bool)); 65 66 /* 67 * Peekc is a peek character for getC, peekread for readc. 68 * There is a subtlety here in many places... history routines 69 * will read ahead and then insert stuff into the input stream. 70 * If they push back a character then they must push it behind 71 * the text substituted by the history substitution. On the other 72 * hand in several places we need 2 peek characters. To make this 73 * all work, the history routines read with getC, and make use both 74 * of ungetC and unreadc. The key observation is that the state 75 * of getC at the call of a history reference is such that calls 76 * to getC from the history routines will always yield calls of 77 * readc, unless this peeking is involved. That is to say that during 78 * getexcl the variables lap, exclp, and exclnxt are all zero. 79 * 80 * Getdol invokes history substitution, hence the extra peek, peekd, 81 * which it can ungetD to be before history substitutions. 82 */ 83 static Char peekc = 0, peekd = 0; 84 static Char peekread = 0; 85 86 /* (Tail of) current word from ! subst */ 87 static Char *exclp = NULL; 88 89 /* The rest of the ! subst words */ 90 static struct wordent *exclnxt = NULL; 91 92 /* Count of remaining words in ! subst */ 93 static int exclc = 0; 94 95 /* "Globp" for alias resubstitution */ 96 int aret = TCSH_F_SEEK; 97 98 /* 99 * Labuf implements a general buffer for lookahead during lexical operations. 100 * Text which is to be placed in the input stream can be stuck here. 101 * We stick parsed ahead $ constructs during initial input, 102 * process id's from `$$', and modified variable values (from qualifiers 103 * during expansion in sh.dol.c) here. 104 */ 105 static Char labuf[BUFSIZE]; 106 107 /* 108 * Lex returns to its caller not only a wordlist (as a "var" parameter) 109 * but also whether a history substitution occurred. This is used in 110 * the main (process) routine to determine whether to echo, and also 111 * when called by the alias routine to determine whether to keep the 112 * argument list. 113 */ 114 static bool hadhist = 0; 115 116 /* 117 * Avoid alias expansion recursion via \!# 118 */ 119 int hleft; 120 121 Char histline[BUFSIZE + 2]; /* last line input */ 122 123 /* The +2 is to fool hp's optimizer */ 124 bool histvalid = 0; /* is histline valid */ 125 static Char *histlinep = NULL; /* current pointer into histline */ 126 127 static Char getCtmp; 128 129 #define getC(f) (((getCtmp = peekc) != '\0') ? (peekc = 0, getCtmp) : getC1(f)) 130 #define ungetC(c) peekc = (Char) c 131 #define ungetD(c) peekd = (Char) c 132 133 /* Use Htime to store timestamps picked up from history file for enthist() 134 * if reading saved history (sg) 135 */ 136 time_t Htime = (time_t)0; 137 static time_t a2time_t __P((Char *)); 138 139 /* 140 * for history event processing 141 * in the command 'echo !?foo?:1 !$' we want the !$ to expand from the line 142 * 'foo' was found instead of the last command 143 */ 144 static int uselastevent = 1; 145 146 int 147 lex(hp) 148 struct wordent *hp; 149 { 150 struct wordent *wdp; 151 int c; 152 153 154 uselastevent = 1; 155 histvalid = 0; 156 histlinep = histline; 157 *histlinep = '\0'; 158 159 btell(&lineloc); 160 hp->next = hp->prev = hp; 161 hp->word = STRNULL; 162 hadhist = 0; 163 do 164 c = readc(0); 165 while (c == ' ' || c == '\t'); 166 if (c == HISTSUB && intty) 167 /* ^lef^rit from tty is short !:s^lef^rit */ 168 getexcl(c); 169 else 170 unreadc(c); 171 wdp = hp; 172 /* 173 * The following loop is written so that the links needed by freelex will 174 * be ready and rarin to go even if it is interrupted. 175 */ 176 do { 177 struct wordent *new; 178 179 new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 180 new->word = STRNULL; 181 new->prev = wdp; 182 new->next = hp; 183 wdp->next = new; 184 hp->prev = new; 185 wdp = new; 186 wdp->word = word(); 187 } while (wdp->word[0] != '\n'); 188 if (histlinep < histline + BUFSIZE) { 189 *histlinep = '\0'; 190 if (histlinep > histline && histlinep[-1] == '\n') 191 histlinep[-1] = '\0'; 192 histvalid = 1; 193 } 194 else { 195 histline[BUFSIZE - 1] = '\0'; 196 } 197 198 return (hadhist); 199 } 200 201 static time_t 202 a2time_t(word) 203 Char *word; 204 { 205 /* Attempt to distinguish timestamps from other possible entries. 206 * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */ 207 208 time_t ret; 209 Char *s; 210 int ct; 211 212 if (!word || *(s = word) != '+') 213 return (time_t)0; 214 215 for (++s, ret = 0, ct = 0; *s; ++s, ++ct) 216 { 217 if (!isdigit((unsigned char)*s)) 218 return (time_t)0; 219 ret = ret * 10 + (time_t)((unsigned char)*s - '0'); 220 } 221 222 if (ct != 10) 223 return (time_t)0; 224 225 return ret; 226 } 227 228 void 229 prlex(sp0) 230 struct wordent *sp0; 231 { 232 struct wordent *sp = sp0->next; 233 234 for (;;) { 235 xprintf("%S", sp->word); 236 sp = sp->next; 237 if (sp == sp0) 238 break; 239 if (sp->word[0] != '\n') 240 xputchar(' '); 241 } 242 } 243 244 void 245 copylex(hp, fp) 246 struct wordent *hp; 247 struct wordent *fp; 248 { 249 struct wordent *wdp; 250 251 wdp = hp; 252 fp = fp->next; 253 do { 254 struct wordent *new; 255 256 new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); 257 new->word = STRNULL; 258 new->prev = wdp; 259 new->next = hp; 260 wdp->next = new; 261 hp->prev = new; 262 wdp = new; 263 wdp->word = Strsave(fp->word); 264 fp = fp->next; 265 } while (wdp->word[0] != '\n'); 266 } 267 268 void 269 freelex(vp) 270 struct wordent *vp; 271 { 272 struct wordent *fp; 273 274 while (vp->next != vp) { 275 fp = vp->next; 276 vp->next = fp->next; 277 if (fp->word != STRNULL) 278 xfree((ptr_t) fp->word); 279 xfree((ptr_t) fp); 280 } 281 vp->prev = vp; 282 } 283 284 static Char * 285 word() 286 { 287 Char c, c1; 288 Char *wp; 289 Char wbuf[BUFSIZE]; 290 Char hbuf[12]; 291 int h; 292 bool dolflg; 293 int i; 294 #if defined(DSPMBYTE) 295 int mbytepos = 1; 296 #endif /* DSPMBYTE */ 297 298 wp = wbuf; 299 i = BUFSIZE - 4; 300 loop: 301 while ((c = getC(DOALL)) == ' ' || c == '\t') 302 continue; 303 if (cmap(c, _META | _ESC)) 304 switch (c) { 305 case '&': 306 case '|': 307 case '<': 308 case '>': 309 *wp++ = c; 310 c1 = getC(DOALL); 311 if (c1 == c) 312 *wp++ = c1; 313 else 314 ungetC(c1); 315 goto ret; 316 317 case '#': 318 if (intty) 319 break; 320 c = 0; 321 h = 0; 322 do { 323 c1 = c; 324 c = getC(0); 325 if (h < 12) 326 hbuf[h++] = c; 327 } while (c != '\n'); 328 hbuf[11] = '\0'; 329 Htime = a2time_t(hbuf); 330 if (c1 == '\\') 331 goto loop; 332 /*FALLTHROUGH*/ 333 334 case ';': 335 case '(': 336 case ')': 337 case '\n': 338 *wp++ = c; 339 goto ret; 340 341 case '\\': 342 c = getC(0); 343 if (c == '\n') { 344 if (onelflg == 1) 345 onelflg = 2; 346 goto loop; 347 } 348 if (c != HIST) 349 *wp++ = '\\', --i; 350 c |= QUOTE; 351 default: 352 break; 353 } 354 c1 = 0; 355 dolflg = DOALL; 356 for (;;) { 357 #if defined(DSPMBYTE) 358 if (mbytepos == 2) 359 mbytepos = 1; 360 else if (mbytepos == 1 && Ismbyte1(c) && 2 <= i) 361 mbytepos = 2; 362 else 363 #endif /* DSPMBYTE */ 364 if (c1) { 365 if (c == c1) { 366 c1 = 0; 367 dolflg = DOALL; 368 } 369 else if (c == '\\') { 370 c = getC(0); 371 /* 372 * PWP: this is dumb, but how all of the other shells work. If \ quotes 373 * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY 374 * following character INSIDE a set of ''s. 375 * 376 * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar 377 */ 378 if (c == HIST) 379 c |= QUOTE; 380 else { 381 if (bslash_quote && 382 ((c == '\'') || (c == '"') || 383 (c == '\\'))) { 384 c |= QUOTE; 385 } 386 else { 387 if (c == '\n') 388 /* 389 * if (c1 == '`') c = ' '; else 390 */ 391 c |= QUOTE; 392 ungetC(c); 393 c = '\\'; 394 } 395 } 396 } 397 else if (c == '\n') { 398 seterror(ERR_UNMATCHED, c1); 399 ungetC(c); 400 break; 401 } 402 } 403 else if (cmap(c, _META | _QF | _QB | _ESC)) { 404 if (c == '\\') { 405 c = getC(0); 406 if (c == '\n') { 407 if (onelflg == 1) 408 onelflg = 2; 409 break; 410 } 411 if (c != HIST) 412 *wp++ = '\\', --i; 413 c |= QUOTE; 414 } 415 else if (cmap(c, _QF | _QB)) { /* '"` */ 416 c1 = c; 417 dolflg = c == '"' ? DOALL : DOEXCL; 418 } 419 else if (c != '#' || !intty) { 420 ungetC(c); 421 break; 422 } 423 } 424 if (--i > 0) { 425 *wp++ = c; 426 c = getC(dolflg); 427 } 428 else { 429 seterror(ERR_WTOOLONG); 430 wp = &wbuf[1]; 431 break; 432 } 433 } 434 ret: 435 *wp = 0; 436 return (Strsave(wbuf)); 437 } 438 439 static int 440 getC1(flag) 441 int flag; 442 { 443 Char c; 444 445 for (;;) { 446 if ((c = peekc) != 0) { 447 peekc = 0; 448 return (c); 449 } 450 if (lap) { 451 if ((c = *lap++) == 0) 452 lap = 0; 453 else { 454 if (cmap(c, _META | _QF | _QB)) 455 c |= QUOTE; 456 return (c); 457 } 458 } 459 if ((c = peekd) != 0) { 460 peekd = 0; 461 return (c); 462 } 463 if (exclp) { 464 if ((c = *exclp++) != 0) 465 return (c); 466 if (exclnxt && --exclc >= 0) { 467 exclnxt = exclnxt->next; 468 setexclp(exclnxt->word); 469 return (' '); 470 } 471 exclp = 0; 472 exclnxt = 0; 473 /* this will throw away the dummy history entries */ 474 savehist(NULL, 0); 475 476 } 477 if (exclnxt) { 478 exclnxt = exclnxt->next; 479 if (--exclc < 0) 480 exclnxt = 0; 481 else 482 setexclp(exclnxt->word); 483 continue; 484 } 485 c = readc(0); 486 if (c == '$' && (flag & DODOL)) { 487 getdol(); 488 continue; 489 } 490 if (c == HIST && (flag & DOEXCL)) { 491 getexcl(0); 492 continue; 493 } 494 break; 495 } 496 return (c); 497 } 498 499 static void 500 getdol() 501 { 502 Char *np, *ep; 503 Char name[4 * MAXVARLEN + 1]; 504 int c; 505 int sc; 506 bool special = 0, toolong; 507 508 np = name, *np++ = '$'; 509 c = sc = getC(DOEXCL); 510 if (any("\t \n", c)) { 511 ungetD(c); 512 ungetC('$' | QUOTE); 513 return; 514 } 515 if (c == '{') 516 *np++ = (Char) c, c = getC(DOEXCL); 517 if (c == '#' || c == '?' || c == '%') 518 special++, *np++ = (Char) c, c = getC(DOEXCL); 519 *np++ = (Char) c; 520 switch (c) { 521 522 case '<': 523 case '$': 524 case '!': 525 if (special) 526 seterror(ERR_SPDOLLT); 527 *np = 0; 528 addla(name); 529 return; 530 531 case '\n': 532 ungetD(c); 533 np--; 534 if (!special) 535 seterror(ERR_NEWLINE); 536 *np = 0; 537 addla(name); 538 return; 539 540 case '*': 541 if (special) 542 seterror(ERR_SPSTAR); 543 *np = 0; 544 addla(name); 545 return; 546 547 default: 548 toolong = 0; 549 if (Isdigit(c)) { 550 #ifdef notdef 551 /* let $?0 pass for now */ 552 if (special) { 553 seterror(ERR_DIGIT); 554 *np = 0; 555 addla(name); 556 return; 557 } 558 #endif 559 /* we know that np < &name[4] */ 560 ep = &np[MAXVARLEN]; 561 while ((c = getC(DOEXCL)) != 0) { 562 if (!Isdigit(c)) 563 break; 564 if (np < ep) 565 *np++ = (Char) c; 566 else 567 toolong = 1; 568 } 569 } 570 else if (letter(c)) { 571 /* we know that np < &name[4] */ 572 ep = &np[MAXVARLEN]; 573 toolong = 0; 574 while ((c = getC(DOEXCL)) != 0) { 575 /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ 576 if (!letter(c) && !Isdigit(c)) 577 break; 578 if (np < ep) 579 *np++ = (Char) c; 580 else 581 toolong = 1; 582 } 583 } 584 else { 585 if (!special) 586 seterror(ERR_VARILL); 587 else { 588 ungetD(c); 589 --np; 590 } 591 *np = 0; 592 addla(name); 593 return; 594 } 595 if (toolong) { 596 seterror(ERR_VARTOOLONG); 597 *np = 0; 598 addla(name); 599 return; 600 } 601 break; 602 } 603 if (c == '[') { 604 *np++ = (Char) c; 605 /* 606 * Name up to here is a max of MAXVARLEN + 8. 607 */ 608 ep = &np[2 * MAXVARLEN + 8]; 609 do { 610 /* 611 * Michael Greim: Allow $ expansion to take place in selector 612 * expressions. (limits the number of characters returned) 613 */ 614 c = getC(DOEXCL | DODOL); 615 if (c == '\n') { 616 ungetD(c); 617 np--; 618 seterror(ERR_NLINDEX); 619 *np = 0; 620 addla(name); 621 return; 622 } 623 if (np < ep) 624 *np++ = (Char) c; 625 } while (c != ']'); 626 *np = '\0'; 627 if (np >= ep) { 628 seterror(ERR_SELOVFL); 629 addla(name); 630 return; 631 } 632 c = getC(DOEXCL); 633 } 634 /* 635 * Name up to here is a max of 2 * MAXVARLEN + 8. 636 */ 637 if (c == ':') { 638 /* 639 * if the :g modifier is followed by a newline, then error right away! 640 * -strike 641 */ 642 643 int gmodflag = 0, amodflag = 0; 644 645 #ifndef COMPAT 646 do { 647 #endif /* COMPAT */ 648 *np++ = (Char) c, c = getC(DOEXCL); 649 if (c == 'g' || c == 'a') { 650 if (c == 'g') 651 gmodflag++; 652 else 653 amodflag++; 654 *np++ = (Char) c; c = getC(DOEXCL); 655 } 656 if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { 657 if (c == 'g') 658 gmodflag++; 659 else 660 amodflag++; 661 *np++ = (Char) c; c = getC(DOEXCL); 662 } 663 *np++ = (Char) c; 664 /* scan s// [eichin:19910926.0512EST] */ 665 if (c == 's') { 666 int delimcnt = 2; 667 int delim = getC(0); 668 *np++ = (Char) delim; 669 670 if (!delim || letter(delim) 671 || Isdigit(delim) || any(" \t\n", delim)) { 672 seterror(ERR_BADSUBST); 673 break; 674 } 675 while ((c = getC(0)) != (-1)) { 676 *np++ = (Char) c; 677 if(c == delim) delimcnt--; 678 if(!delimcnt) break; 679 } 680 if(delimcnt) { 681 seterror(ERR_BADSUBST); 682 break; 683 } 684 c = 's'; 685 } 686 if (!any("htrqxesul", c)) { 687 if ((amodflag || gmodflag) && c == '\n') 688 stderror(ERR_VARSYN); /* strike */ 689 seterror(ERR_BADMOD, c); 690 *np = 0; 691 addla(name); 692 return; 693 } 694 #ifndef COMPAT 695 } 696 while ((c = getC(DOEXCL)) == ':'); 697 ungetD(c); 698 #endif /* COMPAT */ 699 } 700 else 701 ungetD(c); 702 if (sc == '{') { 703 c = getC(DOEXCL); 704 if (c != '}') { 705 ungetD(c); 706 seterror(ERR_MISSING, '}'); 707 *np = 0; 708 addla(name); 709 return; 710 } 711 *np++ = (Char) c; 712 } 713 *np = 0; 714 addla(name); 715 return; 716 } 717 718 void 719 addla(cp) 720 Char *cp; 721 { 722 Char buf[BUFSIZE]; 723 724 if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= 725 (sizeof(labuf) - 4) / sizeof(Char)) { 726 seterror(ERR_EXPOVFL); 727 return; 728 } 729 if (lap) 730 (void) Strcpy(buf, lap); 731 (void) Strcpy(labuf, cp); 732 if (lap) 733 (void) Strcat(labuf, buf); 734 lap = labuf; 735 } 736 737 static Char lhsb[32]; 738 static Char slhs[32]; 739 static Char rhsb[64]; 740 static int quesarg; 741 742 static void 743 getexcl(sc) 744 int sc; 745 { 746 struct wordent *hp, *ip; 747 int left, right, dol; 748 int c; 749 750 if (sc == 0) { 751 sc = getC(0); 752 if (sc != '{') { 753 ungetC(sc); 754 sc = 0; 755 } 756 } 757 quesarg = -1; 758 759 if (uselastevent) { 760 uselastevent = 0; 761 lastev = eventno; 762 } 763 else 764 lastev = eventno; 765 hp = gethent(sc); 766 if (hp == 0) 767 return; 768 hadhist = 1; 769 dol = 0; 770 if (hp == alhistp) 771 for (ip = hp->next->next; ip != alhistt; ip = ip->next) 772 dol++; 773 else 774 for (ip = hp->next->next; ip != hp->prev; ip = ip->next) 775 dol++; 776 left = 0, right = dol; 777 if (sc == HISTSUB) { 778 ungetC('s'), unreadc(HISTSUB), c = ':'; 779 goto subst; 780 } 781 c = getC(0); 782 if (!any(":^$*-%", c)) 783 goto subst; 784 left = right = -1; 785 if (c == ':') { 786 c = getC(0); 787 unreadc(c); 788 if (letter(c) || c == '&') { 789 c = ':'; 790 left = 0, right = dol; 791 goto subst; 792 } 793 } 794 else 795 ungetC(c); 796 if (!getsel(&left, &right, dol)) 797 return; 798 c = getC(0); 799 if (c == '*') 800 ungetC(c), c = '-'; 801 if (c == '-') { 802 if (!getsel(&left, &right, dol)) 803 return; 804 c = getC(0); 805 } 806 subst: 807 exclc = right - left + 1; 808 while (--left >= 0) 809 hp = hp->next; 810 if (sc == HISTSUB || c == ':') { 811 do { 812 hp = getsub(hp); 813 c = getC(0); 814 } while (c == ':'); 815 } 816 unreadc(c); 817 if (sc == '{') { 818 c = getC(0); 819 if (c != '}') 820 seterror(ERR_BADBANG); 821 } 822 exclnxt = hp; 823 } 824 825 static struct wordent * 826 getsub(en) 827 struct wordent *en; 828 { 829 Char *cp; 830 int delim; 831 int c; 832 int sc; 833 bool global; 834 Char orhsb[sizeof(rhsb) / sizeof(Char)]; 835 836 #ifndef COMPAT 837 do { 838 #endif /* COMPAT */ 839 exclnxt = 0; 840 global = 0; 841 sc = c = getC(0); 842 if (c == 'g' || c == 'a') { 843 global |= (c == 'g') ? 1 : 2; 844 sc = c = getC(0); 845 } 846 if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) { 847 global |= (c == 'g') ? 1 : 2; 848 sc = c = getC(0); 849 } 850 851 switch (c) { 852 case 'p': 853 justpr++; 854 return (en); 855 856 case 'x': 857 case 'q': 858 global |= 1; 859 /*FALLTHROUGH*/ 860 861 case 'h': 862 case 'r': 863 case 't': 864 case 'e': 865 case 'u': 866 case 'l': 867 break; 868 869 case '&': 870 if (slhs[0] == 0) { 871 seterror(ERR_NOSUBST); 872 return (en); 873 } 874 (void) Strcpy(lhsb, slhs); 875 break; 876 877 #ifdef notdef 878 case '~': 879 if (lhsb[0] == 0) 880 goto badlhs; 881 break; 882 #endif 883 884 case 's': 885 delim = getC(0); 886 if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { 887 unreadc(delim); 888 lhsb[0] = 0; 889 seterror(ERR_BADSUBST); 890 return (en); 891 } 892 cp = lhsb; 893 for (;;) { 894 c = getC(0); 895 if (c == '\n') { 896 unreadc(c); 897 break; 898 } 899 if (c == delim) 900 break; 901 if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { 902 lhsb[0] = 0; 903 seterror(ERR_BADSUBST); 904 return (en); 905 } 906 if (c == '\\') { 907 c = getC(0); 908 if (c != delim && c != '\\') 909 *cp++ = '\\'; 910 } 911 *cp++ = (Char) c; 912 } 913 if (cp != lhsb) 914 *cp++ = 0; 915 else if (lhsb[0] == 0) { 916 seterror(ERR_LHS); 917 return (en); 918 } 919 cp = rhsb; 920 (void) Strcpy(orhsb, cp); 921 for (;;) { 922 c = getC(0); 923 if (c == '\n') { 924 unreadc(c); 925 break; 926 } 927 if (c == delim) 928 break; 929 #ifdef notdef 930 if (c == '~') { 931 if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) / 932 sizeof(Char) - 2]) 933 goto toorhs; 934 (void) Strcpy(cp, orhsb); 935 cp = Strend(cp); 936 continue; 937 } 938 #endif 939 if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { 940 seterror(ERR_RHSLONG); 941 return (en); 942 } 943 if (c == '\\') { 944 c = getC(0); 945 if (c != delim /* && c != '~' */ ) 946 *cp++ = '\\'; 947 } 948 *cp++ = (Char) c; 949 } 950 *cp++ = 0; 951 break; 952 953 default: 954 if (c == '\n') 955 unreadc(c); 956 seterror(ERR_BADBANGMOD, c); 957 return (en); 958 } 959 (void) Strcpy(slhs, lhsb); 960 if (exclc) 961 en = dosub(sc, en, global); 962 #ifndef COMPAT 963 } 964 while ((c = getC(0)) == ':'); 965 unreadc(c); 966 #endif /* COMPAT */ 967 return (en); 968 } 969 970 /* 971 * 972 * From Beto Appleton (beto@aixwiz.austin.ibm.com) 973 * 974 * when using history substitution, and the variable 975 * 'history' is set to a value higher than 1000, 976 * the shell might either freeze (hang) or core-dump. 977 * We raise the limit to 50000000 978 */ 979 980 #define HIST_PURGE -50000000 981 static struct wordent * 982 dosub(sc, en, global) 983 int sc; 984 struct wordent *en; 985 bool global; 986 { 987 struct wordent lexi; 988 bool didsub = 0, didone = 0; 989 struct wordent *hp = &lexi; 990 struct wordent *wdp; 991 int i = exclc; 992 struct Hist *hst; 993 994 wdp = hp; 995 while (--i >= 0) { 996 struct wordent *new = 997 (struct wordent *) xcalloc(1, sizeof *wdp); 998 999 new->word = 0; 1000 new->prev = wdp; 1001 new->next = hp; 1002 wdp->next = new; 1003 wdp = new; 1004 en = en->next; 1005 if (en->word) { 1006 Char *tword, *otword; 1007 1008 if ((global & 1) || didsub == 0) { 1009 tword = subword(en->word, sc, &didone); 1010 if (didone) 1011 didsub = 1; 1012 if (global & 2) { 1013 while (didone && tword != STRNULL) { 1014 otword = tword; 1015 tword = subword(otword, sc, &didone); 1016 if (Strcmp(tword, otword) == 0) { 1017 xfree((ptr_t) otword); 1018 break; 1019 } 1020 else 1021 xfree((ptr_t) otword); 1022 } 1023 } 1024 } 1025 else 1026 tword = Strsave(en->word); 1027 wdp->word = tword; 1028 } 1029 } 1030 if (didsub == 0) 1031 seterror(ERR_MODFAIL); 1032 hp->prev = wdp; 1033 /* 1034 * ANSI mode HP/UX compiler chokes on 1035 * return &enthist(HIST_PURGE, &lexi, 0)->Hlex; 1036 */ 1037 hst = enthist(HIST_PURGE, &lexi, 0, 0); 1038 return &(hst->Hlex); 1039 } 1040 1041 static Char * 1042 subword(cp, type, adid) 1043 Char *cp; 1044 int type; 1045 bool *adid; 1046 { 1047 Char wbuf[BUFSIZE]; 1048 Char *wp, *mp, *np; 1049 int i; 1050 1051 *adid = 0; 1052 switch (type) { 1053 1054 case 'r': 1055 case 'e': 1056 case 'h': 1057 case 't': 1058 case 'q': 1059 case 'x': 1060 case 'u': 1061 case 'l': 1062 wp = domod(cp, type); 1063 if (wp == 0) 1064 return (Strsave(cp)); 1065 *adid = 1; 1066 return (wp); 1067 1068 default: 1069 wp = wbuf; 1070 i = BUFSIZE - 4; 1071 for (mp = cp; *mp; mp++) 1072 if (matchs(mp, lhsb)) { 1073 for (np = cp; np < mp;) 1074 *wp++ = *np++, --i; 1075 for (np = rhsb; *np; np++) 1076 switch (*np) { 1077 1078 case '\\': 1079 if (np[1] == '&') 1080 np++; 1081 /* fall into ... */ 1082 1083 default: 1084 if (--i < 0) { 1085 seterror(ERR_SUBOVFL); 1086 return (STRNULL); 1087 } 1088 *wp++ = *np; 1089 continue; 1090 1091 case '&': 1092 i -= Strlen(lhsb); 1093 if (i < 0) { 1094 seterror(ERR_SUBOVFL); 1095 return (STRNULL); 1096 } 1097 *wp = 0; 1098 (void) Strcat(wp, lhsb); 1099 wp = Strend(wp); 1100 continue; 1101 } 1102 mp += Strlen(lhsb); 1103 i -= Strlen(mp); 1104 if (i < 0) { 1105 seterror(ERR_SUBOVFL); 1106 return (STRNULL); 1107 } 1108 *wp = 0; 1109 (void) Strcat(wp, mp); 1110 *adid = 1; 1111 return (Strsave(wbuf)); 1112 } 1113 return (Strsave(cp)); 1114 } 1115 } 1116 1117 Char * 1118 domod(cp, type) 1119 Char *cp; 1120 int type; 1121 { 1122 Char *wp, *xp; 1123 int c; 1124 1125 switch (type) { 1126 1127 case 'x': 1128 case 'q': 1129 wp = Strsave(cp); 1130 for (xp = wp; (c = *xp) != 0; xp++) 1131 if ((c != ' ' && c != '\t') || type == 'q') 1132 *xp |= QUOTE; 1133 return (wp); 1134 1135 case 'l': 1136 wp = Strsave(cp); 1137 for (cp = wp; *cp; cp++) 1138 if (Isupper(*cp)) { 1139 *cp = Tolower(*cp); 1140 return wp; 1141 } 1142 return wp; 1143 1144 case 'u': 1145 wp = Strsave(cp); 1146 for (cp = wp; *cp; cp++) 1147 if (Islower(*cp)) { 1148 *cp = Toupper(*cp); 1149 return wp; 1150 } 1151 return wp; 1152 1153 case 'h': 1154 case 't': 1155 if (!any(short2str(cp), '/')) 1156 return (type == 't' ? Strsave(cp) : 0); 1157 wp = Strend(cp); 1158 while (*--wp != '/') 1159 continue; 1160 if (type == 'h') 1161 xp = Strsave(cp), xp[wp - cp] = 0; 1162 else 1163 xp = Strsave(wp + 1); 1164 return (xp); 1165 1166 case 'e': 1167 case 'r': 1168 wp = Strend(cp); 1169 for (wp--; wp >= cp && *wp != '/'; wp--) 1170 if (*wp == '.') { 1171 if (type == 'e') 1172 xp = Strsave(wp + 1); 1173 else 1174 xp = Strsave(cp), xp[wp - cp] = 0; 1175 return (xp); 1176 } 1177 return (Strsave(type == 'e' ? STRNULL : cp)); 1178 default: 1179 break; 1180 } 1181 return (0); 1182 } 1183 1184 static int 1185 matchs(str, pat) 1186 Char *str, *pat; 1187 { 1188 while (*str && *pat && *str == *pat) 1189 str++, pat++; 1190 return (*pat == 0); 1191 } 1192 1193 static int 1194 getsel(al, ar, dol) 1195 int *al, *ar; 1196 int dol; 1197 { 1198 int c = getC(0); 1199 int i; 1200 bool first = *al < 0; 1201 1202 switch (c) { 1203 1204 case '%': 1205 if (quesarg == -1) { 1206 seterror(ERR_BADBANGARG); 1207 return (0); 1208 } 1209 if (*al < 0) 1210 *al = quesarg; 1211 *ar = quesarg; 1212 break; 1213 1214 case '-': 1215 if (*al < 0) { 1216 *al = 0; 1217 *ar = dol - 1; 1218 unreadc(c); 1219 } 1220 return (1); 1221 1222 case '^': 1223 if (*al < 0) 1224 *al = 1; 1225 *ar = 1; 1226 break; 1227 1228 case '$': 1229 if (*al < 0) 1230 *al = dol; 1231 *ar = dol; 1232 break; 1233 1234 case '*': 1235 if (*al < 0) 1236 *al = 1; 1237 *ar = dol; 1238 if (*ar < *al) { 1239 *ar = 0; 1240 *al = 1; 1241 return (1); 1242 } 1243 break; 1244 1245 default: 1246 if (Isdigit(c)) { 1247 i = 0; 1248 while (Isdigit(c)) { 1249 i = i * 10 + c - '0'; 1250 c = getC(0); 1251 } 1252 if (i < 0) 1253 i = dol + 1; 1254 if (*al < 0) 1255 *al = i; 1256 *ar = i; 1257 } 1258 else if (*al < 0) 1259 *al = 0, *ar = dol; 1260 else 1261 *ar = dol - 1; 1262 unreadc(c); 1263 break; 1264 } 1265 if (first) { 1266 c = getC(0); 1267 unreadc(c); 1268 if (any("-$*", c)) 1269 return (1); 1270 } 1271 if (*al > *ar || *ar > dol) { 1272 seterror(ERR_BADBANGARG); 1273 return (0); 1274 } 1275 return (1); 1276 1277 } 1278 1279 static struct wordent * 1280 gethent(sc) 1281 int sc; 1282 { 1283 struct Hist *hp; 1284 Char *np; 1285 int c; 1286 int event; 1287 bool back = 0; 1288 1289 c = sc == HISTSUB ? HIST : getC(0); 1290 if (c == HIST) { 1291 if (alhistp) 1292 return (alhistp); 1293 event = eventno; 1294 } 1295 else 1296 switch (c) { 1297 1298 case ':': 1299 case '^': 1300 case '$': 1301 case '*': 1302 case '%': 1303 ungetC(c); 1304 if (lastev == eventno && alhistp) 1305 return (alhistp); 1306 event = lastev; 1307 break; 1308 1309 case '#': /* !# is command being typed in (mrh) */ 1310 if (--hleft == 0) { 1311 seterror(ERR_HISTLOOP); 1312 return (0); 1313 } 1314 else 1315 return (¶ml); 1316 /* NOTREACHED */ 1317 1318 case '-': 1319 back = 1; 1320 c = getC(0); 1321 /* FALLSTHROUGH */ 1322 1323 default: 1324 if (any("(=~", c)) { 1325 unreadc(c); 1326 ungetC(HIST); 1327 return (0); 1328 } 1329 np = lhsb; 1330 event = 0; 1331 while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) { 1332 if (event != -1 && Isdigit(c)) 1333 event = event * 10 + c - '0'; 1334 else 1335 event = -1; 1336 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1337 *np++ = (Char) c; 1338 c = getC(0); 1339 } 1340 unreadc(c); 1341 if (np == lhsb) { 1342 ungetC(HIST); 1343 return (0); 1344 } 1345 *np++ = 0; 1346 if (event != -1) { 1347 /* 1348 * History had only digits 1349 */ 1350 if (back) 1351 event = eventno + (alhistp == 0) - (event ? event : 0); 1352 break; 1353 } 1354 if (back) { 1355 event = sizeof(lhsb) / sizeof(lhsb[0]); 1356 np = &lhsb[--event]; 1357 *np-- = '\0'; 1358 for (event--; np > lhsb; *np-- = lhsb[--event]) 1359 continue; 1360 *np = '-'; 1361 } 1362 hp = findev(lhsb, 0); 1363 if (hp) 1364 lastev = hp->Hnum; 1365 return (&hp->Hlex); 1366 1367 case '?': 1368 np = lhsb; 1369 for (;;) { 1370 c = getC(0); 1371 if (c == '\n') { 1372 unreadc(c); 1373 break; 1374 } 1375 if (c == '?') 1376 break; 1377 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) 1378 *np++ = (Char) c; 1379 } 1380 if (np == lhsb) { 1381 if (lhsb[0] == 0) { 1382 seterror(ERR_NOSEARCH); 1383 return (0); 1384 } 1385 } 1386 else 1387 *np++ = 0; 1388 hp = findev(lhsb, 1); 1389 if (hp) 1390 lastev = hp->Hnum; 1391 return (&hp->Hlex); 1392 } 1393 1394 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) 1395 if (hp->Hnum == event) { 1396 hp->Href = eventno; 1397 lastev = hp->Hnum; 1398 return (&hp->Hlex); 1399 } 1400 np = putn(event); 1401 seterror(ERR_NOEVENT, short2str(np)); 1402 return (0); 1403 } 1404 1405 static struct Hist * 1406 findev(cp, anyarg) 1407 Char *cp; 1408 bool anyarg; 1409 { 1410 struct Hist *hp; 1411 1412 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { 1413 Char *dp; 1414 Char *p, *q; 1415 struct wordent *lp = hp->Hlex.next; 1416 int argno = 0; 1417 1418 /* 1419 * The entries added by alias substitution don't have a newline but do 1420 * have a negative event number. Savehist() trims off these entries, 1421 * but it happens before alias expansion, too early to delete those 1422 * from the previous command. 1423 */ 1424 if (hp->Hnum < 0) 1425 continue; 1426 if (lp->word[0] == '\n') 1427 continue; 1428 if (!anyarg) { 1429 p = cp; 1430 q = lp->word; 1431 do 1432 if (!*p) 1433 return (hp); 1434 while (*p++ == *q++); 1435 continue; 1436 } 1437 do { 1438 for (dp = lp->word; *dp; dp++) { 1439 p = cp; 1440 q = dp; 1441 do 1442 if (!*p) { 1443 quesarg = argno; 1444 return (hp); 1445 } 1446 while (*p++ == *q++); 1447 } 1448 lp = lp->next; 1449 argno++; 1450 } while (lp->word[0] != '\n'); 1451 } 1452 seterror(ERR_NOEVENT, short2str(cp)); 1453 return (0); 1454 } 1455 1456 1457 static void 1458 setexclp(cp) 1459 Char *cp; 1460 { 1461 if (cp && cp[0] == '\n') 1462 return; 1463 exclp = cp; 1464 } 1465 1466 void 1467 unreadc(c) 1468 int c; 1469 { 1470 peekread = (Char) c; 1471 } 1472 1473 int 1474 readc(wanteof) 1475 bool wanteof; 1476 { 1477 int c; 1478 static int sincereal; /* Number of real EOFs we've seen */ 1479 Char *ptr; /* For STRignoreeof */ 1480 int numeof = 0; /* Value of STRignoreeof */ 1481 1482 #ifdef DEBUG_INP 1483 xprintf("readc\n"); 1484 #endif 1485 if ((c = peekread) != 0) { 1486 peekread = 0; 1487 return (c); 1488 } 1489 1490 /* Compute the value of EOFs */ 1491 if ((ptr = varval(STRignoreeof)) != STRNULL) { 1492 while (*ptr) { 1493 if (!Isdigit(*ptr)) { 1494 numeof = 0; 1495 break; 1496 } 1497 numeof = numeof * 10 + *ptr++ - '0'; 1498 } 1499 if (numeof != 0) 1500 numeof++; 1501 } 1502 if (numeof < 0) numeof = 26; /* Sanity check */ 1503 1504 top: 1505 aret = TCSH_F_SEEK; 1506 if (alvecp) { 1507 arun = 1; 1508 #ifdef DEBUG_INP 1509 xprintf("alvecp %c\n", *alvecp & 0xff); 1510 #endif 1511 aret = TCSH_A_SEEK; 1512 if ((c = *alvecp++) != 0) 1513 return (c); 1514 if (alvec && *alvec) { 1515 alvecp = *alvec++; 1516 return (' '); 1517 } 1518 else { 1519 alvecp = NULL; 1520 aret = TCSH_F_SEEK; 1521 return('\n'); 1522 } 1523 } 1524 if (alvec) { 1525 arun = 1; 1526 if ((alvecp = *alvec) != 0) { 1527 alvec++; 1528 goto top; 1529 } 1530 /* Infinite source! */ 1531 return ('\n'); 1532 } 1533 arun = 0; 1534 if (evalp) { 1535 aret = TCSH_E_SEEK; 1536 if ((c = *evalp++) != 0) 1537 return (c); 1538 if (evalvec && *evalvec) { 1539 evalp = *evalvec++; 1540 return (' '); 1541 } 1542 aret = TCSH_F_SEEK; 1543 evalp = 0; 1544 } 1545 if (evalvec) { 1546 if (evalvec == INVPPTR) { 1547 doneinp = 1; 1548 reset(); 1549 } 1550 if ((evalp = *evalvec) != 0) { 1551 evalvec++; 1552 goto top; 1553 } 1554 evalvec = INVPPTR; 1555 return ('\n'); 1556 } 1557 do { 1558 if (arginp == INVPTR || onelflg == 1) { 1559 if (wanteof) 1560 return (-1); 1561 exitstat(); 1562 } 1563 if (arginp) { 1564 if ((c = *arginp++) == 0) { 1565 arginp = INVPTR; 1566 return ('\n'); 1567 } 1568 return (c); 1569 } 1570 #ifdef BSDJOBS 1571 reread: 1572 #endif /* BSDJOBS */ 1573 c = bgetc(); 1574 if (c < 0) { 1575 #ifndef WINNT_NATIVE 1576 # ifndef POSIX 1577 # ifdef TERMIO 1578 struct termio tty; 1579 # else /* SGTTYB */ 1580 struct sgttyb tty; 1581 # endif /* TERMIO */ 1582 # else /* POSIX */ 1583 struct termios tty; 1584 # endif /* POSIX */ 1585 #endif /* !WINNT_NATIVE */ 1586 if (wanteof) 1587 return (-1); 1588 /* was isatty but raw with ignoreeof yields problems */ 1589 #ifndef WINNT_NATIVE 1590 # ifndef POSIX 1591 # ifdef TERMIO 1592 if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 && 1593 (tty.c_lflag & ICANON)) 1594 # else /* GSTTYB */ 1595 if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 && 1596 (tty.sg_flags & RAW) == 0) 1597 # endif /* TERMIO */ 1598 # else /* POSIX */ 1599 if (tcgetattr(SHIN, &tty) == 0 && 1600 (tty.c_lflag & ICANON)) 1601 # endif /* POSIX */ 1602 #else /* WINNT_NATIVE */ 1603 if (isatty(SHIN)) 1604 #endif /* !WINNT_NATIVE */ 1605 { 1606 #ifdef BSDJOBS 1607 int ctpgrp; 1608 #endif /* BSDJOBS */ 1609 1610 if (numeof != 0 && ++sincereal >= numeof) /* Too many EOFs? Bye! */ 1611 goto oops; 1612 #ifdef BSDJOBS 1613 if (tpgrp != -1 && 1614 (ctpgrp = tcgetpgrp(FSHTTY)) != -1 && 1615 tpgrp != ctpgrp) { 1616 (void) tcsetpgrp(FSHTTY, tpgrp); 1617 # ifdef _SEQUENT_ 1618 if (ctpgrp) 1619 # endif /* _SEQUENT */ 1620 (void) killpg((pid_t) ctpgrp, SIGHUP); 1621 # ifdef notdef 1622 /* 1623 * With the walking process group fix, this message 1624 * is now obsolete. As the foreground process group 1625 * changes, the shell needs to adjust. Well too bad. 1626 */ 1627 xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"), 1628 ctpgrp, tpgrp); 1629 # endif /* notdef */ 1630 goto reread; 1631 } 1632 #endif /* BSDJOBS */ 1633 /* What follows is complicated EOF handling -- sterling@netcom.com */ 1634 /* First, we check to see if we have ignoreeof set */ 1635 if (adrof(STRignoreeof)) { 1636 /* If so, we check for any stopped jobs only on the first EOF */ 1637 if ((sincereal == 1) && (chkstop == 0)) { 1638 panystop(1); 1639 } 1640 } else { 1641 /* If we don't have ignoreeof set, always check for stopped jobs */ 1642 if (chkstop == 0) { 1643 panystop(1); 1644 } 1645 } 1646 /* At this point, if there were stopped jobs, we would have already 1647 * called reset(). If we got this far, assume we can print an 1648 * exit/logout message if we ignoreeof, or just exit. 1649 */ 1650 if (adrof(STRignoreeof)) { 1651 /* If so, tell the user to use exit or logout */ 1652 if (loginsh) { 1653 xprintf(CGETS(16, 2, 1654 "\nUse \"logout\" to logout.\n")); 1655 } else { 1656 xprintf(CGETS(16, 3, 1657 "\nUse \"exit\" to leave %s.\n"), 1658 progname); 1659 } 1660 reset(); 1661 } else { 1662 /* If we don't have ignoreeof set, just fall through */ 1663 ; /* EMPTY */ 1664 } 1665 } 1666 oops: 1667 doneinp = 1; 1668 reset(); 1669 } 1670 sincereal = 0; 1671 if (c == '\n' && onelflg) 1672 onelflg--; 1673 } while (c == 0); 1674 if (histlinep < histline + BUFSIZE) 1675 *histlinep++ = (Char) c; 1676 return (c); 1677 } 1678 1679 static void 1680 balloc(buf) 1681 int buf; 1682 { 1683 Char **nfbuf; 1684 1685 while (buf >= fblocks) { 1686 nfbuf = (Char **) xcalloc((size_t) (fblocks + 2), 1687 sizeof(Char **)); 1688 if (fbuf) { 1689 (void) blkcpy(nfbuf, fbuf); 1690 xfree((ptr_t) fbuf); 1691 } 1692 fbuf = nfbuf; 1693 fbuf[fblocks] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 1694 fblocks++; 1695 } 1696 } 1697 1698 static int 1699 bgetc() 1700 { 1701 int c, off, buf; 1702 int numleft = 0, roomleft; 1703 char tbuf[BUFSIZE + 1]; 1704 1705 if (cantell) { 1706 if (fseekp < fbobp || fseekp > feobp) { 1707 fbobp = feobp = fseekp; 1708 (void) lseek(SHIN, fseekp, L_SET); 1709 } 1710 if (fseekp == feobp) { 1711 int i; 1712 1713 fbobp = feobp; 1714 do 1715 c = read(SHIN, tbuf, BUFSIZE); 1716 while (c < 0 && errno == EINTR); 1717 #ifdef convex 1718 if (c < 0) 1719 stderror(ERR_SYSTEM, progname, strerror(errno)); 1720 #endif /* convex */ 1721 if (c <= 0) 1722 return (-1); 1723 for (i = 0; i < c; i++) 1724 fbuf[0][i] = (unsigned char) tbuf[i]; 1725 feobp += c; 1726 } 1727 #ifndef WINNT_NATIVE 1728 c = fbuf[0][fseekp - fbobp]; 1729 fseekp++; 1730 #else 1731 do { 1732 c = fbuf[0][fseekp - fbobp]; 1733 fseekp++; 1734 } while(c == '\r'); 1735 #endif /* !WINNT_NATIVE */ 1736 return (c); 1737 } 1738 1739 while (fseekp >= feobp) { 1740 if ((editing 1741 #if defined(FILEC) && defined(TIOCSTI) 1742 || filec 1743 #endif /* FILEC && TIOCSTI */ 1744 ) && intty) { /* then use twenex routine */ 1745 fseekp = feobp; /* where else? */ 1746 #if defined(FILEC) && defined(TIOCSTI) 1747 if (!editing) 1748 c = numleft = tenex(InputBuf, BUFSIZE); 1749 else 1750 #endif /* FILEC && TIOCSTI */ 1751 c = numleft = Inputl(); /* PWP: get a line */ 1752 while (numleft > 0) { 1753 off = (int) feobp % BUFSIZE; 1754 buf = (int) feobp / BUFSIZE; 1755 balloc(buf); 1756 roomleft = BUFSIZE - off; 1757 if (roomleft > numleft) 1758 roomleft = numleft; 1759 (void) memmove((ptr_t) (fbuf[buf] + off), 1760 (ptr_t) (InputBuf + c - numleft), 1761 (size_t) (roomleft * sizeof(Char))); 1762 numleft -= roomleft; 1763 feobp += roomleft; 1764 } 1765 } else { 1766 off = (int) feobp % BUFSIZE; 1767 buf = (int) feobp / BUFSIZE; 1768 balloc(buf); 1769 roomleft = BUFSIZE - off; 1770 c = read(SHIN, tbuf, (size_t) roomleft); 1771 if (c > 0) { 1772 int i; 1773 Char *ptr = fbuf[buf] + off; 1774 1775 for (i = 0; i < c; i++) 1776 ptr[i] = (unsigned char) tbuf[i]; 1777 feobp += c; 1778 } 1779 } 1780 if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1)) 1781 return (-1); 1782 } 1783 #ifndef WINNT_NATIVE 1784 c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 1785 fseekp++; 1786 #else 1787 do { 1788 c = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE]; 1789 fseekp++; 1790 } while(c == '\r'); 1791 #endif /* !WINNT_NATIVE */ 1792 return (c); 1793 } 1794 1795 static void 1796 bfree() 1797 { 1798 int sb, i; 1799 1800 if (cantell) 1801 return; 1802 if (whyles) 1803 return; 1804 sb = (int) (fseekp - 1) / BUFSIZE; 1805 if (sb > 0) { 1806 for (i = 0; i < sb; i++) 1807 xfree((ptr_t) fbuf[i]); 1808 (void) blkcpy(fbuf, &fbuf[sb]); 1809 fseekp -= BUFSIZE * sb; 1810 feobp -= BUFSIZE * sb; 1811 fblocks -= sb; 1812 } 1813 } 1814 1815 void 1816 bseek(l) 1817 struct Ain *l; 1818 { 1819 switch (aret = l->type) { 1820 case TCSH_E_SEEK: 1821 evalvec = l->a_seek; 1822 evalp = l->c_seek; 1823 #ifdef DEBUG_SEEK 1824 xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp); 1825 #endif 1826 return; 1827 case TCSH_A_SEEK: 1828 alvec = l->a_seek; 1829 alvecp = l->c_seek; 1830 #ifdef DEBUG_SEEK 1831 xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp); 1832 #endif 1833 return; 1834 case TCSH_F_SEEK: 1835 #ifdef DEBUG_SEEK 1836 xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp); 1837 #endif 1838 fseekp = l->f_seek; 1839 return; 1840 default: 1841 xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 1842 abort(); 1843 } 1844 } 1845 1846 /* any similarity to bell telephone is purely accidental */ 1847 void 1848 btell(l) 1849 struct Ain *l; 1850 { 1851 switch (l->type = aret) { 1852 case TCSH_E_SEEK: 1853 l->a_seek = evalvec; 1854 l->c_seek = evalp; 1855 #ifdef DEBUG_SEEK 1856 xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp); 1857 #endif 1858 return; 1859 case TCSH_A_SEEK: 1860 l->a_seek = alvec; 1861 l->c_seek = alvecp; 1862 #ifdef DEBUG_SEEK 1863 xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp); 1864 #endif 1865 return; 1866 case TCSH_F_SEEK: 1867 /*SUPPRESS 112*/ 1868 l->f_seek = fseekp; 1869 l->a_seek = NULL; 1870 #ifdef DEBUG_SEEK 1871 xprintf(CGETS(16, 10, "tell file %x\n"), fseekp); 1872 #endif 1873 return; 1874 default: 1875 xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret); 1876 abort(); 1877 } 1878 } 1879 1880 void 1881 btoeof() 1882 { 1883 (void) lseek(SHIN, (off_t) 0, L_XTND); 1884 aret = TCSH_F_SEEK; 1885 fseekp = feobp; 1886 alvec = NULL; 1887 alvecp = NULL; 1888 evalvec = NULL; 1889 evalp = NULL; 1890 wfree(); 1891 bfree(); 1892 } 1893 1894 void 1895 settell() 1896 { 1897 off_t x; 1898 cantell = 0; 1899 if (arginp || onelflg || intty) 1900 return; 1901 if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1) 1902 return; 1903 fbuf = (Char **) xcalloc(2, sizeof(Char **)); 1904 fblocks = 1; 1905 fbuf[0] = (Char *) xcalloc(BUFSIZE, sizeof(Char)); 1906 fseekp = fbobp = feobp = x; 1907 cantell = 1; 1908 } 1909