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