1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * KornShell  lexical analyzer
23*4887Schin  *
24*4887Schin  * Written by David Korn
25*4887Schin  * AT&T Labs
26*4887Schin  *
27*4887Schin  */
28*4887Schin 
29*4887Schin #include	<ast.h>
30*4887Schin #include	<stak.h>
31*4887Schin #include	<fcin.h>
32*4887Schin #include	<nval.h>
33*4887Schin #include	"FEATURE/options"
34*4887Schin 
35*4887Schin #if KSHELL
36*4887Schin #   include	"defs.h"
37*4887Schin #else
38*4887Schin #   include	<shell.h>
39*4887Schin #   define	nv_getval(np)	((np)->nvalue)
40*4887Schin     Shell_t sh  =  {1};
41*4887Schin #endif /* KSHELL */
42*4887Schin 
43*4887Schin #include	"argnod.h"
44*4887Schin #include	"test.h"
45*4887Schin #include	"lexstates.h"
46*4887Schin #include	"io.h"
47*4887Schin 
48*4887Schin #define TEST_RE		3
49*4887Schin #define SYNBAD		3	/* exit value for syntax errors */
50*4887Schin #define STACK_ARRAY	3	/* size of depth match stack growth */
51*4887Schin 
52*4887Schin #if _lib_iswblank < 0	/* set in lexstates.h to enable this code */
53*4887Schin 
54*4887Schin int
55*4887Schin local_iswblank(wchar_t wc)
56*4887Schin {
57*4887Schin 	static int      initialized;
58*4887Schin 	static wctype_t wt;
59*4887Schin 
60*4887Schin 	if (!initialized)
61*4887Schin 	{
62*4887Schin 		initialized = 1;
63*4887Schin 		wt = wctype("blank");
64*4887Schin 	}
65*4887Schin 	return(iswctype(wc, wt));
66*4887Schin }
67*4887Schin 
68*4887Schin #endif
69*4887Schin 
70*4887Schin /*
71*4887Schin  * This structure allows for arbitrary depth nesting of (...), {...}, [...]
72*4887Schin  */
73*4887Schin struct lexstate
74*4887Schin {
75*4887Schin 	char		incase;		/* 1 for case pattern, 2 after case */
76*4887Schin 	char		intest;		/* 1 inside [[...]] */
77*4887Schin 	char		testop1;	/* 1 when unary test op legal */
78*4887Schin 	char		testop2;	/* 1 when binary test op legal */
79*4887Schin 	char		reservok;	/* >0 for reserved word legal */
80*4887Schin 	char		skipword;	/* next word can't be reserved */
81*4887Schin 	char		last_quote;	/* last multi-line quote character */
82*4887Schin 	char		comp_assign;	/* inside compound assignment */
83*4887Schin };
84*4887Schin 
85*4887Schin struct lexdata
86*4887Schin {
87*4887Schin 	char		nocopy;
88*4887Schin 	char		paren;
89*4887Schin 	char		dolparen;
90*4887Schin 	char		nest;
91*4887Schin 	char		docword;
92*4887Schin 	char 		*docend;
93*4887Schin 	char		noarg;
94*4887Schin 	char		balance;
95*4887Schin 	char		warn;
96*4887Schin 	char		message;
97*4887Schin 	char		arith;
98*4887Schin 	char 		*first;
99*4887Schin 	int		level;
100*4887Schin 	int		lastc;
101*4887Schin 	int		lex_max;
102*4887Schin 	int		*lex_match;
103*4887Schin 	int		lex_state;
104*4887Schin #if SHOPT_KIA
105*4887Schin 	off_t		kiaoff;
106*4887Schin #endif
107*4887Schin };
108*4887Schin 
109*4887Schin #define _SHLEX_PRIVATE \
110*4887Schin 	struct lexdata  _lexd; \
111*4887Schin 	struct lexstate  _lex;
112*4887Schin 
113*4887Schin #include	"shlex.h"
114*4887Schin 
115*4887Schin #define lexd	lp->_lexd
116*4887Schin #define lex	lp->_lex
117*4887Schin #undef shlex
118*4887Schin #define shlex	lp->_shlex
119*4887Schin 
120*4887Schin 
121*4887Schin #define	pushlevel(c,s)	((lexd.level>=lexd.lex_max?stack_grow(lp):1) &&\
122*4887Schin 				((lexd.lex_match[lexd.level++]=lexd.lastc),\
123*4887Schin 				lexd.lastc=(((s)<<CHAR_BIT)|(c))))
124*4887Schin #define oldmode()	(lexd.lastc>>CHAR_BIT)
125*4887Schin #define endchar()	(lexd.lastc&0xff)
126*4887Schin #define setchar(c)	(lexd.lastc = ((lexd.lastc&~0xff)|(c)))
127*4887Schin #define poplevel()	(lexd.lastc=lexd.lex_match[--lexd.level])
128*4887Schin 
129*4887Schin static char		*fmttoken(Lex_t*, int, char*);
130*4887Schin #ifdef SF_BUFCONST
131*4887Schin     static int          alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
132*4887Schin #else
133*4887Schin     static int 		alias_exceptf(Sfio_t*, int, Sfdisc_t*);
134*4887Schin #endif
135*4887Schin static void		setupalias(Lex_t*,const char*, Namval_t*);
136*4887Schin static int		comsub(Lex_t*);
137*4887Schin static void		nested_here(Lex_t*);
138*4887Schin static int		here_copy(Lex_t*, struct ionod*);
139*4887Schin static int 		stack_grow(Lex_t*);
140*4887Schin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL };
141*4887Schin 
142*4887Schin #if SHOPT_KIA
143*4887Schin 
144*4887Schin static void refvar(int type)
145*4887Schin {
146*4887Schin 	register Shell_t *shp = sh_getinterp();
147*4887Schin 	register Lex_t *lp = (Lex_t*)shp->lex_context;
148*4887Schin 	off_t off = (fcseek(0)-(type+1))-(lexd.first?lexd.first:fcfirst());
149*4887Schin 	unsigned long r;
150*4887Schin 	if(lexd.first)
151*4887Schin 	{
152*4887Schin 		off = (fcseek(0)-(type+1)) - lexd.first;
153*4887Schin 		r=kiaentity(lexd.first+lexd.kiaoff+type,off-lexd.kiaoff,'v',-1,-1,shlex.current,'v',0,"");
154*4887Schin 	}
155*4887Schin 	else
156*4887Schin 	{
157*4887Schin 		int n,offset = staktell();
158*4887Schin 		char *savptr,*begin;
159*4887Schin 		off = offset + (fcseek(0)-(type+1)) - fcfirst();
160*4887Schin 		if(lexd.kiaoff < offset)
161*4887Schin 		{
162*4887Schin 			/* variable starts on stak, copy remainder */
163*4887Schin 			if(off>offset)
164*4887Schin 				stakwrite(fcfirst()+type,off-offset);
165*4887Schin 			n = staktell()-lexd.kiaoff;
166*4887Schin 			begin = stakptr(lexd.kiaoff);
167*4887Schin 		}
168*4887Schin 		else
169*4887Schin 		{
170*4887Schin 			/* variable in data buffer */
171*4887Schin 			begin = fcfirst()+(type+lexd.kiaoff-offset);
172*4887Schin 			n = off-lexd.kiaoff;
173*4887Schin 		}
174*4887Schin 		savptr = stakfreeze(0);
175*4887Schin 		r=kiaentity(begin,n,'v',-1,-1,shlex.current,'v',0,"");
176*4887Schin 		stakset(savptr,offset);
177*4887Schin 	}
178*4887Schin 	sfprintf(shlex.kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",shlex.current,r,shp->inlineno,shp->inlineno);
179*4887Schin }
180*4887Schin #endif /* SHOPT_KIA */
181*4887Schin 
182*4887Schin /*
183*4887Schin  * This routine gets called when reading across a buffer boundary
184*4887Schin  * If lexd.nocopy is off, then current token is saved on the stack
185*4887Schin  */
186*4887Schin static void lex_advance(Sfio_t *iop, const char *buff, register int size)
187*4887Schin {
188*4887Schin 	register Shell_t *shp = sh_getinterp();
189*4887Schin 	register Lex_t *lp = (Lex_t*)shp->lex_context;
190*4887Schin 	register Sfio_t *log= shp->funlog;
191*4887Schin #if KSHELL
192*4887Schin 	/* write to history file and to stderr if necessary */
193*4887Schin 	if(iop && !sfstacked(iop))
194*4887Schin 	{
195*4887Schin 		if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
196*4887Schin 			log = shp->hist_ptr->histfp;
197*4887Schin 		sfwrite(log, (void*)buff, size);
198*4887Schin 		if(sh_isstate(SH_VERBOSE))
199*4887Schin 			sfwrite(sfstderr, buff, size);
200*4887Schin 	}
201*4887Schin #endif
202*4887Schin 	if(lexd.nocopy)
203*4887Schin 		return;
204*4887Schin 	if(lexd.first)
205*4887Schin 	{
206*4887Schin 		size -= (lexd.first-(char*)buff);
207*4887Schin 		buff = lexd.first;
208*4887Schin 		if(!lexd.noarg)
209*4887Schin 			shlex.arg = (struct argnod*)stakseek(ARGVAL);
210*4887Schin #if SHOPT_KIA
211*4887Schin 		lexd.kiaoff += ARGVAL;
212*4887Schin #endif /* SHOPT_KIA */
213*4887Schin 	}
214*4887Schin 	if(size>0 && (shlex.arg||lexd.noarg))
215*4887Schin 	{
216*4887Schin 		stakwrite(buff,size);
217*4887Schin 		lexd.first = 0;
218*4887Schin 	}
219*4887Schin }
220*4887Schin 
221*4887Schin /*
222*4887Schin  * fill up another input buffer
223*4887Schin  * preserves lexical state
224*4887Schin  */
225*4887Schin static int lexfill(void)
226*4887Schin {
227*4887Schin 	Shell_t *shp = sh_getinterp();
228*4887Schin 	register int c;
229*4887Schin 	register Lex_t *lp = (Lex_t*)shp->lex_context;
230*4887Schin 	struct shlex_t savelex;
231*4887Schin 	struct lexdata savedata;
232*4887Schin 	struct lexstate savestate;
233*4887Schin 	struct argnod *ap;
234*4887Schin 	int aok;
235*4887Schin 	savelex = shlex;
236*4887Schin 	savedata = lexd;
237*4887Schin 	savestate = lex;
238*4887Schin 	ap = shlex.arg;
239*4887Schin 	c = fcfill();
240*4887Schin 	if(ap)
241*4887Schin 		shlex.arg = ap;
242*4887Schin 	lex = savestate;
243*4887Schin 	lexd = savedata;
244*4887Schin 	lexd.first = 0;
245*4887Schin 	aok= shlex.aliasok;
246*4887Schin 	ap = shlex.arg;
247*4887Schin 	shlex = savelex;
248*4887Schin 	shlex.arg = ap;
249*4887Schin 	shlex.aliasok = aok;
250*4887Schin 	return(c);
251*4887Schin }
252*4887Schin 
253*4887Schin /*
254*4887Schin  * mode=1 for reinitialization
255*4887Schin  */
256*4887Schin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode)
257*4887Schin {
258*4887Schin 	fcnotify(lex_advance);
259*4887Schin 	if(!lp)
260*4887Schin 	{
261*4887Schin 		lp = (Lex_t*)newof(0,Lex_t,1,0);
262*4887Schin 		lp->_shlex.sh = sp;
263*4887Schin 	}
264*4887Schin 	lex.intest = lex.incase = lex.skipword = lexd.warn = 0;
265*4887Schin 	lex.comp_assign = 0;
266*4887Schin 	lex.reservok = 1;
267*4887Schin 	if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC))
268*4887Schin 		lexd.warn=1;
269*4887Schin 	if(!mode)
270*4887Schin 	{
271*4887Schin 		lexd.noarg = lexd.level= lexd.dolparen = 0;
272*4887Schin 		lexd.nocopy = lexd.docword = lexd.nest = lexd.paren = 0;
273*4887Schin 	}
274*4887Schin 	shlex.comsub = 0;
275*4887Schin 	return(lp);
276*4887Schin }
277*4887Schin 
278*4887Schin #ifdef DBUG
279*4887Schin extern int lextoken(void);
280*4887Schin int sh_lex(void)
281*4887Schin {
282*4887Schin 	Shell_t *shp = sh_getinterp();
283*4887Schin 	register Lex_t *lp = (Lex_t*)shp->lex_context;
284*4887Schin 	register int flag;
285*4887Schin 	char *quoted, *macro, *split, *expand;
286*4887Schin 	char tokstr[3];
287*4887Schin 	register int tok = lextoken();
288*4887Schin 	quoted = macro = split = expand = "";
289*4887Schin 	if(tok==0 && (flag=shlex.arg->argflag))
290*4887Schin 	{
291*4887Schin 		if(flag&ARG_MAC)
292*4887Schin 			macro = "macro:";
293*4887Schin 		if(flag&ARG_EXP)
294*4887Schin 			expand = "expand:";
295*4887Schin 		if(flag&ARG_QUOTED)
296*4887Schin 			quoted = "quoted:";
297*4887Schin 	}
298*4887Schin 	sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted,
299*4887Schin 		macro, split, expand, fmttoken(lp,tok,tokstr));
300*4887Schin 	return(tok);
301*4887Schin }
302*4887Schin #define sh_lex	lextoken
303*4887Schin #endif
304*4887Schin 
305*4887Schin /*
306*4887Schin  * Get the next word and put it on the top of the stak
307*4887Schin  * A pointer to the current word is stored in shlex.arg
308*4887Schin  * Returns the token type
309*4887Schin  */
310*4887Schin int sh_lex(void)
311*4887Schin {
312*4887Schin 	register Shell_t *shp = sh_getinterp();
313*4887Schin 	register const char	*state;
314*4887Schin 	register int	n, c, mode=ST_BEGIN, wordflags=0;
315*4887Schin 	register Lex_t *lp = (Lex_t*)shp->lex_context;
316*4887Schin 	int		inlevel=lexd.level, assignment=0, ingrave=0;
317*4887Schin 	Sfio_t *sp;
318*4887Schin #if SHOPT_MULTIBYTE
319*4887Schin 	LEN=1;
320*4887Schin #endif /* SHOPT_MULTIBYTE */
321*4887Schin 	if(lexd.paren)
322*4887Schin 	{
323*4887Schin 		lexd.paren = 0;
324*4887Schin 		return(shlex.token=LPAREN);
325*4887Schin 	}
326*4887Schin 	if(lex.incase)
327*4887Schin 		shlex.assignok = 0;
328*4887Schin 	else
329*4887Schin 		shlex.assignok |= lex.reservok;
330*4887Schin 	if(lex.comp_assign==2)
331*4887Schin 		lex.comp_assign = lex.reservok = 0;
332*4887Schin 	lexd.arith = (lexd.nest==1);
333*4887Schin 	if(lexd.nest)
334*4887Schin 	{
335*4887Schin 		pushlevel(lexd.nest,ST_NONE);
336*4887Schin 		lexd.nest = 0;
337*4887Schin 		mode = lexd.lex_state;
338*4887Schin 	}
339*4887Schin 	else if(lexd.docword)
340*4887Schin 	{
341*4887Schin 		if(fcgetc(c)=='-' || c=='#')
342*4887Schin 		{
343*4887Schin 			lexd.docword++;
344*4887Schin 			shlex.digits=(c=='#'?3:1);
345*4887Schin 		}
346*4887Schin 		else if(c=='<')
347*4887Schin 		{
348*4887Schin 			shlex.digits=2;
349*4887Schin 			lexd.docword=0;
350*4887Schin 		}
351*4887Schin 		else if(c>0)
352*4887Schin 			fcseek(-1);
353*4887Schin 	}
354*4887Schin 	if(!lexd.dolparen)
355*4887Schin 	{
356*4887Schin 		shlex.arg = 0;
357*4887Schin 		if(mode!=ST_BEGIN)
358*4887Schin 			lexd.first = fcseek(0);
359*4887Schin 		else
360*4887Schin 			lexd.first = 0;
361*4887Schin 	}
362*4887Schin 	shlex.lastline = sh.inlineno;
363*4887Schin 	while(1)
364*4887Schin 	{
365*4887Schin 		/* skip over characters in the current state */
366*4887Schin 		state = sh_lexstates[mode];
367*4887Schin 		while((n=STATE(state,c))==0);
368*4887Schin 		switch(n)
369*4887Schin 		{
370*4887Schin 			case S_BREAK:
371*4887Schin 				fcseek(-1);
372*4887Schin 				goto breakloop;
373*4887Schin 			case S_EOF:
374*4887Schin 				sp = fcfile();
375*4887Schin 				if((n=lexfill()) > 0)
376*4887Schin 				{
377*4887Schin 					fcseek(-1);
378*4887Schin 					continue;
379*4887Schin 				}
380*4887Schin 				/* check for zero byte in file */
381*4887Schin 				if(n==0 && fcfile())
382*4887Schin 				{
383*4887Schin 					if(shp->readscript)
384*4887Schin 					{
385*4887Schin 						char *cp = error_info.id;
386*4887Schin 						errno = ENOEXEC;
387*4887Schin 						error_info.id = shp->readscript;
388*4887Schin 						errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp);
389*4887Schin 					}
390*4887Schin 					else
391*4887Schin 					{
392*4887Schin 						shlex.token = -1;
393*4887Schin 						sh_syntax();
394*4887Schin 					}
395*4887Schin 				}
396*4887Schin 				/* end-of-file */
397*4887Schin 				if(mode==ST_BEGIN)
398*4887Schin 					return(shlex.token=EOFSYM);
399*4887Schin 				if(mode >ST_NORM && lexd.level>0)
400*4887Schin 				{
401*4887Schin 					switch(c=endchar())
402*4887Schin 					{
403*4887Schin 						case '$':
404*4887Schin 							if(mode==ST_LIT)
405*4887Schin 							{
406*4887Schin 								c = '\'';
407*4887Schin 								break;
408*4887Schin 							}
409*4887Schin 							mode = oldmode();
410*4887Schin 							poplevel();
411*4887Schin 							continue;
412*4887Schin 						case RBRACT:
413*4887Schin 							c = LBRACT;
414*4887Schin 							break;
415*4887Schin 						case 1:	/* for ((...)) */
416*4887Schin 						case RPAREN:
417*4887Schin 							c = LPAREN;
418*4887Schin 							break;
419*4887Schin 						default:
420*4887Schin 							c = LBRACE;
421*4887Schin 							break;
422*4887Schin 						case '"': case '`': case '\'':
423*4887Schin 							lexd.balance = c;
424*4887Schin 							break;
425*4887Schin 					}
426*4887Schin 					if(sp && !(sfset(sp,0,0)&SF_STRING))
427*4887Schin 					{
428*4887Schin 						shlex.lasttok = c;
429*4887Schin 						shlex.token = EOFSYM;
430*4887Schin 						sh_syntax();
431*4887Schin 					}
432*4887Schin 					lexd.balance = c;
433*4887Schin 				}
434*4887Schin 				goto breakloop;
435*4887Schin 			case S_COM:
436*4887Schin 				/* skip one or more comment line(s) */
437*4887Schin 				lex.reservok = !lex.intest;
438*4887Schin 				if((n=lexd.nocopy) && lexd.dolparen)
439*4887Schin 					lexd.nocopy--;
440*4887Schin 				do
441*4887Schin 				{
442*4887Schin 					while(fcgetc(c)>0 && c!='\n');
443*4887Schin 					if(c<=0 || shlex.heredoc)
444*4887Schin 						break;
445*4887Schin 					while(shp->inlineno++,fcpeek(0)=='\n')
446*4887Schin 						fcseek(1);
447*4887Schin 					while(state[c=fcpeek(0)]==0)
448*4887Schin 						fcseek(1);
449*4887Schin 				}
450*4887Schin 				while(c=='#');
451*4887Schin 				lexd.nocopy = n;
452*4887Schin 				if(c<0)
453*4887Schin 					return(shlex.token=EOFSYM);
454*4887Schin 				n = S_NLTOK;
455*4887Schin 				shp->inlineno--;
456*4887Schin 				/* FALL THRU */
457*4887Schin 			case S_NLTOK:
458*4887Schin 				/* check for here-document */
459*4887Schin 				if(shlex.heredoc)
460*4887Schin 				{
461*4887Schin 					if(!lexd.dolparen)
462*4887Schin 						lexd.nocopy++;
463*4887Schin 					c = shp->inlineno;
464*4887Schin 					if(here_copy(lp,shlex.heredoc)<=0 && shlex.lasttok)
465*4887Schin 					{
466*4887Schin 						shlex.lasttok = IODOCSYM;
467*4887Schin 						shlex.token = EOFSYM;
468*4887Schin 						shlex.lastline = c;
469*4887Schin 						sh_syntax();
470*4887Schin 					}
471*4887Schin 					if(!lexd.dolparen)
472*4887Schin 						lexd.nocopy--;
473*4887Schin 					shlex.heredoc = 0;
474*4887Schin 				}
475*4887Schin 				lex.reservok = !lex.intest;
476*4887Schin 				lex.skipword = 0;
477*4887Schin 				/* FALL THRU */
478*4887Schin 			case S_NL:
479*4887Schin 				/* skip over new-lines */
480*4887Schin 				lex.last_quote = 0;
481*4887Schin 				while(shp->inlineno++,fcget()=='\n');
482*4887Schin 				fcseek(-1);
483*4887Schin 				if(n==S_NLTOK)
484*4887Schin 				{
485*4887Schin 					lex.comp_assign = 0;
486*4887Schin 					return(shlex.token='\n');
487*4887Schin 				}
488*4887Schin 			case S_BLNK:
489*4887Schin 				if(lex.incase<=TEST_RE)
490*4887Schin 					continue;
491*4887Schin 				/* implicit RPAREN for =~ test operator */
492*4887Schin 				if(inlevel+1==lexd.level)
493*4887Schin 				{
494*4887Schin 					fcseek(-1);
495*4887Schin 					c = RPAREN;
496*4887Schin 					goto do_pop;
497*4887Schin 				}
498*4887Schin 				continue;
499*4887Schin 			case S_OP:
500*4887Schin 				/* return operator token */
501*4887Schin 				if(c=='<' || c=='>')
502*4887Schin 				{
503*4887Schin 					if(lex.testop2)
504*4887Schin 						lex.testop2 = 0;
505*4887Schin 					else
506*4887Schin 					{
507*4887Schin 						shlex.digits = (c=='>');
508*4887Schin 						lex.skipword = 1;
509*4887Schin 						shlex.aliasok = lex.reservok;
510*4887Schin 						lex.reservok = 0;
511*4887Schin 					}
512*4887Schin 				}
513*4887Schin 				else
514*4887Schin 				{
515*4887Schin 					lex.reservok = !lex.intest;
516*4887Schin 					if(c==RPAREN)
517*4887Schin 					{
518*4887Schin 						if(!lexd.dolparen)
519*4887Schin 							lex.incase = 0;
520*4887Schin 						return(shlex.token=c);
521*4887Schin 					}
522*4887Schin 					lex.testop1 = lex.intest;
523*4887Schin 				}
524*4887Schin 				if(fcgetc(n)>0)
525*4887Schin 					fcseek(-1);
526*4887Schin 				if(state[n]==S_OP || n=='#')
527*4887Schin 				{
528*4887Schin 					if(n==c)
529*4887Schin 					{
530*4887Schin 						if(c=='<')
531*4887Schin 							lexd.docword=1;
532*4887Schin 						else if(n==LPAREN)
533*4887Schin 						{
534*4887Schin 							lexd.nest=1;
535*4887Schin 							shlex.lastline = shp->inlineno;
536*4887Schin 							lexd.lex_state = ST_NESTED;
537*4887Schin 							fcseek(1);
538*4887Schin 							return(sh_lex());
539*4887Schin 						}
540*4887Schin 						c  |= SYMREP;
541*4887Schin 					}
542*4887Schin 					else if(c=='(' || c==')')
543*4887Schin 						return(shlex.token=c);
544*4887Schin 					else if(c=='&')
545*4887Schin 					{
546*4887Schin #if SHOPT_BASH
547*4887Schin 						if(!sh_isoption(SH_POSIX) && n=='>')
548*4887Schin 						{
549*4887Schin 							shlex.digits = -1;
550*4887Schin 							c = '>';
551*4887Schin 						}
552*4887Schin 						else
553*4887Schin #endif
554*4887Schin 							n = 0;
555*4887Schin 					}
556*4887Schin 					else if(n=='&')
557*4887Schin 						c  |= SYMAMP;
558*4887Schin 					else if(c!='<' && c!='>')
559*4887Schin 						n = 0;
560*4887Schin 					else if(n==LPAREN)
561*4887Schin 					{
562*4887Schin 						c  |= SYMLPAR;
563*4887Schin 						lex.reservok = 1;
564*4887Schin 						lex.skipword = 0;
565*4887Schin 					}
566*4887Schin 					else if(n=='|')
567*4887Schin 						c  |= SYMPIPE;
568*4887Schin 					else if(c=='<' && n=='>')
569*4887Schin 						c = IORDWRSYM;
570*4887Schin 					else if(n=='#' && (c=='<'||c=='>'))
571*4887Schin 						c |= SYMSHARP;
572*4887Schin 					else
573*4887Schin 						n = 0;
574*4887Schin 					if(n)
575*4887Schin 					{
576*4887Schin 						fcseek(1);
577*4887Schin 						lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM);
578*4887Schin 					}
579*4887Schin 					else
580*4887Schin 					{
581*4887Schin 						if((n=fcpeek(0))!=RPAREN && n!=LPAREN && lexd.warn)
582*4887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n);
583*4887Schin 					}
584*4887Schin 				}
585*4887Schin 				if(c==LPAREN && lex.comp_assign && !lex.intest && !lex.incase)
586*4887Schin 					lex.comp_assign = 2;
587*4887Schin 				else
588*4887Schin 					lex.comp_assign = 0;
589*4887Schin 				return(shlex.token=c);
590*4887Schin 			case S_ESC:
591*4887Schin 				/* check for \<new-line> */
592*4887Schin 				fcgetc(n);
593*4887Schin 				c=2;
594*4887Schin #if SHOPT_CRNL
595*4887Schin 				if(n=='\r')
596*4887Schin 				{
597*4887Schin 					if(fcgetc(n)=='\n')
598*4887Schin 						c=3;
599*4887Schin 					else
600*4887Schin 					{
601*4887Schin 						n='\r';
602*4887Schin 						fcseek(-1);
603*4887Schin 					}
604*4887Schin 				}
605*4887Schin #endif /* SHOPT_CRNL */
606*4887Schin 				if(n=='\n')
607*4887Schin 				{
608*4887Schin 					Sfio_t *sp;
609*4887Schin 					struct argnod *ap;
610*4887Schin 					shp->inlineno++;
611*4887Schin 					/* synchronize */
612*4887Schin 					if(!(sp=fcfile()))
613*4887Schin 						state=fcseek(0);
614*4887Schin 					fcclose();
615*4887Schin 					ap = shlex.arg;
616*4887Schin 					if(sp)
617*4887Schin 						fcfopen(sp);
618*4887Schin 					else
619*4887Schin 						fcsopen((char*)state);
620*4887Schin 					/* remove \new-line */
621*4887Schin 					n = staktell()-c;
622*4887Schin 					stakseek(n);
623*4887Schin 					shlex.arg = ap;
624*4887Schin 					if(n<=ARGVAL)
625*4887Schin 					{
626*4887Schin 						mode = 0;
627*4887Schin 						lexd.first = 0;
628*4887Schin 					}
629*4887Schin 					continue;
630*4887Schin 				}
631*4887Schin 				wordflags |= ARG_QUOTED;
632*4887Schin 				if(mode==ST_DOL)
633*4887Schin 					goto err;
634*4887Schin #ifndef STR_MAXIMAL
635*4887Schin 				else if(mode==ST_NESTED && lexd.warn &&
636*4887Schin 					endchar()==RBRACE &&
637*4887Schin 					sh_lexstates[ST_DOL][n]==S_DIG
638*4887Schin 				)
639*4887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n);
640*4887Schin #endif /* STR_MAXIMAL */
641*4887Schin 				break;
642*4887Schin 			case S_NAME:
643*4887Schin 				if(!lex.skipword)
644*4887Schin 					lex.reservok *= 2;
645*4887Schin 				/* FALL THRU */
646*4887Schin 			case S_TILDE:
647*4887Schin 			case S_RES:
648*4887Schin 				if(!lexd.dolparen)
649*4887Schin 					lexd.first = fcseek(0)-LEN;
650*4887Schin 				else if(lexd.docword)
651*4887Schin 					lexd.docend = fcseek(0)-LEN;
652*4887Schin 				mode = ST_NAME;
653*4887Schin 				if(c=='.')
654*4887Schin 					fcseek(-1);
655*4887Schin 				if(n!=S_TILDE)
656*4887Schin 					continue;
657*4887Schin 				fcgetc(n);
658*4887Schin 				if(n>0)
659*4887Schin 					fcseek(-1);
660*4887Schin 				if(n==LPAREN)
661*4887Schin 					goto epat;
662*4887Schin 				wordflags = ARG_MAC;
663*4887Schin 				mode = ST_NORM;
664*4887Schin 				continue;
665*4887Schin 			case S_REG:
666*4887Schin 				if(mode==ST_BEGIN)
667*4887Schin 				{
668*4887Schin 					/* skip new-line joining */
669*4887Schin 					if(c=='\\' && fcpeek(0)=='\n')
670*4887Schin 					{
671*4887Schin 						shp->inlineno++;
672*4887Schin 						fcseek(1);
673*4887Schin 						continue;
674*4887Schin 					}
675*4887Schin 					fcseek(-1);
676*4887Schin 					if(!lexd.dolparen)
677*4887Schin 						lexd.first = fcseek(0);
678*4887Schin 					else if(lexd.docword)
679*4887Schin 						lexd.docend = fcseek(0);
680*4887Schin 					if(c=='[' && shlex.assignok>=SH_ASSIGN)
681*4887Schin 					{
682*4887Schin 						mode = ST_NAME;
683*4887Schin 						continue;
684*4887Schin 					}
685*4887Schin 				}
686*4887Schin 				mode = ST_NORM;
687*4887Schin 				continue;
688*4887Schin 			case S_LIT:
689*4887Schin 				if(oldmode()==ST_NONE)	/*  in ((...)) */
690*4887Schin 				{
691*4887Schin 					if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']')
692*4887Schin 					{
693*4887Schin 						if(fcpeek(1)=='\'')
694*4887Schin 							fcseek(2);
695*4887Schin 					}
696*4887Schin 					continue;
697*4887Schin 				}
698*4887Schin 				wordflags |= ARG_QUOTED;
699*4887Schin 				if(mode==ST_DOL)
700*4887Schin 				{
701*4887Schin 					if(endchar()!='$')
702*4887Schin 						goto err;
703*4887Schin 					if(oldmode()==ST_QUOTE) /* $' within "" or `` */
704*4887Schin 					{
705*4887Schin 						if(lexd.warn)
706*4887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
707*4887Schin 						mode = ST_LIT;
708*4887Schin 					}
709*4887Schin 				}
710*4887Schin 				if(mode!=ST_LIT)
711*4887Schin 				{
712*4887Schin 					if(lexd.warn && lex.last_quote && shp->inlineno > shlex.lastline)
713*4887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,shlex.lastline,lex.last_quote);
714*4887Schin 					lex.last_quote = 0;
715*4887Schin 					shlex.lastline = shp->inlineno;
716*4887Schin 					if(mode!=ST_DOL)
717*4887Schin 						pushlevel('\'',mode);
718*4887Schin 					mode = ST_LIT;
719*4887Schin 					continue;
720*4887Schin 				}
721*4887Schin 				/* check for multi-line single-quoted string */
722*4887Schin 				else if(shp->inlineno > shlex.lastline)
723*4887Schin 					lex.last_quote = '\'';
724*4887Schin 				mode = oldmode();
725*4887Schin 				poplevel();
726*4887Schin 				break;
727*4887Schin 			case S_ESC2:
728*4887Schin 				/* \ inside '' */
729*4887Schin 				if(endchar()=='$')
730*4887Schin 				{
731*4887Schin 					fcgetc(n);
732*4887Schin 					if(n=='\n')
733*4887Schin 						shp->inlineno++;
734*4887Schin 				}
735*4887Schin 				continue;
736*4887Schin 			case S_GRAVE:
737*4887Schin 				if(lexd.warn && (mode!=ST_QUOTE || endchar()!='`'))
738*4887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno);
739*4887Schin 				wordflags |=(ARG_MAC|ARG_EXP);
740*4887Schin 				if(mode==ST_QUOTE)
741*4887Schin 					ingrave = !ingrave;
742*4887Schin 				/* FALL THRU */
743*4887Schin 			case S_QUOTE:
744*4887Schin 				if(oldmode()==ST_NONE && lexd.arith)	/*  in ((...)) */
745*4887Schin 					continue;
746*4887Schin 				if(n==S_QUOTE)
747*4887Schin 					wordflags |=ARG_QUOTED;
748*4887Schin 				if(mode!=ST_QUOTE)
749*4887Schin 				{
750*4887Schin 					if(c!='"' || mode!=ST_QNEST)
751*4887Schin 					{
752*4887Schin 						if(lexd.warn && lex.last_quote && shp->inlineno > shlex.lastline)
753*4887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,shlex.lastline,lex.last_quote);
754*4887Schin 						lex.last_quote=0;
755*4887Schin 						shlex.lastline = shp->inlineno;
756*4887Schin 						pushlevel(c,mode);
757*4887Schin 					}
758*4887Schin 					ingrave = (c=='`');
759*4887Schin 					mode = ST_QUOTE;
760*4887Schin 					continue;
761*4887Schin 				}
762*4887Schin 				else if((n=endchar())==c)
763*4887Schin 				{
764*4887Schin 					if(shp->inlineno > shlex.lastline)
765*4887Schin 						lex.last_quote = c;
766*4887Schin 					mode = oldmode();
767*4887Schin 					poplevel();
768*4887Schin 				}
769*4887Schin 				else if(c=='"' && n==RBRACE)
770*4887Schin 					mode = ST_QNEST;
771*4887Schin 				break;
772*4887Schin 			case S_DOL:
773*4887Schin 				/* don't check syntax inside `` */
774*4887Schin 				if(mode==ST_QUOTE && ingrave)
775*4887Schin 					continue;
776*4887Schin #if SHOPT_KIA
777*4887Schin 				if(lexd.first)
778*4887Schin 					lexd.kiaoff = fcseek(0)-lexd.first;
779*4887Schin 				else
780*4887Schin 					lexd.kiaoff = staktell()+fcseek(0)-fcfirst();
781*4887Schin #endif /* SHOPT_KIA */
782*4887Schin 				pushlevel('$',mode);
783*4887Schin 				mode = ST_DOL;
784*4887Schin 				continue;
785*4887Schin 			case S_PAR:
786*4887Schin 				wordflags |= ARG_MAC;
787*4887Schin 				mode = oldmode();
788*4887Schin 				poplevel();
789*4887Schin 				fcseek(-1);
790*4887Schin 				wordflags |= comsub(lp);
791*4887Schin 				continue;
792*4887Schin 			case S_RBRA:
793*4887Schin 				if((n=endchar()) == '$')
794*4887Schin 					goto err;
795*4887Schin 				if(mode!=ST_QUOTE || n==RBRACE)
796*4887Schin 				{
797*4887Schin 					mode = oldmode();
798*4887Schin 					poplevel();
799*4887Schin 				}
800*4887Schin 				break;
801*4887Schin 			case S_EDOL:
802*4887Schin 				/* end $identifier */
803*4887Schin #if SHOPT_KIA
804*4887Schin 				if(shlex.kiafile)
805*4887Schin 					refvar(0);
806*4887Schin #endif /* SHOPT_KIA */
807*4887Schin 				if(lexd.warn && c==LBRACT)
808*4887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno);
809*4887Schin 				fcseek(-1);
810*4887Schin 				mode = oldmode();
811*4887Schin 				poplevel();
812*4887Schin 				break;
813*4887Schin 			case S_DOT:
814*4887Schin 				/* make sure next character is alpha */
815*4887Schin 				if(fcgetc(n)>0)
816*4887Schin 					fcseek(-1);
817*4887Schin 				if(isaletter(n) || n==LBRACT)
818*4887Schin 					continue;
819*4887Schin 				if(mode==ST_NAME)
820*4887Schin 				{
821*4887Schin 					if(n=='=')
822*4887Schin 						continue;
823*4887Schin 					break;
824*4887Schin 				}
825*4887Schin 				else if(n==RBRACE)
826*4887Schin 					continue;
827*4887Schin 				if(isastchar(n))
828*4887Schin 					continue;
829*4887Schin 				goto err;
830*4887Schin 			case S_SPC1:
831*4887Schin 				wordflags |= ARG_MAC;
832*4887Schin 				if(endchar()==RBRACE)
833*4887Schin 				{
834*4887Schin 					setchar(c);
835*4887Schin 					continue;
836*4887Schin 				}
837*4887Schin 				/* FALL THRU */
838*4887Schin 			case S_ALP:
839*4887Schin 				if(c=='.' && endchar()=='$')
840*4887Schin 					goto err;
841*4887Schin 			case S_SPC2:
842*4887Schin 			case S_DIG:
843*4887Schin 				wordflags |= ARG_MAC;
844*4887Schin 				switch(endchar())
845*4887Schin 				{
846*4887Schin 					case '$':
847*4887Schin 						if(n==S_ALP) /* $identifier */
848*4887Schin 							mode = ST_DOLNAME;
849*4887Schin 						else
850*4887Schin 						{
851*4887Schin 							mode = oldmode();
852*4887Schin 							poplevel();
853*4887Schin 						}
854*4887Schin 						break;
855*4887Schin #if SHOPT_TYPEDEF
856*4887Schin 					case '@':
857*4887Schin #endif /* SHOPT_TYPEDEF */
858*4887Schin 					case '!':
859*4887Schin 						if(n!=S_ALP)
860*4887Schin 							goto dolerr;
861*4887Schin 					case '#':
862*4887Schin 					case RBRACE:
863*4887Schin 						if(n==S_ALP)
864*4887Schin 						{
865*4887Schin 							setchar(RBRACE);
866*4887Schin 							if(c=='.')
867*4887Schin 								fcseek(-1);
868*4887Schin 							mode = ST_BRACE;
869*4887Schin 						}
870*4887Schin 						else
871*4887Schin 						{
872*4887Schin 							if(fcgetc(c)>0)
873*4887Schin 								fcseek(-1);
874*4887Schin 							if(state[c]==S_ALP)
875*4887Schin 								goto err;
876*4887Schin 							if(n==S_DIG)
877*4887Schin 								setchar('0');
878*4887Schin 							else
879*4887Schin 								setchar('!');
880*4887Schin 						}
881*4887Schin 						break;
882*4887Schin 					case '0':
883*4887Schin 						if(n==S_DIG)
884*4887Schin 							break;
885*4887Schin 					default:
886*4887Schin 						goto dolerr;
887*4887Schin 				}
888*4887Schin 				break;
889*4887Schin 			dolerr:
890*4887Schin 			case S_ERR:
891*4887Schin 				if((n=endchar()) == '$')
892*4887Schin 					goto err;
893*4887Schin 				if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2)
894*4887Schin 				{
895*4887Schin 					/* see whether inside `...` */
896*4887Schin 					mode = oldmode();
897*4887Schin 					poplevel();
898*4887Schin 					if((n = endchar()) != '`')
899*4887Schin 						goto err;
900*4887Schin 					pushlevel(RBRACE,mode);
901*4887Schin 				}
902*4887Schin 				else
903*4887Schin 					setchar(RBRACE);
904*4887Schin 				mode = ST_NESTED;
905*4887Schin 				continue;
906*4887Schin 			case S_MOD1:
907*4887Schin 				if(oldmode()==ST_QUOTE || oldmode()==ST_NONE)
908*4887Schin 				{
909*4887Schin 					/* allow ' inside "${...}" */
910*4887Schin 					if(c==':' && fcgetc(n)>0)
911*4887Schin 					{
912*4887Schin 						n = state[n];
913*4887Schin 						fcseek(-1);
914*4887Schin 					}
915*4887Schin 					if(n==S_MOD1)
916*4887Schin 					{
917*4887Schin 						mode = ST_QUOTE;
918*4887Schin 						continue;
919*4887Schin 					}
920*4887Schin 				}
921*4887Schin 				/* FALL THRU */
922*4887Schin 			case S_MOD2:
923*4887Schin #if SHOPT_KIA
924*4887Schin 				if(shlex.kiafile)
925*4887Schin 					refvar(1);
926*4887Schin #endif /* SHOPT_KIA */
927*4887Schin 				if(c!=':' && fcgetc(n)>0)
928*4887Schin 				{
929*4887Schin 					if(n!=c)
930*4887Schin 						c = 0;
931*4887Schin 					if(!c || (fcgetc(n)>0))
932*4887Schin 					{
933*4887Schin 						fcseek(-1);
934*4887Schin 						if(n==LPAREN)
935*4887Schin 						{
936*4887Schin 							if(c!='%')
937*4887Schin 							{
938*4887Schin 								shlex.token = n;
939*4887Schin 								sh_syntax();
940*4887Schin 							}
941*4887Schin 							else if(lexd.warn)
942*4887Schin 								errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%');
943*4887Schin 						}
944*4887Schin 					}
945*4887Schin 				}
946*4887Schin 				mode = ST_NESTED;
947*4887Schin 				continue;
948*4887Schin 			case S_LBRA:
949*4887Schin 				if((c=endchar()) == '$')
950*4887Schin 				{
951*4887Schin 					setchar(RBRACE);
952*4887Schin 					if(fcgetc(c)>0)
953*4887Schin 						fcseek(-1);
954*4887Schin 					if(state[c]!=S_ERR && c!=RBRACE)
955*4887Schin 						continue;
956*4887Schin 				}
957*4887Schin 			err:
958*4887Schin 				n = endchar();
959*4887Schin 				mode = oldmode();
960*4887Schin 				poplevel();
961*4887Schin 				if(n!='$')
962*4887Schin 				{
963*4887Schin 					shlex.token = c;
964*4887Schin 					sh_syntax();
965*4887Schin 				}
966*4887Schin 				else
967*4887Schin 				{
968*4887Schin 					if(lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE))
969*4887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
970*4887Schin 					else if(c=='"' && mode!=ST_QUOTE)
971*4887Schin 						wordflags |= ARG_MESSAGE;
972*4887Schin 					fcseek(-1);
973*4887Schin 				}
974*4887Schin 				continue;
975*4887Schin 			case S_META:
976*4887Schin 				if(lexd.warn && endchar()==RBRACE)
977*4887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
978*4887Schin 				continue;
979*4887Schin 			case S_PUSH:
980*4887Schin 				pushlevel(RPAREN,mode);
981*4887Schin 				mode = ST_NESTED;
982*4887Schin 				continue;
983*4887Schin 			case S_POP:
984*4887Schin 			do_pop:
985*4887Schin 				if(lexd.level <= inlevel)
986*4887Schin 					break;
987*4887Schin 				n = endchar();
988*4887Schin 				if(c==RBRACT  && !(n==RBRACT || n==RPAREN))
989*4887Schin 					continue;
990*4887Schin 				if((c==RBRACE||c==RPAREN) && n==RPAREN)
991*4887Schin 				{
992*4887Schin 					if(fcgetc(n)==LPAREN)
993*4887Schin 					{
994*4887Schin 						if(c!=RPAREN)
995*4887Schin 							fcseek(-1);
996*4887Schin 						continue;
997*4887Schin 					}
998*4887Schin 					if(n>0)
999*4887Schin 						fcseek(-1);
1000*4887Schin 					n = RPAREN;
1001*4887Schin 				}
1002*4887Schin 				if(c==';' && n!=';')
1003*4887Schin 				{
1004*4887Schin 					if(lexd.warn && n==RBRACE)
1005*4887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
1006*4887Schin 					continue;
1007*4887Schin 				}
1008*4887Schin 				if(mode==ST_QNEST)
1009*4887Schin 				{
1010*4887Schin 					if(lexd.warn)
1011*4887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c);
1012*4887Schin 					continue;
1013*4887Schin 				}
1014*4887Schin 				mode = oldmode();
1015*4887Schin 				poplevel();
1016*4887Schin 				/* quotes in subscript need expansion */
1017*4887Schin 				if(mode==ST_NAME && (wordflags&ARG_QUOTED))
1018*4887Schin 					wordflags |= ARG_MAC;
1019*4887Schin 				/* check for ((...)) */
1020*4887Schin 				if(n==1 && c==RPAREN)
1021*4887Schin 				{
1022*4887Schin 					if(fcgetc(n)==RPAREN)
1023*4887Schin 					{
1024*4887Schin 						if(mode==ST_NONE && !lexd.dolparen)
1025*4887Schin 							goto breakloop;
1026*4887Schin 						lex.reservok = 1;
1027*4887Schin 						lex.skipword = 0;
1028*4887Schin 						return(shlex.token=EXPRSYM);
1029*4887Schin 					}
1030*4887Schin 					/* backward compatibility */
1031*4887Schin 					if(lexd.dolparen)
1032*4887Schin 						fcseek(-1);
1033*4887Schin 					else
1034*4887Schin 					{
1035*4887Schin 						if(lexd.warn)
1036*4887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
1037*4887Schin 						if(!(state=lexd.first))
1038*4887Schin 							state = fcfirst();
1039*4887Schin 						fcseek(state-fcseek(0));
1040*4887Schin 						if(shlex.arg)
1041*4887Schin 						{
1042*4887Schin 							shlex.arg = (struct argnod*)stakfreeze(1);
1043*4887Schin 							setupalias(lp,shlex.arg->argval,NIL(Namval_t*));
1044*4887Schin 						}
1045*4887Schin 						lexd.paren = 1;
1046*4887Schin 					}
1047*4887Schin 					return(shlex.token=LPAREN);
1048*4887Schin 				}
1049*4887Schin 				if(mode==ST_NONE)
1050*4887Schin 					return(0);
1051*4887Schin 				if(c!=n)
1052*4887Schin 				{
1053*4887Schin 					shlex.token = c;
1054*4887Schin 					sh_syntax();
1055*4887Schin 				}
1056*4887Schin 				if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
1057*4887Schin 					goto epat;
1058*4887Schin 				continue;
1059*4887Schin 			case S_EQ:
1060*4887Schin 				assignment = shlex.assignok;
1061*4887Schin 				/* FALL THRU */
1062*4887Schin 			case S_COLON:
1063*4887Schin 				if(assignment)
1064*4887Schin 				{
1065*4887Schin 					if((c=fcget())=='~')
1066*4887Schin 						wordflags |= ARG_MAC;
1067*4887Schin 					else if(c!=LPAREN && assignment==SH_COMPASSIGN)
1068*4887Schin 						assignment = 0;
1069*4887Schin 					fcseek(-1);
1070*4887Schin 				}
1071*4887Schin 				break;
1072*4887Schin 			case S_LABEL:
1073*4887Schin 				if(lex.reservok && !lex.incase)
1074*4887Schin 				{
1075*4887Schin 					c = fcget();
1076*4887Schin 					fcseek(-1);
1077*4887Schin 					if(state[c]==S_BREAK)
1078*4887Schin 					{
1079*4887Schin 						assignment = -1;
1080*4887Schin 						goto breakloop;
1081*4887Schin 					}
1082*4887Schin 				}
1083*4887Schin 				break;
1084*4887Schin 			case S_BRACT:
1085*4887Schin 				/* check for possible subscript */
1086*4887Schin 				if((n=endchar())==RBRACT || n==RPAREN ||
1087*4887Schin 					(mode==ST_BRACE) ||
1088*4887Schin 					(oldmode()==ST_NONE) ||
1089*4887Schin 					(mode==ST_NAME && (shlex.assignok||lexd.level)))
1090*4887Schin 				{
1091*4887Schin 					pushlevel(RBRACT,mode);
1092*4887Schin 					wordflags |= ARG_QUOTED;
1093*4887Schin 					mode = ST_NESTED;
1094*4887Schin 					continue;
1095*4887Schin 				}
1096*4887Schin 				wordflags |= ARG_EXP;
1097*4887Schin 				break;
1098*4887Schin 			case S_BRACE:
1099*4887Schin 			{
1100*4887Schin 				int isfirst;
1101*4887Schin 				if(lexd.dolparen)
1102*4887Schin 					break;
1103*4887Schin 				isfirst = (lexd.first&&fcseek(0)==lexd.first+1);
1104*4887Schin 				fcgetc(n);
1105*4887Schin 				/* check for {} */
1106*4887Schin 				if(c==LBRACE && n==RBRACE)
1107*4887Schin 					break;
1108*4887Schin 				if(n>0)
1109*4887Schin 					fcseek(-1);
1110*4887Schin 				else if(lex.reservok)
1111*4887Schin 					break;
1112*4887Schin 				/* check for reserved word { or } */
1113*4887Schin 				if(lex.reservok && state[n]==S_BREAK && isfirst)
1114*4887Schin 					break;
1115*4887Schin 				if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
1116*4887Schin 					&& !lex.incase && !lex.intest
1117*4887Schin 					&& !lex.skipword)
1118*4887Schin 				{
1119*4887Schin 					wordflags |= ARG_EXP;
1120*4887Schin 				}
1121*4887Schin 				if(c==RBRACE && n==LPAREN)
1122*4887Schin 					goto epat;
1123*4887Schin 				break;
1124*4887Schin 			}
1125*4887Schin 			case S_PAT:
1126*4887Schin 				wordflags |= ARG_EXP;
1127*4887Schin 				/* FALL THRU */
1128*4887Schin 			case S_EPAT:
1129*4887Schin 			epat:
1130*4887Schin 				if(fcgetc(n)==LPAREN)
1131*4887Schin 				{
1132*4887Schin 					if(lex.incase==TEST_RE)
1133*4887Schin 					{
1134*4887Schin 						lex.incase++;
1135*4887Schin 						pushlevel(RPAREN,ST_NORM);
1136*4887Schin 						mode = ST_NESTED;
1137*4887Schin 					}
1138*4887Schin 					wordflags |= ARG_EXP;
1139*4887Schin 					pushlevel(RPAREN,mode);
1140*4887Schin 					mode = ST_NESTED;
1141*4887Schin 					continue;
1142*4887Schin 				}
1143*4887Schin 				if(n>0)
1144*4887Schin 					fcseek(-1);
1145*4887Schin 				if(n=='=' && c=='+' && mode==ST_NAME)
1146*4887Schin 					continue;
1147*4887Schin 				break;
1148*4887Schin 		}
1149*4887Schin 		lex.comp_assign = 0;
1150*4887Schin 		if(mode==ST_NAME)
1151*4887Schin 			mode = ST_NORM;
1152*4887Schin 		else if(mode==ST_NONE)
1153*4887Schin 			return(0);
1154*4887Schin 	}
1155*4887Schin breakloop:
1156*4887Schin 	if(lexd.dolparen)
1157*4887Schin 	{
1158*4887Schin 		lexd.balance = 0;
1159*4887Schin 		if(lexd.docword)
1160*4887Schin 			nested_here(lp);
1161*4887Schin 		lexd.message = (wordflags&ARG_MESSAGE);
1162*4887Schin 		return(shlex.token=0);
1163*4887Schin 	}
1164*4887Schin 	if(!(state=lexd.first))
1165*4887Schin 		state = fcfirst();
1166*4887Schin 	n = fcseek(0)-(char*)state;
1167*4887Schin 	if(!shlex.arg)
1168*4887Schin 		shlex.arg = (struct argnod*)stakseek(ARGVAL);
1169*4887Schin 	if(n>0)
1170*4887Schin 		stakwrite(state,n);
1171*4887Schin 	/* add balancing character if necessary */
1172*4887Schin 	if(lexd.balance)
1173*4887Schin 	{
1174*4887Schin 		stakputc(lexd.balance);
1175*4887Schin 		lexd.balance = 0;
1176*4887Schin 	}
1177*4887Schin 	stakputc(0);
1178*4887Schin 	stakseek(staktell()-1);
1179*4887Schin 	state = stakptr(ARGVAL);
1180*4887Schin 	n = staktell()-ARGVAL;
1181*4887Schin 	lexd.first=0;
1182*4887Schin 	if(n==1)
1183*4887Schin 	{
1184*4887Schin 		/* check for numbered redirection */
1185*4887Schin 		n = state[0];
1186*4887Schin 		if((c=='<' || c=='>') && isadigit(n))
1187*4887Schin 		{
1188*4887Schin 			c = sh_lex();
1189*4887Schin 			shlex.digits = (n-'0');
1190*4887Schin 			return(c);
1191*4887Schin 		}
1192*4887Schin 		if(n==LBRACT)
1193*4887Schin 			c = 0;
1194*4887Schin 		else if(n=='~')
1195*4887Schin 			c = ARG_MAC;
1196*4887Schin 		else
1197*4887Schin 			c = (wordflags&ARG_EXP);
1198*4887Schin 		n = 1;
1199*4887Schin 	}
1200*4887Schin 	else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lex.intest && !lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
1201*4887Schin 	{
1202*4887Schin 		if(!strchr(state,','))
1203*4887Schin 		{
1204*4887Schin 			stakseek(staktell()-1);
1205*4887Schin 			shlex.arg = (struct argnod*)stakfreeze(1);
1206*4887Schin 			return(shlex.token=IOVNAME);
1207*4887Schin 		}
1208*4887Schin 		c = wordflags;
1209*4887Schin 	}
1210*4887Schin 	else
1211*4887Schin 		c = wordflags;
1212*4887Schin 	if(assignment<0)
1213*4887Schin 	{
1214*4887Schin 		stakseek(staktell()-1);
1215*4887Schin 		shlex.arg = (struct argnod*)stakfreeze(1);
1216*4887Schin 		lex.reservok = 1;
1217*4887Schin 		return(shlex.token=LABLSYM);
1218*4887Schin 	}
1219*4887Schin 	if(assignment || (lex.intest&&!lex.incase) || mode==ST_NONE)
1220*4887Schin 		c &= ~ARG_EXP;
1221*4887Schin 	if((c&ARG_EXP) && (c&ARG_QUOTED))
1222*4887Schin 		c |= ARG_MAC;
1223*4887Schin 	if(mode==ST_NONE)
1224*4887Schin 	{
1225*4887Schin 		/* eliminate trailing )) */
1226*4887Schin 		stakseek(staktell()-2);
1227*4887Schin 	}
1228*4887Schin 	if(c&ARG_MESSAGE)
1229*4887Schin 	{
1230*4887Schin 		if(sh_isoption(SH_DICTIONARY))
1231*4887Schin 			shlex.arg = sh_endword(2);
1232*4887Schin 		if(!sh_isoption(SH_NOEXEC))
1233*4887Schin 		{
1234*4887Schin 			shlex.arg = sh_endword(1);
1235*4887Schin 			c &= ~ARG_MESSAGE;
1236*4887Schin 		}
1237*4887Schin 	}
1238*4887Schin 	if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lexd.warn && !lexd.docword))
1239*4887Schin 	{
1240*4887Schin 		shlex.arg = (struct argnod*)stakfreeze(1);
1241*4887Schin 		shlex.arg->argflag = (c?c:ARG_RAW);
1242*4887Schin 	}
1243*4887Schin 	else if(mode==ST_NONE)
1244*4887Schin 		shlex.arg = sh_endword(-1);
1245*4887Schin 	else
1246*4887Schin 		shlex.arg = sh_endword(0);
1247*4887Schin 	state = shlex.arg->argval;
1248*4887Schin 	lex.comp_assign = assignment;
1249*4887Schin 	if(assignment)
1250*4887Schin 		shlex.arg->argflag |= ARG_ASSIGN;
1251*4887Schin 	else if(!lex.skipword)
1252*4887Schin 		shlex.assignok = 0;
1253*4887Schin 	shlex.arg->argchn.cp = 0;
1254*4887Schin 	shlex.arg->argnxt.ap = 0;
1255*4887Schin 	if(mode==ST_NONE)
1256*4887Schin 		return(shlex.token=EXPRSYM);
1257*4887Schin 	if(lex.intest)
1258*4887Schin 	{
1259*4887Schin 		if(lex.testop1)
1260*4887Schin 		{
1261*4887Schin 			lex.testop1 = 0;
1262*4887Schin 			if(n==2 && state[0]=='-' && state[2]==0 &&
1263*4887Schin 				strchr(test_opchars,state[1]))
1264*4887Schin 			{
1265*4887Schin 				if(lexd.warn && state[1]=='a')
1266*4887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
1267*4887Schin 				shlex.digits = state[1];
1268*4887Schin 				shlex.token = TESTUNOP;
1269*4887Schin 			}
1270*4887Schin 			else if(n==1 && state[0]=='!' && state[1]==0)
1271*4887Schin 			{
1272*4887Schin 				lex.testop1 = 1;
1273*4887Schin 				shlex.token = '!';
1274*4887Schin 			}
1275*4887Schin 			else
1276*4887Schin 			{
1277*4887Schin 				lex.testop2 = 1;
1278*4887Schin 				shlex.token = 0;
1279*4887Schin 			}
1280*4887Schin 			return(shlex.token);
1281*4887Schin 		}
1282*4887Schin 		lex.incase = 0;
1283*4887Schin 		c = sh_lookup(state,shtab_testops);
1284*4887Schin 		switch(c)
1285*4887Schin 		{
1286*4887Schin 		case TEST_END:
1287*4887Schin 			lex.testop2 = lex.intest = 0;
1288*4887Schin 			lex.reservok = 1;
1289*4887Schin 			shlex.token = ETESTSYM;
1290*4887Schin 			return(shlex.token);
1291*4887Schin 
1292*4887Schin 		case TEST_SEQ:
1293*4887Schin 			if(lexd.warn && state[1]==0)
1294*4887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
1295*4887Schin 			/* FALL THRU */
1296*4887Schin 		default:
1297*4887Schin 			if(lex.testop2)
1298*4887Schin 			{
1299*4887Schin 				if(lexd.warn && (c&TEST_ARITH))
1300*4887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
1301*4887Schin 				if(c&TEST_PATTERN)
1302*4887Schin 					lex.incase = 1;
1303*4887Schin 				else if(c==TEST_REP)
1304*4887Schin 					lex.incase = TEST_RE;
1305*4887Schin 				lex.testop2 = 0;
1306*4887Schin 				shlex.digits = c;
1307*4887Schin 				shlex.token = TESTBINOP;
1308*4887Schin 				return(shlex.token);
1309*4887Schin 			}
1310*4887Schin 
1311*4887Schin 		case TEST_OR: case TEST_AND:
1312*4887Schin 		case 0:
1313*4887Schin 			return(shlex.token=0);
1314*4887Schin 		}
1315*4887Schin 	}
1316*4887Schin 	if(lex.reservok /* && !lex.incase*/ && n<=2)
1317*4887Schin 	{
1318*4887Schin 		/* check for {, }, ! */
1319*4887Schin 		c = state[0];
1320*4887Schin 		if(n==1 && (c=='{' || c=='}' || c=='!'))
1321*4887Schin 		{
1322*4887Schin 			if(lexd.warn && c=='{' && lex.incase==2)
1323*4887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
1324*4887Schin 			if(lex.incase==1 && c==RBRACE)
1325*4887Schin 				lex.incase = 0;
1326*4887Schin 			return(shlex.token=c);
1327*4887Schin 		}
1328*4887Schin 		else if(!lex.incase && c==LBRACT && state[1]==LBRACT)
1329*4887Schin 		{
1330*4887Schin 			lex.intest = lex.testop1 = 1;
1331*4887Schin 			lex.testop2 = lex.reservok = 0;
1332*4887Schin 			return(shlex.token=BTESTSYM);
1333*4887Schin 		}
1334*4887Schin 	}
1335*4887Schin 	c = 0;
1336*4887Schin 	if(!lex.skipword)
1337*4887Schin 	{
1338*4887Schin 		if(n>1 && lex.reservok==1 && mode==ST_NAME &&
1339*4887Schin 			(c=sh_lookup(state,shtab_reserved)))
1340*4887Schin 		{
1341*4887Schin 			if(lex.incase)
1342*4887Schin 			{
1343*4887Schin 				if(lex.incase >1)
1344*4887Schin 					lex.incase = 1;
1345*4887Schin 				else if(c==ESACSYM)
1346*4887Schin 					lex.incase = 0;
1347*4887Schin 				else
1348*4887Schin 					c = 0;
1349*4887Schin 			}
1350*4887Schin 			else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
1351*4887Schin 			{
1352*4887Schin 				lex.skipword = 1;
1353*4887Schin 				lex.incase = 2*(c==CASESYM);
1354*4887Schin 			}
1355*4887Schin 			else
1356*4887Schin 				lex.skipword = 0;
1357*4887Schin 			if(c==INSYM)
1358*4887Schin 				lex.reservok = 0;
1359*4887Schin 			else if(c==TIMESYM)
1360*4887Schin 			{
1361*4887Schin 				/* yech - POSIX requires time -p */
1362*4887Schin 				while(fcgetc(n)==' ' || n=='\t');
1363*4887Schin 				if(n>0)
1364*4887Schin 					fcseek(-1);
1365*4887Schin 				if(n=='-')
1366*4887Schin 					c=0;
1367*4887Schin 			}
1368*4887Schin 			return(shlex.token=c);
1369*4887Schin 		}
1370*4887Schin 		if(!(wordflags&ARG_QUOTED) && (lex.reservok||shlex.aliasok))
1371*4887Schin 		{
1372*4887Schin 			/* check for aliases */
1373*4887Schin 			Namval_t* np;
1374*4887Schin 			if(!lex.incase && !assignment && fcpeek(0)!=LPAREN &&
1375*4887Schin 				(np=nv_search(state,shp->alias_tree,HASH_SCOPE))
1376*4887Schin 				&& !nv_isattr(np,NV_NOEXPAND)
1377*4887Schin #if KSHELL
1378*4887Schin 				&& (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
1379*4887Schin #endif /* KSHELL */
1380*4887Schin 				&& (state=nv_getval(np)))
1381*4887Schin 			{
1382*4887Schin 				setupalias(lp,state,np);
1383*4887Schin 				nv_onattr(np,NV_NOEXPAND);
1384*4887Schin 				lex.reservok = 1;
1385*4887Schin 				shlex.assignok |= lex.reservok;
1386*4887Schin 				return(sh_lex());
1387*4887Schin 			}
1388*4887Schin 		}
1389*4887Schin 		lex.reservok = 0;
1390*4887Schin 	}
1391*4887Schin 	lex.skipword = lexd.docword = 0;
1392*4887Schin 	return(shlex.token=c);
1393*4887Schin }
1394*4887Schin 
1395*4887Schin /*
1396*4887Schin  * read to end of command substitution
1397*4887Schin  */
1398*4887Schin static int comsub(register Lex_t *lp)
1399*4887Schin {
1400*4887Schin 	register int	n,c,count=1;
1401*4887Schin 	register int	line=shlex.sh->inlineno;
1402*4887Schin 	char word[5];
1403*4887Schin 	int messages=0, assignok=shlex.assignok;
1404*4887Schin 	struct lexstate	save;
1405*4887Schin 	save = lex;
1406*4887Schin 	sh_lexopen(lp,shlex.sh,1);
1407*4887Schin 	lexd.dolparen++;
1408*4887Schin 	lex.incase=0;
1409*4887Schin 	pushlevel(0,0);
1410*4887Schin 	if(sh_lex()==LPAREN)
1411*4887Schin 	{
1412*4887Schin 		while(1)
1413*4887Schin 		{
1414*4887Schin 			/* look for case and esac */
1415*4887Schin 			n=0;
1416*4887Schin 			while(1)
1417*4887Schin 			{
1418*4887Schin 				fcgetc(c);
1419*4887Schin 				/* skip leading white space */
1420*4887Schin 				if(n==0 && !sh_lexstates[ST_BEGIN][c])
1421*4887Schin 					continue;
1422*4887Schin 				if(n==4)
1423*4887Schin 					break;
1424*4887Schin 				if(sh_lexstates[ST_NAME][c])
1425*4887Schin 					goto skip;
1426*4887Schin 				word[n++] = c;
1427*4887Schin 			}
1428*4887Schin 			if(sh_lexstates[ST_NAME][c]==S_BREAK)
1429*4887Schin 			{
1430*4887Schin 				if(memcmp(word,"case",4)==0)
1431*4887Schin 					lex.incase=1;
1432*4887Schin 				else if(memcmp(word,"esac",4)==0)
1433*4887Schin 					lex.incase=0;
1434*4887Schin 			}
1435*4887Schin 		skip:
1436*4887Schin 			if(c && (c!='#' || n==0))
1437*4887Schin 				fcseek(-1);
1438*4887Schin 			if(c==RBRACE && lex.incase)
1439*4887Schin 				lex.incase=0;
1440*4887Schin 			switch(sh_lex())
1441*4887Schin 			{
1442*4887Schin 			    case LPAREN: case IPROCSYM:	case OPROCSYM:
1443*4887Schin 				if(!lex.incase)
1444*4887Schin 					count++;
1445*4887Schin 				break;
1446*4887Schin 			    case RPAREN:
1447*4887Schin 				if(lex.incase)
1448*4887Schin 					lex.incase=0;
1449*4887Schin 				else if(--count<=0)
1450*4887Schin 					goto done;
1451*4887Schin 				break;
1452*4887Schin 			    case EOFSYM:
1453*4887Schin 				shlex.lastline = line;
1454*4887Schin 				shlex.lasttok = LPAREN;
1455*4887Schin 				sh_syntax();
1456*4887Schin 			    case IOSEEKSYM:
1457*4887Schin 				if(fcgetc(c)!='#' && c>0)
1458*4887Schin 					fcseek(-1);
1459*4887Schin 				break;
1460*4887Schin 			    case IODOCSYM:
1461*4887Schin 				sh_lex();
1462*4887Schin 				break;
1463*4887Schin 			    case 0:
1464*4887Schin 				messages |= lexd.message;
1465*4887Schin 			}
1466*4887Schin 		}
1467*4887Schin 	}
1468*4887Schin done:
1469*4887Schin 	poplevel();
1470*4887Schin 	shlex.lastline = line;
1471*4887Schin 	lexd.dolparen--;
1472*4887Schin 	lex = save;
1473*4887Schin 	shlex.assignok = (endchar()==RBRACT?assignok:0);
1474*4887Schin 	return(messages);
1475*4887Schin }
1476*4887Schin 
1477*4887Schin /*
1478*4887Schin  * here-doc nested in $(...)
1479*4887Schin  * allocate ionode with delimiter filled in without disturbing stak
1480*4887Schin  */
1481*4887Schin static void nested_here(register Lex_t *lp)
1482*4887Schin {
1483*4887Schin 	register struct ionod *iop;
1484*4887Schin 	register int n,offset;
1485*4887Schin 	struct argnod *arg = shlex.arg;
1486*4887Schin 	char *base;
1487*4887Schin 	if(offset=staktell())
1488*4887Schin 		base = stakfreeze(0);
1489*4887Schin 	n = fcseek(0)-lexd.docend;
1490*4887Schin 	iop = newof(0,struct ionod,1,n+ARGVAL);
1491*4887Schin 	iop->iolst = shlex.heredoc;
1492*4887Schin 	stakseek(ARGVAL);
1493*4887Schin 	stakwrite(lexd.docend,n);
1494*4887Schin 	shlex.arg = sh_endword(0);
1495*4887Schin 	iop->ioname = (char*)(iop+1);
1496*4887Schin 	strcpy(iop->ioname,shlex.arg->argval);
1497*4887Schin 	iop->iofile = (IODOC|IORAW);
1498*4887Schin 	if(lexd.docword>1)
1499*4887Schin 		iop->iofile |= IOSTRIP;
1500*4887Schin 	shlex.heredoc = iop;
1501*4887Schin 	shlex.arg = arg;
1502*4887Schin 	lexd.docword = 0;
1503*4887Schin 	if(offset)
1504*4887Schin 		stakset(base,offset);
1505*4887Schin 	else
1506*4887Schin 		stakseek(0);
1507*4887Schin }
1508*4887Schin 
1509*4887Schin /*
1510*4887Schin  * skip to <close> character
1511*4887Schin  * if <copy> is non,zero, then the characters are copied to the stack
1512*4887Schin  * <state> is the initial lexical state
1513*4887Schin  */
1514*4887Schin void sh_lexskip(int close, register int copy, int  state)
1515*4887Schin {
1516*4887Schin 	register Lex_t	*lp = (Lex_t*)sh.lex_context;
1517*4887Schin 	register char	*cp;
1518*4887Schin 	lexd.nest = close;
1519*4887Schin 	lexd.lex_state = state;
1520*4887Schin 	lexd.noarg = 1;
1521*4887Schin 	if(copy)
1522*4887Schin 		fcnotify(lex_advance);
1523*4887Schin 	else
1524*4887Schin 		lexd.nocopy++;
1525*4887Schin 	sh_lex();
1526*4887Schin 	lexd.noarg = 0;
1527*4887Schin 	if(copy)
1528*4887Schin 	{
1529*4887Schin 		fcnotify(0);
1530*4887Schin 		if(!(cp=lexd.first))
1531*4887Schin 			cp = fcfirst();
1532*4887Schin 		if((copy = fcseek(0)-cp) > 0)
1533*4887Schin 			stakwrite(cp,copy);
1534*4887Schin 	}
1535*4887Schin 	else
1536*4887Schin 		lexd.nocopy--;
1537*4887Schin }
1538*4887Schin 
1539*4887Schin #if SHOPT_CRNL
1540*4887Schin     ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
1541*4887Schin     {
1542*4887Schin 	const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
1543*4887Schin 	int m=0,k;
1544*4887Schin 	while(next = (const char*)memchr(next,'\r',ep-next))
1545*4887Schin 		if(*++next=='\n')
1546*4887Schin 		{
1547*4887Schin 			if(k=next-cp-1)
1548*4887Schin 			{
1549*4887Schin 				if((k=sfwrite(sp,cp,k)) < 0)
1550*4887Schin 					return(m>0?m:-1);
1551*4887Schin 				m += k;
1552*4887Schin 			}
1553*4887Schin 			cp = next;
1554*4887Schin 		}
1555*4887Schin 	if((k=sfwrite(sp,cp,ep-cp)) < 0)
1556*4887Schin 		return(m>0?m:-1);
1557*4887Schin 	return(m+k);
1558*4887Schin     }
1559*4887Schin #   define sfwrite	_sfwrite
1560*4887Schin #endif /* SHOPT_CRNL */
1561*4887Schin 
1562*4887Schin /*
1563*4887Schin  * read in here-document from script
1564*4887Schin  * quoted here documents, and here-documents without special chars are
1565*4887Schin  * noted with the IOQUOTE flag
1566*4887Schin  * returns 1 for complete here-doc, 0 for EOF
1567*4887Schin  */
1568*4887Schin 
1569*4887Schin static int here_copy(Lex_t *lp,register struct ionod *iop)
1570*4887Schin {
1571*4887Schin 	register const char	*state;
1572*4887Schin 	register int		c,n;
1573*4887Schin 	register char		*bufp,*cp;
1574*4887Schin 	register Sfio_t		*sp=shlex.sh->heredocs, *funlog;
1575*4887Schin 	int			stripcol=0,stripflg, nsave, special=0;
1576*4887Schin 	if(funlog=shlex.sh->funlog)
1577*4887Schin 	{
1578*4887Schin 		if(fcfill()>0)
1579*4887Schin 			fcseek(-1);
1580*4887Schin 		shlex.sh->funlog = 0;
1581*4887Schin 	}
1582*4887Schin 	if(iop->iolst)
1583*4887Schin 		here_copy(lp,iop->iolst);
1584*4887Schin 	iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
1585*4887Schin 	iop->iosize = 0;
1586*4887Schin 	iop->iodelim=iop->ioname;
1587*4887Schin 	/* check for and strip quoted characters in delimiter string */
1588*4887Schin 	if(stripflg=iop->iofile&IOSTRIP)
1589*4887Schin 	{
1590*4887Schin 		while(*iop->iodelim=='\t')
1591*4887Schin 			iop->iodelim++;
1592*4887Schin 		/* skip over leading tabs in document */
1593*4887Schin 		if(iop->iofile&IOLSEEK)
1594*4887Schin 		{
1595*4887Schin 			iop->iofile &= ~IOLSEEK;
1596*4887Schin 			while(fcgetc(c)=='\t' || c==' ')
1597*4887Schin 			{
1598*4887Schin 				if(c==' ')
1599*4887Schin 					stripcol++;
1600*4887Schin 				else
1601*4887Schin 					stripcol += 8 - stripcol%8;
1602*4887Schin 			}
1603*4887Schin 		}
1604*4887Schin 		else
1605*4887Schin 			while(fcgetc(c)=='\t');
1606*4887Schin 		if(c>0)
1607*4887Schin 			fcseek(-1);
1608*4887Schin 	}
1609*4887Schin 	if(iop->iofile&IOQUOTE)
1610*4887Schin 		state = sh_lexstates[ST_LIT];
1611*4887Schin 	else
1612*4887Schin 		state = sh_lexstates[ST_QUOTE];
1613*4887Schin 	bufp = fcseek(0);
1614*4887Schin 	n = S_NL;
1615*4887Schin 	while(1)
1616*4887Schin 	{
1617*4887Schin 		if(n!=S_NL)
1618*4887Schin 		{
1619*4887Schin 			/* skip over regular characters */
1620*4887Schin 			while((n=STATE(state,c))==0);
1621*4887Schin 		}
1622*4887Schin 		if(n==S_EOF || !(c=fcget()))
1623*4887Schin 		{
1624*4887Schin 			if(!lexd.dolparen && (c=(fcseek(0)-1)-bufp))
1625*4887Schin 			{
1626*4887Schin 				if(n==S_ESC)
1627*4887Schin 					c--;
1628*4887Schin 				if((c=sfwrite(sp,bufp,c))>0)
1629*4887Schin 					iop->iosize += c;
1630*4887Schin 			}
1631*4887Schin 			if((c=lexfill())<=0)
1632*4887Schin 				break;
1633*4887Schin 			if(n==S_ESC)
1634*4887Schin 			{
1635*4887Schin #if SHOPT_CRNL
1636*4887Schin 				if(c=='\r' && (c=fcget())!=NL)
1637*4887Schin 					fcseek(-1);
1638*4887Schin #endif /* SHOPT_CRNL */
1639*4887Schin 				if(c==NL)
1640*4887Schin 					fcseek(1);
1641*4887Schin 				else
1642*4887Schin 					sfputc(sp,'\\');
1643*4887Schin 			}
1644*4887Schin 			bufp = fcseek(-1);
1645*4887Schin 		}
1646*4887Schin 		else
1647*4887Schin 			fcseek(-1);
1648*4887Schin 		switch(n)
1649*4887Schin 		{
1650*4887Schin 		    case S_NL:
1651*4887Schin 			shlex.sh->inlineno++;
1652*4887Schin 			if((stripcol && c==' ') || (stripflg && c=='\t'))
1653*4887Schin 			{
1654*4887Schin 				if(!lexd.dolparen)
1655*4887Schin 				{
1656*4887Schin 					/* write out line */
1657*4887Schin 					n = fcseek(0)-bufp;
1658*4887Schin 					if((n=sfwrite(sp,bufp,n))>0)
1659*4887Schin 						iop->iosize += n;
1660*4887Schin 				}
1661*4887Schin 				/* skip over tabs */
1662*4887Schin 				if(stripcol)
1663*4887Schin 				{
1664*4887Schin 					int col=0;
1665*4887Schin 					do
1666*4887Schin 					{
1667*4887Schin 						fcgetc(c);
1668*4887Schin 						if(c==' ')
1669*4887Schin 							col++;
1670*4887Schin 						else
1671*4887Schin 							col += 8 - col%8;
1672*4887Schin 						if(col>stripcol)
1673*4887Schin 							break;
1674*4887Schin 					}
1675*4887Schin 					while (c==' ' || c=='\t');
1676*4887Schin 				}
1677*4887Schin 				else while(c=='\t')
1678*4887Schin 					fcgetc(c);
1679*4887Schin 				if(c<=0)
1680*4887Schin 					goto done;
1681*4887Schin 				bufp = fcseek(-1);
1682*4887Schin 			}
1683*4887Schin 			if(c!=iop->iodelim[0])
1684*4887Schin 				break;
1685*4887Schin 			cp = fcseek(0);
1686*4887Schin 			nsave = n = 0;
1687*4887Schin 			while(1)
1688*4887Schin 			{
1689*4887Schin 				if(!(c=fcget()))
1690*4887Schin 				{
1691*4887Schin 					if(!lexd.dolparen && (c=cp-bufp))
1692*4887Schin 					{
1693*4887Schin 						if((c=sfwrite(sp,cp=bufp,c))>0)
1694*4887Schin 							iop->iosize+=c;
1695*4887Schin 					}
1696*4887Schin 					nsave = n;
1697*4887Schin 					if((c=lexfill())<=0)
1698*4887Schin 					{
1699*4887Schin 						c = iop->iodelim[n]==0;
1700*4887Schin 						goto done;
1701*4887Schin 					}
1702*4887Schin 				}
1703*4887Schin #if SHOPT_CRNL
1704*4887Schin 				if(c=='\r' && (c=fcget())!=NL)
1705*4887Schin 				{
1706*4887Schin 					if(c)
1707*4887Schin 						fcseek(-1);
1708*4887Schin 					c='\r';
1709*4887Schin 				}
1710*4887Schin #endif /* SHOPT_CRNL */
1711*4887Schin 				if(c==NL)
1712*4887Schin 					shlex.sh->inlineno++;
1713*4887Schin 				if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
1714*4887Schin 				{
1715*4887Schin 					if(!lexd.dolparen && (n=cp-bufp))
1716*4887Schin 					{
1717*4887Schin 						if((n=sfwrite(sp,bufp,n))>0)
1718*4887Schin 							iop->iosize += n;
1719*4887Schin 					}
1720*4887Schin 					shlex.sh->inlineno--;
1721*4887Schin 					if(c==RPAREN)
1722*4887Schin 						fcseek(-1);
1723*4887Schin 					goto done;
1724*4887Schin 				}
1725*4887Schin 				if(iop->iodelim[n++]!=c)
1726*4887Schin 				{
1727*4887Schin 					/*
1728*4887Schin 					 * The match for delimiter failed.
1729*4887Schin 					 * nsave>0 only when a buffer boundary
1730*4887Schin 					 * was crossed while checking the
1731*4887Schin 					 * delimiter
1732*4887Schin 					 */
1733*4887Schin 					if(!lexd.dolparen && nsave>0)
1734*4887Schin 					{
1735*4887Schin 						if((n=sfwrite(sp,bufp,nsave))>0)
1736*4887Schin 							iop->iosize += n;
1737*4887Schin 						bufp = fcfirst();
1738*4887Schin 					}
1739*4887Schin 					if(c==NL)
1740*4887Schin 						fcseek(-1);
1741*4887Schin 					break;
1742*4887Schin 				}
1743*4887Schin 			}
1744*4887Schin 			break;
1745*4887Schin 		    case S_ESC:
1746*4887Schin 			n=1;
1747*4887Schin #if SHOPT_CRNL
1748*4887Schin 			if(c=='\r')
1749*4887Schin 			{
1750*4887Schin 				fcseek(1);
1751*4887Schin 				if(c=fcget())
1752*4887Schin 					fcseek(-1);
1753*4887Schin 				if(c==NL)
1754*4887Schin 					n=2;
1755*4887Schin 				else
1756*4887Schin 				{
1757*4887Schin 					special++;
1758*4887Schin 					break;
1759*4887Schin 				}
1760*4887Schin 			}
1761*4887Schin #endif /* SHOPT_CRNL */
1762*4887Schin 			if(c==NL)
1763*4887Schin 			{
1764*4887Schin 				/* new-line joining */
1765*4887Schin 				shlex.sh->inlineno++;
1766*4887Schin 				if(!lexd.dolparen && (n=(fcseek(0)-bufp)-n)>0)
1767*4887Schin 				{
1768*4887Schin 					if((n=sfwrite(sp,bufp,n))>0)
1769*4887Schin 						iop->iosize += n;
1770*4887Schin 					bufp = fcseek(0)+1;
1771*4887Schin 				}
1772*4887Schin 			}
1773*4887Schin 			else
1774*4887Schin 				special++;
1775*4887Schin 			fcget();
1776*4887Schin 			break;
1777*4887Schin 
1778*4887Schin 		    case S_GRAVE:
1779*4887Schin 		    case S_DOL:
1780*4887Schin 			special++;
1781*4887Schin 			break;
1782*4887Schin 		}
1783*4887Schin 		n=0;
1784*4887Schin 	}
1785*4887Schin done:
1786*4887Schin 	shlex.sh->funlog = funlog;
1787*4887Schin 	if(lexd.dolparen)
1788*4887Schin 		free((void*)iop);
1789*4887Schin 	else if(!special)
1790*4887Schin 		iop->iofile |= IOQUOTE;
1791*4887Schin 	return(c);
1792*4887Schin }
1793*4887Schin 
1794*4887Schin /*
1795*4887Schin  * generates string for given token
1796*4887Schin  */
1797*4887Schin static char	*fmttoken(Lex_t *lp, register int sym, char *tok)
1798*4887Schin {
1799*4887Schin 	if(sym < 0)
1800*4887Schin 		return((char*)sh_translate(e_lexzerobyte));
1801*4887Schin 	if(sym==0)
1802*4887Schin 		return(shlex.arg?shlex.arg->argval:"?");
1803*4887Schin 	if(lex.intest && shlex.arg && *shlex.arg->argval)
1804*4887Schin 		return(shlex.arg->argval);
1805*4887Schin 	if(sym&SYMRES)
1806*4887Schin 	{
1807*4887Schin 		register const Shtable_t *tp=shtab_reserved;
1808*4887Schin 		while(tp->sh_number && tp->sh_number!=sym)
1809*4887Schin 			tp++;
1810*4887Schin 		return((char*)tp->sh_name);
1811*4887Schin 	}
1812*4887Schin 	if(sym==EOFSYM)
1813*4887Schin 		return((char*)sh_translate(e_endoffile));
1814*4887Schin 	if(sym==NL)
1815*4887Schin 		return((char*)sh_translate(e_newline));
1816*4887Schin 	tok[0] = sym;
1817*4887Schin 	if(sym&SYMREP)
1818*4887Schin 		tok[1] = sym;
1819*4887Schin 	else
1820*4887Schin 	{
1821*4887Schin 		switch(sym&SYMMASK)
1822*4887Schin 		{
1823*4887Schin 			case SYMAMP:
1824*4887Schin 				sym = '&';
1825*4887Schin 				break;
1826*4887Schin 			case SYMPIPE:
1827*4887Schin 				sym = '|';
1828*4887Schin 				break;
1829*4887Schin 			case SYMGT:
1830*4887Schin 				sym = '>';
1831*4887Schin 				break;
1832*4887Schin 			case SYMLPAR:
1833*4887Schin 				sym = LPAREN;
1834*4887Schin 				break;
1835*4887Schin 			case SYMSHARP:
1836*4887Schin 				sym = '#';
1837*4887Schin 				break;
1838*4887Schin 			default:
1839*4887Schin 				sym = 0;
1840*4887Schin 		}
1841*4887Schin 		tok[1] = sym;
1842*4887Schin 	}
1843*4887Schin 	tok[2] = 0;
1844*4887Schin 	return(tok);
1845*4887Schin }
1846*4887Schin 
1847*4887Schin /*
1848*4887Schin  * print a bad syntax message
1849*4887Schin  */
1850*4887Schin 
1851*4887Schin void	sh_syntax(void)
1852*4887Schin {
1853*4887Schin 	register Shell_t *shp = sh_getinterp();
1854*4887Schin 	register const char *cp = sh_translate(e_unexpected);
1855*4887Schin 	register char *tokstr;
1856*4887Schin 	register Lex_t	*lp = (Lex_t*)shp->lex_context;
1857*4887Schin 	register int tok = shlex.token;
1858*4887Schin 	char tokbuf[3];
1859*4887Schin 	Sfio_t *sp;
1860*4887Schin 	if((tok==EOFSYM) && shlex.lasttok)
1861*4887Schin 	{
1862*4887Schin 		tok = shlex.lasttok;
1863*4887Schin 		cp = sh_translate(e_unmatched);
1864*4887Schin 	}
1865*4887Schin 	else
1866*4887Schin 		shlex.lastline = shp->inlineno;
1867*4887Schin 	tokstr = fmttoken(lp,tok,tokbuf);
1868*4887Schin 	if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
1869*4887Schin 	{
1870*4887Schin 		/* clear out any pending input */
1871*4887Schin 		register Sfio_t *top;
1872*4887Schin 		while(fcget()>0);
1873*4887Schin 		fcclose();
1874*4887Schin 		while(top=sfstack(sp,SF_POPSTACK))
1875*4887Schin 			sfclose(top);
1876*4887Schin 	}
1877*4887Schin 	else
1878*4887Schin 		fcclose();
1879*4887Schin 	shp->inlineno = shlex.inlineno;
1880*4887Schin 	shp->st.firstline = shlex.firstline;
1881*4887Schin #if KSHELL
1882*4887Schin 	if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
1883*4887Schin #else
1884*4887Schin 	if(shp->inlineno!=1)
1885*4887Schin #endif
1886*4887Schin 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,shlex.lastline,tokstr,cp);
1887*4887Schin 	else
1888*4887Schin 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
1889*4887Schin }
1890*4887Schin 
1891*4887Schin static char *stack_shift(register char *sp,char *dp)
1892*4887Schin {
1893*4887Schin 	register char *ep;
1894*4887Schin 	register int offset = staktell();
1895*4887Schin 	register int left = offset-(sp-stakptr(0));
1896*4887Schin 	register int shift = (dp+1-sp);
1897*4887Schin 	offset += shift;
1898*4887Schin 	stakseek(offset);
1899*4887Schin 	sp = stakptr(offset);
1900*4887Schin 	ep = sp - shift;
1901*4887Schin 	while(left--)
1902*4887Schin 		*--sp = *--ep;
1903*4887Schin 	return(sp);
1904*4887Schin }
1905*4887Schin 
1906*4887Schin /*
1907*4887Schin  * Assumes that current word is unfrozen on top of the stak
1908*4887Schin  * If <mode> is zero, gets rid of quoting and consider argument as string
1909*4887Schin  *    and returns pointer to frozen arg
1910*4887Schin  * If mode==1, just replace $"..." strings with international strings
1911*4887Schin  *    The result is left on the stak
1912*4887Schin  * If mode==2, the each $"" string is printed on standard output
1913*4887Schin  */
1914*4887Schin struct argnod *sh_endword(int mode)
1915*4887Schin {
1916*4887Schin 	register const char *state = sh_lexstates[ST_NESTED];
1917*4887Schin 	register int n;
1918*4887Schin 	register char *sp,*dp;
1919*4887Schin 	register int inquote=0, inlit=0; /* set within quoted strings */
1920*4887Schin 	struct argnod* argp=0;
1921*4887Schin 	char	*ep=0, *xp=0;
1922*4887Schin 	int bracket=0;
1923*4887Schin 	stakputc(0);
1924*4887Schin 	sp =  stakptr(ARGVAL);
1925*4887Schin #if SHOPT_MULTIBYTE
1926*4887Schin 	if(mbwide())
1927*4887Schin 	{
1928*4887Schin 		do
1929*4887Schin 		{
1930*4887Schin 			int len;
1931*4887Schin 			switch(len = mbsize(sp))
1932*4887Schin 			{
1933*4887Schin 			    case -1:	/* illegal multi-byte char */
1934*4887Schin 			    case 0:
1935*4887Schin 			    case 1:
1936*4887Schin 				n=state[*sp++];
1937*4887Schin 				break;
1938*4887Schin 			    default:
1939*4887Schin 				/*
1940*4887Schin 				 * None of the state tables contain
1941*4887Schin 				 * entries for multibyte characters,
1942*4887Schin 				 * however, they should be treated
1943*4887Schin 				 * the same as any other alph
1944*4887Schin 				 * character.  Therefore, we'll use
1945*4887Schin 				 * the state of the 'a' character.
1946*4887Schin 				 */
1947*4887Schin 				n=state['a'];
1948*4887Schin 				sp += len;
1949*4887Schin 			}
1950*4887Schin 		}
1951*4887Schin 		while(n == 0);
1952*4887Schin 	}
1953*4887Schin 	else
1954*4887Schin #endif /* SHOPT_MULTIBYTE */
1955*4887Schin 	while((n=state[*sp++])==0);
1956*4887Schin 	dp = sp;
1957*4887Schin 	if(mode<0)
1958*4887Schin 		inquote = 1;
1959*4887Schin 	while(1)
1960*4887Schin 	{
1961*4887Schin 		switch(n)
1962*4887Schin 		{
1963*4887Schin 		    case S_EOF:
1964*4887Schin 			stakseek(dp-stakptr(0));
1965*4887Schin 			if(mode<=0)
1966*4887Schin 			{
1967*4887Schin 				argp = (struct argnod*)stakfreeze(0);
1968*4887Schin 				argp->argflag = ARG_RAW|ARG_QUOTED;
1969*4887Schin 			}
1970*4887Schin 			return(argp);
1971*4887Schin 		    case S_LIT:
1972*4887Schin 			if(!(inquote&1))
1973*4887Schin 			{
1974*4887Schin 				inlit = !inlit;
1975*4887Schin 				if(mode==0 || (mode<0 && bracket))
1976*4887Schin 				{
1977*4887Schin 					dp--;
1978*4887Schin 					if(ep)
1979*4887Schin 					{
1980*4887Schin 						*dp = 0;
1981*4887Schin 						dp = ep+stresc(ep);
1982*4887Schin 					}
1983*4887Schin 					ep = 0;
1984*4887Schin 				}
1985*4887Schin 			}
1986*4887Schin 			break;
1987*4887Schin 		    case S_QUOTE:
1988*4887Schin 			if(mode<0 && !bracket)
1989*4887Schin 				break;
1990*4887Schin 			if(!inlit)
1991*4887Schin 			{
1992*4887Schin 				if(mode<=0)
1993*4887Schin 					dp--;
1994*4887Schin 				inquote = inquote^1;
1995*4887Schin 				if(ep)
1996*4887Schin 				{
1997*4887Schin 					char *msg;
1998*4887Schin 					if(mode==2)
1999*4887Schin 					{
2000*4887Schin 						sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
2001*4887Schin 						ep = 0;
2002*4887Schin 						break;
2003*4887Schin 					}
2004*4887Schin 					*--dp = 0;
2005*4887Schin #if ERROR_VERSION >= 20000317L
2006*4887Schin 					msg = ERROR_translate(0,error_info.id,0,ep);
2007*4887Schin #else
2008*4887Schin #   if ERROR_VERSION >= 20000101L
2009*4887Schin 					msg = ERROR_translate(error_info.id,ep);
2010*4887Schin #   else
2011*4887Schin 					msg = ERROR_translate(ep,2);
2012*4887Schin #   endif
2013*4887Schin #endif
2014*4887Schin 					n = strlen(msg);
2015*4887Schin 					dp = ep+n;
2016*4887Schin 					if(sp-dp <= 1)
2017*4887Schin 					{
2018*4887Schin 						sp = stack_shift(sp,dp);
2019*4887Schin 						dp = sp-1;
2020*4887Schin 						ep = dp-n;
2021*4887Schin 					}
2022*4887Schin 					memmove(ep,msg,n);
2023*4887Schin 					*dp++ = '"';
2024*4887Schin 				}
2025*4887Schin 				ep = 0;
2026*4887Schin 			}
2027*4887Schin 			break;
2028*4887Schin 		    case S_DOL:	/* check for $'...'  and $"..." */
2029*4887Schin 			if(inlit)
2030*4887Schin 				break;
2031*4887Schin 			if(*sp==LPAREN || *sp==LBRACE)
2032*4887Schin 			{
2033*4887Schin 				inquote <<= 1;
2034*4887Schin 				break;
2035*4887Schin 			}
2036*4887Schin 			if(inquote&1)
2037*4887Schin 				break;
2038*4887Schin 			if(*sp=='\'' || *sp=='"')
2039*4887Schin 			{
2040*4887Schin 				if(*sp=='"')
2041*4887Schin 					inquote |= 1;
2042*4887Schin 				else
2043*4887Schin 					inlit = 1;
2044*4887Schin 				sp++;
2045*4887Schin 				if((mode==0||(mode<0&&bracket)) || (inquote&1))
2046*4887Schin 				{
2047*4887Schin 					if(mode==2)
2048*4887Schin 						ep = dp++;
2049*4887Schin 					else if(mode==1)
2050*4887Schin 						(ep=dp)[-1] = '"';
2051*4887Schin 					else
2052*4887Schin 						ep = --dp;
2053*4887Schin 				}
2054*4887Schin 			}
2055*4887Schin 			break;
2056*4887Schin 		    case S_ESC:
2057*4887Schin #if SHOPT_CRNL
2058*4887Schin 			if(*sp=='\r' && sp[1]=='\n')
2059*4887Schin 				sp++;
2060*4887Schin #endif /* SHOPT_CRNL */
2061*4887Schin 			if(inlit || mode>0)
2062*4887Schin 			{
2063*4887Schin 				if(mode<0)
2064*4887Schin 				{
2065*4887Schin 					if(dp>=sp)
2066*4887Schin 					{
2067*4887Schin 						sp = stack_shift(sp,dp+1);
2068*4887Schin 						dp = sp-2;
2069*4887Schin 					}
2070*4887Schin 					*dp++ = '\\';
2071*4887Schin 				}
2072*4887Schin 				if(ep)
2073*4887Schin 					*dp++ = *sp++;
2074*4887Schin 				break;
2075*4887Schin 			}
2076*4887Schin 			n = *sp;
2077*4887Schin #if SHOPT_DOS
2078*4887Schin 			if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
2079*4887Schin 				break;
2080*4887Schin #endif /* SHOPT_DOS */
2081*4887Schin 			if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
2082*4887Schin 			{
2083*4887Schin 				if(n=='\n')
2084*4887Schin 					dp--;
2085*4887Schin 				else
2086*4887Schin 					dp[-1] = n;
2087*4887Schin 				sp++;
2088*4887Schin 			}
2089*4887Schin 			break;
2090*4887Schin 		    case S_POP:
2091*4887Schin 			if(sp[-1]!=RBRACT)
2092*4887Schin 				break;
2093*4887Schin 			if(!inlit && !(inquote&1))
2094*4887Schin 			{
2095*4887Schin 				inquote >>= 1;
2096*4887Schin 				if(xp)
2097*4887Schin 					dp = sh_checkid(xp,dp);
2098*4887Schin 				xp = 0;
2099*4887Schin 				if(--bracket<=0 && mode<0)
2100*4887Schin 					inquote = 1;
2101*4887Schin 			}
2102*4887Schin 			else if((inlit||inquote) && mode<0)
2103*4887Schin 			{
2104*4887Schin 				dp[-1] = '\\';
2105*4887Schin 				if(dp>=sp)
2106*4887Schin 				{
2107*4887Schin 					sp = stack_shift(sp,dp);
2108*4887Schin 					dp = sp-1;
2109*4887Schin 				}
2110*4887Schin 				*dp++ = ']';
2111*4887Schin 			}
2112*4887Schin 			break;
2113*4887Schin 		    case S_BRACT:
2114*4887Schin 			if(dp[-2]=='.')
2115*4887Schin 				xp = dp;
2116*4887Schin 			if(mode<0)
2117*4887Schin 			{
2118*4887Schin 				if(inlit || (bracket&&inquote))
2119*4887Schin 				{
2120*4887Schin 					dp[-1] = '\\';
2121*4887Schin 					if(dp>=sp)
2122*4887Schin 					{
2123*4887Schin 						sp = stack_shift(sp,dp);
2124*4887Schin 						dp = sp-1;
2125*4887Schin 					}
2126*4887Schin 					*dp++ = '[';
2127*4887Schin 				}
2128*4887Schin 				else if(bracket++==0)
2129*4887Schin 					inquote = 0;
2130*4887Schin 			}
2131*4887Schin 			break;
2132*4887Schin 		}
2133*4887Schin #if SHOPT_MULTIBYTE
2134*4887Schin 		if(mbwide())
2135*4887Schin 		{
2136*4887Schin 			do
2137*4887Schin 			{
2138*4887Schin 				int len;
2139*4887Schin 				switch(len = mbsize(sp))
2140*4887Schin 				{
2141*4887Schin 				    case -1: /* illegal multi-byte char */
2142*4887Schin 				    case 0:
2143*4887Schin 				    case 1:
2144*4887Schin 					n=state[*dp++ = *sp++];
2145*4887Schin 					break;
2146*4887Schin 				    default:
2147*4887Schin 					/*
2148*4887Schin 					 * None of the state tables contain
2149*4887Schin 					 * entries for multibyte characters,
2150*4887Schin 					 * however, they should be treated
2151*4887Schin 					 * the same as any other alph
2152*4887Schin 					 * character.  Therefore, we'll use
2153*4887Schin 					 * the state of the 'a' character.
2154*4887Schin 					 */
2155*4887Schin 					while(len--)
2156*4887Schin 						*dp++ = *sp++;
2157*4887Schin 					n=state['a'];
2158*4887Schin 				}
2159*4887Schin 			}
2160*4887Schin 			while(n == 0);
2161*4887Schin 		}
2162*4887Schin 		else
2163*4887Schin #endif /* SHOPT_MULTIBYTE */
2164*4887Schin 		while((n=state[*dp++ = *sp++])==0);
2165*4887Schin 	}
2166*4887Schin }
2167*4887Schin 
2168*4887Schin struct alias
2169*4887Schin {
2170*4887Schin 	Sfdisc_t	disc;
2171*4887Schin 	Namval_t	*np;
2172*4887Schin 	int		nextc;
2173*4887Schin 	int		line;
2174*4887Schin 	char		buf[2];
2175*4887Schin 	Lex_t		*lp;
2176*4887Schin };
2177*4887Schin 
2178*4887Schin /*
2179*4887Schin  * This code gets called whenever an end of string is found with alias
2180*4887Schin  */
2181*4887Schin 
2182*4887Schin #ifndef SF_ATEXIT
2183*4887Schin #   define SF_ATEXIT	0
2184*4887Schin #endif
2185*4887Schin /*
2186*4887Schin  * This code gets called whenever an end of string is found with alias
2187*4887Schin  */
2188*4887Schin #ifdef SF_BUFCONST
2189*4887Schin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
2190*4887Schin #else
2191*4887Schin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
2192*4887Schin #endif
2193*4887Schin {
2194*4887Schin 	register struct alias *ap = (struct alias*)handle;
2195*4887Schin 	register Namval_t *np;
2196*4887Schin 	register Lex_t	*lp;
2197*4887Schin 	if(type==0 || type==SF_ATEXIT || !ap)
2198*4887Schin 		return(0);
2199*4887Schin 	lp = ap->lp;
2200*4887Schin 	np = ap->np;
2201*4887Schin 	if(type!=SF_READ)
2202*4887Schin 	{
2203*4887Schin 		if(type==SF_CLOSING)
2204*4887Schin 		{
2205*4887Schin 			register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
2206*4887Schin 			if(dp!=handle)
2207*4887Schin 				sfdisc(iop,dp);
2208*4887Schin 		}
2209*4887Schin 		else if(type==SF_FINAL)
2210*4887Schin 			free((void*)ap);
2211*4887Schin 		goto done;
2212*4887Schin 	}
2213*4887Schin 	if(ap->nextc)
2214*4887Schin 	{
2215*4887Schin 		/* if last character is a blank, then next work can be alias */
2216*4887Schin 		register int c = fcpeek(-1);
2217*4887Schin 		if(isblank(c))
2218*4887Schin 			shlex.aliasok = 1;
2219*4887Schin 		*ap->buf = ap->nextc;
2220*4887Schin 		ap->nextc = 0;
2221*4887Schin 		sfsetbuf(iop,ap->buf,1);
2222*4887Schin 		return(1);
2223*4887Schin 	}
2224*4887Schin done:
2225*4887Schin 	if(np)
2226*4887Schin 		nv_offattr(np,NV_NOEXPAND);
2227*4887Schin 	return(0);
2228*4887Schin }
2229*4887Schin 
2230*4887Schin 
2231*4887Schin static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
2232*4887Schin {
2233*4887Schin 	register Sfio_t *iop, *base;
2234*4887Schin 	struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
2235*4887Schin 	ap->disc = alias_disc;
2236*4887Schin 	ap->lp = lp;
2237*4887Schin 	ap->buf[1] = 0;
2238*4887Schin 	if(ap->np = np)
2239*4887Schin 	{
2240*4887Schin #if SHOPT_KIA
2241*4887Schin 		if(shlex.kiafile)
2242*4887Schin 		{
2243*4887Schin 			unsigned long r;
2244*4887Schin 			r=kiaentity(nv_name(np),-1,'p',0,0,shlex.current,'a',0,"");
2245*4887Schin 			sfprintf(shlex.kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",shlex.current,r,shlex.sh->inlineno,shlex.sh->inlineno);
2246*4887Schin 		}
2247*4887Schin #endif /* SHOPT_KIA */
2248*4887Schin 		if((ap->nextc=fcget())==0)
2249*4887Schin 			ap->nextc = ' ';
2250*4887Schin 	}
2251*4887Schin 	else
2252*4887Schin 		ap->nextc = 0;
2253*4887Schin 	iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
2254*4887Schin 	sfdisc(iop, &ap->disc);
2255*4887Schin 	lexd.nocopy++;
2256*4887Schin 	if(!(base=fcfile()))
2257*4887Schin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
2258*4887Schin 	fcclose();
2259*4887Schin 	sfstack(base,iop);
2260*4887Schin 	fcfopen(base);
2261*4887Schin 	lexd.nocopy--;
2262*4887Schin }
2263*4887Schin 
2264*4887Schin /*
2265*4887Schin  * grow storage stack for nested constructs by STACK_ARRAY
2266*4887Schin  */
2267*4887Schin static int stack_grow(Lex_t *lp)
2268*4887Schin {
2269*4887Schin 	lexd.lex_max += STACK_ARRAY;
2270*4887Schin 	if(lexd.lex_match)
2271*4887Schin 		lexd.lex_match = (int*)realloc((char*)lexd.lex_match,sizeof(int)*lexd.lex_max);
2272*4887Schin 	else
2273*4887Schin 		lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
2274*4887Schin 	return(lexd.lex_match!=0);
2275*4887Schin }
2276*4887Schin 
2277