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