xref: /titanic_53/usr/src/cmd/csh/sh.dol.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /*
10*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
11*7c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
12*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <unistd.h>		/* for lseek prototype */
18*7c478bd9Sstevel@tonic-gate #include "sh.h"
19*7c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
20*7c478bd9Sstevel@tonic-gate 
21*7c478bd9Sstevel@tonic-gate /*
22*7c478bd9Sstevel@tonic-gate  * C shell
23*7c478bd9Sstevel@tonic-gate  */
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate /*
26*7c478bd9Sstevel@tonic-gate  * These routines perform variable substitution and quoting via ' and ".
27*7c478bd9Sstevel@tonic-gate  * To this point these constructs have been preserved in the divided
28*7c478bd9Sstevel@tonic-gate  * input words.  Here we expand variables and turn quoting via ' and " into
29*7c478bd9Sstevel@tonic-gate  * QUOTE bits on characters (which prevent further interpretation).
30*7c478bd9Sstevel@tonic-gate  * If the `:q' modifier was applied during history expansion, then
31*7c478bd9Sstevel@tonic-gate  * some QUOTEing may have occurred already, so we dont "trim()" here.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate int	Dpeekc, Dpeekrd;		/* Peeks for DgetC and Dreadc */
35*7c478bd9Sstevel@tonic-gate tchar	*Dcp, **Dvp;			/* Input vector for Dreadc */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #define	DEOF	-1
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #define	unDgetC(c)	Dpeekc = c
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #define QUOTES		(_Q|_Q1|_ESC)	/* \ ' " ` */
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate /*
44*7c478bd9Sstevel@tonic-gate  * The following variables give the information about the current
45*7c478bd9Sstevel@tonic-gate  * $ expansion, recording the current word position, the remaining
46*7c478bd9Sstevel@tonic-gate  * words within this expansion, the count of remaining words, and the
47*7c478bd9Sstevel@tonic-gate  * information about any : modifier which is being applied.
48*7c478bd9Sstevel@tonic-gate  */
49*7c478bd9Sstevel@tonic-gate tchar	*dolp;			/* Remaining chars from this word */
50*7c478bd9Sstevel@tonic-gate tchar	**dolnxt;		/* Further words */
51*7c478bd9Sstevel@tonic-gate int	dolcnt;			/* Count of further words */
52*7c478bd9Sstevel@tonic-gate tchar	dolmod;			/* : modifier character */
53*7c478bd9Sstevel@tonic-gate int	dolmcnt;		/* :gx -> 10000, else 1 */
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * Fix up the $ expansions and quotations in the
57*7c478bd9Sstevel@tonic-gate  * argument list to command t.
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate Dfix(t)
60*7c478bd9Sstevel@tonic-gate 	register struct command *t;
61*7c478bd9Sstevel@tonic-gate {
62*7c478bd9Sstevel@tonic-gate 	register tchar **pp;
63*7c478bd9Sstevel@tonic-gate 	register tchar *p;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #ifdef TRACE
66*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dfix()\n");
67*7c478bd9Sstevel@tonic-gate #endif
68*7c478bd9Sstevel@tonic-gate 	if (noexec)
69*7c478bd9Sstevel@tonic-gate 		return;
70*7c478bd9Sstevel@tonic-gate 	/* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
71*7c478bd9Sstevel@tonic-gate 	for (pp = t->t_dcom; p = *pp++;)
72*7c478bd9Sstevel@tonic-gate 		while (*p)
73*7c478bd9Sstevel@tonic-gate 			if (cmap(*p++, _DOL|QUOTES)) {	/* $, \, ', ", ` */
74*7c478bd9Sstevel@tonic-gate 				Dfix2(t->t_dcom);	/* found one */
75*7c478bd9Sstevel@tonic-gate 				blkfree(t->t_dcom);
76*7c478bd9Sstevel@tonic-gate 				t->t_dcom = gargv;
77*7c478bd9Sstevel@tonic-gate 				gargv = 0;
78*7c478bd9Sstevel@tonic-gate 				return;
79*7c478bd9Sstevel@tonic-gate 			}
80*7c478bd9Sstevel@tonic-gate }
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate /*
83*7c478bd9Sstevel@tonic-gate  * $ substitute one word, for i/o redirection
84*7c478bd9Sstevel@tonic-gate  */
85*7c478bd9Sstevel@tonic-gate tchar *
86*7c478bd9Sstevel@tonic-gate Dfix1(cp)
87*7c478bd9Sstevel@tonic-gate 	register tchar *cp;
88*7c478bd9Sstevel@tonic-gate {
89*7c478bd9Sstevel@tonic-gate 	tchar *Dv[2];
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #ifdef TRACE
92*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dfix1()\n");
93*7c478bd9Sstevel@tonic-gate #endif
94*7c478bd9Sstevel@tonic-gate 	if (noexec)
95*7c478bd9Sstevel@tonic-gate 		return (0);
96*7c478bd9Sstevel@tonic-gate 	Dv[0] = cp; Dv[1] = NOSTR;
97*7c478bd9Sstevel@tonic-gate 	Dfix2(Dv);
98*7c478bd9Sstevel@tonic-gate 	if (gargc != 1) {
99*7c478bd9Sstevel@tonic-gate 		setname(cp);
100*7c478bd9Sstevel@tonic-gate 		bferr("Ambiguous");
101*7c478bd9Sstevel@tonic-gate 	}
102*7c478bd9Sstevel@tonic-gate 	cp = savestr(gargv[0]);
103*7c478bd9Sstevel@tonic-gate 	blkfree(gargv), gargv = 0;
104*7c478bd9Sstevel@tonic-gate 	return (cp);
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * Subroutine to do actual fixing after state initialization.
109*7c478bd9Sstevel@tonic-gate  */
110*7c478bd9Sstevel@tonic-gate Dfix2(v)
111*7c478bd9Sstevel@tonic-gate      tchar **v;
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	tchar *agargv[GAVSIZ];
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate #ifdef TRACE
116*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dfix2()\n");
117*7c478bd9Sstevel@tonic-gate #endif
118*7c478bd9Sstevel@tonic-gate 	ginit(agargv);			/* Initialize glob's area pointers */
119*7c478bd9Sstevel@tonic-gate 	Dvp = v; Dcp = S_ /* "" */;/* Setup input vector for Dreadc */
120*7c478bd9Sstevel@tonic-gate 	unDgetC(0); unDredc(0);		/* Clear out any old peeks (at error) */
121*7c478bd9Sstevel@tonic-gate 	dolp = 0; dolcnt = 0;		/* Clear out residual $ expands (...) */
122*7c478bd9Sstevel@tonic-gate 	while (Dword())
123*7c478bd9Sstevel@tonic-gate 		continue;
124*7c478bd9Sstevel@tonic-gate 	gargv = copyblk(gargv);
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate  * Get a word.  This routine is analogous to the routine
129*7c478bd9Sstevel@tonic-gate  * word() in sh.lex.c for the main lexical input.  One difference
130*7c478bd9Sstevel@tonic-gate  * here is that we don't get a newline to terminate our expansion.
131*7c478bd9Sstevel@tonic-gate  * Rather, DgetC will return a DEOF when we hit the end-of-input.
132*7c478bd9Sstevel@tonic-gate  */
133*7c478bd9Sstevel@tonic-gate Dword()
134*7c478bd9Sstevel@tonic-gate {
135*7c478bd9Sstevel@tonic-gate 	register int c, c1;
136*7c478bd9Sstevel@tonic-gate 	static tchar *wbuf = NULL;
137*7c478bd9Sstevel@tonic-gate 	static int wbufsiz = BUFSIZ;
138*7c478bd9Sstevel@tonic-gate 	register int wp = 0;
139*7c478bd9Sstevel@tonic-gate 	register bool dolflg;
140*7c478bd9Sstevel@tonic-gate 	bool sofar = 0;
141*7c478bd9Sstevel@tonic-gate #define	DYNAMICBUFFER() \
142*7c478bd9Sstevel@tonic-gate 	do { \
143*7c478bd9Sstevel@tonic-gate 		if (wp >= wbufsiz) { \
144*7c478bd9Sstevel@tonic-gate 			wbufsiz += BUFSIZ; \
145*7c478bd9Sstevel@tonic-gate 			wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \
146*7c478bd9Sstevel@tonic-gate 		} \
147*7c478bd9Sstevel@tonic-gate 	} while (0)
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate #ifdef TRACE
150*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dword()\n");
151*7c478bd9Sstevel@tonic-gate #endif
152*7c478bd9Sstevel@tonic-gate 	if (wbuf == NULL)
153*7c478bd9Sstevel@tonic-gate 		wbuf = xalloc((wbufsiz+1) * sizeof (tchar));
154*7c478bd9Sstevel@tonic-gate loop:
155*7c478bd9Sstevel@tonic-gate 	c = DgetC(DODOL);
156*7c478bd9Sstevel@tonic-gate 	switch (c) {
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	case DEOF:
159*7c478bd9Sstevel@tonic-gate deof:
160*7c478bd9Sstevel@tonic-gate 		if (sofar == 0)
161*7c478bd9Sstevel@tonic-gate 			return (0);
162*7c478bd9Sstevel@tonic-gate 		/* finish this word and catch the code above the next time */
163*7c478bd9Sstevel@tonic-gate 		unDredc(c);
164*7c478bd9Sstevel@tonic-gate 		/* fall into ... */
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	case '\n':
167*7c478bd9Sstevel@tonic-gate 		wbuf[wp] = 0;
168*7c478bd9Sstevel@tonic-gate 		goto ret;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	case ' ':
171*7c478bd9Sstevel@tonic-gate 	case '\t':
172*7c478bd9Sstevel@tonic-gate 		goto loop;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	case '`':
175*7c478bd9Sstevel@tonic-gate 		/* We preserve ` quotations which are done yet later */
176*7c478bd9Sstevel@tonic-gate 		wbuf[wp++] = c;
177*7c478bd9Sstevel@tonic-gate 	case '\'':
178*7c478bd9Sstevel@tonic-gate 	case '"':
179*7c478bd9Sstevel@tonic-gate 		/*
180*7c478bd9Sstevel@tonic-gate 		 * Note that DgetC never returns a QUOTES character
181*7c478bd9Sstevel@tonic-gate 		 * from an expansion, so only true input quotes will
182*7c478bd9Sstevel@tonic-gate 		 * get us here or out.
183*7c478bd9Sstevel@tonic-gate 		 */
184*7c478bd9Sstevel@tonic-gate 		c1 = c;
185*7c478bd9Sstevel@tonic-gate 		dolflg = c1 == '"' ? DODOL : 0;
186*7c478bd9Sstevel@tonic-gate 		for (;;) {
187*7c478bd9Sstevel@tonic-gate 			c = DgetC(dolflg);
188*7c478bd9Sstevel@tonic-gate 			if (c == c1)
189*7c478bd9Sstevel@tonic-gate 				break;
190*7c478bd9Sstevel@tonic-gate 			if (c == '\n' || c == DEOF)
191*7c478bd9Sstevel@tonic-gate 				error("Unmatched %c", (tchar) c1);
192*7c478bd9Sstevel@tonic-gate 			if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
193*7c478bd9Sstevel@tonic-gate 				--wp;
194*7c478bd9Sstevel@tonic-gate 			DYNAMICBUFFER();
195*7c478bd9Sstevel@tonic-gate 			switch (c1) {
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 			case '"':
198*7c478bd9Sstevel@tonic-gate 				/*
199*7c478bd9Sstevel@tonic-gate 				 * Leave any `s alone for later.
200*7c478bd9Sstevel@tonic-gate 				 * Other chars are all quoted, thus `...`
201*7c478bd9Sstevel@tonic-gate 				 * can tell it was within "...".
202*7c478bd9Sstevel@tonic-gate 				 */
203*7c478bd9Sstevel@tonic-gate 				wbuf[wp++] = c == '`' ? '`' : c | QUOTE;
204*7c478bd9Sstevel@tonic-gate 				break;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 			case '\'':
207*7c478bd9Sstevel@tonic-gate 				/* Prevent all further interpretation */
208*7c478bd9Sstevel@tonic-gate 				wbuf[wp++] = c | QUOTE;
209*7c478bd9Sstevel@tonic-gate 				break;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 			case '`':
212*7c478bd9Sstevel@tonic-gate 				/* Leave all text alone for later */
213*7c478bd9Sstevel@tonic-gate 				wbuf[wp++] = c;
214*7c478bd9Sstevel@tonic-gate 				break;
215*7c478bd9Sstevel@tonic-gate 			}
216*7c478bd9Sstevel@tonic-gate 		}
217*7c478bd9Sstevel@tonic-gate 		if (c1 == '`') {
218*7c478bd9Sstevel@tonic-gate 			DYNAMICBUFFER();
219*7c478bd9Sstevel@tonic-gate 			wbuf[wp++] = '`';
220*7c478bd9Sstevel@tonic-gate 		}
221*7c478bd9Sstevel@tonic-gate 		goto pack;		/* continue the word */
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	case '\\':
224*7c478bd9Sstevel@tonic-gate 		c = DgetC(0);		/* No $ subst! */
225*7c478bd9Sstevel@tonic-gate 		if (c == '\n' || c == DEOF)
226*7c478bd9Sstevel@tonic-gate 			goto loop;
227*7c478bd9Sstevel@tonic-gate 		c |= QUOTE;
228*7c478bd9Sstevel@tonic-gate 		break;
229*7c478bd9Sstevel@tonic-gate #ifdef MBCHAR /* Could be a space char from aux. codeset. */
230*7c478bd9Sstevel@tonic-gate 	default:
231*7c478bd9Sstevel@tonic-gate 		if (isauxsp(c)) goto loop;
232*7c478bd9Sstevel@tonic-gate #endif /* MBCHAR */
233*7c478bd9Sstevel@tonic-gate 	}
234*7c478bd9Sstevel@tonic-gate 	unDgetC(c);
235*7c478bd9Sstevel@tonic-gate pack:
236*7c478bd9Sstevel@tonic-gate 	sofar = 1;
237*7c478bd9Sstevel@tonic-gate 	/* pack up more characters in this word */
238*7c478bd9Sstevel@tonic-gate 	for (;;) {
239*7c478bd9Sstevel@tonic-gate 		c = DgetC(DODOL);
240*7c478bd9Sstevel@tonic-gate 		if (c == '\\') {
241*7c478bd9Sstevel@tonic-gate 			c = DgetC(0);
242*7c478bd9Sstevel@tonic-gate 			if (c == DEOF)
243*7c478bd9Sstevel@tonic-gate 				goto deof;
244*7c478bd9Sstevel@tonic-gate 			if (c == '\n')
245*7c478bd9Sstevel@tonic-gate 				c = ' ';
246*7c478bd9Sstevel@tonic-gate 			else
247*7c478bd9Sstevel@tonic-gate 				c |= QUOTE;
248*7c478bd9Sstevel@tonic-gate 		}
249*7c478bd9Sstevel@tonic-gate 		if (c == DEOF)
250*7c478bd9Sstevel@tonic-gate 			goto deof;
251*7c478bd9Sstevel@tonic-gate 		if (cmap(c, _SP|_NL|_Q|_Q1) ||
252*7c478bd9Sstevel@tonic-gate 		    isauxsp(c)) {		/* sp \t\n'"` or aux. sp */
253*7c478bd9Sstevel@tonic-gate 			unDgetC(c);
254*7c478bd9Sstevel@tonic-gate 			if (cmap(c, QUOTES))
255*7c478bd9Sstevel@tonic-gate 				goto loop;
256*7c478bd9Sstevel@tonic-gate 			DYNAMICBUFFER();
257*7c478bd9Sstevel@tonic-gate 			wbuf[wp++] = 0;
258*7c478bd9Sstevel@tonic-gate 			goto ret;
259*7c478bd9Sstevel@tonic-gate 		}
260*7c478bd9Sstevel@tonic-gate 		DYNAMICBUFFER();
261*7c478bd9Sstevel@tonic-gate 		wbuf[wp++] = c;
262*7c478bd9Sstevel@tonic-gate 	}
263*7c478bd9Sstevel@tonic-gate ret:
264*7c478bd9Sstevel@tonic-gate 	Gcat(S_ /* "" */, wbuf);
265*7c478bd9Sstevel@tonic-gate 	return (1);
266*7c478bd9Sstevel@tonic-gate }
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate /*
269*7c478bd9Sstevel@tonic-gate  * Get a character, performing $ substitution unless flag is 0.
270*7c478bd9Sstevel@tonic-gate  * Any QUOTES character which is returned from a $ expansion is
271*7c478bd9Sstevel@tonic-gate  * QUOTEd so that it will not be recognized above.
272*7c478bd9Sstevel@tonic-gate  */
273*7c478bd9Sstevel@tonic-gate DgetC(flag)
274*7c478bd9Sstevel@tonic-gate 	register int flag;
275*7c478bd9Sstevel@tonic-gate {
276*7c478bd9Sstevel@tonic-gate 	register int c;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate top:
279*7c478bd9Sstevel@tonic-gate 	if (c = Dpeekc) {
280*7c478bd9Sstevel@tonic-gate 		Dpeekc = 0;
281*7c478bd9Sstevel@tonic-gate 		return (c);
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 	if (lap) {
284*7c478bd9Sstevel@tonic-gate 		c = *lap++ & (QUOTE|TRIM);
285*7c478bd9Sstevel@tonic-gate 		if (c == 0) {
286*7c478bd9Sstevel@tonic-gate 			lap = 0;
287*7c478bd9Sstevel@tonic-gate 			goto top;
288*7c478bd9Sstevel@tonic-gate 		}
289*7c478bd9Sstevel@tonic-gate quotspec:
290*7c478bd9Sstevel@tonic-gate 		/*
291*7c478bd9Sstevel@tonic-gate 		 *	don't quote things if there was an error (err!=0)
292*7c478bd9Sstevel@tonic-gate 		 * 	the input is original, not from a substitution and
293*7c478bd9Sstevel@tonic-gate 		 *	therefore should not be quoted
294*7c478bd9Sstevel@tonic-gate 		 */
295*7c478bd9Sstevel@tonic-gate 		if (!err && cmap(c, QUOTES))
296*7c478bd9Sstevel@tonic-gate 			return (c | QUOTE);
297*7c478bd9Sstevel@tonic-gate 		return (c);
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 	if (dolp) {
300*7c478bd9Sstevel@tonic-gate 		if (c = *dolp++ & (QUOTE|TRIM))
301*7c478bd9Sstevel@tonic-gate 			goto quotspec;
302*7c478bd9Sstevel@tonic-gate 		if (dolcnt > 0) {
303*7c478bd9Sstevel@tonic-gate 			setDolp(*dolnxt++);
304*7c478bd9Sstevel@tonic-gate 			--dolcnt;
305*7c478bd9Sstevel@tonic-gate 			return (' ');
306*7c478bd9Sstevel@tonic-gate 		}
307*7c478bd9Sstevel@tonic-gate 		dolp = 0;
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 	if (dolcnt > 0) {
310*7c478bd9Sstevel@tonic-gate 		setDolp(*dolnxt++);
311*7c478bd9Sstevel@tonic-gate 		--dolcnt;
312*7c478bd9Sstevel@tonic-gate 		goto top;
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 	c = Dredc();
315*7c478bd9Sstevel@tonic-gate 	if (c == '$' && flag) {
316*7c478bd9Sstevel@tonic-gate 		Dgetdol();
317*7c478bd9Sstevel@tonic-gate 		goto top;
318*7c478bd9Sstevel@tonic-gate 	}
319*7c478bd9Sstevel@tonic-gate 	return (c);
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate tchar *nulvec[] = { 0 };
323*7c478bd9Sstevel@tonic-gate struct	varent nulargv = { nulvec, S_argv, 0 };
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate /*
326*7c478bd9Sstevel@tonic-gate  * Handle the multitudinous $ expansion forms.
327*7c478bd9Sstevel@tonic-gate  * Ugh.
328*7c478bd9Sstevel@tonic-gate  */
329*7c478bd9Sstevel@tonic-gate Dgetdol()
330*7c478bd9Sstevel@tonic-gate {
331*7c478bd9Sstevel@tonic-gate 	register tchar *np;
332*7c478bd9Sstevel@tonic-gate 	register struct varent *vp;
333*7c478bd9Sstevel@tonic-gate 	tchar name[MAX_VREF_LEN];
334*7c478bd9Sstevel@tonic-gate 	int c, sc;
335*7c478bd9Sstevel@tonic-gate 	int subscr = 0, lwb = 1, upb = 0;
336*7c478bd9Sstevel@tonic-gate 	bool dimen = 0, bitset = 0;
337*7c478bd9Sstevel@tonic-gate 	tchar wbuf[BUFSIZ];
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate #ifdef TRACE
340*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dgetdol()\n");
341*7c478bd9Sstevel@tonic-gate #endif
342*7c478bd9Sstevel@tonic-gate 	dolmod = dolmcnt = 0;
343*7c478bd9Sstevel@tonic-gate 	c = sc = DgetC(0);
344*7c478bd9Sstevel@tonic-gate 	if (c == '{')
345*7c478bd9Sstevel@tonic-gate 		c = DgetC(0);		/* sc is { to take } later */
346*7c478bd9Sstevel@tonic-gate 	if ((c & TRIM) == '#')
347*7c478bd9Sstevel@tonic-gate 		dimen++, c = DgetC(0);		/* $# takes dimension */
348*7c478bd9Sstevel@tonic-gate 	else if (c == '?')
349*7c478bd9Sstevel@tonic-gate 		bitset++, c = DgetC(0);		/* $? tests existence */
350*7c478bd9Sstevel@tonic-gate 	switch (c) {
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	case '$':
353*7c478bd9Sstevel@tonic-gate 		if (dimen || bitset)
354*7c478bd9Sstevel@tonic-gate syntax:
355*7c478bd9Sstevel@tonic-gate 		error("Variable syntax");  /* No $?$, $#$ */
356*7c478bd9Sstevel@tonic-gate 		setDolp(doldol);
357*7c478bd9Sstevel@tonic-gate 		goto eatbrac;
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	case '<'|QUOTE:
360*7c478bd9Sstevel@tonic-gate 		if (dimen || bitset)
361*7c478bd9Sstevel@tonic-gate 			goto syntax;		/* No $?<, $#< */
362*7c478bd9Sstevel@tonic-gate 		for (np = wbuf; read_(OLDSTD, np, 1) == 1; np++) {
363*7c478bd9Sstevel@tonic-gate 			if (np >= &wbuf[BUFSIZ-1])
364*7c478bd9Sstevel@tonic-gate 				error("$< line too long");
365*7c478bd9Sstevel@tonic-gate 			if (*np <= 0 || *np == '\n')
366*7c478bd9Sstevel@tonic-gate 				break;
367*7c478bd9Sstevel@tonic-gate 		}
368*7c478bd9Sstevel@tonic-gate 		*np = 0;
369*7c478bd9Sstevel@tonic-gate 		/*
370*7c478bd9Sstevel@tonic-gate 		 * KLUDGE: dolmod is set here because it will
371*7c478bd9Sstevel@tonic-gate 		 * cause setDolp to call domod and thus to copy wbuf.
372*7c478bd9Sstevel@tonic-gate 		 * Otherwise setDolp would use it directly. If we saved
373*7c478bd9Sstevel@tonic-gate 		 * it ourselves, no one would know when to free it.
374*7c478bd9Sstevel@tonic-gate 		 * The actual function of the 'q' causes filename
375*7c478bd9Sstevel@tonic-gate 		 * expansion not to be done on the interpolated value.
376*7c478bd9Sstevel@tonic-gate 		 */
377*7c478bd9Sstevel@tonic-gate 		dolmod = 'q';
378*7c478bd9Sstevel@tonic-gate 		dolmcnt = 10000;
379*7c478bd9Sstevel@tonic-gate 		setDolp(wbuf);
380*7c478bd9Sstevel@tonic-gate 		goto eatbrac;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	case DEOF:
383*7c478bd9Sstevel@tonic-gate 	case '\n':
384*7c478bd9Sstevel@tonic-gate 		goto syntax;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	case '*':
387*7c478bd9Sstevel@tonic-gate 		(void) strcpy_(name, S_argv);
388*7c478bd9Sstevel@tonic-gate 		vp = adrof(S_argv);
389*7c478bd9Sstevel@tonic-gate 		subscr = -1;			/* Prevent eating [...] */
390*7c478bd9Sstevel@tonic-gate 		break;
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	default:
393*7c478bd9Sstevel@tonic-gate 		np = name;
394*7c478bd9Sstevel@tonic-gate 		if (digit(c)) {
395*7c478bd9Sstevel@tonic-gate 			if (dimen)
396*7c478bd9Sstevel@tonic-gate 				goto syntax;	/* No $#1, e.g. */
397*7c478bd9Sstevel@tonic-gate 			subscr = 0;
398*7c478bd9Sstevel@tonic-gate 			do {
399*7c478bd9Sstevel@tonic-gate 				subscr = subscr * 10 + c - '0';
400*7c478bd9Sstevel@tonic-gate 				c = DgetC(0);
401*7c478bd9Sstevel@tonic-gate 			} while (digit(c));
402*7c478bd9Sstevel@tonic-gate 			unDredc(c);
403*7c478bd9Sstevel@tonic-gate 			if (subscr < 0)
404*7c478bd9Sstevel@tonic-gate 				error("Subscript out of range");
405*7c478bd9Sstevel@tonic-gate 			if (subscr == 0) {
406*7c478bd9Sstevel@tonic-gate 				if (bitset) {
407*7c478bd9Sstevel@tonic-gate 					dolp = file ? S_1/*"1"*/ : S_0/*"0"*/;
408*7c478bd9Sstevel@tonic-gate 					goto eatbrac;
409*7c478bd9Sstevel@tonic-gate 				}
410*7c478bd9Sstevel@tonic-gate 				if (file == 0)
411*7c478bd9Sstevel@tonic-gate 					error("No file for $0");
412*7c478bd9Sstevel@tonic-gate 				setDolp(file);
413*7c478bd9Sstevel@tonic-gate 				goto eatbrac;
414*7c478bd9Sstevel@tonic-gate 			}
415*7c478bd9Sstevel@tonic-gate 			if (bitset)
416*7c478bd9Sstevel@tonic-gate 				goto syntax;
417*7c478bd9Sstevel@tonic-gate 			vp = adrof(S_argv);
418*7c478bd9Sstevel@tonic-gate 			if (vp == 0) {
419*7c478bd9Sstevel@tonic-gate 				vp = &nulargv;
420*7c478bd9Sstevel@tonic-gate 				goto eatmod;
421*7c478bd9Sstevel@tonic-gate 			}
422*7c478bd9Sstevel@tonic-gate 			break;
423*7c478bd9Sstevel@tonic-gate 		}
424*7c478bd9Sstevel@tonic-gate 		if (!alnum(c))
425*7c478bd9Sstevel@tonic-gate 			goto syntax;
426*7c478bd9Sstevel@tonic-gate 		for (;;) {
427*7c478bd9Sstevel@tonic-gate 			*np++ = c;
428*7c478bd9Sstevel@tonic-gate 			c = DgetC(0);
429*7c478bd9Sstevel@tonic-gate 			if (!alnum(c))
430*7c478bd9Sstevel@tonic-gate 				break;
431*7c478bd9Sstevel@tonic-gate 			/* if variable name is > 20, complain */
432*7c478bd9Sstevel@tonic-gate 			if (np >= &name[MAX_VAR_LEN])
433*7c478bd9Sstevel@tonic-gate 				error("Variable name too long");
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 		*np++ = 0;
437*7c478bd9Sstevel@tonic-gate 		unDredc(c);
438*7c478bd9Sstevel@tonic-gate 		vp = adrof(name);
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 	if (bitset) {
441*7c478bd9Sstevel@tonic-gate 		/* getenv() to getenv_(), because 'name''s type is now tchar * */
442*7c478bd9Sstevel@tonic-gate 		/* no need to xalloc */
443*7c478bd9Sstevel@tonic-gate 		dolp = (vp || getenv_(name)) ? S_1 /*"1"*/ : S_0/*"0"*/;
444*7c478bd9Sstevel@tonic-gate 		goto eatbrac;
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate 	if (vp == 0) {
447*7c478bd9Sstevel@tonic-gate 		/* getenv() to getenv_(), because 'name''s type is now tchar * */
448*7c478bd9Sstevel@tonic-gate 		/* no need to xalloc */
449*7c478bd9Sstevel@tonic-gate 		np = getenv_(name);
450*7c478bd9Sstevel@tonic-gate 		if (np) {
451*7c478bd9Sstevel@tonic-gate 			addla(np);
452*7c478bd9Sstevel@tonic-gate 			goto eatbrac;
453*7c478bd9Sstevel@tonic-gate 		}
454*7c478bd9Sstevel@tonic-gate 		udvar(name);
455*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate 	c = DgetC(0);
458*7c478bd9Sstevel@tonic-gate 	upb = blklen(vp->vec);
459*7c478bd9Sstevel@tonic-gate 	if (dimen == 0 && subscr == 0 && c == '[') {
460*7c478bd9Sstevel@tonic-gate 		np = name;
461*7c478bd9Sstevel@tonic-gate 		for (;;) {
462*7c478bd9Sstevel@tonic-gate 			c = DgetC(DODOL);	/* Allow $ expand within [ ] */
463*7c478bd9Sstevel@tonic-gate 			if (c == ']')
464*7c478bd9Sstevel@tonic-gate 				break;
465*7c478bd9Sstevel@tonic-gate 			if (c == '\n' || c == DEOF)
466*7c478bd9Sstevel@tonic-gate 				goto syntax;
467*7c478bd9Sstevel@tonic-gate 			if (np >= &name[MAX_VREF_LEN])
468*7c478bd9Sstevel@tonic-gate 				error("Variable reference too long");
469*7c478bd9Sstevel@tonic-gate 			*np++ = c;
470*7c478bd9Sstevel@tonic-gate 		}
471*7c478bd9Sstevel@tonic-gate 		*np = 0, np = name;
472*7c478bd9Sstevel@tonic-gate 		if (dolp || dolcnt)		/* $ exp must end before ] */
473*7c478bd9Sstevel@tonic-gate 			goto syntax;
474*7c478bd9Sstevel@tonic-gate 		if (!*np)
475*7c478bd9Sstevel@tonic-gate 			goto syntax;
476*7c478bd9Sstevel@tonic-gate 		if (digit(*np)) {
477*7c478bd9Sstevel@tonic-gate 			register int i = 0;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 			while (digit(*np))
480*7c478bd9Sstevel@tonic-gate 				i = i * 10 + *np++ - '0';
481*7c478bd9Sstevel@tonic-gate /*			if ((i < 0 || i > upb) && !any(*np, "-*")) {*/
482*7c478bd9Sstevel@tonic-gate 			if ((i < 0 || i > upb) && (*np!='-') && (*np!='*')) {
483*7c478bd9Sstevel@tonic-gate oob:
484*7c478bd9Sstevel@tonic-gate 				setname(vp->v_name);
485*7c478bd9Sstevel@tonic-gate 				error("Subscript out of range");
486*7c478bd9Sstevel@tonic-gate 			}
487*7c478bd9Sstevel@tonic-gate 			lwb = i;
488*7c478bd9Sstevel@tonic-gate 			if (!*np)
489*7c478bd9Sstevel@tonic-gate 				upb = lwb, np = S_AST/*"*"*/;
490*7c478bd9Sstevel@tonic-gate 		}
491*7c478bd9Sstevel@tonic-gate 		if (*np == '*')
492*7c478bd9Sstevel@tonic-gate 			np++;
493*7c478bd9Sstevel@tonic-gate 		else if (*np != '-')
494*7c478bd9Sstevel@tonic-gate 			goto syntax;
495*7c478bd9Sstevel@tonic-gate 		else {
496*7c478bd9Sstevel@tonic-gate 			register int i = upb;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 			np++;
499*7c478bd9Sstevel@tonic-gate 			if (digit(*np)) {
500*7c478bd9Sstevel@tonic-gate 				i = 0;
501*7c478bd9Sstevel@tonic-gate 				while (digit(*np))
502*7c478bd9Sstevel@tonic-gate 					i = i * 10 + *np++ - '0';
503*7c478bd9Sstevel@tonic-gate 				if (i < 0 || i > upb)
504*7c478bd9Sstevel@tonic-gate 					goto oob;
505*7c478bd9Sstevel@tonic-gate 			}
506*7c478bd9Sstevel@tonic-gate 			if (i < lwb)
507*7c478bd9Sstevel@tonic-gate 				upb = lwb - 1;
508*7c478bd9Sstevel@tonic-gate 			else
509*7c478bd9Sstevel@tonic-gate 				upb = i;
510*7c478bd9Sstevel@tonic-gate 		}
511*7c478bd9Sstevel@tonic-gate 		if (lwb == 0) {
512*7c478bd9Sstevel@tonic-gate 			if (upb != 0)
513*7c478bd9Sstevel@tonic-gate 				goto oob;
514*7c478bd9Sstevel@tonic-gate 			upb = -1;
515*7c478bd9Sstevel@tonic-gate 		}
516*7c478bd9Sstevel@tonic-gate 		if (*np)
517*7c478bd9Sstevel@tonic-gate 			goto syntax;
518*7c478bd9Sstevel@tonic-gate 	} else {
519*7c478bd9Sstevel@tonic-gate 		if (subscr > 0)
520*7c478bd9Sstevel@tonic-gate 			if (subscr > upb)
521*7c478bd9Sstevel@tonic-gate 				lwb = 1, upb = 0;
522*7c478bd9Sstevel@tonic-gate 			else
523*7c478bd9Sstevel@tonic-gate 				lwb = upb = subscr;
524*7c478bd9Sstevel@tonic-gate 		unDredc(c);
525*7c478bd9Sstevel@tonic-gate 	}
526*7c478bd9Sstevel@tonic-gate 	if (dimen) {
527*7c478bd9Sstevel@tonic-gate 		tchar *cp = putn(upb - lwb + 1);
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 		addla(cp);
530*7c478bd9Sstevel@tonic-gate 		xfree(cp);
531*7c478bd9Sstevel@tonic-gate 	} else {
532*7c478bd9Sstevel@tonic-gate eatmod:
533*7c478bd9Sstevel@tonic-gate 		c = DgetC(0);
534*7c478bd9Sstevel@tonic-gate 		if (c == ':') {
535*7c478bd9Sstevel@tonic-gate 			c = DgetC(0), dolmcnt = 1;
536*7c478bd9Sstevel@tonic-gate 			if (c == 'g')
537*7c478bd9Sstevel@tonic-gate 				c = DgetC(0), dolmcnt = 10000;
538*7c478bd9Sstevel@tonic-gate 			if (!any(c, S_htrqxe))
539*7c478bd9Sstevel@tonic-gate 				error("Bad : mod in $");
540*7c478bd9Sstevel@tonic-gate 			dolmod = c;
541*7c478bd9Sstevel@tonic-gate 			if (c == 'q')
542*7c478bd9Sstevel@tonic-gate 				dolmcnt = 10000;
543*7c478bd9Sstevel@tonic-gate 		} else
544*7c478bd9Sstevel@tonic-gate 			unDredc(c);
545*7c478bd9Sstevel@tonic-gate 		dolnxt = &vp->vec[lwb - 1];
546*7c478bd9Sstevel@tonic-gate 		dolcnt = upb - lwb + 1;
547*7c478bd9Sstevel@tonic-gate 	}
548*7c478bd9Sstevel@tonic-gate eatbrac:
549*7c478bd9Sstevel@tonic-gate 	if (sc == '{') {
550*7c478bd9Sstevel@tonic-gate 		c = Dredc();
551*7c478bd9Sstevel@tonic-gate 		if (c != '}')
552*7c478bd9Sstevel@tonic-gate 			goto syntax;
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate setDolp(cp)
557*7c478bd9Sstevel@tonic-gate 	register tchar *cp;
558*7c478bd9Sstevel@tonic-gate {
559*7c478bd9Sstevel@tonic-gate 	register tchar *dp;
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate #ifdef TRACE
562*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- setDolp()\n");
563*7c478bd9Sstevel@tonic-gate #endif
564*7c478bd9Sstevel@tonic-gate 	if (dolmod == 0 || dolmcnt == 0) {
565*7c478bd9Sstevel@tonic-gate 		dolp = cp;
566*7c478bd9Sstevel@tonic-gate 		return;
567*7c478bd9Sstevel@tonic-gate 	}
568*7c478bd9Sstevel@tonic-gate 	dp = domod(cp, dolmod);
569*7c478bd9Sstevel@tonic-gate 	if (dp) {
570*7c478bd9Sstevel@tonic-gate 		dolmcnt--;
571*7c478bd9Sstevel@tonic-gate 		addla(dp);
572*7c478bd9Sstevel@tonic-gate 		xfree(dp);
573*7c478bd9Sstevel@tonic-gate 	} else
574*7c478bd9Sstevel@tonic-gate 		addla(cp);
575*7c478bd9Sstevel@tonic-gate 	dolp = S_/*""*/;
576*7c478bd9Sstevel@tonic-gate }
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate unDredc(c)
579*7c478bd9Sstevel@tonic-gate 	int c;
580*7c478bd9Sstevel@tonic-gate {
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	Dpeekrd = c;
583*7c478bd9Sstevel@tonic-gate }
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate Dredc()
586*7c478bd9Sstevel@tonic-gate {
587*7c478bd9Sstevel@tonic-gate 	register int c;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	if (c = Dpeekrd) {
590*7c478bd9Sstevel@tonic-gate 		Dpeekrd = 0;
591*7c478bd9Sstevel@tonic-gate 		return (c);
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 	if (Dcp && (c = *Dcp++))
594*7c478bd9Sstevel@tonic-gate 		return (c&(QUOTE|TRIM));
595*7c478bd9Sstevel@tonic-gate 	if (*Dvp == 0) {
596*7c478bd9Sstevel@tonic-gate 		Dcp = 0;
597*7c478bd9Sstevel@tonic-gate 		return (DEOF);
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 	Dcp = *Dvp++;
600*7c478bd9Sstevel@tonic-gate 	return (' ');
601*7c478bd9Sstevel@tonic-gate }
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate Dtestq(c)
604*7c478bd9Sstevel@tonic-gate 	register int c;
605*7c478bd9Sstevel@tonic-gate {
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (cmap(c, QUOTES))
608*7c478bd9Sstevel@tonic-gate 		gflag = 1;
609*7c478bd9Sstevel@tonic-gate }
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate /*
612*7c478bd9Sstevel@tonic-gate  * Form a shell temporary file (in unit 0) from the words
613*7c478bd9Sstevel@tonic-gate  * of the shell input up to a line the same as "term".
614*7c478bd9Sstevel@tonic-gate  * Unit 0 should have been closed before this call.
615*7c478bd9Sstevel@tonic-gate  */
616*7c478bd9Sstevel@tonic-gate heredoc(term)
617*7c478bd9Sstevel@tonic-gate      tchar *term;
618*7c478bd9Sstevel@tonic-gate {
619*7c478bd9Sstevel@tonic-gate 	register int c;
620*7c478bd9Sstevel@tonic-gate 	tchar *Dv[2];
621*7c478bd9Sstevel@tonic-gate 	tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
622*7c478bd9Sstevel@tonic-gate 	int ocnt, lcnt, mcnt;
623*7c478bd9Sstevel@tonic-gate 	register tchar *lbp, *obp, *mbp;
624*7c478bd9Sstevel@tonic-gate 	tchar **vp;
625*7c478bd9Sstevel@tonic-gate 	bool quoted;
626*7c478bd9Sstevel@tonic-gate 	tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X',
627*7c478bd9Sstevel@tonic-gate 'X', 'X', 'X', 0};
628*7c478bd9Sstevel@tonic-gate 	int fd1;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate #ifdef TRACE
631*7c478bd9Sstevel@tonic-gate 	tprintf("TRACE- heredoc()\n");
632*7c478bd9Sstevel@tonic-gate #endif
633*7c478bd9Sstevel@tonic-gate 	if ((fd1 = mkstemp_(shtemp)) < 0)
634*7c478bd9Sstevel@tonic-gate 		Perror(shtemp);
635*7c478bd9Sstevel@tonic-gate 	(void) unlink_(shtemp);			/* 0 0 inode! */
636*7c478bd9Sstevel@tonic-gate 	unsetfd(fd1);
637*7c478bd9Sstevel@tonic-gate 	Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
638*7c478bd9Sstevel@tonic-gate 	trim(Dv); rscan(Dv, Dtestq); quoted = gflag;
639*7c478bd9Sstevel@tonic-gate 	ocnt = BUFSIZ; obp = obuf;
640*7c478bd9Sstevel@tonic-gate 	for (;;) {
641*7c478bd9Sstevel@tonic-gate 		/*
642*7c478bd9Sstevel@tonic-gate 		 * Read up a line
643*7c478bd9Sstevel@tonic-gate 		 */
644*7c478bd9Sstevel@tonic-gate 		lbp = lbuf; lcnt = BUFSIZ - 4;
645*7c478bd9Sstevel@tonic-gate 		for (;;) {
646*7c478bd9Sstevel@tonic-gate 			c = readc(1);		/* 1 -> Want EOF returns */
647*7c478bd9Sstevel@tonic-gate 			if (c < 0) {
648*7c478bd9Sstevel@tonic-gate 				setname(term);
649*7c478bd9Sstevel@tonic-gate 				bferr("<< terminator not found");
650*7c478bd9Sstevel@tonic-gate 			}
651*7c478bd9Sstevel@tonic-gate 			if (c == '\n')
652*7c478bd9Sstevel@tonic-gate 				break;
653*7c478bd9Sstevel@tonic-gate 			if (c &= TRIM) {
654*7c478bd9Sstevel@tonic-gate 				*lbp++ = c;
655*7c478bd9Sstevel@tonic-gate 				if (--lcnt < 0) {
656*7c478bd9Sstevel@tonic-gate 					setname(S_LESLES/*"<<"*/);
657*7c478bd9Sstevel@tonic-gate 					error("Line overflow");
658*7c478bd9Sstevel@tonic-gate 				}
659*7c478bd9Sstevel@tonic-gate 			}
660*7c478bd9Sstevel@tonic-gate 		}
661*7c478bd9Sstevel@tonic-gate 		*lbp = 0;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 		/*
664*7c478bd9Sstevel@tonic-gate 		 * Compare to terminator -- before expansion
665*7c478bd9Sstevel@tonic-gate 		 */
666*7c478bd9Sstevel@tonic-gate 		if (eq(lbuf, term)) {
667*7c478bd9Sstevel@tonic-gate 			(void) write_(0, obuf, BUFSIZ - ocnt);
668*7c478bd9Sstevel@tonic-gate 			(void) lseek(0, (off_t)0, 0);
669*7c478bd9Sstevel@tonic-gate 			return;
670*7c478bd9Sstevel@tonic-gate 		}
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 		/*
673*7c478bd9Sstevel@tonic-gate 		 * If term was quoted or -n just pass it on
674*7c478bd9Sstevel@tonic-gate 		 */
675*7c478bd9Sstevel@tonic-gate 		if (quoted || noexec) {
676*7c478bd9Sstevel@tonic-gate 			*lbp++ = '\n'; *lbp = 0;
677*7c478bd9Sstevel@tonic-gate 			for (lbp = lbuf; c = *lbp++;) {
678*7c478bd9Sstevel@tonic-gate 				*obp++ = c;
679*7c478bd9Sstevel@tonic-gate 				if (--ocnt == 0) {
680*7c478bd9Sstevel@tonic-gate 					(void) write_(0, obuf, BUFSIZ);
681*7c478bd9Sstevel@tonic-gate 					obp = obuf; ocnt = BUFSIZ;
682*7c478bd9Sstevel@tonic-gate 				}
683*7c478bd9Sstevel@tonic-gate 			}
684*7c478bd9Sstevel@tonic-gate 			continue;
685*7c478bd9Sstevel@tonic-gate 		}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 		/*
688*7c478bd9Sstevel@tonic-gate 		 * Term wasn't quoted so variable and then command
689*7c478bd9Sstevel@tonic-gate 		 * expand the input line
690*7c478bd9Sstevel@tonic-gate 		 */
691*7c478bd9Sstevel@tonic-gate 		Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
692*7c478bd9Sstevel@tonic-gate 		for (;;) {
693*7c478bd9Sstevel@tonic-gate 			c = DgetC(DODOL);
694*7c478bd9Sstevel@tonic-gate 			if (c == DEOF)
695*7c478bd9Sstevel@tonic-gate 				break;
696*7c478bd9Sstevel@tonic-gate 			if ((c &= TRIM) == 0)
697*7c478bd9Sstevel@tonic-gate 				continue;
698*7c478bd9Sstevel@tonic-gate 			/* \ quotes \ $ ` here */
699*7c478bd9Sstevel@tonic-gate 			if (c =='\\') {
700*7c478bd9Sstevel@tonic-gate 				c = DgetC(0);
701*7c478bd9Sstevel@tonic-gate /*				if (!any(c, "$\\`"))*/
702*7c478bd9Sstevel@tonic-gate 				if ((c!='$')&&(c!='\\')&&(c!='`'))
703*7c478bd9Sstevel@tonic-gate 					unDgetC(c | QUOTE), c = '\\';
704*7c478bd9Sstevel@tonic-gate 				else
705*7c478bd9Sstevel@tonic-gate 					c |= QUOTE;
706*7c478bd9Sstevel@tonic-gate 			}
707*7c478bd9Sstevel@tonic-gate 			*mbp++ = c;
708*7c478bd9Sstevel@tonic-gate 			if (--mcnt == 0) {
709*7c478bd9Sstevel@tonic-gate 				setname(S_LESLES/*"<<"*/);
710*7c478bd9Sstevel@tonic-gate 				bferr("Line overflow");
711*7c478bd9Sstevel@tonic-gate 			}
712*7c478bd9Sstevel@tonic-gate 		}
713*7c478bd9Sstevel@tonic-gate 		*mbp++ = 0;
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 		/*
716*7c478bd9Sstevel@tonic-gate 		 * If any ` in line do command substitution
717*7c478bd9Sstevel@tonic-gate 		 */
718*7c478bd9Sstevel@tonic-gate 		mbp = mbuf;
719*7c478bd9Sstevel@tonic-gate 		if (any('`', mbp)) {
720*7c478bd9Sstevel@tonic-gate 			/*
721*7c478bd9Sstevel@tonic-gate 			 * 1 arg to dobackp causes substitution to be literal.
722*7c478bd9Sstevel@tonic-gate 			 * Words are broken only at newlines so that all blanks
723*7c478bd9Sstevel@tonic-gate 			 * and tabs are preserved.  Blank lines (null words)
724*7c478bd9Sstevel@tonic-gate 			 * are not discarded.
725*7c478bd9Sstevel@tonic-gate 			 */
726*7c478bd9Sstevel@tonic-gate 			vp = dobackp(mbuf, 1);
727*7c478bd9Sstevel@tonic-gate 		} else
728*7c478bd9Sstevel@tonic-gate 			/* Setup trivial vector similar to return of dobackp */
729*7c478bd9Sstevel@tonic-gate 			Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 		/*
732*7c478bd9Sstevel@tonic-gate 		 * Resurrect the words from the command substitution
733*7c478bd9Sstevel@tonic-gate 		 * each separated by a newline.  Note that the last
734*7c478bd9Sstevel@tonic-gate 		 * newline of a command substitution will have been
735*7c478bd9Sstevel@tonic-gate 		 * discarded, but we put a newline after the last word
736*7c478bd9Sstevel@tonic-gate 		 * because this represents the newline after the last
737*7c478bd9Sstevel@tonic-gate 		 * input line!
738*7c478bd9Sstevel@tonic-gate 		 */
739*7c478bd9Sstevel@tonic-gate 		for (; *vp; vp++) {
740*7c478bd9Sstevel@tonic-gate 			for (mbp = *vp; *mbp; mbp++) {
741*7c478bd9Sstevel@tonic-gate 				*obp++ = *mbp & TRIM;
742*7c478bd9Sstevel@tonic-gate 				if (--ocnt == 0) {
743*7c478bd9Sstevel@tonic-gate 					(void) write_(0, obuf, BUFSIZ);
744*7c478bd9Sstevel@tonic-gate 					obp = obuf; ocnt = BUFSIZ;
745*7c478bd9Sstevel@tonic-gate 				}
746*7c478bd9Sstevel@tonic-gate 			}
747*7c478bd9Sstevel@tonic-gate 			*obp++ = '\n';
748*7c478bd9Sstevel@tonic-gate 			if (--ocnt == 0) {
749*7c478bd9Sstevel@tonic-gate 				(void) write_(0, obuf, BUFSIZ);
750*7c478bd9Sstevel@tonic-gate 				obp = obuf; ocnt = BUFSIZ;
751*7c478bd9Sstevel@tonic-gate 			}
752*7c478bd9Sstevel@tonic-gate 		}
753*7c478bd9Sstevel@tonic-gate 		if (pargv)
754*7c478bd9Sstevel@tonic-gate 			blkfree(pargv), pargv = 0;
755*7c478bd9Sstevel@tonic-gate 	}
756*7c478bd9Sstevel@tonic-gate }
757