dol.c revision 1.20 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