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