mandoc(1): -width is redundant for a item list
[netbsd-mini2440.git] / bin / csh / dol.c
blob1529f5564e96b38e8ed49715bc528123d52dcb44
1 /* $NetBSD: dol.c,v 1.25 2007/07/16 14:07:00 christos Exp $ */
3 /*-
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)dol.c 8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: dol.c,v 1.25 2007/07/16 14:07:00 christos Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/types.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
50 #include "csh.h"
51 #include "extern.h"
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.
62 static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
63 static Char *Dcp, **Dvp; /* Input vector for Dreadc */
65 #define DEOF -1
66 #define unDgetC(c) Dpeekc = c
67 #define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */
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.
75 #define MAXWLEN (BUFSIZE - 4)
76 #define MAXMOD MAXWLEN /* This cannot overflow */
77 static Char dolmod[MAXMOD]; /* : modifier character */
78 static Char *dolp; /* Remaining chars from this word */
79 static Char **dolnxt; /* Further words */
80 static int dolcnt; /* Count of further words */
81 static int dolnmod; /* Number of modifiers */
82 static int dolmcnt; /* :gx -> 10000, else 1 */
83 static int dolwcnt; /* :wx -> 10000, else 1 */
85 static void Dfix2(Char **);
86 static Char *Dpack(Char *, Char *);
87 static int Dword(void);
88 static void dolerror(Char *);
89 static int DgetC(int);
90 static void Dgetdol(void);
91 static void fixDolMod(void);
92 static void setDolp(Char *);
93 static void unDredc(int);
94 static int Dredc(void);
95 static void Dtestq(int);
99 * Fix up the $ expansions and quotations in the
100 * argument list to command t.
102 void
103 Dfix(struct command *t)
105 Char *p, **pp;
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;
123 * $ substitute one word, for i/o redirection
125 Char *
126 Dfix1(Char *cp)
128 Char *Dv[2];
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);
139 cp = Strsave(gargv[0]);
140 blkfree(gargv), gargv = 0;
141 return (cp);
145 * Subroutine to do actual fixing after state initialization.
147 static void
148 Dfix2(Char **v)
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;
162 * Pack up more characters in this word
164 static Char *
165 Dpack(Char *wbuf, Char *wp)
167 int c, i;
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);
180 if (c == '\n')
181 c = ' ';
182 else
183 c |= QUOTE;
185 if (c == DEOF) {
186 unDredc(c);
187 *wp = 0;
188 Gcat(STRNULL, wbuf);
189 return (NULL);
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);
199 if (--i <= 0)
200 stderror(ERR_WTOOLONG);
201 *wp++ = c;
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.
211 static int
212 Dword(void)
214 Char wbuf[BUFSIZE], *wp;
215 int c, c1, i;
216 int dolflg, done, sofar;
218 done = 0;
219 i = MAXWLEN;
220 sofar = 0;
221 wp = wbuf;
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 '"':
248 * Note that DgetC never returns a QUOTES character from an
249 * expansion, so only true input quotes will get us here or out.
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 '"':
266 * Leave any `s alone for later. Other chars are all
267 * quoted, thus `...` can tell it was within "...".
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;
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;
292 break;
293 case '\\':
294 c = DgetC(0); /* No $ subst! */
295 if (c == '\n' || c == DEOF) {
296 done = 0;
297 break;
299 c |= QUOTE;
300 break;
301 default:
302 break;
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;
315 /* Really NOTREACHED */
316 return (0);
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.
325 static int
326 DgetC(int flag)
328 int c;
329 top:
330 if ((c = Dpeekc) != '\0') {
331 Dpeekc = 0;
332 return (c);
334 if (lap) {
335 c = *lap++ & (QUOTE | TRIM);
336 if (c == 0) {
337 lap = 0;
338 goto top;
340 quotspec:
341 if (cmap(c, QUOTES))
342 return (c | QUOTE);
343 return (c);
345 if (dolp) {
346 if ((c = *dolp++ & (QUOTE | TRIM)) != '\0')
347 goto quotspec;
348 if (dolcnt > 0) {
349 setDolp(*dolnxt++);
350 --dolcnt;
351 return (' ');
353 dolp = 0;
355 if (dolcnt > 0) {
356 setDolp(*dolnxt++);
357 --dolcnt;
358 goto top;
360 c = Dredc();
361 if (c == '$' && flag) {
362 Dgetdol();
363 goto top;
365 return (c);
368 static Char *nulvec[] = {0};
369 static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0};
371 static void
372 dolerror(Char *s)
374 setname(vis_str(s));
375 stderror(ERR_NAME | ERR_RANGE);
376 /* NOTREACHED */
380 * Handle the multitudinous $ expansion forms.
381 * Ugh.
383 static void
384 Dgetdol(void)
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;
395 bitset = 0;
396 dimen = 0;
397 lwb = 1;
398 upb = 0;
399 subscr = 0;
400 vp = NULL;
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));
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;
437 *np = 0;
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.
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;
476 if (ffile == 0)
477 stderror(ERR_DOLZERO);
478 fixDolMod();
479 setDolp(ffile);
480 goto eatbrac;
482 if (bitset)
483 stderror(ERR_DOLQUEST);
484 vp = adrof(STRargv);
485 if (vp == 0) {
486 vp = &nulargv;
487 goto eatmod;
489 break;
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);
501 *np++ = 0;
502 unDredc(c);
503 vp = adrof(name);
505 if (bitset) {
506 dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
507 goto eatbrac;
509 if (vp == 0) {
510 np = str2short(getenv(short2str(name)));
511 if (np) {
512 fixDolMod();
513 setDolp(np);
514 goto eatbrac;
516 udvar(name);
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;
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;
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;
546 lwb = i;
547 if (!*np)
548 upb = lwb, np = STRstar;
550 if (*np == '*')
551 np++;
552 else if (*np != '-')
553 stderror(ERR_MISSING, '-');
554 else {
555 int i = upb;
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;
567 if (i < lwb)
568 upb = lwb - 1;
569 else
570 upb = i;
572 if (lwb == 0) {
573 if (upb != 0) {
574 dolerror(vp->v_name);
575 return;
577 upb = -1;
579 if (*np)
580 stderror(ERR_SYNTAX);
582 else {
583 if (subscr > 0) {
584 if (subscr > upb)
585 lwb = 1, upb = 0;
586 else
587 lwb = upb = subscr;
589 unDredc(c);
591 if (dimen) {
592 Char *cp = putn(upb - lwb + 1);
594 addla(cp);
595 xfree((ptr_t) cp);
597 else {
598 eatmod:
599 fixDolMod();
600 dolnxt = &vp->vec[lwb - 1];
601 dolcnt = upb - lwb + 1;
603 eatbrac:
604 if (sc == '{') {
605 c = Dredc();
606 if (c != '}')
607 stderror(ERR_MISSING, '}');
611 static void
612 fixDolMod(void)
614 int c;
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);
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);
636 if (c == 's') { /* [eichin:19910926.0755EST] */
637 int delimcnt = 2;
638 int delim = DgetC(0);
639 dolmod[dolnmod++] = c;
640 dolmod[dolnmod++] = delim;
642 if (!delim || letter(delim)
643 || Isdigit(delim) || any(" \t\n", delim)) {
644 seterror(ERR_BADSUBST);
645 break;
647 while ((c = DgetC(0)) != (-1)) {
648 dolmod[dolnmod++] = c;
649 if(c == delim) delimcnt--;
650 if(!delimcnt) break;
652 if(delimcnt) {
653 seterror(ERR_BADSUBST);
654 break;
656 continue;
658 if (!any("htrqxes", c))
659 stderror(ERR_BADMOD, c);
660 dolmod[dolnmod++] = c;
661 if (c == 'q')
662 dolmcnt = 10000;
664 while ((c = DgetC(0)) == ':');
665 unDredc(c);
667 else
668 unDredc(c);
671 static void
672 setDolp(Char *cp)
674 Char *dp;
675 int i;
677 if (dolnmod == 0 || dolmcnt == 0) {
678 dolp = cp;
679 return;
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;
690 delim = dolmod[++i];
691 if (!delim || letter(delim)
692 || Isdigit(delim) || any(" \t\n", delim)) {
693 seterror(ERR_BADSUBST);
694 break;
696 lhsub = &dolmod[++i];
697 while(dolmod[i] != delim && dolmod[++i]) {
698 lhlen++;
700 dolmod[i] = 0;
701 rhsub = &dolmod[++i];
702 while(dolmod[i] != delim && dolmod[++i]) {
703 rhlen++;
705 dolmod[i] = 0;
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);
717 xfree((ptr_t) cp);
718 dp = cp = np;
719 didmod = 1;
720 } else {
721 /* should this do a seterror? */
722 break;
725 while (dolwcnt == 10000);
727 * restore dolmod for additional words
729 dolmod[i] = rhsub[-1] = delim;
730 if (didmod)
731 dolmcnt--;
732 else
733 break;
734 } else {
735 int didmod = 0;
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;
745 else {
746 xfree((ptr_t) cp);
747 cp = dp;
750 else
751 break;
753 while (dolwcnt == 10000);
754 dp = cp;
755 if (didmod)
756 dolmcnt--;
757 else
758 break;
762 if (dp) {
763 addla(dp);
764 xfree((ptr_t) dp);
766 else {
767 addla(cp);
768 xfree((ptr_t) cp);
771 dolp = STRNULL;
772 if (seterr)
773 stderror(ERR_OLD);
776 static void
777 unDredc(int c)
779 Dpeekrd = c;
782 static int
783 Dredc(void)
785 int c;
787 if ((c = Dpeekrd) != '\0') {
788 Dpeekrd = 0;
789 return (c);
791 if (Dcp && (c = *Dcp++))
792 return (c & (QUOTE | TRIM));
793 if (*Dvp == 0) {
794 Dcp = 0;
795 return (DEOF);
797 Dcp = *Dvp++;
798 return (' ');
801 static void
802 Dtestq(int c)
804 if (cmap(c, QUOTES))
805 gflag = 1;
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.
813 void
814 /*ARGSUSED*/
815 heredoc(Char *term)
817 Char obuf[BUFSIZE], lbuf[BUFSIZE], mbuf[BUFSIZE];
818 struct timeval tv;
819 Char *Dv[2], *lbp, *obp, *mbp, **vp;
820 char *tmp;
821 int c, ocnt, lcnt, mcnt;
822 int quoted;
824 again:
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)gettimeofday(&tv, NULL);
830 mbp = putn((((int)tv.tv_sec) ^
831 ((int)tv.tv_usec) ^ ((int)getpid())) & 0x00ffffff);
832 shtemp = Strspl(STRtmpsh, mbp);
833 xfree((ptr_t)mbp);
835 goto again;
837 stderror(ERR_SYSTEM, tmp, strerror(errno));
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 (;;) {
850 * Read up a line
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);
866 *lbp = 0;
869 * Check for EOF or compare to terminator -- before expansion
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;
878 * If term was quoted or -n just pass it on
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;
891 continue;
895 * Term wasn't quoted so variable and then command expand the input
896 * line
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;
916 *mbp++ = c;
917 if (--mcnt == 0) {
918 setname("<<");
919 stderror(ERR_NAME | ERR_OVERFLOW);
922 *mbp++ = 0;
925 * If any ` in line do command substitution
927 mbp = mbuf;
928 if (any(short2str(mbp), '`')) {
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.
934 vp = dobackp(mbuf, 1);
936 else
937 /* Setup trivial vector similar to return of dobackp */
938 Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
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!
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;
955 *obp++ = '\n';
956 if (--ocnt == 0) {
957 (void)write(0, short2str(obuf), BUFSIZE);
958 obp = obuf;
959 ocnt = BUFSIZE;
962 if (pargv)
963 blkfree(pargv), pargv = 0;