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