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