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