1 /* $OpenBSD: dol.c,v 1.26 2019/06/28 05:35:34 deraadt Exp $ */ 2 /* $NetBSD: dol.c,v 1.8 1995/09/27 00:38:38 jtc Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1991, 1993 6 * The Regents of the University of California. 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 33 #include <sys/types.h> 34 #include <fcntl.h> 35 #include <errno.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 #include <stdarg.h> 40 41 #include "csh.h" 42 #include "extern.h" 43 44 /* 45 * These routines perform variable substitution and quoting via ' and ". 46 * To this point these constructs have been preserved in the divided 47 * input words. Here we expand variables and turn quoting via ' and " into 48 * QUOTE bits on characters (which prevent further interpretation). 49 * If the `:q' modifier was applied during history expansion, then 50 * some QUOTEing may have occurred already, so we dont "trim()" here. 51 */ 52 53 static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */ 54 static Char *Dcp, **Dvp; /* Input vector for Dreadc */ 55 56 #define DEOF -1 57 58 #define unDgetC(c) Dpeekc = c 59 60 #define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */ 61 62 /* 63 * The following variables give the information about the current 64 * $ expansion, recording the current word position, the remaining 65 * words within this expansion, the count of remaining words, and the 66 * information about any : modifier which is being applied. 67 */ 68 #define MAXWLEN (BUFSIZ - 4) 69 #define MAXMOD MAXWLEN /* This cannot overflow */ 70 static Char *dolp; /* Remaining chars from this word */ 71 static Char **dolnxt; /* Further words */ 72 static int dolcnt; /* Count of further words */ 73 static Char dolmod[MAXMOD]; /* : modifier character */ 74 static int dolnmod; /* Number of modifiers */ 75 static int dolmcnt; /* :gx -> 10000, else 1 */ 76 static int dolwcnt; /* :wx -> 10000, else 1 */ 77 78 static void Dfix2(Char **); 79 static Char *Dpack(Char *, Char *); 80 static int Dword(void); 81 static void dolerror(Char *); 82 static int DgetC(int); 83 static void Dgetdol(void); 84 static void fixDolMod(void); 85 static void setDolp(Char *); 86 static void unDredc(int); 87 static int Dredc(void); 88 static void Dtestq(int); 89 90 91 /* 92 * Fix up the $ expansions and quotations in the 93 * argument list to command t. 94 */ 95 void 96 Dfix(struct command *t) 97 { 98 Char **pp; 99 Char *p; 100 101 if (noexec) 102 return; 103 /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */ 104 for (pp = t->t_dcom; (p = *pp++) != NULL;) 105 for (; *p; p++) { 106 if (cmap(*p, _DOL | QUOTES)) { /* $, \, ', ", ` */ 107 Dfix2(t->t_dcom); /* found one */ 108 blkfree(t->t_dcom); 109 t->t_dcom = gargv; 110 gargv = 0; 111 return; 112 } 113 } 114 } 115 116 /* 117 * $ substitute one word, for i/o redirection 118 */ 119 Char * 120 Dfix1(Char *cp) 121 { 122 Char *Dv[2]; 123 124 if (noexec) 125 return (0); 126 Dv[0] = cp; 127 Dv[1] = NULL; 128 Dfix2(Dv); 129 if (gargc != 1) { 130 setname(vis_str(cp)); 131 stderror(ERR_NAME | ERR_AMBIG); 132 } 133 cp = Strsave(gargv[0]); 134 blkfree(gargv), gargv = 0; 135 return (cp); 136 } 137 138 /* 139 * Subroutine to do actual fixing after state initialization. 140 */ 141 static void 142 Dfix2(Char **v) 143 { 144 ginit(); /* Initialize glob's area pointers */ 145 Dvp = v; 146 Dcp = STRNULL; /* Setup input vector for Dreadc */ 147 unDgetC(0); 148 unDredc(0); /* Clear out any old peeks (at error) */ 149 dolp = 0; 150 dolcnt = 0; /* Clear out residual $ expands (...) */ 151 while (Dword()) 152 continue; 153 } 154 155 /* 156 * Pack up more characters in this word 157 */ 158 static Char * 159 Dpack(Char *wbuf, Char *wp) 160 { 161 int c; 162 int i = MAXWLEN - (wp - wbuf); 163 164 for (;;) { 165 c = DgetC(DODOL); 166 if (c == '\\') { 167 c = DgetC(0); 168 if (c == DEOF) { 169 unDredc(c); 170 *wp = 0; 171 Gcat(STRNULL, wbuf); 172 return (NULL); 173 } 174 if (c == '\n') 175 c = ' '; 176 else 177 c |= QUOTE; 178 } 179 if (c == DEOF) { 180 unDredc(c); 181 *wp = 0; 182 Gcat(STRNULL, wbuf); 183 return (NULL); 184 } 185 if (cmap(c, _SP | _NL | _QF | _QB)) { /* sp \t\n'"` */ 186 unDgetC(c); 187 if (cmap(c, QUOTES)) 188 return (wp); 189 *wp++ = 0; 190 Gcat(STRNULL, wbuf); 191 return (NULL); 192 } 193 if (--i <= 0) 194 stderror(ERR_WTOOLONG); 195 *wp++ = c; 196 } 197 } 198 199 /* 200 * Get a word. This routine is analogous to the routine 201 * word() in sh.lex.c for the main lexical input. One difference 202 * here is that we don't get a newline to terminate our expansion. 203 * Rather, DgetC will return a DEOF when we hit the end-of-input. 204 */ 205 static int 206 Dword(void) 207 { 208 int c, c1; 209 Char wbuf[BUFSIZ]; 210 Char *wp = wbuf; 211 int i = MAXWLEN; 212 bool dolflg; 213 bool sofar = 0, done = 0; 214 215 while (!done) { 216 done = 1; 217 c = DgetC(DODOL); 218 switch (c) { 219 220 case DEOF: 221 if (sofar == 0) 222 return (0); 223 /* finish this word and catch the code above the next time */ 224 unDredc(c); 225 /* fall into ... */ 226 227 case '\n': 228 *wp = 0; 229 Gcat(STRNULL, wbuf); 230 return (1); 231 232 case ' ': 233 case '\t': 234 done = 0; 235 break; 236 237 case '`': 238 /* We preserve ` quotations which are done yet later */ 239 *wp++ = c, --i; 240 case '\'': 241 case '"': 242 /* 243 * Note that DgetC never returns a QUOTES character from an 244 * expansion, so only true input quotes will get us here or out. 245 */ 246 c1 = c; 247 dolflg = c1 == '"' ? DODOL : 0; 248 for (;;) { 249 c = DgetC(dolflg); 250 if (c == c1) 251 break; 252 if (c == '\n' || c == DEOF) 253 stderror(ERR_UNMATCHED, c1); 254 if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE)) 255 --wp, ++i; 256 if (--i <= 0) 257 stderror(ERR_WTOOLONG); 258 switch (c1) { 259 260 case '"': 261 /* 262 * Leave any `s alone for later. Other chars are all 263 * quoted, thus `...` can tell it was within "...". 264 */ 265 *wp++ = c == '`' ? '`' : c | QUOTE; 266 break; 267 268 case '\'': 269 /* Prevent all further interpretation */ 270 *wp++ = c | QUOTE; 271 break; 272 273 case '`': 274 /* Leave all text alone for later */ 275 *wp++ = c; 276 break; 277 278 default: 279 break; 280 } 281 } 282 if (c1 == '`') 283 *wp++ = '`' /* i--; eliminated */; 284 sofar = 1; 285 if ((wp = Dpack(wbuf, wp)) == NULL) 286 return (1); 287 else { 288 i = MAXWLEN - (wp - wbuf); 289 done = 0; 290 } 291 break; 292 293 case '\\': 294 c = DgetC(0); /* No $ subst! */ 295 if (c == '\n' || c == DEOF) { 296 done = 0; 297 break; 298 } 299 c |= QUOTE; 300 break; 301 302 default: 303 break; 304 } 305 if (done) { 306 unDgetC(c); 307 sofar = 1; 308 if ((wp = Dpack(wbuf, wp)) == NULL) 309 return (1); 310 else { 311 i = MAXWLEN - (wp - wbuf); 312 done = 0; 313 } 314 } 315 } 316 /* Really NOTREACHED */ 317 return (0); 318 } 319 320 321 /* 322 * Get a character, performing $ substitution unless flag is 0. 323 * Any QUOTES character which is returned from a $ expansion is 324 * QUOTEd so that it will not be recognized above. 325 */ 326 static int 327 DgetC(int flag) 328 { 329 int c; 330 331 top: 332 if ((c = Dpeekc) != '\0') { 333 Dpeekc = 0; 334 return (c); 335 } 336 if (lap) { 337 c = *lap++ & (QUOTE | TRIM); 338 if (c == 0) { 339 lap = 0; 340 goto top; 341 } 342 quotspec: 343 if (cmap(c, QUOTES)) 344 return (c | QUOTE); 345 return (c); 346 } 347 if (dolp) { 348 if ((c = *dolp++ & (QUOTE | TRIM)) != '\0') 349 goto quotspec; 350 if (dolcnt > 0) { 351 setDolp(*dolnxt++); 352 --dolcnt; 353 return (' '); 354 } 355 dolp = 0; 356 } 357 if (dolcnt > 0) { 358 setDolp(*dolnxt++); 359 --dolcnt; 360 goto top; 361 } 362 c = Dredc(); 363 if (c == '$' && flag) { 364 Dgetdol(); 365 goto top; 366 } 367 return (c); 368 } 369 370 static Char *nulvec[] = {0}; 371 static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0}; 372 373 static void 374 dolerror(Char *s) 375 { 376 setname(vis_str(s)); 377 stderror(ERR_NAME | ERR_RANGE); 378 } 379 380 /* 381 * Handle the multitudinous $ expansion forms. 382 * Ugh. 383 */ 384 static void 385 Dgetdol(void) 386 { 387 Char *np; 388 struct varent *vp = NULL; 389 Char name[4 * MAXVARLEN + 1]; 390 int c, sc; 391 int subscr = 0, lwb = 1, upb = 0; 392 bool dimen = 0, bitset = 0; 393 char tnp; 394 Char wbuf[BUFSIZ]; 395 static Char *dolbang = NULL; 396 397 dolnmod = dolmcnt = dolwcnt = 0; 398 c = sc = DgetC(0); 399 if (c == '{') 400 c = DgetC(0); /* sc is { to take } later */ 401 if ((c & TRIM) == '#') 402 dimen++, c = DgetC(0); /* $# takes dimension */ 403 else if (c == '?') 404 bitset++, c = DgetC(0); /* $? tests existence */ 405 switch (c) { 406 407 case '!': 408 if (dimen || bitset) 409 stderror(ERR_SYNTAX); 410 if (backpid != 0) { 411 free(dolbang); 412 setDolp(dolbang = putn(backpid)); 413 } 414 goto eatbrac; 415 416 case '$': 417 if (dimen || bitset) 418 stderror(ERR_SYNTAX); 419 setDolp(doldol); 420 goto eatbrac; 421 422 case '<' | QUOTE: 423 if (bitset) 424 stderror(ERR_NOTALLOWED, "$?<"); 425 if (dimen) 426 stderror(ERR_NOTALLOWED, "$?#"); 427 for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) { 428 *np = (unsigned char) tnp; 429 if (np >= &wbuf[BUFSIZ - 1]) 430 stderror(ERR_LTOOLONG); 431 if (tnp == '\n') 432 break; 433 } 434 *np = 0; 435 /* 436 * KLUDGE: dolmod is set here because it will cause setDolp to call 437 * domod and thus to copy wbuf. Otherwise setDolp would use it 438 * directly. If we saved it ourselves, no one would know when to free 439 * it. The actual function of the 'q' causes filename expansion not to 440 * be done on the interpolated value. 441 */ 442 dolmod[dolnmod++] = 'q'; 443 dolmcnt = 10000; 444 setDolp(wbuf); 445 goto eatbrac; 446 447 case DEOF: 448 case '\n': 449 stderror(ERR_SYNTAX); 450 /* NOTREACHED */ 451 break; 452 453 case '*': 454 (void) Strlcpy(name, STRargv, sizeof name/sizeof(Char)); 455 vp = adrof(STRargv); 456 subscr = -1; /* Prevent eating [...] */ 457 break; 458 459 default: 460 np = name; 461 if (Isdigit(c)) { 462 if (dimen) 463 stderror(ERR_NOTALLOWED, "$#<num>"); 464 subscr = 0; 465 do { 466 subscr = subscr * 10 + c - '0'; 467 c = DgetC(0); 468 } while (Isdigit(c)); 469 unDredc(c); 470 if (subscr < 0) 471 stderror(ERR_RANGE); 472 if (subscr == 0) { 473 if (bitset) { 474 dolp = ffile ? STR1 : STR0; 475 goto eatbrac; 476 } 477 if (ffile == 0) 478 stderror(ERR_DOLZERO); 479 fixDolMod(); 480 setDolp(ffile); 481 goto eatbrac; 482 } 483 if (bitset) 484 stderror(ERR_DOLQUEST); 485 vp = adrof(STRargv); 486 if (vp == 0) { 487 vp = &nulargv; 488 goto eatmod; 489 } 490 break; 491 } 492 if (!alnum(c)) 493 stderror(ERR_VARALNUM); 494 for (;;) { 495 *np++ = c; 496 c = DgetC(0); 497 if (!alnum(c)) 498 break; 499 if (np >= &name[MAXVARLEN]) 500 stderror(ERR_VARTOOLONG); 501 } 502 *np++ = 0; 503 unDredc(c); 504 vp = adrof(name); 505 } 506 if (bitset) { 507 dolp = (vp || getenv(short2str(name))) ? STR1 : STR0; 508 goto eatbrac; 509 } 510 if (vp == 0) { 511 np = str2short(getenv(short2str(name))); 512 if (np) { 513 fixDolMod(); 514 setDolp(np); 515 goto eatbrac; 516 } 517 udvar(name); 518 /* NOTREACHED */ 519 } 520 c = DgetC(0); 521 upb = blklen(vp->vec); 522 if (dimen == 0 && subscr == 0 && c == '[') { 523 np = name; 524 for (;;) { 525 c = DgetC(DODOL); /* Allow $ expand within [ ] */ 526 if (c == ']') 527 break; 528 if (c == '\n' || c == DEOF) 529 stderror(ERR_INCBR); 530 if (np >= &name[sizeof(name) / sizeof(Char) - 2]) 531 stderror(ERR_VARTOOLONG); 532 *np++ = c; 533 } 534 *np = 0, np = name; 535 if (dolp || dolcnt) /* $ exp must end before ] */ 536 stderror(ERR_EXPORD); 537 if (!*np) 538 stderror(ERR_SYNTAX); 539 if (Isdigit(*np)) { 540 int i; 541 542 for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0') 543 continue; 544 if ((i < 0 || i > upb) && !any("-*", *np)) { 545 dolerror(vp->v_name); 546 return; 547 } 548 lwb = i; 549 if (!*np) 550 upb = lwb, np = STRstar; 551 } 552 if (*np == '*') 553 np++; 554 else if (*np != '-') 555 stderror(ERR_MISSING, '-'); 556 else { 557 int i = upb; 558 559 np++; 560 if (Isdigit(*np)) { 561 i = 0; 562 while (Isdigit(*np)) 563 i = i * 10 + *np++ - '0'; 564 if (i < 0 || i > upb) { 565 dolerror(vp->v_name); 566 return; 567 } 568 } 569 if (i < lwb) 570 upb = lwb - 1; 571 else 572 upb = i; 573 } 574 if (lwb == 0) { 575 if (upb != 0) { 576 dolerror(vp->v_name); 577 return; 578 } 579 upb = -1; 580 } 581 if (*np) 582 stderror(ERR_SYNTAX); 583 } 584 else { 585 if (subscr > 0) { 586 if (subscr > upb) 587 lwb = 1, upb = 0; 588 else 589 lwb = upb = subscr; 590 } 591 unDredc(c); 592 } 593 if (dimen) { 594 Char *cp = putn(upb - lwb + 1); 595 596 addla(cp); 597 free(cp); 598 } 599 else { 600 eatmod: 601 fixDolMod(); 602 dolnxt = &vp->vec[lwb - 1]; 603 dolcnt = upb - lwb + 1; 604 } 605 eatbrac: 606 if (sc == '{') { 607 c = Dredc(); 608 if (c != '}') 609 stderror(ERR_MISSING, '}'); 610 } 611 } 612 613 static void 614 fixDolMod(void) 615 { 616 int c; 617 618 c = DgetC(0); 619 if (c == ':') { 620 do { 621 c = DgetC(0), dolmcnt = 1, dolwcnt = 1; 622 if (c == 'g' || c == 'a') { 623 if (c == 'g') 624 dolmcnt = 10000; 625 else 626 dolwcnt = 10000; 627 c = DgetC(0); 628 } 629 if ((c == 'g' && dolmcnt != 10000) || 630 (c == 'a' && dolwcnt != 10000)) { 631 if (c == 'g') 632 dolmcnt = 10000; 633 else 634 dolwcnt = 10000; 635 c = DgetC(0); 636 } 637 638 if (c == 's') { /* [eichin:19910926.0755EST] */ 639 int delimcnt = 2; 640 int delim = DgetC(0); 641 dolmod[dolnmod++] = c; 642 dolmod[dolnmod++] = delim; 643 644 if (!delim || letter(delim) 645 || Isdigit(delim) || any(" \t\n", delim)) { 646 seterror(ERR_BADSUBST); 647 break; 648 } 649 while ((c = DgetC(0)) != (-1)) { 650 dolmod[dolnmod++] = c; 651 if(c == delim) delimcnt--; 652 if(!delimcnt) break; 653 } 654 if(delimcnt) { 655 seterror(ERR_BADSUBST); 656 break; 657 } 658 continue; 659 } 660 if (!any("htrqxes", c)) 661 stderror(ERR_BADMOD, c); 662 dolmod[dolnmod++] = c; 663 if (c == 'q') 664 dolmcnt = 10000; 665 } 666 while ((c = DgetC(0)) == ':'); 667 unDredc(c); 668 } 669 else 670 unDredc(c); 671 } 672 673 static void 674 setDolp(Char *cp) 675 { 676 Char *dp; 677 int i; 678 679 if (dolnmod == 0 || dolmcnt == 0) { 680 dolp = cp; 681 return; 682 } 683 dp = cp = Strsave(cp); 684 for (i = 0; i < dolnmod; i++) { 685 /* handle s// [eichin:19910926.0510EST] */ 686 if(dolmod[i] == 's') { 687 int delim; 688 Char *lhsub, *rhsub, *np; 689 size_t lhlen = 0, rhlen = 0; 690 int didmod = 0; 691 692 delim = dolmod[++i]; 693 if (!delim || letter(delim) 694 || Isdigit(delim) || any(" \t\n", delim)) { 695 seterror(ERR_BADSUBST); 696 break; 697 } 698 lhsub = &dolmod[++i]; 699 while(dolmod[i] != delim && dolmod[++i]) { 700 lhlen++; 701 } 702 dolmod[i] = 0; 703 rhsub = &dolmod[++i]; 704 while(dolmod[i] != delim && dolmod[++i]) { 705 rhlen++; 706 } 707 dolmod[i] = 0; 708 709 do { 710 dp = Strstr(cp, lhsub); 711 if (dp) { 712 size_t len = Strlen(cp) + 1 - lhlen + rhlen; 713 714 np = xreallocarray(NULL, len, sizeof(Char)); 715 *dp = 0; 716 (void) Strlcpy(np, cp, len); 717 (void) Strlcat(np, rhsub, len); 718 (void) Strlcat(np, dp + lhlen, len); 719 720 free(cp); 721 dp = cp = np; 722 didmod = 1; 723 } else { 724 /* should this do a seterror? */ 725 break; 726 } 727 } 728 while (dolwcnt == 10000); 729 /* 730 * restore dolmod for additional words 731 */ 732 dolmod[i] = rhsub[-1] = delim; 733 if (didmod) 734 dolmcnt--; 735 else 736 break; 737 } else { 738 int didmod = 0; 739 740 do { 741 if ((dp = domod(cp, dolmod[i]))) { 742 didmod = 1; 743 if (Strcmp(cp, dp) == 0) { 744 free(cp); 745 cp = dp; 746 break; 747 } 748 else { 749 free(cp); 750 cp = dp; 751 } 752 } 753 else 754 break; 755 } 756 while (dolwcnt == 10000); 757 dp = cp; 758 if (didmod) 759 dolmcnt--; 760 else 761 break; 762 } 763 } 764 765 addla(cp); 766 free(cp); 767 768 dolp = STRNULL; 769 if (seterr) 770 stderror(ERR_OLD); 771 } 772 773 static void 774 unDredc(int c) 775 { 776 777 Dpeekrd = c; 778 } 779 780 static int 781 Dredc(void) 782 { 783 int c; 784 785 if ((c = Dpeekrd) != '\0') { 786 Dpeekrd = 0; 787 return (c); 788 } 789 if (Dcp && (c = *Dcp++)) 790 return (c & (QUOTE | TRIM)); 791 if (*Dvp == 0) { 792 Dcp = 0; 793 return (DEOF); 794 } 795 Dcp = *Dvp++; 796 return (' '); 797 } 798 799 static void 800 Dtestq(int c) 801 { 802 803 if (cmap(c, QUOTES)) 804 gflag = 1; 805 } 806 807 /* 808 * Form a shell temporary file (in unit 0) from the words 809 * of the shell input up to EOF or a line the same as "term". 810 * Unit 0 should have been closed before this call. 811 */ 812 void 813 /*ARGSUSED*/ 814 heredoc(Char *term) 815 { 816 int c; 817 Char *Dv[2]; 818 Char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; 819 int ocnt, lcnt, mcnt; 820 Char *lbp, *obp, *mbp; 821 Char **vp; 822 bool quoted; 823 char tmp[] = "/tmp/sh.XXXXXXXX"; 824 825 if (mkstemp(tmp) == -1) 826 stderror(ERR_SYSTEM, tmp, strerror(errno)); 827 (void) unlink(tmp); /* 0 0 inode! */ 828 Dv[0] = term; 829 Dv[1] = NULL; 830 gflag = 0; 831 trim(Dv); 832 rscan(Dv, Dtestq); 833 quoted = gflag; 834 ocnt = BUFSIZ; 835 obp = obuf; 836 for (;;) { 837 /* 838 * Read up a line 839 */ 840 lbp = lbuf; 841 lcnt = BUFSIZ - 4; 842 for (;;) { 843 c = readc(1); /* 1 -> Want EOF returns */ 844 if (c < 0 || c == '\n') 845 break; 846 if ((c &= TRIM) != '\0') { 847 *lbp++ = c; 848 if (--lcnt < 0) { 849 setname("<<"); 850 stderror(ERR_NAME | ERR_OVERFLOW); 851 } 852 } 853 } 854 *lbp = 0; 855 856 /* 857 * Check for EOF or compare to terminator -- before expansion 858 */ 859 if (c < 0 || eq(lbuf, term)) { 860 (void) write(STDIN_FILENO, short2str(obuf), 861 (size_t) (BUFSIZ - ocnt)); 862 (void) lseek(STDIN_FILENO, (off_t) 0, SEEK_SET); 863 return; 864 } 865 866 /* 867 * If term was quoted or -n just pass it on 868 */ 869 if (quoted || noexec) { 870 *lbp++ = '\n'; 871 *lbp = 0; 872 for (lbp = lbuf; (c = *lbp++) != '\0';) { 873 *obp++ = c; 874 if (--ocnt == 0) { 875 (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); 876 obp = obuf; 877 ocnt = BUFSIZ; 878 } 879 } 880 continue; 881 } 882 883 /* 884 * Term wasn't quoted so variable and then command expand the input 885 * line 886 */ 887 Dcp = lbuf; 888 Dvp = Dv + 1; 889 mbp = mbuf; 890 mcnt = BUFSIZ - 4; 891 for (;;) { 892 c = DgetC(DODOL); 893 if (c == DEOF) 894 break; 895 if ((c &= TRIM) == 0) 896 continue; 897 /* \ quotes \ $ ` here */ 898 if (c == '\\') { 899 c = DgetC(0); 900 if (!any("$\\`", c)) 901 unDgetC(c | QUOTE), c = '\\'; 902 else 903 c |= QUOTE; 904 } 905 *mbp++ = c; 906 if (--mcnt == 0) { 907 setname("<<"); 908 stderror(ERR_NAME | ERR_OVERFLOW); 909 } 910 } 911 *mbp++ = 0; 912 913 /* 914 * If any ` in line do command substitution 915 */ 916 mbp = mbuf; 917 if (any(short2str(mbp), '`')) { 918 /* 919 * 1 arg to dobackp causes substitution to be literal. Words are 920 * broken only at newlines so that all blanks and tabs are 921 * preserved. Blank lines (null words) are not discarded. 922 */ 923 vp = dobackp(mbuf, 1); 924 } 925 else 926 /* Setup trivial vector similar to return of dobackp */ 927 Dv[0] = mbp, Dv[1] = NULL, vp = Dv; 928 929 /* 930 * Resurrect the words from the command substitution each separated by 931 * a newline. Note that the last newline of a command substitution 932 * will have been discarded, but we put a newline after the last word 933 * because this represents the newline after the last input line! 934 */ 935 for (; *vp; vp++) { 936 for (mbp = *vp; *mbp; mbp++) { 937 *obp++ = *mbp & TRIM; 938 if (--ocnt == 0) { 939 (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); 940 obp = obuf; 941 ocnt = BUFSIZ; 942 } 943 } 944 *obp++ = '\n'; 945 if (--ocnt == 0) { 946 (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); 947 obp = obuf; 948 ocnt = BUFSIZ; 949 } 950 } 951 blkfree(pargv); 952 pargv = NULL; 953 } 954 } 955