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