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