xref: /plan9/sys/src/ape/cmd/pdksh/lex.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier /*
2*7dd7cddfSDavid du Colombier  * lexical analysis and source input
3*7dd7cddfSDavid du Colombier  */
4*7dd7cddfSDavid du Colombier 
5*7dd7cddfSDavid du Colombier #include "sh.h"
6*7dd7cddfSDavid du Colombier #include <ctype.h>
7*7dd7cddfSDavid du Colombier 
8*7dd7cddfSDavid du Colombier 
9*7dd7cddfSDavid du Colombier /* Structure to keep track of the lexing state and the various pieces of info
10*7dd7cddfSDavid du Colombier  * needed for each particular state.
11*7dd7cddfSDavid du Colombier  */
12*7dd7cddfSDavid du Colombier typedef struct lex_state Lex_state;
13*7dd7cddfSDavid du Colombier struct lex_state {
14*7dd7cddfSDavid du Colombier 	int ls_state;
15*7dd7cddfSDavid du Colombier 	union {
16*7dd7cddfSDavid du Colombier 	    /* $(...) */
17*7dd7cddfSDavid du Colombier 	    struct scsparen_info {
18*7dd7cddfSDavid du Colombier 		    int nparen;		/* count open parenthesis */
19*7dd7cddfSDavid du Colombier 		    int csstate; /* XXX remove */
20*7dd7cddfSDavid du Colombier #define ls_scsparen ls_info.u_scsparen
21*7dd7cddfSDavid du Colombier 	    } u_scsparen;
22*7dd7cddfSDavid du Colombier 
23*7dd7cddfSDavid du Colombier 	    /* $((...)) */
24*7dd7cddfSDavid du Colombier 	    struct sasparen_info {
25*7dd7cddfSDavid du Colombier 		    int nparen;		/* count open parenthesis */
26*7dd7cddfSDavid du Colombier 		    int start;		/* marks start of $(( in output str */
27*7dd7cddfSDavid du Colombier #define ls_sasparen ls_info.u_sasparen
28*7dd7cddfSDavid du Colombier 	    } u_sasparen;
29*7dd7cddfSDavid du Colombier 
30*7dd7cddfSDavid du Colombier 	    /* ((...)) */
31*7dd7cddfSDavid du Colombier 	    struct sletparen_info {
32*7dd7cddfSDavid du Colombier 		    int nparen;		/* count open parenthesis */
33*7dd7cddfSDavid du Colombier #define ls_sletparen ls_info.u_sletparen
34*7dd7cddfSDavid du Colombier 	    } u_sletparen;
35*7dd7cddfSDavid du Colombier 
36*7dd7cddfSDavid du Colombier 	    /* `...` */
37*7dd7cddfSDavid du Colombier 	    struct sbquote_info {
38*7dd7cddfSDavid du Colombier 		    int indquotes;	/* true if in double quotes: "`...`" */
39*7dd7cddfSDavid du Colombier #define ls_sbquote ls_info.u_sbquote
40*7dd7cddfSDavid du Colombier 	    } u_sbquote;
41*7dd7cddfSDavid du Colombier 
42*7dd7cddfSDavid du Colombier 	    Lex_state *base;		/* used to point to next state block */
43*7dd7cddfSDavid du Colombier 	} ls_info;
44*7dd7cddfSDavid du Colombier };
45*7dd7cddfSDavid du Colombier 
46*7dd7cddfSDavid du Colombier typedef struct State_info State_info;
47*7dd7cddfSDavid du Colombier struct State_info {
48*7dd7cddfSDavid du Colombier 	Lex_state	*base;
49*7dd7cddfSDavid du Colombier 	Lex_state	*end;
50*7dd7cddfSDavid du Colombier };
51*7dd7cddfSDavid du Colombier 
52*7dd7cddfSDavid du Colombier 
53*7dd7cddfSDavid du Colombier static void	readhere ARGS((struct ioword *iop));
54*7dd7cddfSDavid du Colombier static int	getsc__ ARGS((void));
55*7dd7cddfSDavid du Colombier static void	getsc_line ARGS((Source *s));
56*7dd7cddfSDavid du Colombier static int	getsc_bn ARGS((void));
57*7dd7cddfSDavid du Colombier static char	*get_brace_var ARGS((XString *wsp, char *wp));
58*7dd7cddfSDavid du Colombier static int	arraysub ARGS((char **strp));
59*7dd7cddfSDavid du Colombier static const char *ungetsc ARGS((int c));
60*7dd7cddfSDavid du Colombier static void	gethere ARGS((void));
61*7dd7cddfSDavid du Colombier static Lex_state *push_state_ ARGS((State_info *si, Lex_state *old_end));
62*7dd7cddfSDavid du Colombier static Lex_state *pop_state_ ARGS((State_info *si, Lex_state *old_end));
63*7dd7cddfSDavid du Colombier 
64*7dd7cddfSDavid du Colombier static int backslash_skip;
65*7dd7cddfSDavid du Colombier static int ignore_backslash_newline;
66*7dd7cddfSDavid du Colombier 
67*7dd7cddfSDavid du Colombier /* optimized getsc_bn() */
68*7dd7cddfSDavid du Colombier #define getsc()		(*source->str != '\0' && *source->str != '\\' \
69*7dd7cddfSDavid du Colombier 			 && !backslash_skip ? *source->str++ : getsc_bn())
70*7dd7cddfSDavid du Colombier /* optimized getsc__() */
71*7dd7cddfSDavid du Colombier #define	getsc_()	((*source->str != '\0') ? *source->str++ : getsc__())
72*7dd7cddfSDavid du Colombier 
73*7dd7cddfSDavid du Colombier #define STATE_BSIZE	32
74*7dd7cddfSDavid du Colombier 
75*7dd7cddfSDavid du Colombier #define PUSH_STATE(s)	do { \
76*7dd7cddfSDavid du Colombier 			    if (++statep == state_info.end) \
77*7dd7cddfSDavid du Colombier 				statep = push_state_(&state_info, statep); \
78*7dd7cddfSDavid du Colombier 			    state = statep->ls_state = (s); \
79*7dd7cddfSDavid du Colombier 			} while (0)
80*7dd7cddfSDavid du Colombier 
81*7dd7cddfSDavid du Colombier #define POP_STATE()	do { \
82*7dd7cddfSDavid du Colombier 			    if (--statep == state_info.base) \
83*7dd7cddfSDavid du Colombier 				statep = pop_state_(&state_info, statep); \
84*7dd7cddfSDavid du Colombier 			    state = statep->ls_state; \
85*7dd7cddfSDavid du Colombier 			} while (0)
86*7dd7cddfSDavid du Colombier 
87*7dd7cddfSDavid du Colombier 
88*7dd7cddfSDavid du Colombier 
89*7dd7cddfSDavid du Colombier /*
90*7dd7cddfSDavid du Colombier  * Lexical analyzer
91*7dd7cddfSDavid du Colombier  *
92*7dd7cddfSDavid du Colombier  * tokens are not regular expressions, they are LL(1).
93*7dd7cddfSDavid du Colombier  * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
94*7dd7cddfSDavid du Colombier  * hence the state stack.
95*7dd7cddfSDavid du Colombier  */
96*7dd7cddfSDavid du Colombier 
97*7dd7cddfSDavid du Colombier int
yylex(cf)98*7dd7cddfSDavid du Colombier yylex(cf)
99*7dd7cddfSDavid du Colombier 	int cf;
100*7dd7cddfSDavid du Colombier {
101*7dd7cddfSDavid du Colombier 	Lex_state states[STATE_BSIZE], *statep;
102*7dd7cddfSDavid du Colombier 	State_info state_info;
103*7dd7cddfSDavid du Colombier 	register int c, state;
104*7dd7cddfSDavid du Colombier 	XString ws;		/* expandable output word */
105*7dd7cddfSDavid du Colombier 	register char *wp;	/* output word pointer */
106*7dd7cddfSDavid du Colombier 	char *sp, *dp;
107*7dd7cddfSDavid du Colombier 	int c2;
108*7dd7cddfSDavid du Colombier 
109*7dd7cddfSDavid du Colombier 
110*7dd7cddfSDavid du Colombier   Again:
111*7dd7cddfSDavid du Colombier 	states[0].ls_state = -1;
112*7dd7cddfSDavid du Colombier 	states[0].ls_info.base = (Lex_state *) 0;
113*7dd7cddfSDavid du Colombier 	statep = &states[1];
114*7dd7cddfSDavid du Colombier 	state_info.base = states;
115*7dd7cddfSDavid du Colombier 	state_info.end = &states[STATE_BSIZE];
116*7dd7cddfSDavid du Colombier 
117*7dd7cddfSDavid du Colombier 	Xinit(ws, wp, 64, ATEMP);
118*7dd7cddfSDavid du Colombier 
119*7dd7cddfSDavid du Colombier 	backslash_skip = 0;
120*7dd7cddfSDavid du Colombier 	ignore_backslash_newline = 0;
121*7dd7cddfSDavid du Colombier 
122*7dd7cddfSDavid du Colombier 	if (cf&ONEWORD)
123*7dd7cddfSDavid du Colombier 		state = SWORD;
124*7dd7cddfSDavid du Colombier #ifdef KSH
125*7dd7cddfSDavid du Colombier 	else if (cf&LETEXPR) {
126*7dd7cddfSDavid du Colombier 		*wp++ = OQUOTE;	 /* enclose arguments in (double) quotes */
127*7dd7cddfSDavid du Colombier 		state = SLETPAREN;
128*7dd7cddfSDavid du Colombier 		statep->ls_sletparen.nparen = 0;
129*7dd7cddfSDavid du Colombier 	}
130*7dd7cddfSDavid du Colombier #endif /* KSH */
131*7dd7cddfSDavid du Colombier 	else {		/* normal lexing */
132*7dd7cddfSDavid du Colombier 		state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
133*7dd7cddfSDavid du Colombier 		while ((c = getsc()) == ' ' || c == '\t')
134*7dd7cddfSDavid du Colombier 			;
135*7dd7cddfSDavid du Colombier 		if (c == '#') {
136*7dd7cddfSDavid du Colombier 			ignore_backslash_newline++;
137*7dd7cddfSDavid du Colombier 			while ((c = getsc()) != '\0' && c != '\n')
138*7dd7cddfSDavid du Colombier 				;
139*7dd7cddfSDavid du Colombier 			ignore_backslash_newline--;
140*7dd7cddfSDavid du Colombier 		}
141*7dd7cddfSDavid du Colombier 		ungetsc(c);
142*7dd7cddfSDavid du Colombier 	}
143*7dd7cddfSDavid du Colombier 	if (source->flags & SF_ALIAS) {	/* trailing ' ' in alias definition */
144*7dd7cddfSDavid du Colombier 		source->flags &= ~SF_ALIAS;
145*7dd7cddfSDavid du Colombier 		/* In POSIX mode, a trailing space only counts if we are
146*7dd7cddfSDavid du Colombier 		 * parsing a simple command
147*7dd7cddfSDavid du Colombier 		 */
148*7dd7cddfSDavid du Colombier 		if (!Flag(FPOSIX) || (cf & CMDWORD))
149*7dd7cddfSDavid du Colombier 			cf |= ALIAS;
150*7dd7cddfSDavid du Colombier 	}
151*7dd7cddfSDavid du Colombier 
152*7dd7cddfSDavid du Colombier 	/* Initial state: one of SBASE SHEREDELIM SWORD SASPAREN */
153*7dd7cddfSDavid du Colombier 	statep->ls_state = state;
154*7dd7cddfSDavid du Colombier 
155*7dd7cddfSDavid du Colombier 	/* collect non-special or quoted characters to form word */
156*7dd7cddfSDavid du Colombier 	while (!((c = getsc()) == 0
157*7dd7cddfSDavid du Colombier 		 || ((state == SBASE || state == SHEREDELIM)
158*7dd7cddfSDavid du Colombier 		     && ctype(c, C_LEX1))))
159*7dd7cddfSDavid du Colombier 	{
160*7dd7cddfSDavid du Colombier 		Xcheck(ws, wp);
161*7dd7cddfSDavid du Colombier 		switch (state) {
162*7dd7cddfSDavid du Colombier 		  case SBASE:
163*7dd7cddfSDavid du Colombier 			if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
164*7dd7cddfSDavid du Colombier 				*wp = EOS; /* temporary */
165*7dd7cddfSDavid du Colombier 				if (is_wdvarname(Xstring(ws, wp), FALSE))
166*7dd7cddfSDavid du Colombier 				{
167*7dd7cddfSDavid du Colombier 					char *p, *tmp;
168*7dd7cddfSDavid du Colombier 
169*7dd7cddfSDavid du Colombier 					if (arraysub(&tmp)) {
170*7dd7cddfSDavid du Colombier 						*wp++ = CHAR;
171*7dd7cddfSDavid du Colombier 						*wp++ = c;
172*7dd7cddfSDavid du Colombier 						for (p = tmp; *p; ) {
173*7dd7cddfSDavid du Colombier 							Xcheck(ws, wp);
174*7dd7cddfSDavid du Colombier 							*wp++ = CHAR;
175*7dd7cddfSDavid du Colombier 							*wp++ = *p++;
176*7dd7cddfSDavid du Colombier 						}
177*7dd7cddfSDavid du Colombier 						afree(tmp, ATEMP);
178*7dd7cddfSDavid du Colombier 						break;
179*7dd7cddfSDavid du Colombier 					} else {
180*7dd7cddfSDavid du Colombier 						Source *s;
181*7dd7cddfSDavid du Colombier 
182*7dd7cddfSDavid du Colombier 						s = pushs(SREREAD,
183*7dd7cddfSDavid du Colombier 							  source->areap);
184*7dd7cddfSDavid du Colombier 						s->start = s->str
185*7dd7cddfSDavid du Colombier 							= s->u.freeme = tmp;
186*7dd7cddfSDavid du Colombier 						s->next = source;
187*7dd7cddfSDavid du Colombier 						source = s;
188*7dd7cddfSDavid du Colombier 					}
189*7dd7cddfSDavid du Colombier 				}
190*7dd7cddfSDavid du Colombier 				*wp++ = CHAR;
191*7dd7cddfSDavid du Colombier 				*wp++ = c;
192*7dd7cddfSDavid du Colombier 				break;
193*7dd7cddfSDavid du Colombier 			}
194*7dd7cddfSDavid du Colombier 			/* fall through.. */
195*7dd7cddfSDavid du Colombier 		  Sbase1:	/* includes *(...|...) pattern (*+?@!) */
196*7dd7cddfSDavid du Colombier #ifdef KSH
197*7dd7cddfSDavid du Colombier 			if (c == '*' || c == '@' || c == '+' || c == '?'
198*7dd7cddfSDavid du Colombier 			    || c == '!')
199*7dd7cddfSDavid du Colombier 			{
200*7dd7cddfSDavid du Colombier 				c2 = getsc();
201*7dd7cddfSDavid du Colombier 				if (c2 == '(' /*)*/ ) {
202*7dd7cddfSDavid du Colombier 					*wp++ = OPAT;
203*7dd7cddfSDavid du Colombier 					*wp++ = c;
204*7dd7cddfSDavid du Colombier 					PUSH_STATE(SPATTERN);
205*7dd7cddfSDavid du Colombier 					break;
206*7dd7cddfSDavid du Colombier 				}
207*7dd7cddfSDavid du Colombier 				ungetsc(c2);
208*7dd7cddfSDavid du Colombier 			}
209*7dd7cddfSDavid du Colombier #endif /* KSH */
210*7dd7cddfSDavid du Colombier 			/* fall through.. */
211*7dd7cddfSDavid du Colombier 		  Sbase2:	/* doesn't include *(...|...) pattern (*+?@!) */
212*7dd7cddfSDavid du Colombier 			switch (c) {
213*7dd7cddfSDavid du Colombier 			  case '\\':
214*7dd7cddfSDavid du Colombier 				c = getsc();
215*7dd7cddfSDavid du Colombier #ifdef OS2
216*7dd7cddfSDavid du Colombier 				if (isalnum(c)) {
217*7dd7cddfSDavid du Colombier 					*wp++ = CHAR, *wp++ = '\\';
218*7dd7cddfSDavid du Colombier 					*wp++ = CHAR, *wp++ = c;
219*7dd7cddfSDavid du Colombier 				} else
220*7dd7cddfSDavid du Colombier #endif
221*7dd7cddfSDavid du Colombier 				if (c) /* trailing \ is lost */
222*7dd7cddfSDavid du Colombier 					*wp++ = QCHAR, *wp++ = c;
223*7dd7cddfSDavid du Colombier 				break;
224*7dd7cddfSDavid du Colombier 			  case '\'':
225*7dd7cddfSDavid du Colombier 				*wp++ = OQUOTE;
226*7dd7cddfSDavid du Colombier 				ignore_backslash_newline++;
227*7dd7cddfSDavid du Colombier 				PUSH_STATE(SSQUOTE);
228*7dd7cddfSDavid du Colombier 				break;
229*7dd7cddfSDavid du Colombier 			  case '"':
230*7dd7cddfSDavid du Colombier 				*wp++ = OQUOTE;
231*7dd7cddfSDavid du Colombier 				PUSH_STATE(SDQUOTE);
232*7dd7cddfSDavid du Colombier 				break;
233*7dd7cddfSDavid du Colombier 			  default:
234*7dd7cddfSDavid du Colombier 				goto Subst;
235*7dd7cddfSDavid du Colombier 			}
236*7dd7cddfSDavid du Colombier 			break;
237*7dd7cddfSDavid du Colombier 
238*7dd7cddfSDavid du Colombier 		  Subst:
239*7dd7cddfSDavid du Colombier 			switch (c) {
240*7dd7cddfSDavid du Colombier 			  case '\\':
241*7dd7cddfSDavid du Colombier 				c = getsc();
242*7dd7cddfSDavid du Colombier 				switch (c) {
243*7dd7cddfSDavid du Colombier 				  case '"': case '\\':
244*7dd7cddfSDavid du Colombier 				  case '$': case '`':
245*7dd7cddfSDavid du Colombier 					*wp++ = QCHAR, *wp++ = c;
246*7dd7cddfSDavid du Colombier 					break;
247*7dd7cddfSDavid du Colombier 				  default:
248*7dd7cddfSDavid du Colombier 					Xcheck(ws, wp);
249*7dd7cddfSDavid du Colombier 					if (c) { /* trailing \ is lost */
250*7dd7cddfSDavid du Colombier 						*wp++ = CHAR, *wp++ = '\\';
251*7dd7cddfSDavid du Colombier 						*wp++ = CHAR, *wp++ = c;
252*7dd7cddfSDavid du Colombier 					}
253*7dd7cddfSDavid du Colombier 					break;
254*7dd7cddfSDavid du Colombier 				}
255*7dd7cddfSDavid du Colombier 				break;
256*7dd7cddfSDavid du Colombier 			  case '$':
257*7dd7cddfSDavid du Colombier 				c = getsc();
258*7dd7cddfSDavid du Colombier 				if (c == '(') /*)*/ {
259*7dd7cddfSDavid du Colombier 					c = getsc();
260*7dd7cddfSDavid du Colombier 					if (c == '(') /*)*/ {
261*7dd7cddfSDavid du Colombier 						PUSH_STATE(SASPAREN);
262*7dd7cddfSDavid du Colombier 						statep->ls_sasparen.nparen = 2;
263*7dd7cddfSDavid du Colombier 						statep->ls_sasparen.start =
264*7dd7cddfSDavid du Colombier 							Xsavepos(ws, wp);
265*7dd7cddfSDavid du Colombier 						*wp++ = EXPRSUB;
266*7dd7cddfSDavid du Colombier 					} else {
267*7dd7cddfSDavid du Colombier 						ungetsc(c);
268*7dd7cddfSDavid du Colombier 						PUSH_STATE(SCSPAREN);
269*7dd7cddfSDavid du Colombier 						statep->ls_scsparen.nparen = 1;
270*7dd7cddfSDavid du Colombier 						statep->ls_scsparen.csstate = 0;
271*7dd7cddfSDavid du Colombier 						*wp++ = COMSUB;
272*7dd7cddfSDavid du Colombier 					}
273*7dd7cddfSDavid du Colombier 				} else if (c == '{') /*}*/ {
274*7dd7cddfSDavid du Colombier 					*wp++ = OSUBST;
275*7dd7cddfSDavid du Colombier 					*wp++ = '{'; /*}*/
276*7dd7cddfSDavid du Colombier 					wp = get_brace_var(&ws, wp);
277*7dd7cddfSDavid du Colombier 					c = getsc();
278*7dd7cddfSDavid du Colombier 					/* allow :# and :% (ksh88 compat) */
279*7dd7cddfSDavid du Colombier 					if (c == ':') {
280*7dd7cddfSDavid du Colombier 						*wp++ = CHAR, *wp++ = c;
281*7dd7cddfSDavid du Colombier 						c = getsc();
282*7dd7cddfSDavid du Colombier 					}
283*7dd7cddfSDavid du Colombier 					/* If this is a trim operation,
284*7dd7cddfSDavid du Colombier 					 * treat (,|,) specially in STBRACE.
285*7dd7cddfSDavid du Colombier 					 */
286*7dd7cddfSDavid du Colombier 					if (c == '#' || c == '%') {
287*7dd7cddfSDavid du Colombier 						ungetsc(c);
288*7dd7cddfSDavid du Colombier 						PUSH_STATE(STBRACE);
289*7dd7cddfSDavid du Colombier 					} else {
290*7dd7cddfSDavid du Colombier 						ungetsc(c);
291*7dd7cddfSDavid du Colombier 						PUSH_STATE(SBRACE);
292*7dd7cddfSDavid du Colombier 					}
293*7dd7cddfSDavid du Colombier 				} else if (ctype(c, C_ALPHA)) {
294*7dd7cddfSDavid du Colombier 					*wp++ = OSUBST;
295*7dd7cddfSDavid du Colombier 					*wp++ = 'X';
296*7dd7cddfSDavid du Colombier 					do {
297*7dd7cddfSDavid du Colombier 						Xcheck(ws, wp);
298*7dd7cddfSDavid du Colombier 						*wp++ = c;
299*7dd7cddfSDavid du Colombier 						c = getsc();
300*7dd7cddfSDavid du Colombier 					} while (ctype(c, C_ALPHA|C_DIGIT));
301*7dd7cddfSDavid du Colombier 					*wp++ = '\0';
302*7dd7cddfSDavid du Colombier 					*wp++ = CSUBST;
303*7dd7cddfSDavid du Colombier 					*wp++ = 'X';
304*7dd7cddfSDavid du Colombier 					ungetsc(c);
305*7dd7cddfSDavid du Colombier 				} else if (ctype(c, C_DIGIT|C_VAR1)) {
306*7dd7cddfSDavid du Colombier 					Xcheck(ws, wp);
307*7dd7cddfSDavid du Colombier 					*wp++ = OSUBST;
308*7dd7cddfSDavid du Colombier 					*wp++ = 'X';
309*7dd7cddfSDavid du Colombier 					*wp++ = c;
310*7dd7cddfSDavid du Colombier 					*wp++ = '\0';
311*7dd7cddfSDavid du Colombier 					*wp++ = CSUBST;
312*7dd7cddfSDavid du Colombier 					*wp++ = 'X';
313*7dd7cddfSDavid du Colombier 				} else {
314*7dd7cddfSDavid du Colombier 					*wp++ = CHAR, *wp++ = '$';
315*7dd7cddfSDavid du Colombier 					ungetsc(c);
316*7dd7cddfSDavid du Colombier 				}
317*7dd7cddfSDavid du Colombier 				break;
318*7dd7cddfSDavid du Colombier 			  case '`':
319*7dd7cddfSDavid du Colombier 				PUSH_STATE(SBQUOTE);
320*7dd7cddfSDavid du Colombier 				*wp++ = COMSUB;
321*7dd7cddfSDavid du Colombier 				/* Need to know if we are inside double quotes
322*7dd7cddfSDavid du Colombier 				 * since sh/at&t-ksh translate the \" to " in
323*7dd7cddfSDavid du Colombier 				 * "`..\"..`".
324*7dd7cddfSDavid du Colombier 				 * This is not done in posix mode (section
325*7dd7cddfSDavid du Colombier 				 * 3.2.3, Double Quotes: "The backquote shall
326*7dd7cddfSDavid du Colombier 				 * retain its special meaning introducing the
327*7dd7cddfSDavid du Colombier 				 * other form of command substitution (see
328*7dd7cddfSDavid du Colombier 				 * 3.6.3). The portion of the quoted string
329*7dd7cddfSDavid du Colombier 				 * from the initial backquote and the
330*7dd7cddfSDavid du Colombier 				 * characters up to the next backquote that
331*7dd7cddfSDavid du Colombier 				 * is not preceded by a backslash (having
332*7dd7cddfSDavid du Colombier 				 * escape characters removed) defines that
333*7dd7cddfSDavid du Colombier 				 * command whose output replaces `...` when
334*7dd7cddfSDavid du Colombier 				 * the word is expanded."
335*7dd7cddfSDavid du Colombier 				 * Section 3.6.3, Command Substitution:
336*7dd7cddfSDavid du Colombier 				 * "Within the backquoted style of command
337*7dd7cddfSDavid du Colombier 				 * substitution, backslash shall retain its
338*7dd7cddfSDavid du Colombier 				 * literal meaning, except when followed by
339*7dd7cddfSDavid du Colombier 				 * $ ` \.").
340*7dd7cddfSDavid du Colombier 				 */
341*7dd7cddfSDavid du Colombier 				statep->ls_sbquote.indquotes = 0;
342*7dd7cddfSDavid du Colombier 				if (!Flag(FPOSIX)) {
343*7dd7cddfSDavid du Colombier 					Lex_state *s = statep;
344*7dd7cddfSDavid du Colombier 					Lex_state *base = state_info.base;
345*7dd7cddfSDavid du Colombier 					while (1) {
346*7dd7cddfSDavid du Colombier 						for (; s != base; s--) {
347*7dd7cddfSDavid du Colombier 							if (s->ls_state == SDQUOTE) {
348*7dd7cddfSDavid du Colombier 								statep->ls_sbquote.indquotes = 1;
349*7dd7cddfSDavid du Colombier 								break;
350*7dd7cddfSDavid du Colombier 							}
351*7dd7cddfSDavid du Colombier 						}
352*7dd7cddfSDavid du Colombier 						if (s != base)
353*7dd7cddfSDavid du Colombier 							break;
354*7dd7cddfSDavid du Colombier 						if (!(s = s->ls_info.base))
355*7dd7cddfSDavid du Colombier 							break;
356*7dd7cddfSDavid du Colombier 						base = s-- - STATE_BSIZE;
357*7dd7cddfSDavid du Colombier 					}
358*7dd7cddfSDavid du Colombier 				}
359*7dd7cddfSDavid du Colombier 				break;
360*7dd7cddfSDavid du Colombier 			  default:
361*7dd7cddfSDavid du Colombier 				*wp++ = CHAR, *wp++ = c;
362*7dd7cddfSDavid du Colombier 			}
363*7dd7cddfSDavid du Colombier 			break;
364*7dd7cddfSDavid du Colombier 
365*7dd7cddfSDavid du Colombier 		  case SSQUOTE:
366*7dd7cddfSDavid du Colombier 			if (c == '\'') {
367*7dd7cddfSDavid du Colombier 				POP_STATE();
368*7dd7cddfSDavid du Colombier 				*wp++ = CQUOTE;
369*7dd7cddfSDavid du Colombier 				ignore_backslash_newline--;
370*7dd7cddfSDavid du Colombier 			} else
371*7dd7cddfSDavid du Colombier 				*wp++ = QCHAR, *wp++ = c;
372*7dd7cddfSDavid du Colombier 			break;
373*7dd7cddfSDavid du Colombier 
374*7dd7cddfSDavid du Colombier 		  case SDQUOTE:
375*7dd7cddfSDavid du Colombier 			if (c == '"') {
376*7dd7cddfSDavid du Colombier 				POP_STATE();
377*7dd7cddfSDavid du Colombier 				*wp++ = CQUOTE;
378*7dd7cddfSDavid du Colombier 			} else
379*7dd7cddfSDavid du Colombier 				goto Subst;
380*7dd7cddfSDavid du Colombier 			break;
381*7dd7cddfSDavid du Colombier 
382*7dd7cddfSDavid du Colombier 		  case SCSPAREN: /* $( .. ) */
383*7dd7cddfSDavid du Colombier 			/* todo: deal with $(...) quoting properly
384*7dd7cddfSDavid du Colombier 			 * kludge to partly fake quoting inside $(..): doesn't
385*7dd7cddfSDavid du Colombier 			 * really work because nested $(..) or ${..} inside
386*7dd7cddfSDavid du Colombier 			 * double quotes aren't dealt with.
387*7dd7cddfSDavid du Colombier 			 */
388*7dd7cddfSDavid du Colombier 			switch (statep->ls_scsparen.csstate) {
389*7dd7cddfSDavid du Colombier 			  case 0: /* normal */
390*7dd7cddfSDavid du Colombier 				switch (c) {
391*7dd7cddfSDavid du Colombier 				  case '(':
392*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.nparen++;
393*7dd7cddfSDavid du Colombier 					break;
394*7dd7cddfSDavid du Colombier 				  case ')':
395*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.nparen--;
396*7dd7cddfSDavid du Colombier 					break;
397*7dd7cddfSDavid du Colombier 				  case '\\':
398*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.csstate = 1;
399*7dd7cddfSDavid du Colombier 					break;
400*7dd7cddfSDavid du Colombier 				  case '"':
401*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.csstate = 2;
402*7dd7cddfSDavid du Colombier 					break;
403*7dd7cddfSDavid du Colombier 				  case '\'':
404*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.csstate = 4;
405*7dd7cddfSDavid du Colombier 					ignore_backslash_newline++;
406*7dd7cddfSDavid du Colombier 					break;
407*7dd7cddfSDavid du Colombier 				}
408*7dd7cddfSDavid du Colombier 				break;
409*7dd7cddfSDavid du Colombier 
410*7dd7cddfSDavid du Colombier 			  case 1: /* backslash in normal mode */
411*7dd7cddfSDavid du Colombier 			  case 3: /* backslash in double quotes */
412*7dd7cddfSDavid du Colombier 				--statep->ls_scsparen.csstate;
413*7dd7cddfSDavid du Colombier 				break;
414*7dd7cddfSDavid du Colombier 
415*7dd7cddfSDavid du Colombier 			  case 2: /* double quotes */
416*7dd7cddfSDavid du Colombier 				if (c == '"')
417*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.csstate = 0;
418*7dd7cddfSDavid du Colombier 				else if (c == '\\')
419*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.csstate = 3;
420*7dd7cddfSDavid du Colombier 				break;
421*7dd7cddfSDavid du Colombier 
422*7dd7cddfSDavid du Colombier 			  case 4: /* single quotes */
423*7dd7cddfSDavid du Colombier 				if (c == '\'') {
424*7dd7cddfSDavid du Colombier 					statep->ls_scsparen.csstate = 0;
425*7dd7cddfSDavid du Colombier 					ignore_backslash_newline--;
426*7dd7cddfSDavid du Colombier 				}
427*7dd7cddfSDavid du Colombier 				break;
428*7dd7cddfSDavid du Colombier 			}
429*7dd7cddfSDavid du Colombier 			if (statep->ls_scsparen.nparen == 0) {
430*7dd7cddfSDavid du Colombier 				POP_STATE();
431*7dd7cddfSDavid du Colombier 				*wp++ = 0; /* end of COMSUB */
432*7dd7cddfSDavid du Colombier 			} else
433*7dd7cddfSDavid du Colombier 				*wp++ = c;
434*7dd7cddfSDavid du Colombier 			break;
435*7dd7cddfSDavid du Colombier 
436*7dd7cddfSDavid du Colombier 		  case SASPAREN: /* $(( .. )) */
437*7dd7cddfSDavid du Colombier 			/* todo: deal with $((...); (...)) properly */
438*7dd7cddfSDavid du Colombier 			/* XXX should nest using existing state machine
439*7dd7cddfSDavid du Colombier 			 *     (embed "..", $(...), etc.) */
440*7dd7cddfSDavid du Colombier 			if (c == '(')
441*7dd7cddfSDavid du Colombier 				statep->ls_sasparen.nparen++;
442*7dd7cddfSDavid du Colombier 			else if (c == ')') {
443*7dd7cddfSDavid du Colombier 				statep->ls_sasparen.nparen--;
444*7dd7cddfSDavid du Colombier 				if (statep->ls_sasparen.nparen == 1) {
445*7dd7cddfSDavid du Colombier 					/*(*/
446*7dd7cddfSDavid du Colombier 					if ((c2 = getsc()) == ')') {
447*7dd7cddfSDavid du Colombier 						POP_STATE();
448*7dd7cddfSDavid du Colombier 						*wp++ = 0; /* end of EXPRSUB */
449*7dd7cddfSDavid du Colombier 						break;
450*7dd7cddfSDavid du Colombier 					} else {
451*7dd7cddfSDavid du Colombier 						char *s;
452*7dd7cddfSDavid du Colombier 
453*7dd7cddfSDavid du Colombier 						ungetsc(c2);
454*7dd7cddfSDavid du Colombier 						/* mismatched parenthesis -
455*7dd7cddfSDavid du Colombier 						 * assume we were really
456*7dd7cddfSDavid du Colombier 						 * parsing a $(..) expression
457*7dd7cddfSDavid du Colombier 						 */
458*7dd7cddfSDavid du Colombier 						s = Xrestpos(ws, wp,
459*7dd7cddfSDavid du Colombier 						     statep->ls_sasparen.start);
460*7dd7cddfSDavid du Colombier 						memmove(s + 1, s, wp - s);
461*7dd7cddfSDavid du Colombier 						*s++ = COMSUB;
462*7dd7cddfSDavid du Colombier 						*s = '('; /*)*/
463*7dd7cddfSDavid du Colombier 						wp++;
464*7dd7cddfSDavid du Colombier 						statep->ls_scsparen.nparen = 1;
465*7dd7cddfSDavid du Colombier 						statep->ls_scsparen.csstate = 0;
466*7dd7cddfSDavid du Colombier 						state = statep->ls_state
467*7dd7cddfSDavid du Colombier 							= SCSPAREN;
468*7dd7cddfSDavid du Colombier 
469*7dd7cddfSDavid du Colombier 					}
470*7dd7cddfSDavid du Colombier 				}
471*7dd7cddfSDavid du Colombier 			}
472*7dd7cddfSDavid du Colombier 			*wp++ = c;
473*7dd7cddfSDavid du Colombier 			break;
474*7dd7cddfSDavid du Colombier 
475*7dd7cddfSDavid du Colombier 		  case SBRACE:
476*7dd7cddfSDavid du Colombier 			/*{*/
477*7dd7cddfSDavid du Colombier 			if (c == '}') {
478*7dd7cddfSDavid du Colombier 				POP_STATE();
479*7dd7cddfSDavid du Colombier 				*wp++ = CSUBST;
480*7dd7cddfSDavid du Colombier 				*wp++ = /*{*/ '}';
481*7dd7cddfSDavid du Colombier 			} else
482*7dd7cddfSDavid du Colombier 				goto Sbase1;
483*7dd7cddfSDavid du Colombier 			break;
484*7dd7cddfSDavid du Colombier 
485*7dd7cddfSDavid du Colombier 		  case STBRACE:
486*7dd7cddfSDavid du Colombier 			/* Same as SBRACE, except (,|,) treated specially */
487*7dd7cddfSDavid du Colombier 			/*{*/
488*7dd7cddfSDavid du Colombier 			if (c == '}') {
489*7dd7cddfSDavid du Colombier 				POP_STATE();
490*7dd7cddfSDavid du Colombier 				*wp++ = CSUBST;
491*7dd7cddfSDavid du Colombier 				*wp++ = /*{*/ '}';
492*7dd7cddfSDavid du Colombier 			} else if (c == '|') {
493*7dd7cddfSDavid du Colombier 				*wp++ = SPAT;
494*7dd7cddfSDavid du Colombier 			} else if (c == '(') {
495*7dd7cddfSDavid du Colombier 				*wp++ = OPAT;
496*7dd7cddfSDavid du Colombier 				*wp++ = ' ';	/* simile for @ */
497*7dd7cddfSDavid du Colombier 				PUSH_STATE(SPATTERN);
498*7dd7cddfSDavid du Colombier 			} else
499*7dd7cddfSDavid du Colombier 				goto Sbase1;
500*7dd7cddfSDavid du Colombier 			break;
501*7dd7cddfSDavid du Colombier 
502*7dd7cddfSDavid du Colombier 		  case SBQUOTE:
503*7dd7cddfSDavid du Colombier 			if (c == '`') {
504*7dd7cddfSDavid du Colombier 				*wp++ = 0;
505*7dd7cddfSDavid du Colombier 				POP_STATE();
506*7dd7cddfSDavid du Colombier 			} else if (c == '\\') {
507*7dd7cddfSDavid du Colombier 				switch (c = getsc()) {
508*7dd7cddfSDavid du Colombier 				  case '\\':
509*7dd7cddfSDavid du Colombier 				  case '$': case '`':
510*7dd7cddfSDavid du Colombier 					*wp++ = c;
511*7dd7cddfSDavid du Colombier 					break;
512*7dd7cddfSDavid du Colombier 				  case '"':
513*7dd7cddfSDavid du Colombier 					if (statep->ls_sbquote.indquotes) {
514*7dd7cddfSDavid du Colombier 						*wp++ = c;
515*7dd7cddfSDavid du Colombier 						break;
516*7dd7cddfSDavid du Colombier 					}
517*7dd7cddfSDavid du Colombier 					/* fall through.. */
518*7dd7cddfSDavid du Colombier 				  default:
519*7dd7cddfSDavid du Colombier 					if (c) { /* trailing \ is lost */
520*7dd7cddfSDavid du Colombier 						*wp++ = '\\';
521*7dd7cddfSDavid du Colombier 						*wp++ = c;
522*7dd7cddfSDavid du Colombier 					}
523*7dd7cddfSDavid du Colombier 					break;
524*7dd7cddfSDavid du Colombier 				}
525*7dd7cddfSDavid du Colombier 			} else
526*7dd7cddfSDavid du Colombier 				*wp++ = c;
527*7dd7cddfSDavid du Colombier 			break;
528*7dd7cddfSDavid du Colombier 
529*7dd7cddfSDavid du Colombier 		  case SWORD:	/* ONEWORD */
530*7dd7cddfSDavid du Colombier 			goto Subst;
531*7dd7cddfSDavid du Colombier 
532*7dd7cddfSDavid du Colombier #ifdef KSH
533*7dd7cddfSDavid du Colombier 		  case SLETPAREN:	/* LETEXPR: (( ... )) */
534*7dd7cddfSDavid du Colombier 			/*(*/
535*7dd7cddfSDavid du Colombier 			if (c == ')') {
536*7dd7cddfSDavid du Colombier 				if (statep->ls_sletparen.nparen > 0)
537*7dd7cddfSDavid du Colombier 				    --statep->ls_sletparen.nparen;
538*7dd7cddfSDavid du Colombier 				/*(*/
539*7dd7cddfSDavid du Colombier 				else if ((c2 = getsc()) == ')') {
540*7dd7cddfSDavid du Colombier 					c = 0;
541*7dd7cddfSDavid du Colombier 					*wp++ = CQUOTE;
542*7dd7cddfSDavid du Colombier 					goto Done;
543*7dd7cddfSDavid du Colombier 				} else
544*7dd7cddfSDavid du Colombier 					ungetsc(c2);
545*7dd7cddfSDavid du Colombier 			} else if (c == '(')
546*7dd7cddfSDavid du Colombier 				/* parenthesis inside quotes and backslashes
547*7dd7cddfSDavid du Colombier 				 * are lost, but at&t ksh doesn't count them
548*7dd7cddfSDavid du Colombier 				 * either
549*7dd7cddfSDavid du Colombier 				 */
550*7dd7cddfSDavid du Colombier 				++statep->ls_sletparen.nparen;
551*7dd7cddfSDavid du Colombier 			goto Sbase2;
552*7dd7cddfSDavid du Colombier #endif /* KSH */
553*7dd7cddfSDavid du Colombier 
554*7dd7cddfSDavid du Colombier 		  case SHEREDELIM:	/* <<,<<- delimiter */
555*7dd7cddfSDavid du Colombier 			/* XXX chuck this state (and the next) - use
556*7dd7cddfSDavid du Colombier 			 * the existing states ($ and \`..` should be
557*7dd7cddfSDavid du Colombier 			 * stripped of their specialness after the
558*7dd7cddfSDavid du Colombier 			 * fact).
559*7dd7cddfSDavid du Colombier 			 */
560*7dd7cddfSDavid du Colombier 			/* here delimiters need a special case since
561*7dd7cddfSDavid du Colombier 			 * $ and `..` are not to be treated specially
562*7dd7cddfSDavid du Colombier 			 */
563*7dd7cddfSDavid du Colombier 			if (c == '\\') {
564*7dd7cddfSDavid du Colombier 				c = getsc();
565*7dd7cddfSDavid du Colombier 				if (c) { /* trailing \ is lost */
566*7dd7cddfSDavid du Colombier 					*wp++ = QCHAR;
567*7dd7cddfSDavid du Colombier 					*wp++ = c;
568*7dd7cddfSDavid du Colombier 				}
569*7dd7cddfSDavid du Colombier 			} else if (c == '\'') {
570*7dd7cddfSDavid du Colombier 				PUSH_STATE(SSQUOTE);
571*7dd7cddfSDavid du Colombier 				*wp++ = OQUOTE;
572*7dd7cddfSDavid du Colombier 				ignore_backslash_newline++;
573*7dd7cddfSDavid du Colombier 			} else if (c == '"') {
574*7dd7cddfSDavid du Colombier 				state = statep->ls_state = SHEREDQUOTE;
575*7dd7cddfSDavid du Colombier 				*wp++ = OQUOTE;
576*7dd7cddfSDavid du Colombier 			} else {
577*7dd7cddfSDavid du Colombier 				*wp++ = CHAR;
578*7dd7cddfSDavid du Colombier 				*wp++ = c;
579*7dd7cddfSDavid du Colombier 			}
580*7dd7cddfSDavid du Colombier 			break;
581*7dd7cddfSDavid du Colombier 
582*7dd7cddfSDavid du Colombier 		  case SHEREDQUOTE:	/* " in <<,<<- delimiter */
583*7dd7cddfSDavid du Colombier 			if (c == '"') {
584*7dd7cddfSDavid du Colombier 				*wp++ = CQUOTE;
585*7dd7cddfSDavid du Colombier 				state = statep->ls_state = SHEREDELIM;
586*7dd7cddfSDavid du Colombier 			} else {
587*7dd7cddfSDavid du Colombier 				if (c == '\\') {
588*7dd7cddfSDavid du Colombier 					switch (c = getsc()) {
589*7dd7cddfSDavid du Colombier 					  case '\\': case '"':
590*7dd7cddfSDavid du Colombier 					  case '$': case '`':
591*7dd7cddfSDavid du Colombier 						break;
592*7dd7cddfSDavid du Colombier 					  default:
593*7dd7cddfSDavid du Colombier 						if (c) { /* trailing \ lost */
594*7dd7cddfSDavid du Colombier 							*wp++ = CHAR;
595*7dd7cddfSDavid du Colombier 							*wp++ = '\\';
596*7dd7cddfSDavid du Colombier 						}
597*7dd7cddfSDavid du Colombier 						break;
598*7dd7cddfSDavid du Colombier 					}
599*7dd7cddfSDavid du Colombier 				}
600*7dd7cddfSDavid du Colombier 				*wp++ = CHAR;
601*7dd7cddfSDavid du Colombier 				*wp++ = c;
602*7dd7cddfSDavid du Colombier 			}
603*7dd7cddfSDavid du Colombier 			break;
604*7dd7cddfSDavid du Colombier 
605*7dd7cddfSDavid du Colombier 		  case SPATTERN:	/* in *(...|...) pattern (*+?@!) */
606*7dd7cddfSDavid du Colombier 			if ( /*(*/ c == ')') {
607*7dd7cddfSDavid du Colombier 				*wp++ = CPAT;
608*7dd7cddfSDavid du Colombier 				POP_STATE();
609*7dd7cddfSDavid du Colombier 			} else if (c == '|') {
610*7dd7cddfSDavid du Colombier 				*wp++ = SPAT;
611*7dd7cddfSDavid du Colombier 			} else if (c == '(') {
612*7dd7cddfSDavid du Colombier 				*wp++ = OPAT;
613*7dd7cddfSDavid du Colombier 				*wp++ = ' ';	/* simile for @ */
614*7dd7cddfSDavid du Colombier 				PUSH_STATE(SPATTERN);
615*7dd7cddfSDavid du Colombier 			} else
616*7dd7cddfSDavid du Colombier 				goto Sbase1;
617*7dd7cddfSDavid du Colombier 			break;
618*7dd7cddfSDavid du Colombier 		}
619*7dd7cddfSDavid du Colombier 	}
620*7dd7cddfSDavid du Colombier Done:
621*7dd7cddfSDavid du Colombier 	Xcheck(ws, wp);
622*7dd7cddfSDavid du Colombier 	if (statep != &states[1])
623*7dd7cddfSDavid du Colombier 		/* XXX figure out what is missing */
624*7dd7cddfSDavid du Colombier 		yyerror("no closing quote\n");
625*7dd7cddfSDavid du Colombier 
626*7dd7cddfSDavid du Colombier 	/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
627*7dd7cddfSDavid du Colombier 	if (state == SHEREDELIM)
628*7dd7cddfSDavid du Colombier 		state = SBASE;
629*7dd7cddfSDavid du Colombier 
630*7dd7cddfSDavid du Colombier 	dp = Xstring(ws, wp);
631*7dd7cddfSDavid du Colombier 	if ((c == '<' || c == '>') && state == SBASE
632*7dd7cddfSDavid du Colombier 	    && ((c2 = Xlength(ws, wp)) == 0
633*7dd7cddfSDavid du Colombier 	        || (c2 == 2 && dp[0] == CHAR && digit(dp[1]))))
634*7dd7cddfSDavid du Colombier 	{
635*7dd7cddfSDavid du Colombier 		struct ioword *iop =
636*7dd7cddfSDavid du Colombier 				(struct ioword *) alloc(sizeof(*iop), ATEMP);
637*7dd7cddfSDavid du Colombier 
638*7dd7cddfSDavid du Colombier 		if (c2 == 2)
639*7dd7cddfSDavid du Colombier 			iop->unit = dp[1] - '0';
640*7dd7cddfSDavid du Colombier 		else
641*7dd7cddfSDavid du Colombier 			iop->unit = c == '>'; /* 0 for <, 1 for > */
642*7dd7cddfSDavid du Colombier 
643*7dd7cddfSDavid du Colombier 		c2 = getsc();
644*7dd7cddfSDavid du Colombier 		/* <<, >>, <> are ok, >< is not */
645*7dd7cddfSDavid du Colombier 		if (c == c2 || (c == '<' && c2 == '>')) {
646*7dd7cddfSDavid du Colombier 			iop->flag = c == c2 ?
647*7dd7cddfSDavid du Colombier 				  (c == '>' ? IOCAT : IOHERE) : IORDWR;
648*7dd7cddfSDavid du Colombier 			if (iop->flag == IOHERE)
649*7dd7cddfSDavid du Colombier 				if ((c2 = getsc()) == '-')
650*7dd7cddfSDavid du Colombier 					iop->flag |= IOSKIP;
651*7dd7cddfSDavid du Colombier 				else
652*7dd7cddfSDavid du Colombier 					ungetsc(c2);
653*7dd7cddfSDavid du Colombier 		} else if (c2 == '&')
654*7dd7cddfSDavid du Colombier 			iop->flag = IODUP | (c == '<' ? IORDUP : 0);
655*7dd7cddfSDavid du Colombier 		else {
656*7dd7cddfSDavid du Colombier 			iop->flag = c == '>' ? IOWRITE : IOREAD;
657*7dd7cddfSDavid du Colombier 			if (c == '>' && c2 == '|')
658*7dd7cddfSDavid du Colombier 				iop->flag |= IOCLOB;
659*7dd7cddfSDavid du Colombier 			else
660*7dd7cddfSDavid du Colombier 				ungetsc(c2);
661*7dd7cddfSDavid du Colombier 		}
662*7dd7cddfSDavid du Colombier 
663*7dd7cddfSDavid du Colombier 		iop->name = (char *) 0;
664*7dd7cddfSDavid du Colombier 		iop->delim = (char *) 0;
665*7dd7cddfSDavid du Colombier 		iop->heredoc = (char *) 0;
666*7dd7cddfSDavid du Colombier 		Xfree(ws, wp);	/* free word */
667*7dd7cddfSDavid du Colombier 		yylval.iop = iop;
668*7dd7cddfSDavid du Colombier 		return REDIR;
669*7dd7cddfSDavid du Colombier 	}
670*7dd7cddfSDavid du Colombier 
671*7dd7cddfSDavid du Colombier 	if (wp == dp && state == SBASE) {
672*7dd7cddfSDavid du Colombier 		Xfree(ws, wp);	/* free word */
673*7dd7cddfSDavid du Colombier 		/* no word, process LEX1 character */
674*7dd7cddfSDavid du Colombier 		switch (c) {
675*7dd7cddfSDavid du Colombier 		  default:
676*7dd7cddfSDavid du Colombier 			return c;
677*7dd7cddfSDavid du Colombier 
678*7dd7cddfSDavid du Colombier 		  case '|':
679*7dd7cddfSDavid du Colombier 		  case '&':
680*7dd7cddfSDavid du Colombier 		  case ';':
681*7dd7cddfSDavid du Colombier 			if ((c2 = getsc()) == c)
682*7dd7cddfSDavid du Colombier 				c = (c == ';') ? BREAK :
683*7dd7cddfSDavid du Colombier 				    (c == '|') ? LOGOR :
684*7dd7cddfSDavid du Colombier 				    (c == '&') ? LOGAND :
685*7dd7cddfSDavid du Colombier 				    YYERRCODE;
686*7dd7cddfSDavid du Colombier #ifdef KSH
687*7dd7cddfSDavid du Colombier 			else if (c == '|' && c2 == '&')
688*7dd7cddfSDavid du Colombier 				c = COPROC;
689*7dd7cddfSDavid du Colombier #endif /* KSH */
690*7dd7cddfSDavid du Colombier 			else
691*7dd7cddfSDavid du Colombier 				ungetsc(c2);
692*7dd7cddfSDavid du Colombier 			return c;
693*7dd7cddfSDavid du Colombier 
694*7dd7cddfSDavid du Colombier 		  case '\n':
695*7dd7cddfSDavid du Colombier 			gethere();
696*7dd7cddfSDavid du Colombier 			if (cf & CONTIN)
697*7dd7cddfSDavid du Colombier 				goto Again;
698*7dd7cddfSDavid du Colombier 			return c;
699*7dd7cddfSDavid du Colombier 
700*7dd7cddfSDavid du Colombier 		  case '(':  /*)*/
701*7dd7cddfSDavid du Colombier #ifdef KSH
702*7dd7cddfSDavid du Colombier 			if ((c2 = getsc()) == '(') /*)*/
703*7dd7cddfSDavid du Colombier 				/* XXX need to handle ((...); (...)) */
704*7dd7cddfSDavid du Colombier 				c = MDPAREN;
705*7dd7cddfSDavid du Colombier 			else
706*7dd7cddfSDavid du Colombier 				ungetsc(c2);
707*7dd7cddfSDavid du Colombier #endif /* KSH */
708*7dd7cddfSDavid du Colombier 			return c;
709*7dd7cddfSDavid du Colombier 		  /*(*/
710*7dd7cddfSDavid du Colombier 		  case ')':
711*7dd7cddfSDavid du Colombier 			return c;
712*7dd7cddfSDavid du Colombier 		}
713*7dd7cddfSDavid du Colombier 	}
714*7dd7cddfSDavid du Colombier 
715*7dd7cddfSDavid du Colombier 	*wp++ = EOS;		/* terminate word */
716*7dd7cddfSDavid du Colombier 	yylval.cp = Xclose(ws, wp);
717*7dd7cddfSDavid du Colombier 	if (state == SWORD
718*7dd7cddfSDavid du Colombier #ifdef KSH
719*7dd7cddfSDavid du Colombier 		|| state == SLETPAREN
720*7dd7cddfSDavid du Colombier #endif /* KSH */
721*7dd7cddfSDavid du Colombier 		)	/* ONEWORD? */
722*7dd7cddfSDavid du Colombier 		return LWORD;
723*7dd7cddfSDavid du Colombier 	ungetsc(c);		/* unget terminator */
724*7dd7cddfSDavid du Colombier 
725*7dd7cddfSDavid du Colombier 	/* copy word to unprefixed string ident */
726*7dd7cddfSDavid du Colombier 	for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
727*7dd7cddfSDavid du Colombier 		*dp++ = *sp++;
728*7dd7cddfSDavid du Colombier 	/* Make sure the ident array stays '\0' paded */
729*7dd7cddfSDavid du Colombier 	memset(dp, 0, (ident+IDENT) - dp + 1);
730*7dd7cddfSDavid du Colombier 	if (c != EOS)
731*7dd7cddfSDavid du Colombier 		*ident = '\0';	/* word is not unquoted */
732*7dd7cddfSDavid du Colombier 
733*7dd7cddfSDavid du Colombier 	if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) {
734*7dd7cddfSDavid du Colombier 		struct tbl *p;
735*7dd7cddfSDavid du Colombier 		int h = hash(ident);
736*7dd7cddfSDavid du Colombier 
737*7dd7cddfSDavid du Colombier 		/* { */
738*7dd7cddfSDavid du Colombier 		if ((cf & KEYWORD) && (p = tsearch(&keywords, ident, h))
739*7dd7cddfSDavid du Colombier 		    && (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}'))
740*7dd7cddfSDavid du Colombier 		{
741*7dd7cddfSDavid du Colombier 			afree(yylval.cp, ATEMP);
742*7dd7cddfSDavid du Colombier 			return p->val.i;
743*7dd7cddfSDavid du Colombier 		}
744*7dd7cddfSDavid du Colombier 		if ((cf & ALIAS) && (p = tsearch(&aliases, ident, h))
745*7dd7cddfSDavid du Colombier 		    && (p->flag & ISSET))
746*7dd7cddfSDavid du Colombier 		{
747*7dd7cddfSDavid du Colombier 			register Source *s;
748*7dd7cddfSDavid du Colombier 
749*7dd7cddfSDavid du Colombier 			for (s = source; s->type == SALIAS; s = s->next)
750*7dd7cddfSDavid du Colombier 				if (s->u.tblp == p)
751*7dd7cddfSDavid du Colombier 					return LWORD;
752*7dd7cddfSDavid du Colombier 			/* push alias expansion */
753*7dd7cddfSDavid du Colombier 			s = pushs(SALIAS, source->areap);
754*7dd7cddfSDavid du Colombier 			s->start = s->str = p->val.s;
755*7dd7cddfSDavid du Colombier 			s->u.tblp = p;
756*7dd7cddfSDavid du Colombier 			s->next = source;
757*7dd7cddfSDavid du Colombier 			source = s;
758*7dd7cddfSDavid du Colombier 			afree(yylval.cp, ATEMP);
759*7dd7cddfSDavid du Colombier 			goto Again;
760*7dd7cddfSDavid du Colombier 		}
761*7dd7cddfSDavid du Colombier 	}
762*7dd7cddfSDavid du Colombier 
763*7dd7cddfSDavid du Colombier 	return LWORD;
764*7dd7cddfSDavid du Colombier }
765*7dd7cddfSDavid du Colombier 
766*7dd7cddfSDavid du Colombier static void
gethere()767*7dd7cddfSDavid du Colombier gethere()
768*7dd7cddfSDavid du Colombier {
769*7dd7cddfSDavid du Colombier 	register struct ioword **p;
770*7dd7cddfSDavid du Colombier 
771*7dd7cddfSDavid du Colombier 	for (p = heres; p < herep; p++)
772*7dd7cddfSDavid du Colombier 		readhere(*p);
773*7dd7cddfSDavid du Colombier 	herep = heres;
774*7dd7cddfSDavid du Colombier }
775*7dd7cddfSDavid du Colombier 
776*7dd7cddfSDavid du Colombier /*
777*7dd7cddfSDavid du Colombier  * read "<<word" text into temp file
778*7dd7cddfSDavid du Colombier  */
779*7dd7cddfSDavid du Colombier 
780*7dd7cddfSDavid du Colombier static void
readhere(iop)781*7dd7cddfSDavid du Colombier readhere(iop)
782*7dd7cddfSDavid du Colombier 	struct ioword *iop;
783*7dd7cddfSDavid du Colombier {
784*7dd7cddfSDavid du Colombier 	register int c;
785*7dd7cddfSDavid du Colombier 	char *volatile eof;
786*7dd7cddfSDavid du Colombier 	char *eofp;
787*7dd7cddfSDavid du Colombier 	int skiptabs;
788*7dd7cddfSDavid du Colombier 	XString xs;
789*7dd7cddfSDavid du Colombier 	char *xp;
790*7dd7cddfSDavid du Colombier 	int xpos;
791*7dd7cddfSDavid du Colombier 
792*7dd7cddfSDavid du Colombier 	eof = evalstr(iop->delim, 0);
793*7dd7cddfSDavid du Colombier 
794*7dd7cddfSDavid du Colombier 	if (!(iop->flag & IOEVAL))
795*7dd7cddfSDavid du Colombier 		ignore_backslash_newline++;
796*7dd7cddfSDavid du Colombier 
797*7dd7cddfSDavid du Colombier 	Xinit(xs, xp, 256, ATEMP);
798*7dd7cddfSDavid du Colombier 
799*7dd7cddfSDavid du Colombier 	for (;;) {
800*7dd7cddfSDavid du Colombier 		eofp = eof;
801*7dd7cddfSDavid du Colombier 		skiptabs = iop->flag & IOSKIP;
802*7dd7cddfSDavid du Colombier 		xpos = Xsavepos(xs, xp);
803*7dd7cddfSDavid du Colombier 		while ((c = getsc()) != 0) {
804*7dd7cddfSDavid du Colombier 			if (skiptabs) {
805*7dd7cddfSDavid du Colombier 				if (c == '\t')
806*7dd7cddfSDavid du Colombier 					continue;
807*7dd7cddfSDavid du Colombier 				skiptabs = 0;
808*7dd7cddfSDavid du Colombier 			}
809*7dd7cddfSDavid du Colombier 			if (c != *eofp)
810*7dd7cddfSDavid du Colombier 				break;
811*7dd7cddfSDavid du Colombier 			Xcheck(xs, xp);
812*7dd7cddfSDavid du Colombier 			Xput(xs, xp, c);
813*7dd7cddfSDavid du Colombier 			eofp++;
814*7dd7cddfSDavid du Colombier 		}
815*7dd7cddfSDavid du Colombier 		/* Allow EOF here so commands with out trailing newlines
816*7dd7cddfSDavid du Colombier 		 * will work (eg, ksh -c '...', $(...), etc).
817*7dd7cddfSDavid du Colombier 		 */
818*7dd7cddfSDavid du Colombier 		if (*eofp == '\0' && (c == 0 || c == '\n')) {
819*7dd7cddfSDavid du Colombier 			xp = Xrestpos(xs, xp, xpos);
820*7dd7cddfSDavid du Colombier 			break;
821*7dd7cddfSDavid du Colombier 		}
822*7dd7cddfSDavid du Colombier 		ungetsc(c);
823*7dd7cddfSDavid du Colombier 		while ((c = getsc()) != '\n') {
824*7dd7cddfSDavid du Colombier 			if (c == 0)
825*7dd7cddfSDavid du Colombier 				yyerror("here document `%s' unclosed\n", eof);
826*7dd7cddfSDavid du Colombier 			Xcheck(xs, xp);
827*7dd7cddfSDavid du Colombier 			Xput(xs, xp, c);
828*7dd7cddfSDavid du Colombier 		}
829*7dd7cddfSDavid du Colombier 		Xcheck(xs, xp);
830*7dd7cddfSDavid du Colombier 		Xput(xs, xp, c);
831*7dd7cddfSDavid du Colombier 	}
832*7dd7cddfSDavid du Colombier 	Xput(xs, xp, '\0');
833*7dd7cddfSDavid du Colombier 	iop->heredoc = Xclose(xs, xp);
834*7dd7cddfSDavid du Colombier 
835*7dd7cddfSDavid du Colombier 	if (!(iop->flag & IOEVAL))
836*7dd7cddfSDavid du Colombier 		ignore_backslash_newline--;
837*7dd7cddfSDavid du Colombier }
838*7dd7cddfSDavid du Colombier 
839*7dd7cddfSDavid du Colombier void
840*7dd7cddfSDavid du Colombier #ifdef HAVE_PROTOTYPES
yyerror(const char * fmt,...)841*7dd7cddfSDavid du Colombier yyerror(const char *fmt, ...)
842*7dd7cddfSDavid du Colombier #else
843*7dd7cddfSDavid du Colombier yyerror(fmt, va_alist)
844*7dd7cddfSDavid du Colombier 	const char *fmt;
845*7dd7cddfSDavid du Colombier 	va_dcl
846*7dd7cddfSDavid du Colombier #endif
847*7dd7cddfSDavid du Colombier {
848*7dd7cddfSDavid du Colombier 	va_list va;
849*7dd7cddfSDavid du Colombier 
850*7dd7cddfSDavid du Colombier 	/* pop aliases and re-reads */
851*7dd7cddfSDavid du Colombier 	while (source->type == SALIAS || source->type == SREREAD)
852*7dd7cddfSDavid du Colombier 		source = source->next;
853*7dd7cddfSDavid du Colombier 	source->str = null;	/* zap pending input */
854*7dd7cddfSDavid du Colombier 
855*7dd7cddfSDavid du Colombier 	error_prefix(TRUE);
856*7dd7cddfSDavid du Colombier 	SH_VA_START(va, fmt);
857*7dd7cddfSDavid du Colombier 	shf_vfprintf(shl_out, fmt, va);
858*7dd7cddfSDavid du Colombier 	va_end(va);
859*7dd7cddfSDavid du Colombier 	errorf(null);
860*7dd7cddfSDavid du Colombier }
861*7dd7cddfSDavid du Colombier 
862*7dd7cddfSDavid du Colombier /*
863*7dd7cddfSDavid du Colombier  * input for yylex with alias expansion
864*7dd7cddfSDavid du Colombier  */
865*7dd7cddfSDavid du Colombier 
866*7dd7cddfSDavid du Colombier Source *
pushs(type,areap)867*7dd7cddfSDavid du Colombier pushs(type, areap)
868*7dd7cddfSDavid du Colombier 	int type;
869*7dd7cddfSDavid du Colombier 	Area *areap;
870*7dd7cddfSDavid du Colombier {
871*7dd7cddfSDavid du Colombier 	register Source *s;
872*7dd7cddfSDavid du Colombier 
873*7dd7cddfSDavid du Colombier 	s = (Source *) alloc(sizeof(Source), areap);
874*7dd7cddfSDavid du Colombier 	s->type = type;
875*7dd7cddfSDavid du Colombier 	s->str = null;
876*7dd7cddfSDavid du Colombier 	s->start = NULL;
877*7dd7cddfSDavid du Colombier 	s->line = 0;
878*7dd7cddfSDavid du Colombier 	s->errline = 0;
879*7dd7cddfSDavid du Colombier 	s->file = NULL;
880*7dd7cddfSDavid du Colombier 	s->flags = 0;
881*7dd7cddfSDavid du Colombier 	s->next = NULL;
882*7dd7cddfSDavid du Colombier 	s->areap = areap;
883*7dd7cddfSDavid du Colombier 	if (type == SFILE || type == SSTDIN) {
884*7dd7cddfSDavid du Colombier 		char *dummy;
885*7dd7cddfSDavid du Colombier 		Xinit(s->xs, dummy, 256, s->areap);
886*7dd7cddfSDavid du Colombier 	} else
887*7dd7cddfSDavid du Colombier 		memset(&s->xs, 0, sizeof(s->xs));
888*7dd7cddfSDavid du Colombier 	return s;
889*7dd7cddfSDavid du Colombier }
890*7dd7cddfSDavid du Colombier 
891*7dd7cddfSDavid du Colombier static int
getsc__()892*7dd7cddfSDavid du Colombier getsc__()
893*7dd7cddfSDavid du Colombier {
894*7dd7cddfSDavid du Colombier 	register Source *s = source;
895*7dd7cddfSDavid du Colombier 	register int c;
896*7dd7cddfSDavid du Colombier 
897*7dd7cddfSDavid du Colombier 	while ((c = *s->str++) == 0) {
898*7dd7cddfSDavid du Colombier 		s->str = NULL;		/* return 0 for EOF by default */
899*7dd7cddfSDavid du Colombier 		switch (s->type) {
900*7dd7cddfSDavid du Colombier 		  case SEOF:
901*7dd7cddfSDavid du Colombier 			s->str = null;
902*7dd7cddfSDavid du Colombier 			return 0;
903*7dd7cddfSDavid du Colombier 
904*7dd7cddfSDavid du Colombier 		  case SSTDIN:
905*7dd7cddfSDavid du Colombier 		  case SFILE:
906*7dd7cddfSDavid du Colombier 			getsc_line(s);
907*7dd7cddfSDavid du Colombier 			break;
908*7dd7cddfSDavid du Colombier 
909*7dd7cddfSDavid du Colombier 		  case SWSTR:
910*7dd7cddfSDavid du Colombier 			break;
911*7dd7cddfSDavid du Colombier 
912*7dd7cddfSDavid du Colombier 		  case SSTRING:
913*7dd7cddfSDavid du Colombier 			break;
914*7dd7cddfSDavid du Colombier 
915*7dd7cddfSDavid du Colombier 		  case SWORDS:
916*7dd7cddfSDavid du Colombier 			s->start = s->str = *s->u.strv++;
917*7dd7cddfSDavid du Colombier 			s->type = SWORDSEP;
918*7dd7cddfSDavid du Colombier 			break;
919*7dd7cddfSDavid du Colombier 
920*7dd7cddfSDavid du Colombier 		  case SWORDSEP:
921*7dd7cddfSDavid du Colombier 			if (*s->u.strv == NULL) {
922*7dd7cddfSDavid du Colombier 				s->start = s->str = newline;
923*7dd7cddfSDavid du Colombier 				s->type = SEOF;
924*7dd7cddfSDavid du Colombier 			} else {
925*7dd7cddfSDavid du Colombier 				s->start = s->str = space;
926*7dd7cddfSDavid du Colombier 				s->type = SWORDS;
927*7dd7cddfSDavid du Colombier 			}
928*7dd7cddfSDavid du Colombier 			break;
929*7dd7cddfSDavid du Colombier 
930*7dd7cddfSDavid du Colombier 		  case SALIAS:
931*7dd7cddfSDavid du Colombier 			if (s->flags & SF_ALIASEND) {
932*7dd7cddfSDavid du Colombier 				/* pass on an unused SF_ALIAS flag */
933*7dd7cddfSDavid du Colombier 				source = s->next;
934*7dd7cddfSDavid du Colombier 				source->flags |= s->flags & SF_ALIAS;
935*7dd7cddfSDavid du Colombier 				s = source;
936*7dd7cddfSDavid du Colombier 			} else if (*s->u.tblp->val.s
937*7dd7cddfSDavid du Colombier 				 && isspace(strchr(s->u.tblp->val.s, 0)[-1]))
938*7dd7cddfSDavid du Colombier 			{
939*7dd7cddfSDavid du Colombier 				source = s = s->next;	/* pop source stack */
940*7dd7cddfSDavid du Colombier 				/* Note that this alias ended with a space,
941*7dd7cddfSDavid du Colombier 				 * enabling alias expansion on the following
942*7dd7cddfSDavid du Colombier 				 * word.
943*7dd7cddfSDavid du Colombier 				 */
944*7dd7cddfSDavid du Colombier 				s->flags |= SF_ALIAS;
945*7dd7cddfSDavid du Colombier 			} else {
946*7dd7cddfSDavid du Colombier 				/* At this point, we need to keep the current
947*7dd7cddfSDavid du Colombier 				 * alias in the source list so recursive
948*7dd7cddfSDavid du Colombier 				 * aliases can be detected and we also need
949*7dd7cddfSDavid du Colombier 				 * to return the next character.  Do this
950*7dd7cddfSDavid du Colombier 				 * by temporarily popping the alias to get
951*7dd7cddfSDavid du Colombier 				 * the next character and then put it back
952*7dd7cddfSDavid du Colombier 				 * in the source list with the SF_ALIASEND
953*7dd7cddfSDavid du Colombier 				 * flag set.
954*7dd7cddfSDavid du Colombier 				 */
955*7dd7cddfSDavid du Colombier 				source = s->next;	/* pop source stack */
956*7dd7cddfSDavid du Colombier 				source->flags |= s->flags & SF_ALIAS;
957*7dd7cddfSDavid du Colombier 				c = getsc__();
958*7dd7cddfSDavid du Colombier 				if (c) {
959*7dd7cddfSDavid du Colombier 					s->flags |= SF_ALIASEND;
960*7dd7cddfSDavid du Colombier 					s->ugbuf[0] = c; s->ugbuf[1] = '\0';
961*7dd7cddfSDavid du Colombier 					s->start = s->str = s->ugbuf;
962*7dd7cddfSDavid du Colombier 					s->next = source;
963*7dd7cddfSDavid du Colombier 					source = s;
964*7dd7cddfSDavid du Colombier 				} else {
965*7dd7cddfSDavid du Colombier 					s = source;
966*7dd7cddfSDavid du Colombier 					/* avoid reading eof twice */
967*7dd7cddfSDavid du Colombier 					s->str = NULL;
968*7dd7cddfSDavid du Colombier 					break;
969*7dd7cddfSDavid du Colombier 				}
970*7dd7cddfSDavid du Colombier 			}
971*7dd7cddfSDavid du Colombier 			continue;
972*7dd7cddfSDavid du Colombier 
973*7dd7cddfSDavid du Colombier 		  case SREREAD:
974*7dd7cddfSDavid du Colombier 			if (s->start != s->ugbuf) /* yuck */
975*7dd7cddfSDavid du Colombier 				afree(s->u.freeme, ATEMP);
976*7dd7cddfSDavid du Colombier 			source = s = s->next;
977*7dd7cddfSDavid du Colombier 			continue;
978*7dd7cddfSDavid du Colombier 		}
979*7dd7cddfSDavid du Colombier 		if (s->str == NULL) {
980*7dd7cddfSDavid du Colombier 			s->type = SEOF;
981*7dd7cddfSDavid du Colombier 			s->start = s->str = null;
982*7dd7cddfSDavid du Colombier 			return '\0';
983*7dd7cddfSDavid du Colombier 		}
984*7dd7cddfSDavid du Colombier 		if (s->flags & SF_ECHO) {
985*7dd7cddfSDavid du Colombier 			shf_puts(s->str, shl_out);
986*7dd7cddfSDavid du Colombier 			shf_flush(shl_out);
987*7dd7cddfSDavid du Colombier 		}
988*7dd7cddfSDavid du Colombier 	}
989*7dd7cddfSDavid du Colombier 	return c;
990*7dd7cddfSDavid du Colombier }
991*7dd7cddfSDavid du Colombier 
992*7dd7cddfSDavid du Colombier static void
getsc_line(s)993*7dd7cddfSDavid du Colombier getsc_line(s)
994*7dd7cddfSDavid du Colombier 	Source *s;
995*7dd7cddfSDavid du Colombier {
996*7dd7cddfSDavid du Colombier 	char *xp = Xstring(s->xs, xp);
997*7dd7cddfSDavid du Colombier 	int interactive = Flag(FTALKING) && s->type == SSTDIN;
998*7dd7cddfSDavid du Colombier 	int have_tty = interactive && (s->flags & SF_TTY);
999*7dd7cddfSDavid du Colombier 
1000*7dd7cddfSDavid du Colombier 	/* Done here to ensure nothing odd happens when a timeout occurs */
1001*7dd7cddfSDavid du Colombier 	XcheckN(s->xs, xp, LINE);
1002*7dd7cddfSDavid du Colombier 	*xp = '\0';
1003*7dd7cddfSDavid du Colombier 	s->start = s->str = xp;
1004*7dd7cddfSDavid du Colombier 
1005*7dd7cddfSDavid du Colombier #ifdef KSH
1006*7dd7cddfSDavid du Colombier 	if (have_tty && ksh_tmout) {
1007*7dd7cddfSDavid du Colombier 		ksh_tmout_state = TMOUT_READING;
1008*7dd7cddfSDavid du Colombier 		alarm(ksh_tmout);
1009*7dd7cddfSDavid du Colombier 	}
1010*7dd7cddfSDavid du Colombier #endif /* KSH */
1011*7dd7cddfSDavid du Colombier #ifdef EDIT
1012*7dd7cddfSDavid du Colombier 	if (have_tty && (0
1013*7dd7cddfSDavid du Colombier # ifdef VI
1014*7dd7cddfSDavid du Colombier 			 || Flag(FVI)
1015*7dd7cddfSDavid du Colombier # endif /* VI */
1016*7dd7cddfSDavid du Colombier # ifdef EMACS
1017*7dd7cddfSDavid du Colombier 			 || Flag(FEMACS) || Flag(FGMACS)
1018*7dd7cddfSDavid du Colombier # endif /* EMACS */
1019*7dd7cddfSDavid du Colombier 		))
1020*7dd7cddfSDavid du Colombier 	{
1021*7dd7cddfSDavid du Colombier 		int nread;
1022*7dd7cddfSDavid du Colombier 
1023*7dd7cddfSDavid du Colombier 		nread = x_read(xp, LINE);
1024*7dd7cddfSDavid du Colombier 		if (nread < 0)	/* read error */
1025*7dd7cddfSDavid du Colombier 			nread = 0;
1026*7dd7cddfSDavid du Colombier 		xp[nread] = '\0';
1027*7dd7cddfSDavid du Colombier 		xp += nread;
1028*7dd7cddfSDavid du Colombier 	}
1029*7dd7cddfSDavid du Colombier 	else
1030*7dd7cddfSDavid du Colombier #endif /* EDIT */
1031*7dd7cddfSDavid du Colombier 	{
1032*7dd7cddfSDavid du Colombier 		if (interactive) {
1033*7dd7cddfSDavid du Colombier 			pprompt(prompt, 0);
1034*7dd7cddfSDavid du Colombier 		} else
1035*7dd7cddfSDavid du Colombier 			s->line++;
1036*7dd7cddfSDavid du Colombier 
1037*7dd7cddfSDavid du Colombier 		while (1) {
1038*7dd7cddfSDavid du Colombier 			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
1039*7dd7cddfSDavid du Colombier 
1040*7dd7cddfSDavid du Colombier 			if (!p && shf_error(s->u.shf)
1041*7dd7cddfSDavid du Colombier 			    && shf_errno(s->u.shf) == EINTR)
1042*7dd7cddfSDavid du Colombier 			{
1043*7dd7cddfSDavid du Colombier 				shf_clearerr(s->u.shf);
1044*7dd7cddfSDavid du Colombier 				if (trap)
1045*7dd7cddfSDavid du Colombier 					runtraps(0);
1046*7dd7cddfSDavid du Colombier 				continue;
1047*7dd7cddfSDavid du Colombier 			}
1048*7dd7cddfSDavid du Colombier 			if (!p || (xp = p, xp[-1] == '\n'))
1049*7dd7cddfSDavid du Colombier 				break;
1050*7dd7cddfSDavid du Colombier 			/* double buffer size */
1051*7dd7cddfSDavid du Colombier 			xp++; /* move past null so doubling works... */
1052*7dd7cddfSDavid du Colombier 			XcheckN(s->xs, xp, Xlength(s->xs, xp));
1053*7dd7cddfSDavid du Colombier 			xp--; /* ...and move back again */
1054*7dd7cddfSDavid du Colombier 		}
1055*7dd7cddfSDavid du Colombier 		/* flush any unwanted input so other programs/builtins
1056*7dd7cddfSDavid du Colombier 		 * can read it.  Not very optimal, but less error prone
1057*7dd7cddfSDavid du Colombier 		 * than flushing else where, dealing with redirections,
1058*7dd7cddfSDavid du Colombier 		 * etc..
1059*7dd7cddfSDavid du Colombier 		 * todo: reduce size of shf buffer (~128?) if SSTDIN
1060*7dd7cddfSDavid du Colombier 		 */
1061*7dd7cddfSDavid du Colombier 		if (s->type == SSTDIN)
1062*7dd7cddfSDavid du Colombier 			shf_flush(s->u.shf);
1063*7dd7cddfSDavid du Colombier 	}
1064*7dd7cddfSDavid du Colombier 	/* XXX: temporary kludge to restore source after a
1065*7dd7cddfSDavid du Colombier 	 * trap may have been executed.
1066*7dd7cddfSDavid du Colombier 	 */
1067*7dd7cddfSDavid du Colombier 	source = s;
1068*7dd7cddfSDavid du Colombier #ifdef KSH
1069*7dd7cddfSDavid du Colombier 	if (have_tty && ksh_tmout)
1070*7dd7cddfSDavid du Colombier 	{
1071*7dd7cddfSDavid du Colombier 		ksh_tmout_state = TMOUT_EXECUTING;
1072*7dd7cddfSDavid du Colombier 		alarm(0);
1073*7dd7cddfSDavid du Colombier 	}
1074*7dd7cddfSDavid du Colombier #endif /* KSH */
1075*7dd7cddfSDavid du Colombier 	s->start = s->str = Xstring(s->xs, xp);
1076*7dd7cddfSDavid du Colombier 	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
1077*7dd7cddfSDavid du Colombier 	/* Note: if input is all nulls, this is not eof */
1078*7dd7cddfSDavid du Colombier 	if (Xlength(s->xs, xp) == 0) { /* EOF */
1079*7dd7cddfSDavid du Colombier 		if (s->type == SFILE)
1080*7dd7cddfSDavid du Colombier 			shf_fdclose(s->u.shf);
1081*7dd7cddfSDavid du Colombier 		s->str = NULL;
1082*7dd7cddfSDavid du Colombier 	} else if (interactive) {
1083*7dd7cddfSDavid du Colombier #ifdef HISTORY
1084*7dd7cddfSDavid du Colombier 		char *p = Xstring(s->xs, xp);
1085*7dd7cddfSDavid du Colombier 		if (cur_prompt == PS1)
1086*7dd7cddfSDavid du Colombier 			while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS))
1087*7dd7cddfSDavid du Colombier 				p++;
1088*7dd7cddfSDavid du Colombier 		if (*p) {
1089*7dd7cddfSDavid du Colombier # ifdef EASY_HISTORY
1090*7dd7cddfSDavid du Colombier 			if (cur_prompt == PS2)
1091*7dd7cddfSDavid du Colombier 				histappend(Xstring(s->xs, xp), 1);
1092*7dd7cddfSDavid du Colombier 			else
1093*7dd7cddfSDavid du Colombier # endif /* EASY_HISTORY */
1094*7dd7cddfSDavid du Colombier 			{
1095*7dd7cddfSDavid du Colombier 				s->line++;
1096*7dd7cddfSDavid du Colombier 				histsave(s->line, s->str, 1);
1097*7dd7cddfSDavid du Colombier 			}
1098*7dd7cddfSDavid du Colombier 		}
1099*7dd7cddfSDavid du Colombier #endif /* HISTORY */
1100*7dd7cddfSDavid du Colombier 	}
1101*7dd7cddfSDavid du Colombier 	if (interactive)
1102*7dd7cddfSDavid du Colombier 		set_prompt(PS2, (Source *) 0);
1103*7dd7cddfSDavid du Colombier }
1104*7dd7cddfSDavid du Colombier 
1105*7dd7cddfSDavid du Colombier void
set_prompt(to,s)1106*7dd7cddfSDavid du Colombier set_prompt(to, s)
1107*7dd7cddfSDavid du Colombier 	int to;
1108*7dd7cddfSDavid du Colombier 	Source *s;
1109*7dd7cddfSDavid du Colombier {
1110*7dd7cddfSDavid du Colombier 	cur_prompt = to;
1111*7dd7cddfSDavid du Colombier 
1112*7dd7cddfSDavid du Colombier 	switch (to) {
1113*7dd7cddfSDavid du Colombier 	case PS1: /* command */
1114*7dd7cddfSDavid du Colombier #ifdef KSH
1115*7dd7cddfSDavid du Colombier 		/* Substitute ! and !! here, before substitutions are done
1116*7dd7cddfSDavid du Colombier 		 * so ! in expanded variables are not expanded.
1117*7dd7cddfSDavid du Colombier 		 * NOTE: this is not what at&t ksh does (it does it after
1118*7dd7cddfSDavid du Colombier 		 * substitutions, POSIX doesn't say which is to be done.
1119*7dd7cddfSDavid du Colombier 		 */
1120*7dd7cddfSDavid du Colombier 		{
1121*7dd7cddfSDavid du Colombier 			struct shf *shf;
1122*7dd7cddfSDavid du Colombier 			char *ps1;
1123*7dd7cddfSDavid du Colombier 			Area *saved_atemp;
1124*7dd7cddfSDavid du Colombier 
1125*7dd7cddfSDavid du Colombier 			ps1 = str_val(global("PS1"));
1126*7dd7cddfSDavid du Colombier 			shf = shf_sopen((char *) 0, strlen(ps1) * 2,
1127*7dd7cddfSDavid du Colombier 				SHF_WR | SHF_DYNAMIC, (struct shf *) 0);
1128*7dd7cddfSDavid du Colombier 			while (*ps1) {
1129*7dd7cddfSDavid du Colombier 				if (*ps1 != '!' || *++ps1 == '!')
1130*7dd7cddfSDavid du Colombier 					shf_putchar(*ps1++, shf);
1131*7dd7cddfSDavid du Colombier 				else
1132*7dd7cddfSDavid du Colombier 					shf_fprintf(shf, "%d",
1133*7dd7cddfSDavid du Colombier 						s ? s->line + 1 : 0);
1134*7dd7cddfSDavid du Colombier 			}
1135*7dd7cddfSDavid du Colombier 			ps1 = shf_sclose(shf);
1136*7dd7cddfSDavid du Colombier 			saved_atemp = ATEMP;
1137*7dd7cddfSDavid du Colombier 			newenv(E_ERRH);
1138*7dd7cddfSDavid du Colombier 			if (ksh_sigsetjmp(e->jbuf, 0)) {
1139*7dd7cddfSDavid du Colombier 				prompt = safe_prompt;
1140*7dd7cddfSDavid du Colombier 				/* Don't print an error - assume it has already
1141*7dd7cddfSDavid du Colombier 				 * been printed.  Reason is we may have forked
1142*7dd7cddfSDavid du Colombier 				 * to run a command and the child may be
1143*7dd7cddfSDavid du Colombier 				 * unwinding its stack through this code as it
1144*7dd7cddfSDavid du Colombier 				 * exits.
1145*7dd7cddfSDavid du Colombier 				 */
1146*7dd7cddfSDavid du Colombier 			} else
1147*7dd7cddfSDavid du Colombier 				prompt = str_save(substitute(ps1, 0),
1148*7dd7cddfSDavid du Colombier 						 saved_atemp);
1149*7dd7cddfSDavid du Colombier 			quitenv();
1150*7dd7cddfSDavid du Colombier 		}
1151*7dd7cddfSDavid du Colombier #else /* KSH */
1152*7dd7cddfSDavid du Colombier 		prompt = str_val(global("PS1"));
1153*7dd7cddfSDavid du Colombier #endif /* KSH */
1154*7dd7cddfSDavid du Colombier 		break;
1155*7dd7cddfSDavid du Colombier 
1156*7dd7cddfSDavid du Colombier 	case PS2: /* command continuation */
1157*7dd7cddfSDavid du Colombier 		prompt = str_val(global("PS2"));
1158*7dd7cddfSDavid du Colombier 		break;
1159*7dd7cddfSDavid du Colombier 	}
1160*7dd7cddfSDavid du Colombier }
1161*7dd7cddfSDavid du Colombier 
1162*7dd7cddfSDavid du Colombier /* See also related routine, promptlen() in edit.c */
1163*7dd7cddfSDavid du Colombier void
pprompt(cp,ntruncate)1164*7dd7cddfSDavid du Colombier pprompt(cp, ntruncate)
1165*7dd7cddfSDavid du Colombier 	const char *cp;
1166*7dd7cddfSDavid du Colombier 	int ntruncate;
1167*7dd7cddfSDavid du Colombier {
1168*7dd7cddfSDavid du Colombier #if 0
1169*7dd7cddfSDavid du Colombier 	char nbuf[32];
1170*7dd7cddfSDavid du Colombier 	int c;
1171*7dd7cddfSDavid du Colombier 
1172*7dd7cddfSDavid du Colombier 	while (*cp != 0) {
1173*7dd7cddfSDavid du Colombier 		if (*cp != '!')
1174*7dd7cddfSDavid du Colombier 			c = *cp++;
1175*7dd7cddfSDavid du Colombier 		else if (*++cp == '!')
1176*7dd7cddfSDavid du Colombier 			c = *cp++;
1177*7dd7cddfSDavid du Colombier 		else {
1178*7dd7cddfSDavid du Colombier 			int len;
1179*7dd7cddfSDavid du Colombier 			char *p;
1180*7dd7cddfSDavid du Colombier 
1181*7dd7cddfSDavid du Colombier 			shf_snprintf(p = nbuf, sizeof(nbuf), "%d",
1182*7dd7cddfSDavid du Colombier 				source->line + 1);
1183*7dd7cddfSDavid du Colombier 			len = strlen(nbuf);
1184*7dd7cddfSDavid du Colombier 			if (ntruncate) {
1185*7dd7cddfSDavid du Colombier 				if (ntruncate >= len) {
1186*7dd7cddfSDavid du Colombier 					ntruncate -= len;
1187*7dd7cddfSDavid du Colombier 					continue;
1188*7dd7cddfSDavid du Colombier 				}
1189*7dd7cddfSDavid du Colombier 				p += ntruncate;
1190*7dd7cddfSDavid du Colombier 				len -= ntruncate;
1191*7dd7cddfSDavid du Colombier 				ntruncate = 0;
1192*7dd7cddfSDavid du Colombier 			}
1193*7dd7cddfSDavid du Colombier 			shf_write(p, len, shl_out);
1194*7dd7cddfSDavid du Colombier 			continue;
1195*7dd7cddfSDavid du Colombier 		}
1196*7dd7cddfSDavid du Colombier 		if (ntruncate)
1197*7dd7cddfSDavid du Colombier 			--ntruncate;
1198*7dd7cddfSDavid du Colombier 		else
1199*7dd7cddfSDavid du Colombier 			shf_putc(c, shl_out);
1200*7dd7cddfSDavid du Colombier 	}
1201*7dd7cddfSDavid du Colombier #endif /* 0 */
1202*7dd7cddfSDavid du Colombier 	shf_puts(cp + ntruncate, shl_out);
1203*7dd7cddfSDavid du Colombier 	shf_flush(shl_out);
1204*7dd7cddfSDavid du Colombier }
1205*7dd7cddfSDavid du Colombier 
1206*7dd7cddfSDavid du Colombier /* Read the variable part of a ${...} expression (ie, up to but not including
1207*7dd7cddfSDavid du Colombier  * the :[-+?=#%] or close-brace.
1208*7dd7cddfSDavid du Colombier  */
1209*7dd7cddfSDavid du Colombier static char *
get_brace_var(wsp,wp)1210*7dd7cddfSDavid du Colombier get_brace_var(wsp, wp)
1211*7dd7cddfSDavid du Colombier 	XString *wsp;
1212*7dd7cddfSDavid du Colombier 	char *wp;
1213*7dd7cddfSDavid du Colombier {
1214*7dd7cddfSDavid du Colombier 	enum parse_state {
1215*7dd7cddfSDavid du Colombier 			   PS_INITIAL, PS_SAW_HASH, PS_IDENT,
1216*7dd7cddfSDavid du Colombier 			   PS_NUMBER, PS_VAR1, PS_END
1217*7dd7cddfSDavid du Colombier 			 }
1218*7dd7cddfSDavid du Colombier 		state;
1219*7dd7cddfSDavid du Colombier 	char c;
1220*7dd7cddfSDavid du Colombier 
1221*7dd7cddfSDavid du Colombier 	state = PS_INITIAL;
1222*7dd7cddfSDavid du Colombier 	while (1) {
1223*7dd7cddfSDavid du Colombier 		c = getsc();
1224*7dd7cddfSDavid du Colombier 		/* State machine to figure out where the variable part ends. */
1225*7dd7cddfSDavid du Colombier 		switch (state) {
1226*7dd7cddfSDavid du Colombier 		  case PS_INITIAL:
1227*7dd7cddfSDavid du Colombier 			if (c == '#') {
1228*7dd7cddfSDavid du Colombier 				state = PS_SAW_HASH;
1229*7dd7cddfSDavid du Colombier 				break;
1230*7dd7cddfSDavid du Colombier 			}
1231*7dd7cddfSDavid du Colombier 			/* fall through.. */
1232*7dd7cddfSDavid du Colombier 		  case PS_SAW_HASH:
1233*7dd7cddfSDavid du Colombier 			if (letter(c))
1234*7dd7cddfSDavid du Colombier 				state = PS_IDENT;
1235*7dd7cddfSDavid du Colombier 			else if (digit(c))
1236*7dd7cddfSDavid du Colombier 				state = PS_NUMBER;
1237*7dd7cddfSDavid du Colombier 			else if (ctype(c, C_VAR1))
1238*7dd7cddfSDavid du Colombier 				state = PS_VAR1;
1239*7dd7cddfSDavid du Colombier 			else
1240*7dd7cddfSDavid du Colombier 				state = PS_END;
1241*7dd7cddfSDavid du Colombier 			break;
1242*7dd7cddfSDavid du Colombier 		  case PS_IDENT:
1243*7dd7cddfSDavid du Colombier 			if (!letnum(c)) {
1244*7dd7cddfSDavid du Colombier 				state = PS_END;
1245*7dd7cddfSDavid du Colombier 				if (c == '[') {
1246*7dd7cddfSDavid du Colombier 					char *tmp, *p;
1247*7dd7cddfSDavid du Colombier 
1248*7dd7cddfSDavid du Colombier 					if (!arraysub(&tmp))
1249*7dd7cddfSDavid du Colombier 						yyerror("missing ]\n");
1250*7dd7cddfSDavid du Colombier 					*wp++ = c;
1251*7dd7cddfSDavid du Colombier 					for (p = tmp; *p; ) {
1252*7dd7cddfSDavid du Colombier 						Xcheck(*wsp, wp);
1253*7dd7cddfSDavid du Colombier 						*wp++ = *p++;
1254*7dd7cddfSDavid du Colombier 					}
1255*7dd7cddfSDavid du Colombier 					afree(tmp, ATEMP);
1256*7dd7cddfSDavid du Colombier 					c = getsc(); /* the ] */
1257*7dd7cddfSDavid du Colombier 				}
1258*7dd7cddfSDavid du Colombier 			}
1259*7dd7cddfSDavid du Colombier 			break;
1260*7dd7cddfSDavid du Colombier 		  case PS_NUMBER:
1261*7dd7cddfSDavid du Colombier 			if (!digit(c))
1262*7dd7cddfSDavid du Colombier 				state = PS_END;
1263*7dd7cddfSDavid du Colombier 			break;
1264*7dd7cddfSDavid du Colombier 		  case PS_VAR1:
1265*7dd7cddfSDavid du Colombier 			state = PS_END;
1266*7dd7cddfSDavid du Colombier 			break;
1267*7dd7cddfSDavid du Colombier 		  case PS_END: /* keep gcc happy */
1268*7dd7cddfSDavid du Colombier 			break;
1269*7dd7cddfSDavid du Colombier 		}
1270*7dd7cddfSDavid du Colombier 		if (state == PS_END) {
1271*7dd7cddfSDavid du Colombier 			*wp++ = '\0';	/* end of variable part */
1272*7dd7cddfSDavid du Colombier 			ungetsc(c);
1273*7dd7cddfSDavid du Colombier 			break;
1274*7dd7cddfSDavid du Colombier 		}
1275*7dd7cddfSDavid du Colombier 		Xcheck(*wsp, wp);
1276*7dd7cddfSDavid du Colombier 		*wp++ = c;
1277*7dd7cddfSDavid du Colombier 	}
1278*7dd7cddfSDavid du Colombier 	return wp;
1279*7dd7cddfSDavid du Colombier }
1280*7dd7cddfSDavid du Colombier 
1281*7dd7cddfSDavid du Colombier /*
1282*7dd7cddfSDavid du Colombier  * Save an array subscript - returns true if matching bracket found, false
1283*7dd7cddfSDavid du Colombier  * if eof or newline was found.
1284*7dd7cddfSDavid du Colombier  * (Returned string double null terminated)
1285*7dd7cddfSDavid du Colombier  */
1286*7dd7cddfSDavid du Colombier static int
arraysub(strp)1287*7dd7cddfSDavid du Colombier arraysub(strp)
1288*7dd7cddfSDavid du Colombier 	char **strp;
1289*7dd7cddfSDavid du Colombier {
1290*7dd7cddfSDavid du Colombier 	XString ws;
1291*7dd7cddfSDavid du Colombier 	char	*wp;
1292*7dd7cddfSDavid du Colombier 	char	c;
1293*7dd7cddfSDavid du Colombier 	int 	depth = 1;	/* we are just past the initial [ */
1294*7dd7cddfSDavid du Colombier 
1295*7dd7cddfSDavid du Colombier 	Xinit(ws, wp, 32, ATEMP);
1296*7dd7cddfSDavid du Colombier 
1297*7dd7cddfSDavid du Colombier 	do {
1298*7dd7cddfSDavid du Colombier 		c = getsc();
1299*7dd7cddfSDavid du Colombier 		Xcheck(ws, wp);
1300*7dd7cddfSDavid du Colombier 		*wp++ = c;
1301*7dd7cddfSDavid du Colombier 		if (c == '[')
1302*7dd7cddfSDavid du Colombier 			depth++;
1303*7dd7cddfSDavid du Colombier 		else if (c == ']')
1304*7dd7cddfSDavid du Colombier 			depth--;
1305*7dd7cddfSDavid du Colombier 	} while (depth > 0 && c && c != '\n');
1306*7dd7cddfSDavid du Colombier 
1307*7dd7cddfSDavid du Colombier 	*wp++ = '\0';
1308*7dd7cddfSDavid du Colombier 	*strp = Xclose(ws, wp);
1309*7dd7cddfSDavid du Colombier 
1310*7dd7cddfSDavid du Colombier 	return depth == 0 ? 1 : 0;
1311*7dd7cddfSDavid du Colombier }
1312*7dd7cddfSDavid du Colombier 
1313*7dd7cddfSDavid du Colombier /* Unget a char: handles case when we are already at the start of the buffer */
1314*7dd7cddfSDavid du Colombier static const char *
ungetsc(c)1315*7dd7cddfSDavid du Colombier ungetsc(c)
1316*7dd7cddfSDavid du Colombier 	int c;
1317*7dd7cddfSDavid du Colombier {
1318*7dd7cddfSDavid du Colombier 	if (backslash_skip)
1319*7dd7cddfSDavid du Colombier 		backslash_skip--;
1320*7dd7cddfSDavid du Colombier 	/* Don't unget eof... */
1321*7dd7cddfSDavid du Colombier 	if (source->str == null && c == '\0')
1322*7dd7cddfSDavid du Colombier 		return source->str;
1323*7dd7cddfSDavid du Colombier 	if (source->str > source->start)
1324*7dd7cddfSDavid du Colombier 		source->str--;
1325*7dd7cddfSDavid du Colombier 	else {
1326*7dd7cddfSDavid du Colombier 		Source *s;
1327*7dd7cddfSDavid du Colombier 
1328*7dd7cddfSDavid du Colombier 		s = pushs(SREREAD, source->areap);
1329*7dd7cddfSDavid du Colombier 		s->ugbuf[0] = c; s->ugbuf[1] = '\0';
1330*7dd7cddfSDavid du Colombier 		s->start = s->str = s->ugbuf;
1331*7dd7cddfSDavid du Colombier 		s->next = source;
1332*7dd7cddfSDavid du Colombier 		source = s;
1333*7dd7cddfSDavid du Colombier 	}
1334*7dd7cddfSDavid du Colombier 	return source->str;
1335*7dd7cddfSDavid du Colombier }
1336*7dd7cddfSDavid du Colombier 
1337*7dd7cddfSDavid du Colombier 
1338*7dd7cddfSDavid du Colombier /* Called to get a char that isn't a \newline sequence. */
1339*7dd7cddfSDavid du Colombier static int
getsc_bn(void)1340*7dd7cddfSDavid du Colombier getsc_bn ARGS((void))
1341*7dd7cddfSDavid du Colombier {
1342*7dd7cddfSDavid du Colombier 	int c, c2;
1343*7dd7cddfSDavid du Colombier 
1344*7dd7cddfSDavid du Colombier 	if (ignore_backslash_newline)
1345*7dd7cddfSDavid du Colombier 		return getsc_();
1346*7dd7cddfSDavid du Colombier 
1347*7dd7cddfSDavid du Colombier 	if (backslash_skip == 1) {
1348*7dd7cddfSDavid du Colombier 		backslash_skip = 2;
1349*7dd7cddfSDavid du Colombier 		return getsc_();
1350*7dd7cddfSDavid du Colombier 	}
1351*7dd7cddfSDavid du Colombier 
1352*7dd7cddfSDavid du Colombier 	backslash_skip = 0;
1353*7dd7cddfSDavid du Colombier 
1354*7dd7cddfSDavid du Colombier 	while (1) {
1355*7dd7cddfSDavid du Colombier 		c = getsc_();
1356*7dd7cddfSDavid du Colombier 		if (c == '\\') {
1357*7dd7cddfSDavid du Colombier 			if ((c2 = getsc_()) == '\n')
1358*7dd7cddfSDavid du Colombier 				/* ignore the \newline; get the next char... */
1359*7dd7cddfSDavid du Colombier 				continue;
1360*7dd7cddfSDavid du Colombier 			ungetsc(c2);
1361*7dd7cddfSDavid du Colombier 			backslash_skip = 1;
1362*7dd7cddfSDavid du Colombier 		}
1363*7dd7cddfSDavid du Colombier 		return c;
1364*7dd7cddfSDavid du Colombier 	}
1365*7dd7cddfSDavid du Colombier }
1366*7dd7cddfSDavid du Colombier 
1367*7dd7cddfSDavid du Colombier static Lex_state *
push_state_(si,old_end)1368*7dd7cddfSDavid du Colombier push_state_(si, old_end)
1369*7dd7cddfSDavid du Colombier 	State_info *si;
1370*7dd7cddfSDavid du Colombier 	Lex_state *old_end;
1371*7dd7cddfSDavid du Colombier {
1372*7dd7cddfSDavid du Colombier 	Lex_state	*new = alloc(sizeof(Lex_state) * STATE_BSIZE, ATEMP);
1373*7dd7cddfSDavid du Colombier 
1374*7dd7cddfSDavid du Colombier 	new[0].ls_info.base = old_end;
1375*7dd7cddfSDavid du Colombier 	si->base = &new[0];
1376*7dd7cddfSDavid du Colombier 	si->end = &new[STATE_BSIZE];
1377*7dd7cddfSDavid du Colombier 	return &new[1];
1378*7dd7cddfSDavid du Colombier }
1379*7dd7cddfSDavid du Colombier 
1380*7dd7cddfSDavid du Colombier static Lex_state *
pop_state_(si,old_end)1381*7dd7cddfSDavid du Colombier pop_state_(si, old_end)
1382*7dd7cddfSDavid du Colombier 	State_info *si;
1383*7dd7cddfSDavid du Colombier 	Lex_state *old_end;
1384*7dd7cddfSDavid du Colombier {
1385*7dd7cddfSDavid du Colombier 	Lex_state *old_base = si->base;
1386*7dd7cddfSDavid du Colombier 
1387*7dd7cddfSDavid du Colombier 	si->base = old_end->ls_info.base - STATE_BSIZE;
1388*7dd7cddfSDavid du Colombier 	si->end = old_end->ls_info.base;
1389*7dd7cddfSDavid du Colombier 
1390*7dd7cddfSDavid du Colombier 	afree(old_base, ATEMP);
1391*7dd7cddfSDavid du Colombier 
1392*7dd7cddfSDavid du Colombier 	return si->base + STATE_BSIZE - 1;;
1393*7dd7cddfSDavid du Colombier }
1394