1 /* $OpenBSD: dol.c,v 1.20 2015/12/26 13:48:38 mestre 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 if (dolbang) 412 free(dolbang); 413 setDolp(dolbang = putn(backpid)); 414 } 415 goto eatbrac; 416 417 case '$': 418 if (dimen || bitset) 419 stderror(ERR_SYNTAX); 420 setDolp(doldol); 421 goto eatbrac; 422 423 case '<' | QUOTE: 424 if (bitset) 425 stderror(ERR_NOTALLOWED, "$?<"); 426 if (dimen) 427 stderror(ERR_NOTALLOWED, "$?#"); 428 for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) { 429 *np = (unsigned char) tnp; 430 if (np >= &wbuf[BUFSIZ - 1]) 431 stderror(ERR_LTOOLONG); 432 if (tnp == '\n') 433 break; 434 } 435 *np = 0; 436 /* 437 * KLUDGE: dolmod is set here because it will cause setDolp to call 438 * domod and thus to copy wbuf. Otherwise setDolp would use it 439 * directly. If we saved it ourselves, no one would know when to free 440 * it. The actual function of the 'q' causes filename expansion not to 441 * be done on the interpolated value. 442 */ 443 dolmod[dolnmod++] = 'q'; 444 dolmcnt = 10000; 445 setDolp(wbuf); 446 goto eatbrac; 447 448 case DEOF: 449 case '\n': 450 stderror(ERR_SYNTAX); 451 /* NOTREACHED */ 452 break; 453 454 case '*': 455 (void) Strlcpy(name, STRargv, sizeof name/sizeof(Char)); 456 vp = adrof(STRargv); 457 subscr = -1; /* Prevent eating [...] */ 458 break; 459 460 default: 461 np = name; 462 if (Isdigit(c)) { 463 if (dimen) 464 stderror(ERR_NOTALLOWED, "$#<num>"); 465 subscr = 0; 466 do { 467 subscr = subscr * 10 + c - '0'; 468 c = DgetC(0); 469 } while (Isdigit(c)); 470 unDredc(c); 471 if (subscr < 0) 472 stderror(ERR_RANGE); 473 if (subscr == 0) { 474 if (bitset) { 475 dolp = ffile ? STR1 : STR0; 476 goto eatbrac; 477 } 478 if (ffile == 0) 479 stderror(ERR_DOLZERO); 480 fixDolMod(); 481 setDolp(ffile); 482 goto eatbrac; 483 } 484 if (bitset) 485 stderror(ERR_DOLQUEST); 486 vp = adrof(STRargv); 487 if (vp == 0) { 488 vp = &nulargv; 489 goto eatmod; 490 } 491 break; 492 } 493 if (!alnum(c)) 494 stderror(ERR_VARALNUM); 495 for (;;) { 496 *np++ = c; 497 c = DgetC(0); 498 if (!alnum(c)) 499 break; 500 if (np >= &name[MAXVARLEN]) 501 stderror(ERR_VARTOOLONG); 502 } 503 *np++ = 0; 504 unDredc(c); 505 vp = adrof(name); 506 } 507 if (bitset) { 508 dolp = (vp || getenv(short2str(name))) ? STR1 : STR0; 509 goto eatbrac; 510 } 511 if (vp == 0) { 512 np = str2short(getenv(short2str(name))); 513 if (np) { 514 fixDolMod(); 515 setDolp(np); 516 goto eatbrac; 517 } 518 udvar(name); 519 /* NOTREACHED */ 520 } 521 c = DgetC(0); 522 upb = blklen(vp->vec); 523 if (dimen == 0 && subscr == 0 && c == '[') { 524 np = name; 525 for (;;) { 526 c = DgetC(DODOL); /* Allow $ expand within [ ] */ 527 if (c == ']') 528 break; 529 if (c == '\n' || c == DEOF) 530 stderror(ERR_INCBR); 531 if (np >= &name[sizeof(name) / sizeof(Char) - 2]) 532 stderror(ERR_VARTOOLONG); 533 *np++ = c; 534 } 535 *np = 0, np = name; 536 if (dolp || dolcnt) /* $ exp must end before ] */ 537 stderror(ERR_EXPORD); 538 if (!*np) 539 stderror(ERR_SYNTAX); 540 if (Isdigit(*np)) { 541 int i; 542 543 for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0') 544 continue; 545 if ((i < 0 || i > upb) && !any("-*", *np)) { 546 dolerror(vp->v_name); 547 return; 548 } 549 lwb = i; 550 if (!*np) 551 upb = lwb, np = STRstar; 552 } 553 if (*np == '*') 554 np++; 555 else if (*np != '-') 556 stderror(ERR_MISSING, '-'); 557 else { 558 int i = upb; 559 560 np++; 561 if (Isdigit(*np)) { 562 i = 0; 563 while (Isdigit(*np)) 564 i = i * 10 + *np++ - '0'; 565 if (i < 0 || i > upb) { 566 dolerror(vp->v_name); 567 return; 568 } 569 } 570 if (i < lwb) 571 upb = lwb - 1; 572 else 573 upb = i; 574 } 575 if (lwb == 0) { 576 if (upb != 0) { 577 dolerror(vp->v_name); 578 return; 579 } 580 upb = -1; 581 } 582 if (*np) 583 stderror(ERR_SYNTAX); 584 } 585 else { 586 if (subscr > 0) { 587 if (subscr > upb) 588 lwb = 1, upb = 0; 589 else 590 lwb = upb = subscr; 591 } 592 unDredc(c); 593 } 594 if (dimen) { 595 Char *cp = putn(upb - lwb + 1); 596 597 addla(cp); 598 free(cp); 599 } 600 else { 601 eatmod: 602 fixDolMod(); 603 dolnxt = &vp->vec[lwb - 1]; 604 dolcnt = upb - lwb + 1; 605 } 606 eatbrac: 607 if (sc == '{') { 608 c = Dredc(); 609 if (c != '}') 610 stderror(ERR_MISSING, '}'); 611 } 612 } 613 614 static void 615 fixDolMod(void) 616 { 617 int c; 618 619 c = DgetC(0); 620 if (c == ':') { 621 do { 622 c = DgetC(0), dolmcnt = 1, dolwcnt = 1; 623 if (c == 'g' || c == 'a') { 624 if (c == 'g') 625 dolmcnt = 10000; 626 else 627 dolwcnt = 10000; 628 c = DgetC(0); 629 } 630 if ((c == 'g' && dolmcnt != 10000) || 631 (c == 'a' && dolwcnt != 10000)) { 632 if (c == 'g') 633 dolmcnt = 10000; 634 else 635 dolwcnt = 10000; 636 c = DgetC(0); 637 } 638 639 if (c == 's') { /* [eichin:19910926.0755EST] */ 640 int delimcnt = 2; 641 int delim = DgetC(0); 642 dolmod[dolnmod++] = c; 643 dolmod[dolnmod++] = delim; 644 645 if (!delim || letter(delim) 646 || Isdigit(delim) || any(" \t\n", delim)) { 647 seterror(ERR_BADSUBST); 648 break; 649 } 650 while ((c = DgetC(0)) != (-1)) { 651 dolmod[dolnmod++] = c; 652 if(c == delim) delimcnt--; 653 if(!delimcnt) break; 654 } 655 if(delimcnt) { 656 seterror(ERR_BADSUBST); 657 break; 658 } 659 continue; 660 } 661 if (!any("htrqxes", c)) 662 stderror(ERR_BADMOD, c); 663 dolmod[dolnmod++] = c; 664 if (c == 'q') 665 dolmcnt = 10000; 666 } 667 while ((c = DgetC(0)) == ':'); 668 unDredc(c); 669 } 670 else 671 unDredc(c); 672 } 673 674 static void 675 setDolp(Char *cp) 676 { 677 Char *dp; 678 int i; 679 680 if (dolnmod == 0 || dolmcnt == 0) { 681 dolp = cp; 682 return; 683 } 684 dp = cp = Strsave(cp); 685 for (i = 0; i < dolnmod; i++) { 686 /* handle s// [eichin:19910926.0510EST] */ 687 if(dolmod[i] == 's') { 688 int delim; 689 Char *lhsub, *rhsub, *np; 690 size_t lhlen = 0, rhlen = 0; 691 int didmod = 0; 692 693 delim = dolmod[++i]; 694 if (!delim || letter(delim) 695 || Isdigit(delim) || any(" \t\n", delim)) { 696 seterror(ERR_BADSUBST); 697 break; 698 } 699 lhsub = &dolmod[++i]; 700 while(dolmod[i] != delim && dolmod[++i]) { 701 lhlen++; 702 } 703 dolmod[i] = 0; 704 rhsub = &dolmod[++i]; 705 while(dolmod[i] != delim && dolmod[++i]) { 706 rhlen++; 707 } 708 dolmod[i] = 0; 709 710 do { 711 dp = Strstr(cp, lhsub); 712 if (dp) { 713 size_t len = Strlen(cp) + 1 - lhlen + rhlen; 714 715 np = xreallocarray(NULL, len, sizeof(Char)); 716 *dp = 0; 717 (void) Strlcpy(np, cp, len); 718 (void) Strlcat(np, rhsub, len); 719 (void) Strlcat(np, dp + lhlen, len); 720 721 free(cp); 722 dp = cp = np; 723 didmod = 1; 724 } else { 725 /* should this do a seterror? */ 726 break; 727 } 728 } 729 while (dolwcnt == 10000); 730 /* 731 * restore dolmod for additional words 732 */ 733 dolmod[i] = rhsub[-1] = delim; 734 if (didmod) 735 dolmcnt--; 736 else 737 break; 738 } else { 739 int didmod = 0; 740 741 do { 742 if ((dp = domod(cp, dolmod[i]))) { 743 didmod = 1; 744 if (Strcmp(cp, dp) == 0) { 745 free(cp); 746 cp = dp; 747 break; 748 } 749 else { 750 free(cp); 751 cp = dp; 752 } 753 } 754 else 755 break; 756 } 757 while (dolwcnt == 10000); 758 dp = cp; 759 if (didmod) 760 dolmcnt--; 761 else 762 break; 763 } 764 } 765 766 if (dp) { 767 addla(dp); 768 free(dp); 769 } 770 else 771 addla(cp); 772 773 dolp = STRNULL; 774 if (seterr) 775 stderror(ERR_OLD); 776 } 777 778 static void 779 unDredc(int c) 780 { 781 782 Dpeekrd = c; 783 } 784 785 static int 786 Dredc(void) 787 { 788 int c; 789 790 if ((c = Dpeekrd) != '\0') { 791 Dpeekrd = 0; 792 return (c); 793 } 794 if (Dcp && (c = *Dcp++)) 795 return (c & (QUOTE | TRIM)); 796 if (*Dvp == 0) { 797 Dcp = 0; 798 return (DEOF); 799 } 800 Dcp = *Dvp++; 801 return (' '); 802 } 803 804 static void 805 Dtestq(int c) 806 { 807 808 if (cmap(c, QUOTES)) 809 gflag = 1; 810 } 811 812 /* 813 * Form a shell temporary file (in unit 0) from the words 814 * of the shell input up to EOF or a line the same as "term". 815 * Unit 0 should have been closed before this call. 816 */ 817 void 818 /*ARGSUSED*/ 819 heredoc(Char *term) 820 { 821 int c; 822 Char *Dv[2]; 823 Char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; 824 int ocnt, lcnt, mcnt; 825 Char *lbp, *obp, *mbp; 826 Char **vp; 827 bool quoted; 828 char tmp[] = "/tmp/sh.XXXXXXXX"; 829 830 if (mkstemp(tmp) < 0) 831 stderror(ERR_SYSTEM, tmp, strerror(errno)); 832 (void) unlink(tmp); /* 0 0 inode! */ 833 Dv[0] = term; 834 Dv[1] = NULL; 835 gflag = 0; 836 trim(Dv); 837 rscan(Dv, Dtestq); 838 quoted = gflag; 839 ocnt = BUFSIZ; 840 obp = obuf; 841 for (;;) { 842 /* 843 * Read up a line 844 */ 845 lbp = lbuf; 846 lcnt = BUFSIZ - 4; 847 for (;;) { 848 c = readc(1); /* 1 -> Want EOF returns */ 849 if (c < 0 || c == '\n') 850 break; 851 if ((c &= TRIM) != '\0') { 852 *lbp++ = c; 853 if (--lcnt < 0) { 854 setname("<<"); 855 stderror(ERR_NAME | ERR_OVERFLOW); 856 } 857 } 858 } 859 *lbp = 0; 860 861 /* 862 * Check for EOF or compare to terminator -- before expansion 863 */ 864 if (c < 0 || eq(lbuf, term)) { 865 (void) write(STDIN_FILENO, short2str(obuf), 866 (size_t) (BUFSIZ - ocnt)); 867 (void) lseek(STDIN_FILENO, (off_t) 0, SEEK_SET); 868 return; 869 } 870 871 /* 872 * If term was quoted or -n just pass it on 873 */ 874 if (quoted || noexec) { 875 *lbp++ = '\n'; 876 *lbp = 0; 877 for (lbp = lbuf; (c = *lbp++) != '\0';) { 878 *obp++ = c; 879 if (--ocnt == 0) { 880 (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); 881 obp = obuf; 882 ocnt = BUFSIZ; 883 } 884 } 885 continue; 886 } 887 888 /* 889 * Term wasn't quoted so variable and then command expand the input 890 * line 891 */ 892 Dcp = lbuf; 893 Dvp = Dv + 1; 894 mbp = mbuf; 895 mcnt = BUFSIZ - 4; 896 for (;;) { 897 c = DgetC(DODOL); 898 if (c == DEOF) 899 break; 900 if ((c &= TRIM) == 0) 901 continue; 902 /* \ quotes \ $ ` here */ 903 if (c == '\\') { 904 c = DgetC(0); 905 if (!any("$\\`", c)) 906 unDgetC(c | QUOTE), c = '\\'; 907 else 908 c |= QUOTE; 909 } 910 *mbp++ = c; 911 if (--mcnt == 0) { 912 setname("<<"); 913 stderror(ERR_NAME | ERR_OVERFLOW); 914 } 915 } 916 *mbp++ = 0; 917 918 /* 919 * If any ` in line do command substitution 920 */ 921 mbp = mbuf; 922 if (any(short2str(mbp), '`')) { 923 /* 924 * 1 arg to dobackp causes substitution to be literal. Words are 925 * broken only at newlines so that all blanks and tabs are 926 * preserved. Blank lines (null words) are not discarded. 927 */ 928 vp = dobackp(mbuf, 1); 929 } 930 else 931 /* Setup trivial vector similar to return of dobackp */ 932 Dv[0] = mbp, Dv[1] = NULL, vp = Dv; 933 934 /* 935 * Resurrect the words from the command substitution each separated by 936 * a newline. Note that the last newline of a command substitution 937 * will have been discarded, but we put a newline after the last word 938 * because this represents the newline after the last input line! 939 */ 940 for (; *vp; vp++) { 941 for (mbp = *vp; *mbp; mbp++) { 942 *obp++ = *mbp & TRIM; 943 if (--ocnt == 0) { 944 (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); 945 obp = obuf; 946 ocnt = BUFSIZ; 947 } 948 } 949 *obp++ = '\n'; 950 if (--ocnt == 0) { 951 (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ); 952 obp = obuf; 953 ocnt = BUFSIZ; 954 } 955 } 956 if (pargv) 957 blkfree(pargv), pargv = 0; 958 } 959 } 960