dol.c revision 1.9 1 /* $NetBSD: dol.c,v 1.9 1997/01/13 17:53:17 tls 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 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)dol.c 8.1 (Berkeley) 5/31/93";
39 #else
40 static char rcsid[] = "$NetBSD: dol.c,v 1.9 1997/01/13 17:53:17 tls Exp $";
41 #endif
42 #endif /* not lint */
43
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
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 *
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
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 *
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
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
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
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
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 unDredc(c);
615 }
616 if (dimen) {
617 Char *cp = putn(upb - lwb + 1);
618
619 addla(cp);
620 xfree((ptr_t) cp);
621 }
622 else {
623 eatmod:
624 fixDolMod();
625 dolnxt = &vp->vec[lwb - 1];
626 dolcnt = upb - lwb + 1;
627 }
628 eatbrac:
629 if (sc == '{') {
630 c = Dredc();
631 if (c != '}')
632 stderror(ERR_MISSING, '}');
633 }
634 }
635
636 static void
637 fixDolMod()
638 {
639 int c;
640
641 c = DgetC(0);
642 if (c == ':') {
643 do {
644 c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
645 if (c == 'g' || c == 'a') {
646 if (c == 'g')
647 dolmcnt = 10000;
648 else
649 dolwcnt = 10000;
650 c = DgetC(0);
651 }
652 if ((c == 'g' && dolmcnt != 10000) ||
653 (c == 'a' && dolwcnt != 10000)) {
654 if (c == 'g')
655 dolmcnt = 10000;
656 else
657 dolwcnt = 10000;
658 c = DgetC(0);
659 }
660
661 if (c == 's') { /* [eichin:19910926.0755EST] */
662 int delimcnt = 2;
663 int delim = DgetC(0);
664 dolmod[dolnmod++] = c;
665 dolmod[dolnmod++] = delim;
666
667 if (!delim || letter(delim)
668 || Isdigit(delim) || any(" \t\n", delim)) {
669 seterror(ERR_BADSUBST);
670 break;
671 }
672 while ((c = DgetC(0)) != (-1)) {
673 dolmod[dolnmod++] = c;
674 if(c == delim) delimcnt--;
675 if(!delimcnt) break;
676 }
677 if(delimcnt) {
678 seterror(ERR_BADSUBST);
679 break;
680 }
681 continue;
682 }
683 if (!any("htrqxes", c))
684 stderror(ERR_BADMOD, c);
685 dolmod[dolnmod++] = c;
686 if (c == 'q')
687 dolmcnt = 10000;
688 }
689 while ((c = DgetC(0)) == ':');
690 unDredc(c);
691 }
692 else
693 unDredc(c);
694 }
695
696 static void
697 setDolp(cp)
698 Char *cp;
699 {
700 Char *dp;
701 int i;
702
703 if (dolnmod == 0 || dolmcnt == 0) {
704 dolp = cp;
705 return;
706 }
707 dp = cp = Strsave(cp);
708 for (i = 0; i < dolnmod; i++) {
709 /* handle s// [eichin:19910926.0510EST] */
710 if(dolmod[i] == 's') {
711 int delim;
712 Char *lhsub, *rhsub, *np;
713 size_t lhlen = 0, rhlen = 0;
714 int didmod = 0;
715
716 delim = dolmod[++i];
717 if (!delim || letter(delim)
718 || Isdigit(delim) || any(" \t\n", delim)) {
719 seterror(ERR_BADSUBST);
720 break;
721 }
722 lhsub = &dolmod[++i];
723 while(dolmod[i] != delim && dolmod[++i]) {
724 lhlen++;
725 }
726 dolmod[i] = 0;
727 rhsub = &dolmod[++i];
728 while(dolmod[i] != delim && dolmod[++i]) {
729 rhlen++;
730 }
731 dolmod[i] = 0;
732
733 do {
734 dp = Strstr(cp, lhsub);
735 if (dp) {
736 np = (Char *) xmalloc((size_t)
737 ((Strlen(cp) + 1 - lhlen + rhlen) *
738 sizeof(Char)));
739 (void) Strncpy(np, cp, dp - cp);
740 (void) Strcpy(np + (dp - cp), rhsub);
741 (void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
742
743 xfree((ptr_t) cp);
744 dp = cp = np;
745 didmod = 1;
746 } else {
747 /* should this do a seterror? */
748 break;
749 }
750 }
751 while (dolwcnt == 10000);
752 /*
753 * restore dolmod for additional words
754 */
755 dolmod[i] = rhsub[-1] = delim;
756 if (didmod)
757 dolmcnt--;
758 else
759 break;
760 } else {
761 int didmod = 0;
762
763 do {
764 if ((dp = domod(cp, dolmod[i]))) {
765 didmod = 1;
766 if (Strcmp(cp, dp) == 0) {
767 xfree((ptr_t) cp);
768 cp = dp;
769 break;
770 }
771 else {
772 xfree((ptr_t) cp);
773 cp = dp;
774 }
775 }
776 else
777 break;
778 }
779 while (dolwcnt == 10000);
780 dp = cp;
781 if (didmod)
782 dolmcnt--;
783 else
784 break;
785 }
786 }
787
788 if (dp) {
789 addla(dp);
790 xfree((ptr_t) dp);
791 }
792 else
793 addla(cp);
794
795 dolp = STRNULL;
796 if (seterr)
797 stderror(ERR_OLD);
798 }
799
800 static void
801 unDredc(c)
802 int c;
803 {
804
805 Dpeekrd = c;
806 }
807
808 static int
809 Dredc()
810 {
811 int c;
812
813 if ((c = Dpeekrd) != '\0') {
814 Dpeekrd = 0;
815 return (c);
816 }
817 if (Dcp && (c = *Dcp++))
818 return (c & (QUOTE | TRIM));
819 if (*Dvp == 0) {
820 Dcp = 0;
821 return (DEOF);
822 }
823 Dcp = *Dvp++;
824 return (' ');
825 }
826
827 static void
828 Dtestq(c)
829 int c;
830 {
831
832 if (cmap(c, QUOTES))
833 gflag = 1;
834 }
835
836 /*
837 * Form a shell temporary file (in unit 0) from the words
838 * of the shell input up to EOF or a line the same as "term".
839 * Unit 0 should have been closed before this call.
840 */
841 void
842 /*ARGSUSED*/
843 heredoc(term)
844 Char *term;
845 {
846 int c;
847 Char *Dv[2];
848 Char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
849 int ocnt, lcnt, mcnt;
850 Char *lbp, *obp, *mbp;
851 Char **vp;
852 bool quoted;
853 char *tmp;
854
855 tmp = short2str(shtemp);
856 if (open(tmp, O_RDWR | O_CREAT | O_TRUNC, 0600) < 0)
857 stderror(ERR_SYSTEM, tmp, strerror(errno));
858 (void) unlink(tmp); /* 0 0 inode! */
859 Dv[0] = term;
860 Dv[1] = NULL;
861 gflag = 0;
862 trim(Dv);
863 rscan(Dv, Dtestq);
864 quoted = gflag;
865 ocnt = BUFSIZ;
866 obp = obuf;
867 for (;;) {
868 /*
869 * Read up a line
870 */
871 lbp = lbuf;
872 lcnt = BUFSIZ - 4;
873 for (;;) {
874 c = readc(1); /* 1 -> Want EOF returns */
875 if (c < 0 || c == '\n')
876 break;
877 if ((c &= TRIM) != '\0') {
878 *lbp++ = c;
879 if (--lcnt < 0) {
880 setname("<<");
881 stderror(ERR_NAME | ERR_OVERFLOW);
882 }
883 }
884 }
885 *lbp = 0;
886
887 /*
888 * Check for EOF or compare to terminator -- before expansion
889 */
890 if (c < 0 || eq(lbuf, term)) {
891 (void) write(0, short2str(obuf), (size_t) (BUFSIZ - ocnt));
892 (void) lseek(0, (off_t) 0, SEEK_SET);
893 return;
894 }
895
896 /*
897 * If term was quoted or -n just pass it on
898 */
899 if (quoted || noexec) {
900 *lbp++ = '\n';
901 *lbp = 0;
902 for (lbp = lbuf; (c = *lbp++) != '\0';) {
903 *obp++ = c;
904 if (--ocnt == 0) {
905 (void) write(0, short2str(obuf), BUFSIZ);
906 obp = obuf;
907 ocnt = BUFSIZ;
908 }
909 }
910 continue;
911 }
912
913 /*
914 * Term wasn't quoted so variable and then command expand the input
915 * line
916 */
917 Dcp = lbuf;
918 Dvp = Dv + 1;
919 mbp = mbuf;
920 mcnt = BUFSIZ - 4;
921 for (;;) {
922 c = DgetC(DODOL);
923 if (c == DEOF)
924 break;
925 if ((c &= TRIM) == 0)
926 continue;
927 /* \ quotes \ $ ` here */
928 if (c == '\\') {
929 c = DgetC(0);
930 if (!any("$\\`", c))
931 unDgetC(c | QUOTE), c = '\\';
932 else
933 c |= QUOTE;
934 }
935 *mbp++ = c;
936 if (--mcnt == 0) {
937 setname("<<");
938 stderror(ERR_NAME | ERR_OVERFLOW);
939 }
940 }
941 *mbp++ = 0;
942
943 /*
944 * If any ` in line do command substitution
945 */
946 mbp = mbuf;
947 if (any(short2str(mbp), '`')) {
948 /*
949 * 1 arg to dobackp causes substitution to be literal. Words are
950 * broken only at newlines so that all blanks and tabs are
951 * preserved. Blank lines (null words) are not discarded.
952 */
953 vp = dobackp(mbuf, 1);
954 }
955 else
956 /* Setup trivial vector similar to return of dobackp */
957 Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
958
959 /*
960 * Resurrect the words from the command substitution each separated by
961 * a newline. Note that the last newline of a command substitution
962 * will have been discarded, but we put a newline after the last word
963 * because this represents the newline after the last input line!
964 */
965 for (; *vp; vp++) {
966 for (mbp = *vp; *mbp; mbp++) {
967 *obp++ = *mbp & TRIM;
968 if (--ocnt == 0) {
969 (void) write(0, short2str(obuf), BUFSIZ);
970 obp = obuf;
971 ocnt = BUFSIZ;
972 }
973 }
974 *obp++ = '\n';
975 if (--ocnt == 0) {
976 (void) write(0, short2str(obuf), BUFSIZ);
977 obp = obuf;
978 ocnt = BUFSIZ;
979 }
980 }
981 if (pargv)
982 blkfree(pargv), pargv = 0;
983 }
984 }
985