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