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