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