xref: /illumos-gate/usr/src/contrib/ast/src/cmd/ksh93/sh/lex.c (revision be548e87)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4b30d1939SAndy Fiddaman *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * KornShell  lexical analyzer
23da2e3ebdSchin  *
24da2e3ebdSchin  * Written by David Korn
25da2e3ebdSchin  * AT&T Labs
26da2e3ebdSchin  *
27da2e3ebdSchin  */
28b30d1939SAndy Fiddaman /*
29b30d1939SAndy Fiddaman  * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
30b30d1939SAndy Fiddaman  */
31da2e3ebdSchin 
32da2e3ebdSchin #include	<ast.h>
33da2e3ebdSchin #include	<stak.h>
34da2e3ebdSchin #include	<fcin.h>
35da2e3ebdSchin #include	<nval.h>
36da2e3ebdSchin #include	"FEATURE/options"
37da2e3ebdSchin 
38da2e3ebdSchin #if KSHELL
39da2e3ebdSchin #   include	"defs.h"
40da2e3ebdSchin #else
41da2e3ebdSchin #   include	<shell.h>
42da2e3ebdSchin #   define	nv_getval(np)	((np)->nvalue)
43da2e3ebdSchin     Shell_t sh  =  {1};
44da2e3ebdSchin #endif /* KSHELL */
45da2e3ebdSchin 
46da2e3ebdSchin #include	"argnod.h"
47da2e3ebdSchin #include	"test.h"
48da2e3ebdSchin #include	"lexstates.h"
49da2e3ebdSchin #include	"io.h"
50da2e3ebdSchin 
51da2e3ebdSchin #define TEST_RE		3
52da2e3ebdSchin #define SYNBAD		3	/* exit value for syntax errors */
53da2e3ebdSchin #define STACK_ARRAY	3	/* size of depth match stack growth */
54da2e3ebdSchin 
55da2e3ebdSchin #if _lib_iswblank < 0	/* set in lexstates.h to enable this code */
56da2e3ebdSchin 
57da2e3ebdSchin int
local_iswblank(wchar_t wc)58da2e3ebdSchin local_iswblank(wchar_t wc)
59da2e3ebdSchin {
60da2e3ebdSchin 	static int      initialized;
61da2e3ebdSchin 	static wctype_t wt;
62da2e3ebdSchin 
63da2e3ebdSchin 	if (!initialized)
64da2e3ebdSchin 	{
65da2e3ebdSchin 		initialized = 1;
66da2e3ebdSchin 		wt = wctype("blank");
67da2e3ebdSchin 	}
68da2e3ebdSchin 	return(iswctype(wc, wt));
69da2e3ebdSchin }
70da2e3ebdSchin 
71da2e3ebdSchin #endif
72da2e3ebdSchin 
73da2e3ebdSchin /*
74da2e3ebdSchin  * This structure allows for arbitrary depth nesting of (...), {...}, [...]
75da2e3ebdSchin  */
76da2e3ebdSchin struct lexstate
77da2e3ebdSchin {
78da2e3ebdSchin 	char		incase;		/* 1 for case pattern, 2 after case */
79da2e3ebdSchin 	char		intest;		/* 1 inside [[...]] */
80da2e3ebdSchin 	char		testop1;	/* 1 when unary test op legal */
81da2e3ebdSchin 	char		testop2;	/* 1 when binary test op legal */
82da2e3ebdSchin 	char		reservok;	/* >0 for reserved word legal */
83da2e3ebdSchin 	char		skipword;	/* next word can't be reserved */
84da2e3ebdSchin 	char		last_quote;	/* last multi-line quote character */
85b30d1939SAndy Fiddaman 	char		nestedbrace;	/* ${var op {...}} */
86da2e3ebdSchin };
87da2e3ebdSchin 
88da2e3ebdSchin struct lexdata
89da2e3ebdSchin {
90da2e3ebdSchin 	char		nocopy;
91da2e3ebdSchin 	char		paren;
92da2e3ebdSchin 	char		dolparen;
93da2e3ebdSchin 	char		nest;
94da2e3ebdSchin 	char		docword;
95b30d1939SAndy Fiddaman 	char		nested_tilde;
96da2e3ebdSchin 	char 		*docend;
97da2e3ebdSchin 	char		noarg;
98da2e3ebdSchin 	char		balance;
99da2e3ebdSchin 	char		warn;
100da2e3ebdSchin 	char		message;
101da2e3ebdSchin 	char		arith;
102da2e3ebdSchin 	char 		*first;
103da2e3ebdSchin 	int		level;
104da2e3ebdSchin 	int		lastc;
105da2e3ebdSchin 	int		lex_max;
106da2e3ebdSchin 	int		*lex_match;
107da2e3ebdSchin 	int		lex_state;
10834f9b3eeSRoland Mainz 	int		docextra;
109da2e3ebdSchin #if SHOPT_KIA
110da2e3ebdSchin 	off_t		kiaoff;
111da2e3ebdSchin #endif
112da2e3ebdSchin };
113da2e3ebdSchin 
114da2e3ebdSchin #define _SHLEX_PRIVATE \
1157c2fbfb3SApril Chin 	struct lexdata  lexd; \
1167c2fbfb3SApril Chin 	struct lexstate  lex;
117da2e3ebdSchin 
118da2e3ebdSchin #include	"shlex.h"
119da2e3ebdSchin 
120da2e3ebdSchin 
1217c2fbfb3SApril Chin #define	pushlevel(lp,c,s)	((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\
1227c2fbfb3SApril Chin 				((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\
1237c2fbfb3SApril Chin 				lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
1247c2fbfb3SApril Chin #define oldmode(lp)	(lp->lexd.lastc>>CHAR_BIT)
1257c2fbfb3SApril Chin #define endchar(lp)	(lp->lexd.lastc&0xff)
1267c2fbfb3SApril Chin #define setchar(lp,c)	(lp->lexd.lastc = ((lp->lexd.lastc&~0xff)|(c)))
1277c2fbfb3SApril Chin #define poplevel(lp)	(lp->lexd.lastc=lp->lexd.lex_match[--lp->lexd.level])
128da2e3ebdSchin 
129da2e3ebdSchin static char		*fmttoken(Lex_t*, int, char*);
130da2e3ebdSchin #ifdef SF_BUFCONST
131da2e3ebdSchin     static int          alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
132da2e3ebdSchin #else
133da2e3ebdSchin     static int 		alias_exceptf(Sfio_t*, int, Sfdisc_t*);
134da2e3ebdSchin #endif
135da2e3ebdSchin static void		setupalias(Lex_t*,const char*, Namval_t*);
1367c2fbfb3SApril Chin static int		comsub(Lex_t*,int);
137da2e3ebdSchin static void		nested_here(Lex_t*);
138da2e3ebdSchin static int		here_copy(Lex_t*, struct ionod*);
139da2e3ebdSchin static int 		stack_grow(Lex_t*);
140da2e3ebdSchin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL };
141da2e3ebdSchin 
142da2e3ebdSchin #if SHOPT_KIA
143da2e3ebdSchin 
refvar(Lex_t * lp,int type)1447c2fbfb3SApril Chin static void refvar(Lex_t *lp, int type)
145da2e3ebdSchin {
1467c2fbfb3SApril Chin 	register Shell_t *shp = lp->sh;
1477c2fbfb3SApril Chin 	register Stk_t	*stkp = shp->stk;
1487c2fbfb3SApril Chin 	off_t off = (fcseek(0)-(type+1))-(lp->lexd.first?lp->lexd.first:fcfirst());
149da2e3ebdSchin 	unsigned long r;
1507c2fbfb3SApril Chin 	if(lp->lexd.first)
151da2e3ebdSchin 	{
1527c2fbfb3SApril Chin 		off = (fcseek(0)-(type+1)) - lp->lexd.first;
1537c2fbfb3SApril Chin 		r=kiaentity(lp,lp->lexd.first+lp->lexd.kiaoff+type,off-lp->lexd.kiaoff,'v',-1,-1,lp->current,'v',0,"");
154da2e3ebdSchin 	}
155da2e3ebdSchin 	else
156da2e3ebdSchin 	{
1577c2fbfb3SApril Chin 		int n,offset = stktell(stkp);
158da2e3ebdSchin 		char *savptr,*begin;
159da2e3ebdSchin 		off = offset + (fcseek(0)-(type+1)) - fcfirst();
1607c2fbfb3SApril Chin 		if(lp->lexd.kiaoff < offset)
161da2e3ebdSchin 		{
162da2e3ebdSchin 			/* variable starts on stak, copy remainder */
163da2e3ebdSchin 			if(off>offset)
1647c2fbfb3SApril Chin 				sfwrite(stkp,fcfirst()+type,off-offset);
1657c2fbfb3SApril Chin 			n = stktell(stkp)-lp->lexd.kiaoff;
1667c2fbfb3SApril Chin 			begin = stkptr(stkp,lp->lexd.kiaoff);
167da2e3ebdSchin 		}
168da2e3ebdSchin 		else
169da2e3ebdSchin 		{
170da2e3ebdSchin 			/* variable in data buffer */
1717c2fbfb3SApril Chin 			begin = fcfirst()+(type+lp->lexd.kiaoff-offset);
1727c2fbfb3SApril Chin 			n = off-lp->lexd.kiaoff;
173da2e3ebdSchin 		}
1747c2fbfb3SApril Chin 		savptr = stkfreeze(stkp,0);
1757c2fbfb3SApril Chin 		r=kiaentity(lp,begin,n,'v',-1,-1,lp->current,'v',0,"");
1767c2fbfb3SApril Chin 		stkset(stkp,savptr,offset);
177da2e3ebdSchin 	}
1787c2fbfb3SApril Chin 	sfprintf(lp->kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",lp->current,r,shp->inlineno,shp->inlineno);
179da2e3ebdSchin }
180da2e3ebdSchin #endif /* SHOPT_KIA */
181da2e3ebdSchin 
182da2e3ebdSchin /*
183da2e3ebdSchin  * This routine gets called when reading across a buffer boundary
184da2e3ebdSchin  * If lexd.nocopy is off, then current token is saved on the stack
185da2e3ebdSchin  */
lex_advance(Sfio_t * iop,const char * buff,register int size,void * context)1867c2fbfb3SApril Chin static void lex_advance(Sfio_t *iop, const char *buff, register int size, void *context)
187da2e3ebdSchin {
1887c2fbfb3SApril Chin 	register Lex_t		*lp = (Lex_t*)context;
1897c2fbfb3SApril Chin 	register Shell_t	*shp = lp->sh;
1907c2fbfb3SApril Chin 	register Sfio_t		*log= shp->funlog;
1917c2fbfb3SApril Chin 	Stk_t			*stkp = shp->stk;
192da2e3ebdSchin #if KSHELL
193da2e3ebdSchin 	/* write to history file and to stderr if necessary */
194da2e3ebdSchin 	if(iop && !sfstacked(iop))
195da2e3ebdSchin 	{
196b30d1939SAndy Fiddaman 		if(sh_isstate(SH_HISTORY) && shp->gd->hist_ptr)
197b30d1939SAndy Fiddaman 			log = shp->gd->hist_ptr->histfp;
198da2e3ebdSchin 		sfwrite(log, (void*)buff, size);
199da2e3ebdSchin 		if(sh_isstate(SH_VERBOSE))
200da2e3ebdSchin 			sfwrite(sfstderr, buff, size);
201da2e3ebdSchin 	}
202da2e3ebdSchin #endif
2037c2fbfb3SApril Chin 	if(lp->lexd.nocopy)
204da2e3ebdSchin 		return;
205b30d1939SAndy Fiddaman 	if(lp->lexd.dolparen && lp->lexd.docword && lp->lexd.docend)
20634f9b3eeSRoland Mainz 	{
20734f9b3eeSRoland Mainz 		int n = size - (lp->lexd.docend-(char*)buff);
20834f9b3eeSRoland Mainz 		sfwrite(shp->strbuf,lp->lexd.docend,n);
20934f9b3eeSRoland Mainz 		lp->lexd.docextra  += n;
210b30d1939SAndy Fiddaman 		if(sffileno(iop)>=0)
211b30d1939SAndy Fiddaman 			lp->lexd.docend = sfsetbuf(iop,(Void_t*)iop,0);
212b30d1939SAndy Fiddaman 		else
213b30d1939SAndy Fiddaman 			lp->lexd.docend = fcfirst();
21434f9b3eeSRoland Mainz 	}
2157c2fbfb3SApril Chin 	if(lp->lexd.first)
216da2e3ebdSchin 	{
2177c2fbfb3SApril Chin 		size -= (lp->lexd.first-(char*)buff);
2187c2fbfb3SApril Chin 		buff = lp->lexd.first;
2197c2fbfb3SApril Chin 		if(!lp->lexd.noarg)
2207c2fbfb3SApril Chin 			lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
221da2e3ebdSchin #if SHOPT_KIA
2227c2fbfb3SApril Chin 		lp->lexd.kiaoff += ARGVAL;
223da2e3ebdSchin #endif /* SHOPT_KIA */
224da2e3ebdSchin 	}
2257c2fbfb3SApril Chin 	if(size>0 && (lp->arg||lp->lexd.noarg))
226da2e3ebdSchin 	{
2277c2fbfb3SApril Chin 		sfwrite(stkp,buff,size);
2287c2fbfb3SApril Chin 		lp->lexd.first = 0;
229da2e3ebdSchin 	}
230da2e3ebdSchin }
231da2e3ebdSchin 
232da2e3ebdSchin /*
233da2e3ebdSchin  * fill up another input buffer
234da2e3ebdSchin  * preserves lexical state
235da2e3ebdSchin  */
lexfill(Lex_t * lp)2367c2fbfb3SApril Chin static int lexfill(Lex_t *lp)
237da2e3ebdSchin {
238da2e3ebdSchin 	register int c;
2397c2fbfb3SApril Chin 	Lex_t savelex;
240da2e3ebdSchin 	struct argnod *ap;
24134f9b3eeSRoland Mainz 	int aok,docextra;
2427c2fbfb3SApril Chin 	savelex = *lp;
2437c2fbfb3SApril Chin 	ap = lp->arg;
244da2e3ebdSchin 	c = fcfill();
245da2e3ebdSchin 	if(ap)
2467c2fbfb3SApril Chin 		lp->arg = ap;
24734f9b3eeSRoland Mainz 	docextra = lp->lexd.docextra;
2487c2fbfb3SApril Chin 	lp->lex = savelex.lex;
2497c2fbfb3SApril Chin 	lp->lexd = savelex.lexd;
2507c2fbfb3SApril Chin 	if(fcfile() ||  c)
2517c2fbfb3SApril Chin 		lp->lexd.first = 0;
2527c2fbfb3SApril Chin 	aok= lp->aliasok;
2537c2fbfb3SApril Chin 	ap = lp->arg;
2547c2fbfb3SApril Chin 	memcpy(lp, &savelex, offsetof(Lex_t,lexd));
2557c2fbfb3SApril Chin 	lp->arg = ap;
2567c2fbfb3SApril Chin 	lp->aliasok = aok;
25734f9b3eeSRoland Mainz 	if(lp->lexd.docword && docextra)
25834f9b3eeSRoland Mainz 	{
25934f9b3eeSRoland Mainz 		lp->lexd.docextra = docextra;
26034f9b3eeSRoland Mainz 		lp->lexd.docend = fcseek(0)-1;
26134f9b3eeSRoland Mainz 	}
262da2e3ebdSchin 	return(c);
263da2e3ebdSchin }
264da2e3ebdSchin 
265da2e3ebdSchin /*
266da2e3ebdSchin  * mode=1 for reinitialization
267da2e3ebdSchin  */
sh_lexopen(Lex_t * lp,Shell_t * sp,int mode)268da2e3ebdSchin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode)
269da2e3ebdSchin {
270da2e3ebdSchin 	if(!lp)
271da2e3ebdSchin 	{
272da2e3ebdSchin 		lp = (Lex_t*)newof(0,Lex_t,1,0);
2737c2fbfb3SApril Chin 		lp->sh = sp;
274da2e3ebdSchin 	}
2757c2fbfb3SApril Chin 	fcnotify(lex_advance,lp);
2767c2fbfb3SApril Chin 	lp->lex.intest = lp->lex.incase = lp->lex.skipword = lp->lexd.warn = 0;
2777c2fbfb3SApril Chin 	lp->comp_assign = 0;
2787c2fbfb3SApril Chin 	lp->lex.reservok = 1;
279da2e3ebdSchin 	if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC))
2807c2fbfb3SApril Chin 		lp->lexd.warn=1;
281da2e3ebdSchin 	if(!mode)
282da2e3ebdSchin 	{
2837c2fbfb3SApril Chin 		lp->lexd.noarg = lp->lexd.level= lp->lexd.dolparen = lp->lexd.balance = 0;
2847c2fbfb3SApril Chin 		lp->lexd.nocopy = lp->lexd.docword = lp->lexd.nest = lp->lexd.paren = 0;
2853e14f97fSRoger A. Faulkner 		lp->lexd.lex_state = lp->lexd.lastc=0;
286b30d1939SAndy Fiddaman 		lp->lexd.docend = 0;
287b30d1939SAndy Fiddaman 		lp->lexd.nested_tilde = 0;
288da2e3ebdSchin 	}
2897c2fbfb3SApril Chin 	lp->comsub = 0;
290da2e3ebdSchin 	return(lp);
291da2e3ebdSchin }
292da2e3ebdSchin 
293da2e3ebdSchin #ifdef DBUG
2947c2fbfb3SApril Chin extern int lextoken(Lex_t*);
sh_lex(Lex_t * lp)2957c2fbfb3SApril Chin int sh_lex(Lex_t *lp)
296da2e3ebdSchin {
2977c2fbfb3SApril Chin 	Shell_t *shp = lp->sh;
298da2e3ebdSchin 	register int flag;
299da2e3ebdSchin 	char *quoted, *macro, *split, *expand;
300da2e3ebdSchin 	char tokstr[3];
301b30d1939SAndy Fiddaman 	register int tok = lextoken(lp);
302da2e3ebdSchin 	quoted = macro = split = expand = "";
3037c2fbfb3SApril Chin 	if(tok==0 && (flag=lp->arg->argflag))
304da2e3ebdSchin 	{
305da2e3ebdSchin 		if(flag&ARG_MAC)
306da2e3ebdSchin 			macro = "macro:";
307da2e3ebdSchin 		if(flag&ARG_EXP)
308da2e3ebdSchin 			expand = "expand:";
309da2e3ebdSchin 		if(flag&ARG_QUOTED)
310da2e3ebdSchin 			quoted = "quoted:";
311da2e3ebdSchin 	}
312b30d1939SAndy Fiddaman 	sfprintf(sfstderr,"%d: line %d: %o:%s%s%s%s %s\n",getpid(),shp->inlineno,tok,quoted,
313da2e3ebdSchin 		macro, split, expand, fmttoken(lp,tok,tokstr));
314da2e3ebdSchin 	return(tok);
315da2e3ebdSchin }
316da2e3ebdSchin #define sh_lex	lextoken
317da2e3ebdSchin #endif
318da2e3ebdSchin 
319da2e3ebdSchin /*
320da2e3ebdSchin  * Get the next word and put it on the top of the stak
3217c2fbfb3SApril Chin  * A pointer to the current word is stored in lp->arg
322da2e3ebdSchin  * Returns the token type
323da2e3ebdSchin  */
sh_lex(Lex_t * lp)3247c2fbfb3SApril Chin int sh_lex(Lex_t* lp)
325da2e3ebdSchin {
3267c2fbfb3SApril Chin 	register Shell_t *shp = lp->sh;
327da2e3ebdSchin 	register const char	*state;
3287c2fbfb3SApril Chin 	register int		n, c, mode=ST_BEGIN, wordflags=0;
3297c2fbfb3SApril Chin 	Stk_t			*stkp = shp->stk;
3307c2fbfb3SApril Chin 	int		inlevel=lp->lexd.level, assignment=0, ingrave=0;
331b30d1939SAndy Fiddaman 	int		epatchar=0;
332da2e3ebdSchin 	Sfio_t *sp;
333da2e3ebdSchin #if SHOPT_MULTIBYTE
334da2e3ebdSchin 	LEN=1;
335da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
3367c2fbfb3SApril Chin 	if(lp->lexd.paren)
337da2e3ebdSchin 	{
3387c2fbfb3SApril Chin 		lp->lexd.paren = 0;
3397c2fbfb3SApril Chin 		return(lp->token=LPAREN);
340da2e3ebdSchin 	}
341b30d1939SAndy Fiddaman 	if(lp->noreserv)
342b30d1939SAndy Fiddaman 	{
343b30d1939SAndy Fiddaman 		lp->lex.reservok = 0;
344b30d1939SAndy Fiddaman 		while((fcgetc(c)) && c==' ' || c== '\t' || c=='\n');
345b30d1939SAndy Fiddaman 		fcseek(-LEN);
346b30d1939SAndy Fiddaman 		if(c=='[')
347b30d1939SAndy Fiddaman 			lp->assignok = SH_ASSIGN;
348b30d1939SAndy Fiddaman 	}
3497c2fbfb3SApril Chin 	if(lp->lex.incase)
3507c2fbfb3SApril Chin 		lp->assignok = 0;
351da2e3ebdSchin 	else
3527c2fbfb3SApril Chin 		lp->assignok |= lp->lex.reservok;
3537c2fbfb3SApril Chin 	if(lp->comp_assign==2)
3547c2fbfb3SApril Chin 		lp->comp_assign = lp->lex.reservok = 0;
3557c2fbfb3SApril Chin 	lp->lexd.arith = (lp->lexd.nest==1);
3567c2fbfb3SApril Chin 	if(lp->lexd.nest)
357da2e3ebdSchin 	{
3587c2fbfb3SApril Chin 		pushlevel(lp,lp->lexd.nest,ST_NONE);
3597c2fbfb3SApril Chin 		lp->lexd.nest = 0;
3607c2fbfb3SApril Chin 		mode = lp->lexd.lex_state;
361da2e3ebdSchin 	}
3627c2fbfb3SApril Chin 	else if(lp->lexd.docword)
363da2e3ebdSchin 	{
364da2e3ebdSchin 		if(fcgetc(c)=='-' || c=='#')
365da2e3ebdSchin 		{
3667c2fbfb3SApril Chin 			lp->lexd.docword++;
3677c2fbfb3SApril Chin 			lp->digits=(c=='#'?3:1);
368da2e3ebdSchin 		}
369da2e3ebdSchin 		else if(c=='<')
370da2e3ebdSchin 		{
3717c2fbfb3SApril Chin 			lp->digits=2;
3727c2fbfb3SApril Chin 			lp->lexd.docword=0;
373da2e3ebdSchin 		}
374da2e3ebdSchin 		else if(c>0)
375b30d1939SAndy Fiddaman 			fcseek(-LEN);
376da2e3ebdSchin 	}
3777c2fbfb3SApril Chin 	if(!lp->lexd.dolparen)
378da2e3ebdSchin 	{
3797c2fbfb3SApril Chin 		lp->arg = 0;
380da2e3ebdSchin 		if(mode!=ST_BEGIN)
3817c2fbfb3SApril Chin 			lp->lexd.first = fcseek(0);
382da2e3ebdSchin 		else
3837c2fbfb3SApril Chin 			lp->lexd.first = 0;
384da2e3ebdSchin 	}
3857c2fbfb3SApril Chin 	lp->lastline = lp->sh->inlineno;
386da2e3ebdSchin 	while(1)
387da2e3ebdSchin 	{
388da2e3ebdSchin 		/* skip over characters in the current state */
389da2e3ebdSchin 		state = sh_lexstates[mode];
390da2e3ebdSchin 		while((n=STATE(state,c))==0);
391da2e3ebdSchin 		switch(n)
392da2e3ebdSchin 		{
393da2e3ebdSchin 			case S_BREAK:
394b30d1939SAndy Fiddaman 				fcseek(-LEN);
395da2e3ebdSchin 				goto breakloop;
396da2e3ebdSchin 			case S_EOF:
397da2e3ebdSchin 				sp = fcfile();
3987c2fbfb3SApril Chin 				if((n=lexfill(lp)) > 0)
399da2e3ebdSchin 				{
400da2e3ebdSchin 					fcseek(-1);
401da2e3ebdSchin 					continue;
402da2e3ebdSchin 				}
403da2e3ebdSchin 				/* check for zero byte in file */
404da2e3ebdSchin 				if(n==0 && fcfile())
405da2e3ebdSchin 				{
406da2e3ebdSchin 					if(shp->readscript)
407da2e3ebdSchin 					{
408da2e3ebdSchin 						char *cp = error_info.id;
409da2e3ebdSchin 						errno = ENOEXEC;
410da2e3ebdSchin 						error_info.id = shp->readscript;
411da2e3ebdSchin 						errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp);
412da2e3ebdSchin 					}
413da2e3ebdSchin 					else
414da2e3ebdSchin 					{
4157c2fbfb3SApril Chin 						lp->token = -1;
4167c2fbfb3SApril Chin 						sh_syntax(lp);
417da2e3ebdSchin 					}
418da2e3ebdSchin 				}
419da2e3ebdSchin 				/* end-of-file */
420da2e3ebdSchin 				if(mode==ST_BEGIN)
4217c2fbfb3SApril Chin 					return(lp->token=EOFSYM);
4227c2fbfb3SApril Chin 				if(mode >ST_NORM && lp->lexd.level>0)
423da2e3ebdSchin 				{
4247c2fbfb3SApril Chin 					switch(c=endchar(lp))
425da2e3ebdSchin 					{
426da2e3ebdSchin 						case '$':
427da2e3ebdSchin 							if(mode==ST_LIT)
428da2e3ebdSchin 							{
429da2e3ebdSchin 								c = '\'';
430da2e3ebdSchin 								break;
431da2e3ebdSchin 							}
4327c2fbfb3SApril Chin 							mode = oldmode(lp);
4337c2fbfb3SApril Chin 							poplevel(lp);
434da2e3ebdSchin 							continue;
435da2e3ebdSchin 						case RBRACT:
436da2e3ebdSchin 							c = LBRACT;
437da2e3ebdSchin 							break;
438da2e3ebdSchin 						case 1:	/* for ((...)) */
439da2e3ebdSchin 						case RPAREN:
440da2e3ebdSchin 							c = LPAREN;
441da2e3ebdSchin 							break;
442da2e3ebdSchin 						default:
443da2e3ebdSchin 							c = LBRACE;
444da2e3ebdSchin 							break;
445da2e3ebdSchin 						case '"': case '`': case '\'':
4467c2fbfb3SApril Chin 							lp->lexd.balance = c;
447da2e3ebdSchin 							break;
448da2e3ebdSchin 					}
449da2e3ebdSchin 					if(sp && !(sfset(sp,0,0)&SF_STRING))
450da2e3ebdSchin 					{
4517c2fbfb3SApril Chin 						lp->lasttok = c;
4527c2fbfb3SApril Chin 						lp->token = EOFSYM;
4537c2fbfb3SApril Chin 						sh_syntax(lp);
454da2e3ebdSchin 					}
4557c2fbfb3SApril Chin 					lp->lexd.balance = c;
456da2e3ebdSchin 				}
457da2e3ebdSchin 				goto breakloop;
458da2e3ebdSchin 			case S_COM:
459da2e3ebdSchin 				/* skip one or more comment line(s) */
4607c2fbfb3SApril Chin 				lp->lex.reservok = !lp->lex.intest;
4617c2fbfb3SApril Chin 				if((n=lp->lexd.nocopy) && lp->lexd.dolparen)
4627c2fbfb3SApril Chin 					lp->lexd.nocopy--;
463da2e3ebdSchin 				do
464da2e3ebdSchin 				{
465da2e3ebdSchin 					while(fcgetc(c)>0 && c!='\n');
4667c2fbfb3SApril Chin 					if(c<=0 || lp->heredoc)
467b30d1939SAndy Fiddaman 					{
468b30d1939SAndy Fiddaman 						shp->inlineno++;
469da2e3ebdSchin 						break;
470b30d1939SAndy Fiddaman 					}
471da2e3ebdSchin 					while(shp->inlineno++,fcpeek(0)=='\n')
472da2e3ebdSchin 						fcseek(1);
473da2e3ebdSchin 					while(state[c=fcpeek(0)]==0)
474da2e3ebdSchin 						fcseek(1);
475da2e3ebdSchin 				}
476da2e3ebdSchin 				while(c=='#');
4777c2fbfb3SApril Chin 				lp->lexd.nocopy = n;
478da2e3ebdSchin 				if(c<0)
4797c2fbfb3SApril Chin 					return(lp->token=EOFSYM);
480da2e3ebdSchin 				n = S_NLTOK;
481da2e3ebdSchin 				shp->inlineno--;
482da2e3ebdSchin 				/* FALL THRU */
483da2e3ebdSchin 			case S_NLTOK:
484da2e3ebdSchin 				/* check for here-document */
4857c2fbfb3SApril Chin 				if(lp->heredoc)
486da2e3ebdSchin 				{
4877c2fbfb3SApril Chin 					if(!lp->lexd.dolparen)
4887c2fbfb3SApril Chin 						lp->lexd.nocopy++;
489da2e3ebdSchin 					c = shp->inlineno;
4907c2fbfb3SApril Chin 					if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok)
491da2e3ebdSchin 					{
4927c2fbfb3SApril Chin 						lp->lasttok = IODOCSYM;
4937c2fbfb3SApril Chin 						lp->token = EOFSYM;
4947c2fbfb3SApril Chin 						lp->lastline = c;
4957c2fbfb3SApril Chin 						sh_syntax(lp);
496da2e3ebdSchin 					}
4977c2fbfb3SApril Chin 					if(!lp->lexd.dolparen)
4987c2fbfb3SApril Chin 						lp->lexd.nocopy--;
4997c2fbfb3SApril Chin 					lp->heredoc = 0;
500da2e3ebdSchin 				}
5017c2fbfb3SApril Chin 				lp->lex.reservok = !lp->lex.intest;
5027c2fbfb3SApril Chin 				lp->lex.skipword = 0;
5035ae8bd53SToomas Soome 				/* FALLTHROUGH */
504da2e3ebdSchin 			case S_NL:
505da2e3ebdSchin 				/* skip over new-lines */
5067c2fbfb3SApril Chin 				lp->lex.last_quote = 0;
507da2e3ebdSchin 				while(shp->inlineno++,fcget()=='\n');
508b30d1939SAndy Fiddaman 				fcseek(-LEN);
509da2e3ebdSchin 				if(n==S_NLTOK)
510da2e3ebdSchin 				{
5117c2fbfb3SApril Chin 					lp->comp_assign = 0;
5127c2fbfb3SApril Chin 					return(lp->token='\n');
513da2e3ebdSchin 				}
5145ae8bd53SToomas Soome 				/* FALLTHROUGH */
515da2e3ebdSchin 			case S_BLNK:
5167c2fbfb3SApril Chin 				if(lp->lex.incase<=TEST_RE)
517da2e3ebdSchin 					continue;
518da2e3ebdSchin 				/* implicit RPAREN for =~ test operator */
5197c2fbfb3SApril Chin 				if(inlevel+1==lp->lexd.level)
520da2e3ebdSchin 				{
5217c2fbfb3SApril Chin 					if(lp->lex.intest)
522b30d1939SAndy Fiddaman 						fcseek(-LEN);
523da2e3ebdSchin 					c = RPAREN;
524da2e3ebdSchin 					goto do_pop;
525da2e3ebdSchin 				}
526da2e3ebdSchin 				continue;
527da2e3ebdSchin 			case S_OP:
528da2e3ebdSchin 				/* return operator token */
529da2e3ebdSchin 				if(c=='<' || c=='>')
530da2e3ebdSchin 				{
5317c2fbfb3SApril Chin 					if(lp->lex.testop2)
5327c2fbfb3SApril Chin 						lp->lex.testop2 = 0;
533da2e3ebdSchin 					else
534da2e3ebdSchin 					{
5357c2fbfb3SApril Chin 						lp->digits = (c=='>');
5367c2fbfb3SApril Chin 						lp->lex.skipword = 1;
5377c2fbfb3SApril Chin 						lp->aliasok = lp->lex.reservok;
538b30d1939SAndy Fiddaman 						if(lp->lex.incase<2)
539b30d1939SAndy Fiddaman 							lp->lex.reservok = 0;
540da2e3ebdSchin 					}
541da2e3ebdSchin 				}
542da2e3ebdSchin 				else
543da2e3ebdSchin 				{
5447c2fbfb3SApril Chin 					lp->lex.reservok = !lp->lex.intest;
545da2e3ebdSchin 					if(c==RPAREN)
546da2e3ebdSchin 					{
5477c2fbfb3SApril Chin 						if(!lp->lexd.dolparen)
5487c2fbfb3SApril Chin 							lp->lex.incase = 0;
5497c2fbfb3SApril Chin 						return(lp->token=c);
550da2e3ebdSchin 					}
5517c2fbfb3SApril Chin 					lp->lex.testop1 = lp->lex.intest;
552da2e3ebdSchin 				}
553da2e3ebdSchin 				if(fcgetc(n)>0)
554b30d1939SAndy Fiddaman 					fcseek(-LEN);
555da2e3ebdSchin 				if(state[n]==S_OP || n=='#')
556da2e3ebdSchin 				{
557da2e3ebdSchin 					if(n==c)
558da2e3ebdSchin 					{
559da2e3ebdSchin 						if(c=='<')
5607c2fbfb3SApril Chin 							lp->lexd.docword=1;
561da2e3ebdSchin 						else if(n==LPAREN)
562da2e3ebdSchin 						{
563b30d1939SAndy Fiddaman 							if(lp->lex.intest)
564b30d1939SAndy Fiddaman 								return(c);
5657c2fbfb3SApril Chin 							lp->lexd.nest=1;
5667c2fbfb3SApril Chin 							lp->lastline = shp->inlineno;
5677c2fbfb3SApril Chin 							lp->lexd.lex_state = ST_NESTED;
568da2e3ebdSchin 							fcseek(1);
5697c2fbfb3SApril Chin 							return(sh_lex(lp));
570da2e3ebdSchin 						}
571da2e3ebdSchin 						c  |= SYMREP;
572da2e3ebdSchin 					}
573da2e3ebdSchin 					else if(c=='(' || c==')')
5747c2fbfb3SApril Chin 						return(lp->token=c);
575da2e3ebdSchin 					else if(c=='&')
576da2e3ebdSchin 					{
57734f9b3eeSRoland Mainz 						if(!sh_isoption(SH_POSIX) && n=='>' && (sh_isoption(SH_BASH) || sh_isstate(SH_PROFILE)))
578da2e3ebdSchin 						{
57934f9b3eeSRoland Mainz 							if(!sh_isoption(SH_BASH) && !lp->nonstandard)
58034f9b3eeSRoland Mainz 							{
58134f9b3eeSRoland Mainz 								lp->nonstandard = 1;
58234f9b3eeSRoland Mainz 								errormsg(SH_DICT,ERROR_warn(0),e_lexnonstandard,shp->inlineno);
58334f9b3eeSRoland Mainz 							}
5847c2fbfb3SApril Chin 							lp->digits = -1;
585da2e3ebdSchin 							c = '>';
586da2e3ebdSchin 						}
587b30d1939SAndy Fiddaman 						else if(n=='|')
588b30d1939SAndy Fiddaman 							c |= SYMPIPE;
589da2e3ebdSchin 						else
590da2e3ebdSchin 							n = 0;
591da2e3ebdSchin 					}
592da2e3ebdSchin 					else if(n=='&')
593da2e3ebdSchin 						c  |= SYMAMP;
594da2e3ebdSchin 					else if(c!='<' && c!='>')
595da2e3ebdSchin 						n = 0;
596da2e3ebdSchin 					else if(n==LPAREN)
597da2e3ebdSchin 					{
598da2e3ebdSchin 						c  |= SYMLPAR;
5997c2fbfb3SApril Chin 						lp->lex.reservok = 1;
6007c2fbfb3SApril Chin 						lp->lex.skipword = 0;
601da2e3ebdSchin 					}
602da2e3ebdSchin 					else if(n=='|')
603da2e3ebdSchin 						c  |= SYMPIPE;
604da2e3ebdSchin 					else if(c=='<' && n=='>')
60534f9b3eeSRoland Mainz 					{
60634f9b3eeSRoland Mainz 						lp->digits = 1;
607da2e3ebdSchin 						c = IORDWRSYM;
60834f9b3eeSRoland Mainz 						fcgetc(n);
60934f9b3eeSRoland Mainz 						if(fcgetc(n)==';')
61034f9b3eeSRoland Mainz 						{
61134f9b3eeSRoland Mainz 							lp->token = c = IORDWRSYMT;
61234f9b3eeSRoland Mainz 							if(lp->inexec)
61334f9b3eeSRoland Mainz 								sh_syntax(lp);
61434f9b3eeSRoland Mainz 						}
61534f9b3eeSRoland Mainz 						else if(n>0)
616b30d1939SAndy Fiddaman 							fcseek(-LEN);
61734f9b3eeSRoland Mainz 						n= 0;
61834f9b3eeSRoland Mainz 					}
619da2e3ebdSchin 					else if(n=='#' && (c=='<'||c=='>'))
620da2e3ebdSchin 						c |= SYMSHARP;
6217c2fbfb3SApril Chin 					else if(n==';' && c=='>')
6227c2fbfb3SApril Chin 					{
6237c2fbfb3SApril Chin 						c |= SYMSEMI;
6247c2fbfb3SApril Chin 						if(lp->inexec)
6257c2fbfb3SApril Chin 						{
6267c2fbfb3SApril Chin 							lp->token = c;
6277c2fbfb3SApril Chin 							sh_syntax(lp);
6287c2fbfb3SApril Chin 						}
6297c2fbfb3SApril Chin 					}
630da2e3ebdSchin 					else
631da2e3ebdSchin 						n = 0;
632da2e3ebdSchin 					if(n)
633da2e3ebdSchin 					{
634da2e3ebdSchin 						fcseek(1);
6357c2fbfb3SApril Chin 						lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM);
636da2e3ebdSchin 					}
637da2e3ebdSchin 					else
638da2e3ebdSchin 					{
63934f9b3eeSRoland Mainz 						if(lp->lexd.warn && (n=fcpeek(0))!=RPAREN && n!=' ' && n!='\t')
640da2e3ebdSchin 							errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n);
641da2e3ebdSchin 					}
642da2e3ebdSchin 				}
6437c2fbfb3SApril Chin 				if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase)
6447c2fbfb3SApril Chin 					lp->comp_assign = 2;
645da2e3ebdSchin 				else
6467c2fbfb3SApril Chin 					lp->comp_assign = 0;
6477c2fbfb3SApril Chin 				return(lp->token=c);
648da2e3ebdSchin 			case S_ESC:
649da2e3ebdSchin 				/* check for \<new-line> */
650da2e3ebdSchin 				fcgetc(n);
651da2e3ebdSchin 				c=2;
652da2e3ebdSchin #if SHOPT_CRNL
653da2e3ebdSchin 				if(n=='\r')
654da2e3ebdSchin 				{
655da2e3ebdSchin 					if(fcgetc(n)=='\n')
656da2e3ebdSchin 						c=3;
657da2e3ebdSchin 					else
658da2e3ebdSchin 					{
659da2e3ebdSchin 						n='\r';
660b30d1939SAndy Fiddaman 						fcseek(-LEN);
661da2e3ebdSchin 					}
662da2e3ebdSchin 				}
663da2e3ebdSchin #endif /* SHOPT_CRNL */
664da2e3ebdSchin 				if(n=='\n')
665da2e3ebdSchin 				{
666da2e3ebdSchin 					Sfio_t *sp;
667da2e3ebdSchin 					struct argnod *ap;
668da2e3ebdSchin 					shp->inlineno++;
669da2e3ebdSchin 					/* synchronize */
670da2e3ebdSchin 					if(!(sp=fcfile()))
671da2e3ebdSchin 						state=fcseek(0);
672da2e3ebdSchin 					fcclose();
6737c2fbfb3SApril Chin 					ap = lp->arg;
674da2e3ebdSchin 					if(sp)
675da2e3ebdSchin 						fcfopen(sp);
676da2e3ebdSchin 					else
677da2e3ebdSchin 						fcsopen((char*)state);
678da2e3ebdSchin 					/* remove \new-line */
6797c2fbfb3SApril Chin 					n = stktell(stkp)-c;
6807c2fbfb3SApril Chin 					stkseek(stkp,n);
6817c2fbfb3SApril Chin 					lp->arg = ap;
682da2e3ebdSchin 					if(n<=ARGVAL)
683da2e3ebdSchin 					{
684da2e3ebdSchin 						mode = 0;
6857c2fbfb3SApril Chin 						lp->lexd.first = 0;
686da2e3ebdSchin 					}
687da2e3ebdSchin 					continue;
688da2e3ebdSchin 				}
689da2e3ebdSchin 				wordflags |= ARG_QUOTED;
690da2e3ebdSchin 				if(mode==ST_DOL)
691da2e3ebdSchin 					goto err;
692da2e3ebdSchin #ifndef STR_MAXIMAL
6937c2fbfb3SApril Chin 				else if(mode==ST_NESTED && lp->lexd.warn &&
6947c2fbfb3SApril Chin 					endchar(lp)==RBRACE &&
695da2e3ebdSchin 					sh_lexstates[ST_DOL][n]==S_DIG
696da2e3ebdSchin 				)
697da2e3ebdSchin 					errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n);
698da2e3ebdSchin #endif /* STR_MAXIMAL */
699da2e3ebdSchin 				break;
700da2e3ebdSchin 			case S_NAME:
7017c2fbfb3SApril Chin 				if(!lp->lex.skipword)
7027c2fbfb3SApril Chin 					lp->lex.reservok *= 2;
703da2e3ebdSchin 				/* FALL THRU */
704da2e3ebdSchin 			case S_TILDE:
705b30d1939SAndy Fiddaman 				if(c=='~' && mode==ST_NESTED)
706b30d1939SAndy Fiddaman 				{
707b30d1939SAndy Fiddaman 					if(endchar(lp)==RBRACE)
708b30d1939SAndy Fiddaman 					{
709b30d1939SAndy Fiddaman 						lp->lexd.nested_tilde++;
710b30d1939SAndy Fiddaman 						goto tilde;
711b30d1939SAndy Fiddaman 					}
712b30d1939SAndy Fiddaman 					continue;
713b30d1939SAndy Fiddaman 				}
714b30d1939SAndy Fiddaman 				/* FALLTHROUGH */
715da2e3ebdSchin 			case S_RES:
7167c2fbfb3SApril Chin 				if(!lp->lexd.dolparen)
7177c2fbfb3SApril Chin 					lp->lexd.first = fcseek(0)-LEN;
7187c2fbfb3SApril Chin 				else if(lp->lexd.docword)
7197c2fbfb3SApril Chin 					lp->lexd.docend = fcseek(0)-LEN;
720da2e3ebdSchin 				mode = ST_NAME;
721da2e3ebdSchin 				if(c=='.')
722b30d1939SAndy Fiddaman 					fcseek(-LEN);
723da2e3ebdSchin 				if(n!=S_TILDE)
724da2e3ebdSchin 					continue;
725b30d1939SAndy Fiddaman 			tilde:
726da2e3ebdSchin 				fcgetc(n);
727da2e3ebdSchin 				if(n>0)
7287c2fbfb3SApril Chin 				{
729b30d1939SAndy Fiddaman 					if(c=='~' && n==LPAREN)
730b30d1939SAndy Fiddaman 					{
731b30d1939SAndy Fiddaman 						if(lp->lexd.nested_tilde)
732b30d1939SAndy Fiddaman 							lp->lexd.nested_tilde++;
733b30d1939SAndy Fiddaman 						else if(lp->lex.incase)
734b30d1939SAndy Fiddaman 							lp->lex.incase = TEST_RE;
735b30d1939SAndy Fiddaman 					}
736b30d1939SAndy Fiddaman 					fcseek(-LEN);
737b30d1939SAndy Fiddaman 					if(lp->lexd.nested_tilde)
738b30d1939SAndy Fiddaman 					{
739b30d1939SAndy Fiddaman 						lp->lexd.nested_tilde--;
740b30d1939SAndy Fiddaman 						continue;
741b30d1939SAndy Fiddaman 					}
7427c2fbfb3SApril Chin 				}
743da2e3ebdSchin 				if(n==LPAREN)
744da2e3ebdSchin 					goto epat;
745da2e3ebdSchin 				wordflags = ARG_MAC;
746da2e3ebdSchin 				mode = ST_NORM;
747da2e3ebdSchin 				continue;
748da2e3ebdSchin 			case S_REG:
749da2e3ebdSchin 				if(mode==ST_BEGIN)
750da2e3ebdSchin 				{
7517c2fbfb3SApril Chin 				do_reg:
752da2e3ebdSchin 					/* skip new-line joining */
753da2e3ebdSchin 					if(c=='\\' && fcpeek(0)=='\n')
754da2e3ebdSchin 					{
755da2e3ebdSchin 						shp->inlineno++;
756da2e3ebdSchin 						fcseek(1);
757da2e3ebdSchin 						continue;
758da2e3ebdSchin 					}
759b30d1939SAndy Fiddaman 					fcseek(-LEN);
7607c2fbfb3SApril Chin 					if(!lp->lexd.dolparen)
7617c2fbfb3SApril Chin 						lp->lexd.first = fcseek(0);
7627c2fbfb3SApril Chin 					else if(lp->lexd.docword)
7637c2fbfb3SApril Chin 						lp->lexd.docend = fcseek(0);
7647c2fbfb3SApril Chin 					if(c=='[' && lp->assignok>=SH_ASSIGN)
765da2e3ebdSchin 					{
766da2e3ebdSchin 						mode = ST_NAME;
767da2e3ebdSchin 						continue;
768da2e3ebdSchin 					}
769da2e3ebdSchin 				}
770da2e3ebdSchin 				mode = ST_NORM;
771da2e3ebdSchin 				continue;
772da2e3ebdSchin 			case S_LIT:
7737c2fbfb3SApril Chin 				if(oldmode(lp)==ST_NONE && !lp->lexd.noarg)	/*  in ((...)) */
774da2e3ebdSchin 				{
775da2e3ebdSchin 					if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']')
776da2e3ebdSchin 					{
777da2e3ebdSchin 						if(fcpeek(1)=='\'')
778da2e3ebdSchin 							fcseek(2);
779da2e3ebdSchin 					}
780da2e3ebdSchin 					continue;
781da2e3ebdSchin 				}
782da2e3ebdSchin 				wordflags |= ARG_QUOTED;
783da2e3ebdSchin 				if(mode==ST_DOL)
784da2e3ebdSchin 				{
7857c2fbfb3SApril Chin 					if(endchar(lp)!='$')
786da2e3ebdSchin 						goto err;
7877c2fbfb3SApril Chin 					if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */
788da2e3ebdSchin 					{
7897c2fbfb3SApril Chin 						if(lp->lexd.warn)
790da2e3ebdSchin 							errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
791da2e3ebdSchin 						mode = ST_LIT;
792da2e3ebdSchin 					}
793da2e3ebdSchin 				}
794da2e3ebdSchin 				if(mode!=ST_LIT)
795da2e3ebdSchin 				{
796b30d1939SAndy Fiddaman 					if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline && fcpeek(-2)!='$')
7977c2fbfb3SApril Chin 						errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
7987c2fbfb3SApril Chin 					lp->lex.last_quote = 0;
7997c2fbfb3SApril Chin 					lp->lastline = shp->inlineno;
800da2e3ebdSchin 					if(mode!=ST_DOL)
8017c2fbfb3SApril Chin 						pushlevel(lp,'\'',mode);
802da2e3ebdSchin 					mode = ST_LIT;
803da2e3ebdSchin 					continue;
804da2e3ebdSchin 				}
805da2e3ebdSchin 				/* check for multi-line single-quoted string */
8067c2fbfb3SApril Chin 				else if(shp->inlineno > lp->lastline)
8077c2fbfb3SApril Chin 					lp->lex.last_quote = '\'';
8087c2fbfb3SApril Chin 				mode = oldmode(lp);
8097c2fbfb3SApril Chin 				poplevel(lp);
810da2e3ebdSchin 				break;
811da2e3ebdSchin 			case S_ESC2:
812da2e3ebdSchin 				/* \ inside '' */
8137c2fbfb3SApril Chin 				if(endchar(lp)=='$')
814da2e3ebdSchin 				{
815da2e3ebdSchin 					fcgetc(n);
816da2e3ebdSchin 					if(n=='\n')
817da2e3ebdSchin 						shp->inlineno++;
818da2e3ebdSchin 				}
819da2e3ebdSchin 				continue;
820da2e3ebdSchin 			case S_GRAVE:
8217c2fbfb3SApril Chin 				if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`'))
822da2e3ebdSchin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno);
823da2e3ebdSchin 				wordflags |=(ARG_MAC|ARG_EXP);
824da2e3ebdSchin 				if(mode==ST_QUOTE)
825da2e3ebdSchin 					ingrave = !ingrave;
826da2e3ebdSchin 				/* FALL THRU */
827da2e3ebdSchin 			case S_QUOTE:
8287c2fbfb3SApril Chin 				if(oldmode(lp)==ST_NONE && lp->lexd.arith)	/*  in ((...)) */
8297c2fbfb3SApril Chin 				{
8307c2fbfb3SApril Chin 					if(n!=S_GRAVE || fcpeek(0)=='\'')
8317c2fbfb3SApril Chin 						continue;
8327c2fbfb3SApril Chin 				}
833da2e3ebdSchin 				if(n==S_QUOTE)
834da2e3ebdSchin 					wordflags |=ARG_QUOTED;
835da2e3ebdSchin 				if(mode!=ST_QUOTE)
836da2e3ebdSchin 				{
837da2e3ebdSchin 					if(c!='"' || mode!=ST_QNEST)
838da2e3ebdSchin 					{
8397c2fbfb3SApril Chin 						if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
8407c2fbfb3SApril Chin 							errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
8417c2fbfb3SApril Chin 						lp->lex.last_quote=0;
8427c2fbfb3SApril Chin 						lp->lastline = shp->inlineno;
8437c2fbfb3SApril Chin 						pushlevel(lp,c,mode);
844da2e3ebdSchin 					}
84534f9b3eeSRoland Mainz 					ingrave ^= (c=='`');
846da2e3ebdSchin 					mode = ST_QUOTE;
847da2e3ebdSchin 					continue;
848da2e3ebdSchin 				}
8497c2fbfb3SApril Chin 				else if((n=endchar(lp))==c)
850da2e3ebdSchin 				{
8517c2fbfb3SApril Chin 					if(shp->inlineno > lp->lastline)
8527c2fbfb3SApril Chin 						lp->lex.last_quote = c;
8537c2fbfb3SApril Chin 					mode = oldmode(lp);
8547c2fbfb3SApril Chin 					poplevel(lp);
855da2e3ebdSchin 				}
856da2e3ebdSchin 				else if(c=='"' && n==RBRACE)
857da2e3ebdSchin 					mode = ST_QNEST;
858da2e3ebdSchin 				break;
859da2e3ebdSchin 			case S_DOL:
860da2e3ebdSchin 				/* don't check syntax inside `` */
861da2e3ebdSchin 				if(mode==ST_QUOTE && ingrave)
862da2e3ebdSchin 					continue;
863da2e3ebdSchin #if SHOPT_KIA
8647c2fbfb3SApril Chin 				if(lp->lexd.first)
8657c2fbfb3SApril Chin 					lp->lexd.kiaoff = fcseek(0)-lp->lexd.first;
866da2e3ebdSchin 				else
8677c2fbfb3SApril Chin 					lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst();
868da2e3ebdSchin #endif /* SHOPT_KIA */
8697c2fbfb3SApril Chin 				pushlevel(lp,'$',mode);
870da2e3ebdSchin 				mode = ST_DOL;
871da2e3ebdSchin 				continue;
872da2e3ebdSchin 			case S_PAR:
8737c2fbfb3SApril Chin 			do_comsub:
874da2e3ebdSchin 				wordflags |= ARG_MAC;
8757c2fbfb3SApril Chin 				mode = oldmode(lp);
8767c2fbfb3SApril Chin 				poplevel(lp);
877b30d1939SAndy Fiddaman 				fcseek(-LEN);
878b30d1939SAndy Fiddaman 				n = lp->digits;
8797c2fbfb3SApril Chin 				wordflags |= comsub(lp,c);
880b30d1939SAndy Fiddaman 				lp->digits = n;
881da2e3ebdSchin 				continue;
882da2e3ebdSchin 			case S_RBRA:
8837c2fbfb3SApril Chin 				if((n=endchar(lp)) == '$')
884da2e3ebdSchin 					goto err;
885da2e3ebdSchin 				if(mode!=ST_QUOTE || n==RBRACE)
886da2e3ebdSchin 				{
8877c2fbfb3SApril Chin 					mode = oldmode(lp);
8887c2fbfb3SApril Chin 					poplevel(lp);
889da2e3ebdSchin 				}
890da2e3ebdSchin 				break;
891da2e3ebdSchin 			case S_EDOL:
892da2e3ebdSchin 				/* end $identifier */
893da2e3ebdSchin #if SHOPT_KIA
8947c2fbfb3SApril Chin 				if(lp->kiafile)
8957c2fbfb3SApril Chin 					refvar(lp,0);
896da2e3ebdSchin #endif /* SHOPT_KIA */
8977c2fbfb3SApril Chin 				if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED)
898da2e3ebdSchin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno);
899b30d1939SAndy Fiddaman 				fcseek(-LEN);
9007c2fbfb3SApril Chin 				mode = oldmode(lp);
9017c2fbfb3SApril Chin 				poplevel(lp);
902da2e3ebdSchin 				break;
903da2e3ebdSchin 			case S_DOT:
904da2e3ebdSchin 				/* make sure next character is alpha */
905da2e3ebdSchin 				if(fcgetc(n)>0)
9067c2fbfb3SApril Chin 				{
9077c2fbfb3SApril Chin 					if(n=='.')
9087c2fbfb3SApril Chin 						fcgetc(n);
9097c2fbfb3SApril Chin 					if(n>0)
910b30d1939SAndy Fiddaman 						fcseek(-LEN);
9117c2fbfb3SApril Chin 				}
912da2e3ebdSchin 				if(isaletter(n) || n==LBRACT)
913da2e3ebdSchin 					continue;
914da2e3ebdSchin 				if(mode==ST_NAME)
915da2e3ebdSchin 				{
916da2e3ebdSchin 					if(n=='=')
917da2e3ebdSchin 						continue;
918da2e3ebdSchin 					break;
919da2e3ebdSchin 				}
920da2e3ebdSchin 				else if(n==RBRACE)
921da2e3ebdSchin 					continue;
922da2e3ebdSchin 				if(isastchar(n))
923da2e3ebdSchin 					continue;
924da2e3ebdSchin 				goto err;
925da2e3ebdSchin 			case S_SPC1:
926da2e3ebdSchin 				wordflags |= ARG_MAC;
9277c2fbfb3SApril Chin 				if(endchar(lp)==RBRACE)
928da2e3ebdSchin 				{
9297c2fbfb3SApril Chin 					setchar(lp,c);
930da2e3ebdSchin 					continue;
931da2e3ebdSchin 				}
932da2e3ebdSchin 				/* FALL THRU */
933da2e3ebdSchin 			case S_ALP:
9347c2fbfb3SApril Chin 				if(c=='.' && endchar(lp)=='$')
935da2e3ebdSchin 					goto err;
9365ae8bd53SToomas Soome 				/* FALLTHROUGH */
937da2e3ebdSchin 			case S_SPC2:
938da2e3ebdSchin 			case S_DIG:
939da2e3ebdSchin 				wordflags |= ARG_MAC;
9407c2fbfb3SApril Chin 				switch(endchar(lp))
941da2e3ebdSchin 				{
942da2e3ebdSchin 					case '$':
943da2e3ebdSchin 						if(n==S_ALP) /* $identifier */
944da2e3ebdSchin 							mode = ST_DOLNAME;
945da2e3ebdSchin 						else
946da2e3ebdSchin 						{
9477c2fbfb3SApril Chin 							mode = oldmode(lp);
9487c2fbfb3SApril Chin 							poplevel(lp);
949da2e3ebdSchin 						}
950da2e3ebdSchin 						break;
9515ae8bd53SToomas Soome 					/* FALLTHROUGH */
952da2e3ebdSchin #if SHOPT_TYPEDEF
953da2e3ebdSchin 					case '@':
954da2e3ebdSchin #endif /* SHOPT_TYPEDEF */
955da2e3ebdSchin 					case '!':
956da2e3ebdSchin 						if(n!=S_ALP)
957da2e3ebdSchin 							goto dolerr;
9585ae8bd53SToomas Soome 						/* FALLTHROUGH */
959da2e3ebdSchin 					case '#':
960b30d1939SAndy Fiddaman 						if(c=='#')
961b30d1939SAndy Fiddaman 							n = S_ALP;
962b30d1939SAndy Fiddaman 						/* FALLTHROUGH */
963da2e3ebdSchin 					case RBRACE:
964da2e3ebdSchin 						if(n==S_ALP)
965da2e3ebdSchin 						{
9667c2fbfb3SApril Chin 							setchar(lp,RBRACE);
967da2e3ebdSchin 							if(c=='.')
968b30d1939SAndy Fiddaman 								fcseek(-LEN);
969da2e3ebdSchin 							mode = ST_BRACE;
970da2e3ebdSchin 						}
971da2e3ebdSchin 						else
972da2e3ebdSchin 						{
973da2e3ebdSchin 							if(fcgetc(c)>0)
974b30d1939SAndy Fiddaman 								fcseek(-LEN);
975da2e3ebdSchin 							if(state[c]==S_ALP)
976da2e3ebdSchin 								goto err;
977da2e3ebdSchin 							if(n==S_DIG)
9787c2fbfb3SApril Chin 								setchar(lp,'0');
979da2e3ebdSchin 							else
9807c2fbfb3SApril Chin 								setchar(lp,'!');
981da2e3ebdSchin 						}
982da2e3ebdSchin 						break;
983da2e3ebdSchin 					case '0':
984da2e3ebdSchin 						if(n==S_DIG)
985da2e3ebdSchin 							break;
986da2e3ebdSchin 					default:
987da2e3ebdSchin 						goto dolerr;
988da2e3ebdSchin 				}
989da2e3ebdSchin 				break;
990da2e3ebdSchin 			dolerr:
991da2e3ebdSchin 			case S_ERR:
9927c2fbfb3SApril Chin 				if((n=endchar(lp)) == '$')
993da2e3ebdSchin 					goto err;
994da2e3ebdSchin 				if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2)
995da2e3ebdSchin 				{
996da2e3ebdSchin 					/* see whether inside `...` */
9977c2fbfb3SApril Chin 					mode = oldmode(lp);
9987c2fbfb3SApril Chin 					poplevel(lp);
9997c2fbfb3SApril Chin 					if((n = endchar(lp)) != '`')
1000da2e3ebdSchin 						goto err;
10017c2fbfb3SApril Chin 					pushlevel(lp,RBRACE,mode);
1002da2e3ebdSchin 				}
1003da2e3ebdSchin 				else
10047c2fbfb3SApril Chin 					setchar(lp,RBRACE);
1005da2e3ebdSchin 				mode = ST_NESTED;
1006da2e3ebdSchin 				continue;
1007da2e3ebdSchin 			case S_MOD1:
10087c2fbfb3SApril Chin 				if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE)
1009da2e3ebdSchin 				{
1010da2e3ebdSchin 					/* allow ' inside "${...}" */
1011da2e3ebdSchin 					if(c==':' && fcgetc(n)>0)
1012da2e3ebdSchin 					{
1013da2e3ebdSchin 						n = state[n];
1014b30d1939SAndy Fiddaman 						fcseek(-LEN);
1015da2e3ebdSchin 					}
1016da2e3ebdSchin 					if(n==S_MOD1)
1017da2e3ebdSchin 					{
1018da2e3ebdSchin 						mode = ST_QUOTE;
1019da2e3ebdSchin 						continue;
1020da2e3ebdSchin 					}
1021da2e3ebdSchin 				}
1022da2e3ebdSchin 				/* FALL THRU */
1023da2e3ebdSchin 			case S_MOD2:
1024da2e3ebdSchin #if SHOPT_KIA
10257c2fbfb3SApril Chin 				if(lp->kiafile)
10267c2fbfb3SApril Chin 					refvar(lp,1);
1027da2e3ebdSchin #endif /* SHOPT_KIA */
1028da2e3ebdSchin 				if(c!=':' && fcgetc(n)>0)
1029da2e3ebdSchin 				{
1030da2e3ebdSchin 					if(n!=c)
1031da2e3ebdSchin 						c = 0;
1032da2e3ebdSchin 					if(!c || (fcgetc(n)>0))
1033da2e3ebdSchin 					{
1034b30d1939SAndy Fiddaman 						fcseek(-LEN);
1035da2e3ebdSchin 						if(n==LPAREN)
1036da2e3ebdSchin 						{
1037da2e3ebdSchin 							if(c!='%')
1038da2e3ebdSchin 							{
10397c2fbfb3SApril Chin 								lp->token = n;
10407c2fbfb3SApril Chin 								sh_syntax(lp);
1041da2e3ebdSchin 							}
10427c2fbfb3SApril Chin 							else if(lp->lexd.warn)
1043da2e3ebdSchin 								errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%');
1044da2e3ebdSchin 						}
1045da2e3ebdSchin 					}
1046da2e3ebdSchin 				}
1047b30d1939SAndy Fiddaman 				lp->lex.nestedbrace = 0;
1048da2e3ebdSchin 				mode = ST_NESTED;
1049da2e3ebdSchin 				continue;
1050da2e3ebdSchin 			case S_LBRA:
10517c2fbfb3SApril Chin 				if((c=endchar(lp)) == '$')
1052da2e3ebdSchin 				{
1053da2e3ebdSchin 					if(fcgetc(c)>0)
1054b30d1939SAndy Fiddaman 						fcseek(-LEN);
10557c2fbfb3SApril Chin 					setchar(lp,RBRACE);
1056da2e3ebdSchin 					if(state[c]!=S_ERR && c!=RBRACE)
1057da2e3ebdSchin 						continue;
10587c2fbfb3SApril Chin 					if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK)
10597c2fbfb3SApril Chin 					{
10607c2fbfb3SApril Chin 						c = LBRACE;
10617c2fbfb3SApril Chin 						goto do_comsub;
10627c2fbfb3SApril Chin 					}
1063da2e3ebdSchin 				}
1064da2e3ebdSchin 			err:
1065b30d1939SAndy Fiddaman 				if(iswalpha(c))
1066b30d1939SAndy Fiddaman 					continue;
10677c2fbfb3SApril Chin 				n = endchar(lp);
10687c2fbfb3SApril Chin 				mode = oldmode(lp);
10697c2fbfb3SApril Chin 				poplevel(lp);
1070da2e3ebdSchin 				if(n!='$')
1071da2e3ebdSchin 				{
10727c2fbfb3SApril Chin 					lp->token = c;
10737c2fbfb3SApril Chin 					sh_syntax(lp);
1074da2e3ebdSchin 				}
1075da2e3ebdSchin 				else
1076da2e3ebdSchin 				{
10777c2fbfb3SApril Chin 					if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE))
1078da2e3ebdSchin 						errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
107934f9b3eeSRoland Mainz 					else if(c=='"' && mode!=ST_QUOTE && !ingrave)
1080da2e3ebdSchin 						wordflags |= ARG_MESSAGE;
1081b30d1939SAndy Fiddaman 					fcseek(-LEN);
1082da2e3ebdSchin 				}
1083da2e3ebdSchin 				continue;
1084da2e3ebdSchin 			case S_META:
1085b30d1939SAndy Fiddaman 				if(lp->lexd.warn && endchar(lp)==RBRACE && !lp->lexd.nested_tilde)
1086da2e3ebdSchin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
1087da2e3ebdSchin 				continue;
1088da2e3ebdSchin 			case S_PUSH:
1089b30d1939SAndy Fiddaman 				fcgetc(n);
1090b30d1939SAndy Fiddaman 				if(n==RPAREN)
1091b30d1939SAndy Fiddaman 					continue;
1092b30d1939SAndy Fiddaman 				else
1093b30d1939SAndy Fiddaman 					fcseek(-LEN);
10947c2fbfb3SApril Chin 				pushlevel(lp,RPAREN,mode);
1095da2e3ebdSchin 				mode = ST_NESTED;
1096da2e3ebdSchin 				continue;
1097da2e3ebdSchin 			case S_POP:
1098da2e3ebdSchin 			do_pop:
1099b30d1939SAndy Fiddaman 				if(c==RBRACE && mode==ST_NESTED && lp->lex.nestedbrace)
1100b30d1939SAndy Fiddaman 				{
1101b30d1939SAndy Fiddaman 					lp->lex.nestedbrace--;
1102b30d1939SAndy Fiddaman 					continue;
1103b30d1939SAndy Fiddaman 				}
11047c2fbfb3SApril Chin 				if(lp->lexd.level <= inlevel)
1105da2e3ebdSchin 					break;
11067c2fbfb3SApril Chin 				if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest)
11077c2fbfb3SApril Chin 				{
1108b30d1939SAndy Fiddaman 					fcseek(-LEN);
11097c2fbfb3SApril Chin 					goto breakloop;
11107c2fbfb3SApril Chin 				}
11117c2fbfb3SApril Chin 				n = endchar(lp);
1112da2e3ebdSchin 				if(c==RBRACT  && !(n==RBRACT || n==RPAREN))
1113da2e3ebdSchin 					continue;
1114da2e3ebdSchin 				if((c==RBRACE||c==RPAREN) && n==RPAREN)
1115da2e3ebdSchin 				{
1116da2e3ebdSchin 					if(fcgetc(n)==LPAREN)
1117da2e3ebdSchin 					{
1118da2e3ebdSchin 						if(c!=RPAREN)
1119b30d1939SAndy Fiddaman 							fcseek(-LEN);
1120da2e3ebdSchin 						continue;
1121da2e3ebdSchin 					}
1122da2e3ebdSchin 					if(n>0)
1123b30d1939SAndy Fiddaman 						fcseek(-LEN);
1124da2e3ebdSchin 					n = RPAREN;
1125da2e3ebdSchin 				}
1126b30d1939SAndy Fiddaman 				if(c==RBRACE)
1127b30d1939SAndy Fiddaman 					lp->lexd.nested_tilde = 0;
1128da2e3ebdSchin 				if(c==';' && n!=';')
1129da2e3ebdSchin 				{
11307c2fbfb3SApril Chin 					if(lp->lexd.warn && n==RBRACE)
1131da2e3ebdSchin 						errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
1132da2e3ebdSchin 					continue;
1133da2e3ebdSchin 				}
1134da2e3ebdSchin 				if(mode==ST_QNEST)
1135da2e3ebdSchin 				{
11367c2fbfb3SApril Chin 					if(lp->lexd.warn)
1137da2e3ebdSchin 						errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c);
1138da2e3ebdSchin 					continue;
1139da2e3ebdSchin 				}
11407c2fbfb3SApril Chin 				mode = oldmode(lp);
11417c2fbfb3SApril Chin 				poplevel(lp);
1142b30d1939SAndy Fiddaman 				if(epatchar!='~')
1143b30d1939SAndy Fiddaman 					epatchar = '@';
1144da2e3ebdSchin 				/* quotes in subscript need expansion */
1145da2e3ebdSchin 				if(mode==ST_NAME && (wordflags&ARG_QUOTED))
1146da2e3ebdSchin 					wordflags |= ARG_MAC;
1147da2e3ebdSchin 				/* check for ((...)) */
1148da2e3ebdSchin 				if(n==1 && c==RPAREN)
1149da2e3ebdSchin 				{
1150da2e3ebdSchin 					if(fcgetc(n)==RPAREN)
1151da2e3ebdSchin 					{
11527c2fbfb3SApril Chin 						if(mode==ST_NONE && !lp->lexd.dolparen)
1153da2e3ebdSchin 							goto breakloop;
11547c2fbfb3SApril Chin 						lp->lex.reservok = 1;
11557c2fbfb3SApril Chin 						lp->lex.skipword = 0;
11567c2fbfb3SApril Chin 						return(lp->token=EXPRSYM);
1157da2e3ebdSchin 					}
1158da2e3ebdSchin 					/* backward compatibility */
1159da2e3ebdSchin 					{
11607c2fbfb3SApril Chin 						if(lp->lexd.warn)
1161da2e3ebdSchin 							errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
11627c2fbfb3SApril Chin 						if(!(state=lp->lexd.first))
1163da2e3ebdSchin 							state = fcfirst();
1164b30d1939SAndy Fiddaman 						else
1165da2e3ebdSchin 						{
1166b30d1939SAndy Fiddaman 							n = state-fcseek(0);
1167b30d1939SAndy Fiddaman 							fcseek(n);
1168da2e3ebdSchin 						}
11697c2fbfb3SApril Chin 						lp->lexd.paren = 1;
1170da2e3ebdSchin 					}
11717c2fbfb3SApril Chin 					return(lp->token=LPAREN);
1172da2e3ebdSchin 				}
1173da2e3ebdSchin 				if(mode==ST_NONE)
1174da2e3ebdSchin 					return(0);
1175da2e3ebdSchin 				if(c!=n)
1176da2e3ebdSchin 				{
11777c2fbfb3SApril Chin 					lp->token = c;
11787c2fbfb3SApril Chin 					sh_syntax(lp);
1179da2e3ebdSchin 				}
1180da2e3ebdSchin 				if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
1181da2e3ebdSchin 					goto epat;
1182da2e3ebdSchin 				continue;
1183da2e3ebdSchin 			case S_EQ:
11847c2fbfb3SApril Chin 				assignment = lp->assignok;
1185da2e3ebdSchin 				/* FALL THRU */
1186da2e3ebdSchin 			case S_COLON:
1187da2e3ebdSchin 				if(assignment)
1188da2e3ebdSchin 				{
1189b30d1939SAndy Fiddaman 					if(fcgetc(c)=='~')
1190da2e3ebdSchin 						wordflags |= ARG_MAC;
1191da2e3ebdSchin 					else if(c!=LPAREN && assignment==SH_COMPASSIGN)
1192da2e3ebdSchin 						assignment = 0;
1193b30d1939SAndy Fiddaman 					if(c!=EOF)
1194b30d1939SAndy Fiddaman 						fcseek(-LEN);
1195da2e3ebdSchin 				}
1196da2e3ebdSchin 				break;
1197da2e3ebdSchin 			case S_LABEL:
11987c2fbfb3SApril Chin 				if(lp->lex.reservok && !lp->lex.incase)
1199da2e3ebdSchin 				{
1200da2e3ebdSchin 					c = fcget();
1201b30d1939SAndy Fiddaman 					fcseek(-LEN);
1202da2e3ebdSchin 					if(state[c]==S_BREAK)
1203da2e3ebdSchin 					{
1204da2e3ebdSchin 						assignment = -1;
1205da2e3ebdSchin 						goto breakloop;
1206da2e3ebdSchin 					}
1207da2e3ebdSchin 				}
1208da2e3ebdSchin 				break;
1209da2e3ebdSchin 			case S_BRACT:
1210da2e3ebdSchin 				/* check for possible subscript */
12117c2fbfb3SApril Chin 				if((n=endchar(lp))==RBRACT || n==RPAREN ||
1212da2e3ebdSchin 					(mode==ST_BRACE) ||
12137c2fbfb3SApril Chin 					(oldmode(lp)==ST_NONE) ||
12147c2fbfb3SApril Chin 					(mode==ST_NAME && (lp->assignok||lp->lexd.level)))
1215da2e3ebdSchin 				{
1216b30d1939SAndy Fiddaman 					fcgetc(n);
1217b30d1939SAndy Fiddaman 					if(n>0 && n==']')
121834f9b3eeSRoland Mainz 					{
1219b30d1939SAndy Fiddaman 						if(mode==ST_NAME)
1220b30d1939SAndy Fiddaman 							errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript");
1221b30d1939SAndy Fiddaman 						if(!epatchar || epatchar=='%')
1222b30d1939SAndy Fiddaman 							continue;
122334f9b3eeSRoland Mainz 					}
1224b30d1939SAndy Fiddaman 					else
1225b30d1939SAndy Fiddaman 						fcseek(-LEN);
12267c2fbfb3SApril Chin 					pushlevel(lp,RBRACT,mode);
1227da2e3ebdSchin 					wordflags |= ARG_QUOTED;
1228da2e3ebdSchin 					mode = ST_NESTED;
1229da2e3ebdSchin 					continue;
1230da2e3ebdSchin 				}
1231da2e3ebdSchin 				wordflags |= ARG_EXP;
1232da2e3ebdSchin 				break;
1233da2e3ebdSchin 			case S_BRACE:
1234da2e3ebdSchin 			{
1235da2e3ebdSchin 				int isfirst;
12367c2fbfb3SApril Chin 				if(lp->lexd.dolparen)
12377c2fbfb3SApril Chin 				{
12387c2fbfb3SApril Chin 					if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub))
12397c2fbfb3SApril Chin 					{
1240b30d1939SAndy Fiddaman 						if(lp->comsub)
1241b30d1939SAndy Fiddaman 							return(lp->token=c);
12427c2fbfb3SApril Chin 						fcgetc(n);
12437c2fbfb3SApril Chin 						if(n>0)
1244b30d1939SAndy Fiddaman 							fcseek(-LEN);
12457c2fbfb3SApril Chin 						else
12467c2fbfb3SApril Chin 							n = '\n';
12477c2fbfb3SApril Chin 						if(n==RBRACT || sh_lexstates[ST_NORM][n])
12487c2fbfb3SApril Chin 							return(lp->token=c);
12497c2fbfb3SApril Chin 					}
1250da2e3ebdSchin 					break;
12517c2fbfb3SApril Chin 				}
1252b30d1939SAndy Fiddaman 				else if(mode==ST_NESTED && endchar(lp)==RBRACE)
1253b30d1939SAndy Fiddaman 				{
1254b30d1939SAndy Fiddaman 					lp->lex.nestedbrace++;
1255b30d1939SAndy Fiddaman 					continue;
1256b30d1939SAndy Fiddaman 				}
12577c2fbfb3SApril Chin 				else if(mode==ST_BEGIN)
12587c2fbfb3SApril Chin 				{
12597c2fbfb3SApril Chin 					if(lp->comsub && c==RBRACE)
12607c2fbfb3SApril Chin 						return(lp->token=c);
12617c2fbfb3SApril Chin 					goto do_reg;
12627c2fbfb3SApril Chin 				}
12637c2fbfb3SApril Chin 				isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1);
1264da2e3ebdSchin 				fcgetc(n);
1265da2e3ebdSchin 				/* check for {} */
1266da2e3ebdSchin 				if(c==LBRACE && n==RBRACE)
1267da2e3ebdSchin 					break;
1268da2e3ebdSchin 				if(n>0)
1269b30d1939SAndy Fiddaman 					fcseek(-LEN);
12707c2fbfb3SApril Chin 				else if(lp->lex.reservok)
1271da2e3ebdSchin 					break;
1272da2e3ebdSchin 				/* check for reserved word { or } */
12737c2fbfb3SApril Chin 				if(lp->lex.reservok && state[n]==S_BREAK && isfirst)
1274da2e3ebdSchin 					break;
1275da2e3ebdSchin 				if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
12767c2fbfb3SApril Chin 					&& !lp->lex.incase && !lp->lex.intest
12777c2fbfb3SApril Chin 					&& !lp->lex.skipword)
1278da2e3ebdSchin 				{
1279da2e3ebdSchin 					wordflags |= ARG_EXP;
1280da2e3ebdSchin 				}
1281da2e3ebdSchin 				if(c==RBRACE && n==LPAREN)
1282da2e3ebdSchin 					goto epat;
1283da2e3ebdSchin 				break;
1284da2e3ebdSchin 			}
1285da2e3ebdSchin 			case S_PAT:
1286da2e3ebdSchin 				wordflags |= ARG_EXP;
1287da2e3ebdSchin 				/* FALL THRU */
1288da2e3ebdSchin 			case S_EPAT:
1289da2e3ebdSchin 			epat:
1290b30d1939SAndy Fiddaman 				if(fcgetc(n)==LPAREN && c!='[')
1291da2e3ebdSchin 				{
1292b30d1939SAndy Fiddaman 					epatchar = c;
12937c2fbfb3SApril Chin 					if(lp->lex.incase==TEST_RE)
1294da2e3ebdSchin 					{
12957c2fbfb3SApril Chin 						lp->lex.incase++;
12967c2fbfb3SApril Chin 						pushlevel(lp,RPAREN,ST_NORM);
1297da2e3ebdSchin 						mode = ST_NESTED;
1298da2e3ebdSchin 					}
1299da2e3ebdSchin 					wordflags |= ARG_EXP;
13007c2fbfb3SApril Chin 					pushlevel(lp,RPAREN,mode);
1301da2e3ebdSchin 					mode = ST_NESTED;
1302da2e3ebdSchin 					continue;
1303da2e3ebdSchin 				}
1304b30d1939SAndy Fiddaman 				if(lp->lexd.warn && c=='[' && n=='^')
1305b30d1939SAndy Fiddaman 					errormsg(SH_DICT,ERROR_warn(0),e_lexcharclass,shp->inlineno);
1306da2e3ebdSchin 				if(n>0)
1307b30d1939SAndy Fiddaman 					fcseek(-LEN);
1308da2e3ebdSchin 				if(n=='=' && c=='+' && mode==ST_NAME)
1309da2e3ebdSchin 					continue;
1310da2e3ebdSchin 				break;
1311da2e3ebdSchin 		}
13127c2fbfb3SApril Chin 		lp->comp_assign = 0;
1313da2e3ebdSchin 		if(mode==ST_NAME)
1314da2e3ebdSchin 			mode = ST_NORM;
1315da2e3ebdSchin 		else if(mode==ST_NONE)
1316da2e3ebdSchin 			return(0);
1317da2e3ebdSchin 	}
1318da2e3ebdSchin breakloop:
13197c2fbfb3SApril Chin 	if(lp->lexd.nocopy)
13207c2fbfb3SApril Chin 	{
13217c2fbfb3SApril Chin 		lp->lexd.balance = 0;
13227c2fbfb3SApril Chin 		return(0);
13237c2fbfb3SApril Chin 	}
13247c2fbfb3SApril Chin 	if(lp->lexd.dolparen)
1325da2e3ebdSchin 	{
13267c2fbfb3SApril Chin 		lp->lexd.balance = 0;
13277c2fbfb3SApril Chin 		if(lp->lexd.docword)
1328da2e3ebdSchin 			nested_here(lp);
13297c2fbfb3SApril Chin 		lp->lexd.message = (wordflags&ARG_MESSAGE);
13307c2fbfb3SApril Chin 		return(lp->token=0);
1331da2e3ebdSchin 	}
13327c2fbfb3SApril Chin 	if(!(state=lp->lexd.first))
1333da2e3ebdSchin 		state = fcfirst();
1334da2e3ebdSchin 	n = fcseek(0)-(char*)state;
13357c2fbfb3SApril Chin 	if(!lp->arg)
13367c2fbfb3SApril Chin 		lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
1337da2e3ebdSchin 	if(n>0)
13387c2fbfb3SApril Chin 		sfwrite(stkp,state,n);
1339da2e3ebdSchin 	/* add balancing character if necessary */
13407c2fbfb3SApril Chin 	if(lp->lexd.balance)
1341da2e3ebdSchin 	{
13427c2fbfb3SApril Chin 		sfputc(stkp,lp->lexd.balance);
13437c2fbfb3SApril Chin 		lp->lexd.balance = 0;
1344da2e3ebdSchin 	}
13457c2fbfb3SApril Chin 	sfputc(stkp,0);
13467c2fbfb3SApril Chin 	stkseek(stkp,stktell(stkp)-1);
13477c2fbfb3SApril Chin 	state = stkptr(stkp,ARGVAL);
13487c2fbfb3SApril Chin 	n = stktell(stkp)-ARGVAL;
13497c2fbfb3SApril Chin 	lp->lexd.first=0;
1350da2e3ebdSchin 	if(n==1)
1351da2e3ebdSchin 	{
1352da2e3ebdSchin 		/* check for numbered redirection */
1353da2e3ebdSchin 		n = state[0];
1354da2e3ebdSchin 		if((c=='<' || c=='>') && isadigit(n))
1355da2e3ebdSchin 		{
13567c2fbfb3SApril Chin 			c = sh_lex(lp);
13577c2fbfb3SApril Chin 			lp->digits = (n-'0');
1358da2e3ebdSchin 			return(c);
1359da2e3ebdSchin 		}
1360da2e3ebdSchin 		if(n==LBRACT)
1361da2e3ebdSchin 			c = 0;
13627c2fbfb3SApril Chin 		else if(n==RBRACE && lp->comsub)
13637c2fbfb3SApril Chin 			return(lp->token=n);
1364da2e3ebdSchin 		else if(n=='~')
1365da2e3ebdSchin 			c = ARG_MAC;
1366da2e3ebdSchin 		else
1367da2e3ebdSchin 			c = (wordflags&ARG_EXP);
1368da2e3ebdSchin 		n = 1;
1369da2e3ebdSchin 	}
13707c2fbfb3SApril Chin 	else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
1371da2e3ebdSchin 	{
1372da2e3ebdSchin 		if(!strchr(state,','))
1373da2e3ebdSchin 		{
13747c2fbfb3SApril Chin 			stkseek(stkp,stktell(stkp)-1);
13757c2fbfb3SApril Chin 			lp->arg = (struct argnod*)stkfreeze(stkp,1);
13767c2fbfb3SApril Chin 			return(lp->token=IOVNAME);
1377da2e3ebdSchin 		}
1378da2e3ebdSchin 		c = wordflags;
1379da2e3ebdSchin 	}
1380da2e3ebdSchin 	else
1381da2e3ebdSchin 		c = wordflags;
1382da2e3ebdSchin 	if(assignment<0)
1383da2e3ebdSchin 	{
13847c2fbfb3SApril Chin 		stkseek(stkp,stktell(stkp)-1);
13857c2fbfb3SApril Chin 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
13867c2fbfb3SApril Chin 		lp->lex.reservok = 1;
13877c2fbfb3SApril Chin 		return(lp->token=LABLSYM);
1388da2e3ebdSchin 	}
13897c2fbfb3SApril Chin 	if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE)
1390da2e3ebdSchin 		c &= ~ARG_EXP;
1391da2e3ebdSchin 	if((c&ARG_EXP) && (c&ARG_QUOTED))
1392da2e3ebdSchin 		c |= ARG_MAC;
1393da2e3ebdSchin 	if(mode==ST_NONE)
1394da2e3ebdSchin 	{
1395da2e3ebdSchin 		/* eliminate trailing )) */
13967c2fbfb3SApril Chin 		stkseek(stkp,stktell(stkp)-2);
1397da2e3ebdSchin 	}
1398da2e3ebdSchin 	if(c&ARG_MESSAGE)
1399da2e3ebdSchin 	{
1400da2e3ebdSchin 		if(sh_isoption(SH_DICTIONARY))
14017c2fbfb3SApril Chin 			lp->arg = sh_endword(shp,2);
1402b30d1939SAndy Fiddaman 		c |= ARG_MAC;
1403da2e3ebdSchin 	}
1404b30d1939SAndy Fiddaman 	if(c==0 || (c&(ARG_MAC|ARG_EXP|ARG_MESSAGE)))
1405da2e3ebdSchin 	{
14067c2fbfb3SApril Chin 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
14077c2fbfb3SApril Chin 		lp->arg->argflag = (c?c:ARG_RAW);
1408da2e3ebdSchin 	}
1409da2e3ebdSchin 	else if(mode==ST_NONE)
14107c2fbfb3SApril Chin 		lp->arg = sh_endword(shp,-1);
1411da2e3ebdSchin 	else
14127c2fbfb3SApril Chin 		lp->arg = sh_endword(shp,0);
14137c2fbfb3SApril Chin 	state = lp->arg->argval;
14147c2fbfb3SApril Chin 	lp->comp_assign = assignment;
1415da2e3ebdSchin 	if(assignment)
14167c2fbfb3SApril Chin 		lp->arg->argflag |= ARG_ASSIGN;
14177c2fbfb3SApril Chin 	else if(!lp->lex.skipword)
14187c2fbfb3SApril Chin 		lp->assignok = 0;
14197c2fbfb3SApril Chin 	lp->arg->argchn.cp = 0;
14207c2fbfb3SApril Chin 	lp->arg->argnxt.ap = 0;
1421da2e3ebdSchin 	if(mode==ST_NONE)
14227c2fbfb3SApril Chin 		return(lp->token=EXPRSYM);
14237c2fbfb3SApril Chin 	if(lp->lex.intest)
1424da2e3ebdSchin 	{
14257c2fbfb3SApril Chin 		if(lp->lex.testop1)
1426da2e3ebdSchin 		{
14277c2fbfb3SApril Chin 			lp->lex.testop1 = 0;
1428da2e3ebdSchin 			if(n==2 && state[0]=='-' && state[2]==0 &&
1429da2e3ebdSchin 				strchr(test_opchars,state[1]))
1430da2e3ebdSchin 			{
14317c2fbfb3SApril Chin 				if(lp->lexd.warn && state[1]=='a')
1432da2e3ebdSchin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
14337c2fbfb3SApril Chin 				lp->digits = state[1];
14347c2fbfb3SApril Chin 				lp->token = TESTUNOP;
1435da2e3ebdSchin 			}
1436da2e3ebdSchin 			else if(n==1 && state[0]=='!' && state[1]==0)
1437da2e3ebdSchin 			{
14387c2fbfb3SApril Chin 				lp->lex.testop1 = 1;
14397c2fbfb3SApril Chin 				lp->token = '!';
1440da2e3ebdSchin 			}
1441da2e3ebdSchin 			else
1442da2e3ebdSchin 			{
14437c2fbfb3SApril Chin 				lp->lex.testop2 = 1;
14447c2fbfb3SApril Chin 				lp->token = 0;
1445da2e3ebdSchin 			}
14467c2fbfb3SApril Chin 			return(lp->token);
1447da2e3ebdSchin 		}
14487c2fbfb3SApril Chin 		lp->lex.incase = 0;
1449da2e3ebdSchin 		c = sh_lookup(state,shtab_testops);
1450da2e3ebdSchin 		switch(c)
1451da2e3ebdSchin 		{
1452da2e3ebdSchin 		case TEST_END:
14537c2fbfb3SApril Chin 			lp->lex.testop2 = lp->lex.intest = 0;
14547c2fbfb3SApril Chin 			lp->lex.reservok = 1;
14557c2fbfb3SApril Chin 			lp->token = ETESTSYM;
14567c2fbfb3SApril Chin 			return(lp->token);
1457da2e3ebdSchin 
1458da2e3ebdSchin 		case TEST_SEQ:
14597c2fbfb3SApril Chin 			if(lp->lexd.warn && state[1]==0)
1460da2e3ebdSchin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
14615ae8bd53SToomas Soome 			/* FALLTHROUGH */
1462da2e3ebdSchin 		default:
14637c2fbfb3SApril Chin 			if(lp->lex.testop2)
1464da2e3ebdSchin 			{
1465c7b656fcSAndy Fiddaman 				if(lp->lexd.warn && (c&TEST_ARITH)) {
1466*be548e87SAndy Fiddaman 					char *alt;
1467c7b656fcSAndy Fiddaman 
1468*be548e87SAndy Fiddaman 					switch (c) {
1469*be548e87SAndy Fiddaman 					case TEST_EQ:
1470c7b656fcSAndy Fiddaman 						alt = "==";
1471*be548e87SAndy Fiddaman 						break;
1472*be548e87SAndy Fiddaman 					case TEST_NE:
1473c7b656fcSAndy Fiddaman 						alt = "!=";
1474*be548e87SAndy Fiddaman 						break;
1475*be548e87SAndy Fiddaman 					case TEST_LT:
1476c7b656fcSAndy Fiddaman 						alt = "<";
1477*be548e87SAndy Fiddaman 						break;
1478*be548e87SAndy Fiddaman 					case TEST_GT:
1479c7b656fcSAndy Fiddaman 						alt = ">";
1480*be548e87SAndy Fiddaman 						break;
1481*be548e87SAndy Fiddaman 					case TEST_LE:
1482c7b656fcSAndy Fiddaman 						alt = "<=";
1483*be548e87SAndy Fiddaman 						break;
1484*be548e87SAndy Fiddaman 					case TEST_GE:
1485c7b656fcSAndy Fiddaman 						alt = ">=";
1486*be548e87SAndy Fiddaman 						break;
1487*be548e87SAndy Fiddaman 					default:
1488*be548e87SAndy Fiddaman 						alt = "??";
1489c7b656fcSAndy Fiddaman 					}
1490*be548e87SAndy Fiddaman 					errormsg(SH_DICT, ERROR_warn(0),
1491*be548e87SAndy Fiddaman 					    e_lexobsolete4,
1492*be548e87SAndy Fiddaman 					    shp->inlineno, state, alt);
1493c7b656fcSAndy Fiddaman 				}
1494da2e3ebdSchin 				if(c&TEST_PATTERN)
14957c2fbfb3SApril Chin 					lp->lex.incase = 1;
1496da2e3ebdSchin 				else if(c==TEST_REP)
14977c2fbfb3SApril Chin 					lp->lex.incase = TEST_RE;
14987c2fbfb3SApril Chin 				lp->lex.testop2 = 0;
14997c2fbfb3SApril Chin 				lp->digits = c;
15007c2fbfb3SApril Chin 				lp->token = TESTBINOP;
15017c2fbfb3SApril Chin 				return(lp->token);
1502da2e3ebdSchin 			}
1503da2e3ebdSchin 
15045ae8bd53SToomas Soome 			/* FALLTHROUGH */
1505da2e3ebdSchin 		case TEST_OR: case TEST_AND:
1506da2e3ebdSchin 		case 0:
15077c2fbfb3SApril Chin 			return(lp->token=0);
1508da2e3ebdSchin 		}
1509da2e3ebdSchin 	}
15107c2fbfb3SApril Chin 	if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2)
1511da2e3ebdSchin 	{
1512da2e3ebdSchin 		/* check for {, }, ! */
1513da2e3ebdSchin 		c = state[0];
1514da2e3ebdSchin 		if(n==1 && (c=='{' || c=='}' || c=='!'))
1515da2e3ebdSchin 		{
15167c2fbfb3SApril Chin 			if(lp->lexd.warn && c=='{' && lp->lex.incase==2)
1517da2e3ebdSchin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
15187c2fbfb3SApril Chin 			if(lp->lex.incase==1 && c==RBRACE)
15197c2fbfb3SApril Chin 				lp->lex.incase = 0;
15207c2fbfb3SApril Chin 			return(lp->token=c);
1521da2e3ebdSchin 		}
15227c2fbfb3SApril Chin 		else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT)
1523da2e3ebdSchin 		{
15247c2fbfb3SApril Chin 			lp->lex.intest = lp->lex.testop1 = 1;
15257c2fbfb3SApril Chin 			lp->lex.testop2 = lp->lex.reservok = 0;
15267c2fbfb3SApril Chin 			return(lp->token=BTESTSYM);
1527da2e3ebdSchin 		}
1528da2e3ebdSchin 	}
1529da2e3ebdSchin 	c = 0;
15307c2fbfb3SApril Chin 	if(!lp->lex.skipword)
1531da2e3ebdSchin 	{
15327c2fbfb3SApril Chin 		if(n>1 && lp->lex.reservok==1 && mode==ST_NAME &&
1533da2e3ebdSchin 			(c=sh_lookup(state,shtab_reserved)))
1534da2e3ebdSchin 		{
15357c2fbfb3SApril Chin 			if(lp->lex.incase)
1536da2e3ebdSchin 			{
15377c2fbfb3SApril Chin 				if(lp->lex.incase >1)
15387c2fbfb3SApril Chin 					lp->lex.incase = 1;
1539da2e3ebdSchin 				else if(c==ESACSYM)
15407c2fbfb3SApril Chin 					lp->lex.incase = 0;
1541da2e3ebdSchin 				else
1542da2e3ebdSchin 					c = 0;
1543da2e3ebdSchin 			}
1544da2e3ebdSchin 			else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
1545da2e3ebdSchin 			{
15467c2fbfb3SApril Chin 				lp->lex.skipword = 1;
15477c2fbfb3SApril Chin 				lp->lex.incase = 2*(c==CASESYM);
1548da2e3ebdSchin 			}
1549da2e3ebdSchin 			else
15507c2fbfb3SApril Chin 				lp->lex.skipword = 0;
1551da2e3ebdSchin 			if(c==INSYM)
15527c2fbfb3SApril Chin 				lp->lex.reservok = 0;
1553da2e3ebdSchin 			else if(c==TIMESYM)
1554da2e3ebdSchin 			{
1555da2e3ebdSchin 				/* yech - POSIX requires time -p */
1556da2e3ebdSchin 				while(fcgetc(n)==' ' || n=='\t');
1557da2e3ebdSchin 				if(n>0)
1558b30d1939SAndy Fiddaman 					fcseek(-LEN);
1559da2e3ebdSchin 				if(n=='-')
1560da2e3ebdSchin 					c=0;
1561da2e3ebdSchin 			}
15627c2fbfb3SApril Chin 			return(lp->token=c);
1563da2e3ebdSchin 		}
15647c2fbfb3SApril Chin 		if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok))
1565da2e3ebdSchin 		{
1566da2e3ebdSchin 			/* check for aliases */
1567da2e3ebdSchin 			Namval_t* np;
15687c2fbfb3SApril Chin 			if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN &&
1569da2e3ebdSchin 				(np=nv_search(state,shp->alias_tree,HASH_SCOPE))
1570da2e3ebdSchin 				&& !nv_isattr(np,NV_NOEXPAND)
1571da2e3ebdSchin #if KSHELL
1572b30d1939SAndy Fiddaman 				&& (lp->aliasok!=2 || nv_isattr(np,BLT_DCL))
1573da2e3ebdSchin 				&& (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
1574da2e3ebdSchin #endif /* KSHELL */
1575da2e3ebdSchin 				&& (state=nv_getval(np)))
1576da2e3ebdSchin 			{
1577da2e3ebdSchin 				setupalias(lp,state,np);
1578da2e3ebdSchin 				nv_onattr(np,NV_NOEXPAND);
15797c2fbfb3SApril Chin 				lp->lex.reservok = 1;
15807c2fbfb3SApril Chin 				lp->assignok |= lp->lex.reservok;
15817c2fbfb3SApril Chin 				return(sh_lex(lp));
1582da2e3ebdSchin 			}
1583da2e3ebdSchin 		}
15847c2fbfb3SApril Chin 		lp->lex.reservok = 0;
1585da2e3ebdSchin 	}
15867c2fbfb3SApril Chin 	lp->lex.skipword = lp->lexd.docword = 0;
15877c2fbfb3SApril Chin 	return(lp->token=c);
1588da2e3ebdSchin }
1589da2e3ebdSchin 
1590da2e3ebdSchin /*
1591da2e3ebdSchin  * read to end of command substitution
1592da2e3ebdSchin  */
comsub(register Lex_t * lp,int endtok)15937c2fbfb3SApril Chin static int comsub(register Lex_t *lp, int endtok)
1594da2e3ebdSchin {
1595da2e3ebdSchin 	register int	n,c,count=1;
15967c2fbfb3SApril Chin 	register int	line=lp->sh->inlineno;
1597b30d1939SAndy Fiddaman 	char *first,*cp=fcseek(0),word[5];
15983e14f97fSRoger A. Faulkner 	int off, messages=0, assignok=lp->assignok, csub;
1599da2e3ebdSchin 	struct lexstate	save;
16007c2fbfb3SApril Chin 	save = lp->lex;
16017c2fbfb3SApril Chin 	csub = lp->comsub;
16027c2fbfb3SApril Chin 	sh_lexopen(lp,lp->sh,1);
16037c2fbfb3SApril Chin 	lp->lexd.dolparen++;
16047c2fbfb3SApril Chin 	lp->lex.incase=0;
16057c2fbfb3SApril Chin 	pushlevel(lp,0,0);
16067c2fbfb3SApril Chin 	lp->comsub = (endtok==LBRACE);
1607b30d1939SAndy Fiddaman 	if(first=lp->lexd.first)
1608b30d1939SAndy Fiddaman 		off = cp-first;
1609b30d1939SAndy Fiddaman 	else
1610b30d1939SAndy Fiddaman 		off = cp-fcfirst();
1611b30d1939SAndy Fiddaman 	if(off<0)
1612b30d1939SAndy Fiddaman 		c=*cp, *cp=0;
1613b30d1939SAndy Fiddaman 	n = sh_lex(lp);
1614b30d1939SAndy Fiddaman 	if(off<0)
1615b30d1939SAndy Fiddaman 		*cp = c;
1616b30d1939SAndy Fiddaman 	if(n==endtok || off<0)
1617da2e3ebdSchin 	{
1618b30d1939SAndy Fiddaman 		if(endtok==LPAREN && lp->lexd.paren)
16193e14f97fSRoger A. Faulkner 		{
1620b30d1939SAndy Fiddaman 
1621b30d1939SAndy Fiddaman 			if(first==lp->lexd.first)
1622b30d1939SAndy Fiddaman 			{
1623b30d1939SAndy Fiddaman 				n = cp+1-(char*)fcseek(0);
1624b30d1939SAndy Fiddaman 				fcseek(n);
1625b30d1939SAndy Fiddaman 			}
16263e14f97fSRoger A. Faulkner 			count++;
16273e14f97fSRoger A. Faulkner 			lp->lexd.paren = 0;
1628b30d1939SAndy Fiddaman 			fcgetc(c);
16293e14f97fSRoger A. Faulkner 		}
1630da2e3ebdSchin 		while(1)
1631da2e3ebdSchin 		{
1632da2e3ebdSchin 			/* look for case and esac */
1633da2e3ebdSchin 			n=0;
1634da2e3ebdSchin 			while(1)
1635da2e3ebdSchin 			{
1636da2e3ebdSchin 				fcgetc(c);
1637da2e3ebdSchin 				/* skip leading white space */
1638da2e3ebdSchin 				if(n==0 && !sh_lexstates[ST_BEGIN][c])
1639da2e3ebdSchin 					continue;
1640da2e3ebdSchin 				if(n==4)
1641da2e3ebdSchin 					break;
1642da2e3ebdSchin 				if(sh_lexstates[ST_NAME][c])
1643da2e3ebdSchin 					goto skip;
1644da2e3ebdSchin 				word[n++] = c;
1645da2e3ebdSchin 			}
1646da2e3ebdSchin 			if(sh_lexstates[ST_NAME][c]==S_BREAK)
1647da2e3ebdSchin 			{
1648da2e3ebdSchin 				if(memcmp(word,"case",4)==0)
16497c2fbfb3SApril Chin 					lp->lex.incase=1;
1650da2e3ebdSchin 				else if(memcmp(word,"esac",4)==0)
16517c2fbfb3SApril Chin 					lp->lex.incase=0;
1652da2e3ebdSchin 			}
1653da2e3ebdSchin 		skip:
1654da2e3ebdSchin 			if(c && (c!='#' || n==0))
1655b30d1939SAndy Fiddaman 				fcseek(-LEN);
16567c2fbfb3SApril Chin 			if(c==RBRACE && lp->lex.incase)
16577c2fbfb3SApril Chin 				lp->lex.incase=0;
1658b30d1939SAndy Fiddaman 			c=sh_lex(lp);
1659b30d1939SAndy Fiddaman 			switch(c)
1660da2e3ebdSchin 			{
16617c2fbfb3SApril Chin 			    case LBRACE:
16627c2fbfb3SApril Chin 				if(endtok==LBRACE && !lp->lex.incase)
16637c2fbfb3SApril Chin 				{
16647c2fbfb3SApril Chin 					lp->comsub = 0;
16657c2fbfb3SApril Chin 					count++;
16667c2fbfb3SApril Chin 				}
16677c2fbfb3SApril Chin 				break;
16687c2fbfb3SApril Chin 			    case RBRACE:
16697c2fbfb3SApril Chin 			    rbrace:
16707c2fbfb3SApril Chin 				if(endtok==LBRACE && --count<=0)
16717c2fbfb3SApril Chin 					goto done;
1672b30d1939SAndy Fiddaman 				if(count==1)
1673b30d1939SAndy Fiddaman 					lp->comsub = endtok==LBRACE;
16747c2fbfb3SApril Chin 				break;
16757c2fbfb3SApril Chin 			    case IPROCSYM:	case OPROCSYM:
16767c2fbfb3SApril Chin 			    case LPAREN:
16777c2fbfb3SApril Chin 				if(endtok==LPAREN && !lp->lex.incase)
1678da2e3ebdSchin 					count++;
1679da2e3ebdSchin 				break;
1680da2e3ebdSchin 			    case RPAREN:
16817c2fbfb3SApril Chin 				if(lp->lex.incase)
16827c2fbfb3SApril Chin 					lp->lex.incase=0;
16837c2fbfb3SApril Chin 				else if(endtok==LPAREN && --count<=0)
1684da2e3ebdSchin 					goto done;
1685da2e3ebdSchin 				break;
1686da2e3ebdSchin 			    case EOFSYM:
16877c2fbfb3SApril Chin 				lp->lastline = line;
16887c2fbfb3SApril Chin 				lp->lasttok = endtok;
16897c2fbfb3SApril Chin 				sh_syntax(lp);
16905ae8bd53SToomas Soome 				/* FALLTHROUGH */
1691da2e3ebdSchin 			    case IOSEEKSYM:
1692da2e3ebdSchin 				if(fcgetc(c)!='#' && c>0)
1693b30d1939SAndy Fiddaman 					fcseek(-LEN);
1694da2e3ebdSchin 				break;
1695da2e3ebdSchin 			    case IODOCSYM:
169634f9b3eeSRoland Mainz 				lp->lexd.docextra = 0;
16977c2fbfb3SApril Chin 				sh_lex(lp);
1698da2e3ebdSchin 				break;
1699da2e3ebdSchin 			    case 0:
17007c2fbfb3SApril Chin 				lp->lex.reservok = 0;
17017c2fbfb3SApril Chin 				messages |= lp->lexd.message;
17027c2fbfb3SApril Chin 				break;
17037c2fbfb3SApril Chin 			    case ';':
1704b30d1939SAndy Fiddaman 				do
1705b30d1939SAndy Fiddaman 					fcgetc(c);
1706b30d1939SAndy Fiddaman 				while(!sh_lexstates[ST_BEGIN][c]);
17077c2fbfb3SApril Chin 				if(c==RBRACE && endtok==LBRACE)
17087c2fbfb3SApril Chin 					goto rbrace;
17097c2fbfb3SApril Chin 				if(c>0)
1710b30d1939SAndy Fiddaman 					fcseek(-LEN);
17117c2fbfb3SApril Chin 				/* fall through*/
17127c2fbfb3SApril Chin 			    default:
17137c2fbfb3SApril Chin 				lp->lex.reservok = 1;
1714da2e3ebdSchin 			}
1715da2e3ebdSchin 		}
1716da2e3ebdSchin 	}
1717da2e3ebdSchin done:
17187c2fbfb3SApril Chin 	poplevel(lp);
17197c2fbfb3SApril Chin 	lp->comsub = csub;
17207c2fbfb3SApril Chin 	lp->lastline = line;
17217c2fbfb3SApril Chin 	lp->lexd.dolparen--;
17227c2fbfb3SApril Chin 	lp->lex = save;
17237c2fbfb3SApril Chin 	lp->assignok = (endchar(lp)==RBRACT?assignok:0);
1724b30d1939SAndy Fiddaman 	if(lp->heredoc)
1725b30d1939SAndy Fiddaman 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax5,lp->sh->inlineno,lp->heredoc->ioname);
1726da2e3ebdSchin 	return(messages);
1727da2e3ebdSchin }
1728da2e3ebdSchin 
1729da2e3ebdSchin /*
1730da2e3ebdSchin  * here-doc nested in $(...)
1731da2e3ebdSchin  * allocate ionode with delimiter filled in without disturbing stak
1732da2e3ebdSchin  */
nested_here(register Lex_t * lp)1733da2e3ebdSchin static void nested_here(register Lex_t *lp)
1734da2e3ebdSchin {
17357c2fbfb3SApril Chin 	register struct ionod	*iop;
1736b30d1939SAndy Fiddaman 	register int		n=0,offset;
17377c2fbfb3SApril Chin 	struct argnod		*arg = lp->arg;
17387c2fbfb3SApril Chin 	Stk_t			*stkp = lp->sh->stk;
17397c2fbfb3SApril Chin 	char			*base;
17407c2fbfb3SApril Chin 	if(offset=stktell(stkp))
17417c2fbfb3SApril Chin 		base = stkfreeze(stkp,0);
1742b30d1939SAndy Fiddaman 	if(lp->lexd.docend)
1743b30d1939SAndy Fiddaman 		n = fcseek(0)-lp->lexd.docend;
174434f9b3eeSRoland Mainz 	iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL);
17457c2fbfb3SApril Chin 	iop->iolst = lp->heredoc;
17467c2fbfb3SApril Chin 	stkseek(stkp,ARGVAL);
174734f9b3eeSRoland Mainz 	if(lp->lexd.docextra)
174834f9b3eeSRoland Mainz 	{
174934f9b3eeSRoland Mainz 		sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
175034f9b3eeSRoland Mainz 		sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1);
1751b30d1939SAndy Fiddaman 		sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
175234f9b3eeSRoland Mainz 	}
17537c2fbfb3SApril Chin 	sfwrite(stkp,lp->lexd.docend,n);
17547c2fbfb3SApril Chin 	lp->arg = sh_endword(lp->sh,0);
1755da2e3ebdSchin 	iop->ioname = (char*)(iop+1);
17567c2fbfb3SApril Chin 	strcpy(iop->ioname,lp->arg->argval);
1757da2e3ebdSchin 	iop->iofile = (IODOC|IORAW);
17587c2fbfb3SApril Chin 	if(lp->lexd.docword>1)
1759da2e3ebdSchin 		iop->iofile |= IOSTRIP;
17607c2fbfb3SApril Chin 	lp->heredoc = iop;
17617c2fbfb3SApril Chin 	lp->arg = arg;
17627c2fbfb3SApril Chin 	lp->lexd.docword = 0;
1763da2e3ebdSchin 	if(offset)
17647c2fbfb3SApril Chin 		stkset(stkp,base,offset);
1765da2e3ebdSchin 	else
17667c2fbfb3SApril Chin 		stkseek(stkp,0);
1767da2e3ebdSchin }
1768da2e3ebdSchin 
1769da2e3ebdSchin /*
1770da2e3ebdSchin  * skip to <close> character
1771da2e3ebdSchin  * if <copy> is non,zero, then the characters are copied to the stack
1772da2e3ebdSchin  * <state> is the initial lexical state
1773da2e3ebdSchin  */
sh_lexskip(Lex_t * lp,int close,register int copy,int state)17747c2fbfb3SApril Chin void sh_lexskip(Lex_t *lp,int close, register int copy, int  state)
1775da2e3ebdSchin {
1776da2e3ebdSchin 	register char	*cp;
17777c2fbfb3SApril Chin 	lp->lexd.nest = close;
17787c2fbfb3SApril Chin 	lp->lexd.lex_state = state;
17797c2fbfb3SApril Chin 	lp->lexd.noarg = 1;
1780da2e3ebdSchin 	if(copy)
17817c2fbfb3SApril Chin 		fcnotify(lex_advance,lp);
1782da2e3ebdSchin 	else
17837c2fbfb3SApril Chin 		lp->lexd.nocopy++;
17847c2fbfb3SApril Chin 	sh_lex(lp);
17857c2fbfb3SApril Chin 	lp->lexd.noarg = 0;
1786da2e3ebdSchin 	if(copy)
1787da2e3ebdSchin 	{
17887c2fbfb3SApril Chin 		fcnotify(0,lp);
17897c2fbfb3SApril Chin 		if(!(cp=lp->lexd.first))
1790da2e3ebdSchin 			cp = fcfirst();
1791da2e3ebdSchin 		if((copy = fcseek(0)-cp) > 0)
17927c2fbfb3SApril Chin 			sfwrite(lp->sh->stk,cp,copy);
1793da2e3ebdSchin 	}
1794da2e3ebdSchin 	else
17957c2fbfb3SApril Chin 		lp->lexd.nocopy--;
1796da2e3ebdSchin }
1797da2e3ebdSchin 
1798da2e3ebdSchin #if SHOPT_CRNL
_sfwrite(Sfio_t * sp,const Void_t * buff,size_t n)1799da2e3ebdSchin     ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
1800da2e3ebdSchin     {
1801da2e3ebdSchin 	const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
1802da2e3ebdSchin 	int m=0,k;
1803da2e3ebdSchin 	while(next = (const char*)memchr(next,'\r',ep-next))
1804da2e3ebdSchin 		if(*++next=='\n')
1805da2e3ebdSchin 		{
1806da2e3ebdSchin 			if(k=next-cp-1)
1807da2e3ebdSchin 			{
1808da2e3ebdSchin 				if((k=sfwrite(sp,cp,k)) < 0)
1809da2e3ebdSchin 					return(m>0?m:-1);
1810da2e3ebdSchin 				m += k;
1811da2e3ebdSchin 			}
1812da2e3ebdSchin 			cp = next;
1813da2e3ebdSchin 		}
1814da2e3ebdSchin 	if((k=sfwrite(sp,cp,ep-cp)) < 0)
1815da2e3ebdSchin 		return(m>0?m:-1);
1816da2e3ebdSchin 	return(m+k);
1817da2e3ebdSchin     }
1818da2e3ebdSchin #   define sfwrite	_sfwrite
1819da2e3ebdSchin #endif /* SHOPT_CRNL */
1820da2e3ebdSchin 
1821da2e3ebdSchin /*
1822da2e3ebdSchin  * read in here-document from script
1823da2e3ebdSchin  * quoted here documents, and here-documents without special chars are
1824da2e3ebdSchin  * noted with the IOQUOTE flag
1825da2e3ebdSchin  * returns 1 for complete here-doc, 0 for EOF
1826da2e3ebdSchin  */
1827da2e3ebdSchin 
here_copy(Lex_t * lp,register struct ionod * iop)1828da2e3ebdSchin static int here_copy(Lex_t *lp,register struct ionod *iop)
1829da2e3ebdSchin {
1830da2e3ebdSchin 	register const char	*state;
1831da2e3ebdSchin 	register int		c,n;
1832da2e3ebdSchin 	register char		*bufp,*cp;
18337c2fbfb3SApril Chin 	register Sfio_t		*sp=lp->sh->heredocs, *funlog;
1834da2e3ebdSchin 	int			stripcol=0,stripflg, nsave, special=0;
18357c2fbfb3SApril Chin 	if(funlog=lp->sh->funlog)
1836da2e3ebdSchin 	{
1837da2e3ebdSchin 		if(fcfill()>0)
1838b30d1939SAndy Fiddaman 			fcseek(-LEN);
18397c2fbfb3SApril Chin 		lp->sh->funlog = 0;
1840da2e3ebdSchin 	}
1841da2e3ebdSchin 	if(iop->iolst)
1842da2e3ebdSchin 		here_copy(lp,iop->iolst);
1843da2e3ebdSchin 	iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
1844da2e3ebdSchin 	iop->iosize = 0;
1845da2e3ebdSchin 	iop->iodelim=iop->ioname;
1846da2e3ebdSchin 	/* check for and strip quoted characters in delimiter string */
1847da2e3ebdSchin 	if(stripflg=iop->iofile&IOSTRIP)
1848da2e3ebdSchin 	{
1849da2e3ebdSchin 		while(*iop->iodelim=='\t')
1850da2e3ebdSchin 			iop->iodelim++;
1851da2e3ebdSchin 		/* skip over leading tabs in document */
1852da2e3ebdSchin 		if(iop->iofile&IOLSEEK)
1853da2e3ebdSchin 		{
1854da2e3ebdSchin 			iop->iofile &= ~IOLSEEK;
1855da2e3ebdSchin 			while(fcgetc(c)=='\t' || c==' ')
1856da2e3ebdSchin 			{
1857da2e3ebdSchin 				if(c==' ')
1858da2e3ebdSchin 					stripcol++;
1859da2e3ebdSchin 				else
1860da2e3ebdSchin 					stripcol += 8 - stripcol%8;
1861da2e3ebdSchin 			}
1862da2e3ebdSchin 		}
1863da2e3ebdSchin 		else
1864da2e3ebdSchin 			while(fcgetc(c)=='\t');
1865da2e3ebdSchin 		if(c>0)
1866b30d1939SAndy Fiddaman 			fcseek(-LEN);
1867da2e3ebdSchin 	}
1868da2e3ebdSchin 	if(iop->iofile&IOQUOTE)
1869da2e3ebdSchin 		state = sh_lexstates[ST_LIT];
1870da2e3ebdSchin 	else
1871da2e3ebdSchin 		state = sh_lexstates[ST_QUOTE];
1872da2e3ebdSchin 	bufp = fcseek(0);
1873da2e3ebdSchin 	n = S_NL;
1874da2e3ebdSchin 	while(1)
1875da2e3ebdSchin 	{
1876da2e3ebdSchin 		if(n!=S_NL)
1877da2e3ebdSchin 		{
1878da2e3ebdSchin 			/* skip over regular characters */
1879b30d1939SAndy Fiddaman #if SHOPT_MULTIBYTE
1880b30d1939SAndy Fiddaman 			do
1881b30d1939SAndy Fiddaman 			{
1882b30d1939SAndy Fiddaman 				if(fcleft()< MB_LEN_MAX && mbsize(fcseek(0))<0)
1883b30d1939SAndy Fiddaman 				{
1884b30d1939SAndy Fiddaman 					n = S_EOF;
1885b30d1939SAndy Fiddaman 					LEN = -fcleft();
1886b30d1939SAndy Fiddaman 					break;
1887b30d1939SAndy Fiddaman 				}
1888b30d1939SAndy Fiddaman 			}
1889b30d1939SAndy Fiddaman #endif /* SHOPT_MULTIBYTE */
1890b30d1939SAndy Fiddaman 
1891da2e3ebdSchin 			while((n=STATE(state,c))==0);
1892da2e3ebdSchin 		}
1893da2e3ebdSchin 		if(n==S_EOF || !(c=fcget()))
1894da2e3ebdSchin 		{
1895b30d1939SAndy Fiddaman 			if(LEN < 0)
1896b30d1939SAndy Fiddaman 				c = fclast()-bufp;
1897b30d1939SAndy Fiddaman 			else
1898b30d1939SAndy Fiddaman 				c= (fcseek(0)-1)-bufp;
1899b30d1939SAndy Fiddaman 			if(!lp->lexd.dolparen && c)
1900da2e3ebdSchin 			{
1901da2e3ebdSchin 				if(n==S_ESC)
1902da2e3ebdSchin 					c--;
1903b30d1939SAndy Fiddaman 				if(!lp->lexd.dolparen && (c=sfwrite(sp,bufp,c))>0)
1904da2e3ebdSchin 					iop->iosize += c;
1905da2e3ebdSchin 			}
1906b30d1939SAndy Fiddaman #if SHOPT_MULTIBYTE
1907b30d1939SAndy Fiddaman 			if(LEN==0)
1908b30d1939SAndy Fiddaman 				LEN=1;
1909b30d1939SAndy Fiddaman 			if(LEN < 0)
1910b30d1939SAndy Fiddaman 			{
1911b30d1939SAndy Fiddaman 				n = LEN;
1912b30d1939SAndy Fiddaman 				c = fcmbget(&LEN);
1913b30d1939SAndy Fiddaman 				LEN += n;
1914b30d1939SAndy Fiddaman 			}
1915b30d1939SAndy Fiddaman 			else
1916b30d1939SAndy Fiddaman #endif /* SHOPT_MULTIBYTE */
1917b30d1939SAndy Fiddaman 				c = lexfill(lp);
1918b30d1939SAndy Fiddaman 			if(c<0)
1919da2e3ebdSchin 				break;
1920da2e3ebdSchin 			if(n==S_ESC)
1921da2e3ebdSchin 			{
1922da2e3ebdSchin #if SHOPT_CRNL
1923da2e3ebdSchin 				if(c=='\r' && (c=fcget())!=NL)
1924b30d1939SAndy Fiddaman 					fcseek(-LEN);
1925da2e3ebdSchin #endif /* SHOPT_CRNL */
1926da2e3ebdSchin 				if(c==NL)
1927da2e3ebdSchin 					fcseek(1);
1928b30d1939SAndy Fiddaman 				else if(!lp->lexd.dolparen)
1929b30d1939SAndy Fiddaman 				{
1930b30d1939SAndy Fiddaman 					iop->iosize++;
1931da2e3ebdSchin 					sfputc(sp,'\\');
1932b30d1939SAndy Fiddaman 				}
1933da2e3ebdSchin 			}
1934b30d1939SAndy Fiddaman 			bufp = fcseek(-LEN);
1935da2e3ebdSchin 		}
1936da2e3ebdSchin 		else
1937b30d1939SAndy Fiddaman 			fcseek(-LEN);
1938da2e3ebdSchin 		switch(n)
1939da2e3ebdSchin 		{
1940da2e3ebdSchin 		    case S_NL:
19417c2fbfb3SApril Chin 			lp->sh->inlineno++;
1942da2e3ebdSchin 			if((stripcol && c==' ') || (stripflg && c=='\t'))
1943da2e3ebdSchin 			{
19447c2fbfb3SApril Chin 				if(!lp->lexd.dolparen)
1945da2e3ebdSchin 				{
1946da2e3ebdSchin 					/* write out line */
1947da2e3ebdSchin 					n = fcseek(0)-bufp;
1948da2e3ebdSchin 					if((n=sfwrite(sp,bufp,n))>0)
1949da2e3ebdSchin 						iop->iosize += n;
1950da2e3ebdSchin 				}
1951da2e3ebdSchin 				/* skip over tabs */
1952da2e3ebdSchin 				if(stripcol)
1953da2e3ebdSchin 				{
1954da2e3ebdSchin 					int col=0;
1955da2e3ebdSchin 					do
1956da2e3ebdSchin 					{
1957da2e3ebdSchin 						fcgetc(c);
1958da2e3ebdSchin 						if(c==' ')
1959da2e3ebdSchin 							col++;
1960da2e3ebdSchin 						else
1961da2e3ebdSchin 							col += 8 - col%8;
1962da2e3ebdSchin 						if(col>stripcol)
1963da2e3ebdSchin 							break;
1964da2e3ebdSchin 					}
1965da2e3ebdSchin 					while (c==' ' || c=='\t');
1966da2e3ebdSchin 				}
1967da2e3ebdSchin 				else while(c=='\t')
1968da2e3ebdSchin 					fcgetc(c);
1969da2e3ebdSchin 				if(c<=0)
1970da2e3ebdSchin 					goto done;
1971b30d1939SAndy Fiddaman 				bufp = fcseek(-LEN);
1972da2e3ebdSchin 			}
1973da2e3ebdSchin 			if(c!=iop->iodelim[0])
1974da2e3ebdSchin 				break;
1975da2e3ebdSchin 			cp = fcseek(0);
1976da2e3ebdSchin 			nsave = n = 0;
1977da2e3ebdSchin 			while(1)
1978da2e3ebdSchin 			{
1979da2e3ebdSchin 				if(!(c=fcget()))
1980da2e3ebdSchin 				{
19817c2fbfb3SApril Chin 					if(!lp->lexd.dolparen && (c=cp-bufp))
1982da2e3ebdSchin 					{
1983da2e3ebdSchin 						if((c=sfwrite(sp,cp=bufp,c))>0)
1984da2e3ebdSchin 							iop->iosize+=c;
1985da2e3ebdSchin 					}
1986da2e3ebdSchin 					nsave = n;
19877c2fbfb3SApril Chin 					if((c=lexfill(lp))<=0)
1988da2e3ebdSchin 					{
1989da2e3ebdSchin 						c = iop->iodelim[n]==0;
1990da2e3ebdSchin 						goto done;
1991da2e3ebdSchin 					}
1992da2e3ebdSchin 				}
1993da2e3ebdSchin #if SHOPT_CRNL
1994da2e3ebdSchin 				if(c=='\r' && (c=fcget())!=NL)
1995da2e3ebdSchin 				{
1996da2e3ebdSchin 					if(c)
1997b30d1939SAndy Fiddaman 						fcseek(-LEN);
1998da2e3ebdSchin 					c='\r';
1999da2e3ebdSchin 				}
2000da2e3ebdSchin #endif /* SHOPT_CRNL */
2001da2e3ebdSchin 				if(c==NL)
20027c2fbfb3SApril Chin 					lp->sh->inlineno++;
2003da2e3ebdSchin 				if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
2004da2e3ebdSchin 				{
20057c2fbfb3SApril Chin 					if(!lp->lexd.dolparen && (n=cp-bufp))
2006da2e3ebdSchin 					{
2007da2e3ebdSchin 						if((n=sfwrite(sp,bufp,n))>0)
2008da2e3ebdSchin 							iop->iosize += n;
2009da2e3ebdSchin 					}
20107c2fbfb3SApril Chin 					lp->sh->inlineno--;
2011da2e3ebdSchin 					if(c==RPAREN)
2012b30d1939SAndy Fiddaman 						fcseek(-LEN);
2013da2e3ebdSchin 					goto done;
2014da2e3ebdSchin 				}
2015da2e3ebdSchin 				if(iop->iodelim[n++]!=c)
2016da2e3ebdSchin 				{
2017da2e3ebdSchin 					/*
2018da2e3ebdSchin 					 * The match for delimiter failed.
2019da2e3ebdSchin 					 * nsave>0 only when a buffer boundary
2020da2e3ebdSchin 					 * was crossed while checking the
2021da2e3ebdSchin 					 * delimiter
2022da2e3ebdSchin 					 */
20237c2fbfb3SApril Chin 					if(!lp->lexd.dolparen && nsave>0)
2024da2e3ebdSchin 					{
2025b30d1939SAndy Fiddaman 						if((n=sfwrite(sp,iop->iodelim,nsave))>0)
2026da2e3ebdSchin 							iop->iosize += n;
2027da2e3ebdSchin 						bufp = fcfirst();
2028da2e3ebdSchin 					}
2029da2e3ebdSchin 					if(c==NL)
2030b30d1939SAndy Fiddaman 						fcseek(-LEN);
2031da2e3ebdSchin 					break;
2032da2e3ebdSchin 				}
2033da2e3ebdSchin 			}
2034da2e3ebdSchin 			break;
2035da2e3ebdSchin 		    case S_ESC:
2036da2e3ebdSchin 			n=1;
2037da2e3ebdSchin #if SHOPT_CRNL
2038da2e3ebdSchin 			if(c=='\r')
2039da2e3ebdSchin 			{
2040da2e3ebdSchin 				fcseek(1);
2041da2e3ebdSchin 				if(c=fcget())
2042b30d1939SAndy Fiddaman 					fcseek(-LEN);
2043da2e3ebdSchin 				if(c==NL)
2044da2e3ebdSchin 					n=2;
2045da2e3ebdSchin 				else
2046da2e3ebdSchin 				{
2047da2e3ebdSchin 					special++;
2048da2e3ebdSchin 					break;
2049da2e3ebdSchin 				}
2050da2e3ebdSchin 			}
2051da2e3ebdSchin #endif /* SHOPT_CRNL */
2052da2e3ebdSchin 			if(c==NL)
2053da2e3ebdSchin 			{
2054da2e3ebdSchin 				/* new-line joining */
20557c2fbfb3SApril Chin 				lp->sh->inlineno++;
205634f9b3eeSRoland Mainz 				if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0)
2057da2e3ebdSchin 				{
205834f9b3eeSRoland Mainz 					if(n && (n=sfwrite(sp,bufp,n))>0)
2059da2e3ebdSchin 						iop->iosize += n;
2060da2e3ebdSchin 					bufp = fcseek(0)+1;
2061da2e3ebdSchin 				}
2062da2e3ebdSchin 			}
2063da2e3ebdSchin 			else
2064da2e3ebdSchin 				special++;
2065da2e3ebdSchin 			fcget();
2066da2e3ebdSchin 			break;
2067da2e3ebdSchin 
2068da2e3ebdSchin 		    case S_GRAVE:
2069da2e3ebdSchin 		    case S_DOL:
2070da2e3ebdSchin 			special++;
2071da2e3ebdSchin 			break;
2072da2e3ebdSchin 		}
2073da2e3ebdSchin 		n=0;
2074da2e3ebdSchin 	}
2075da2e3ebdSchin done:
20767c2fbfb3SApril Chin 	lp->sh->funlog = funlog;
20777c2fbfb3SApril Chin 	if(lp->lexd.dolparen)
2078da2e3ebdSchin 		free((void*)iop);
2079da2e3ebdSchin 	else if(!special)
2080da2e3ebdSchin 		iop->iofile |= IOQUOTE;
2081da2e3ebdSchin 	return(c);
2082da2e3ebdSchin }
2083da2e3ebdSchin 
2084da2e3ebdSchin /*
2085da2e3ebdSchin  * generates string for given token
2086da2e3ebdSchin  */
fmttoken(Lex_t * lp,register int sym,char * tok)2087da2e3ebdSchin static char	*fmttoken(Lex_t *lp, register int sym, char *tok)
2088da2e3ebdSchin {
208934f9b3eeSRoland Mainz 	int n=1;
2090da2e3ebdSchin 	if(sym < 0)
2091da2e3ebdSchin 		return((char*)sh_translate(e_lexzerobyte));
2092da2e3ebdSchin 	if(sym==0)
20937c2fbfb3SApril Chin 		return(lp->arg?lp->arg->argval:"?");
20947c2fbfb3SApril Chin 	if(lp->lex.intest && lp->arg && *lp->arg->argval)
20957c2fbfb3SApril Chin 		return(lp->arg->argval);
2096da2e3ebdSchin 	if(sym&SYMRES)
2097da2e3ebdSchin 	{
2098da2e3ebdSchin 		register const Shtable_t *tp=shtab_reserved;
2099da2e3ebdSchin 		while(tp->sh_number && tp->sh_number!=sym)
2100da2e3ebdSchin 			tp++;
2101da2e3ebdSchin 		return((char*)tp->sh_name);
2102da2e3ebdSchin 	}
2103da2e3ebdSchin 	if(sym==EOFSYM)
2104da2e3ebdSchin 		return((char*)sh_translate(e_endoffile));
2105da2e3ebdSchin 	if(sym==NL)
2106da2e3ebdSchin 		return((char*)sh_translate(e_newline));
2107da2e3ebdSchin 	tok[0] = sym;
2108da2e3ebdSchin 	if(sym&SYMREP)
210934f9b3eeSRoland Mainz 		tok[n++] = sym;
2110da2e3ebdSchin 	else
2111da2e3ebdSchin 	{
2112da2e3ebdSchin 		switch(sym&SYMMASK)
2113da2e3ebdSchin 		{
2114da2e3ebdSchin 			case SYMAMP:
2115da2e3ebdSchin 				sym = '&';
2116da2e3ebdSchin 				break;
2117da2e3ebdSchin 			case SYMPIPE:
2118da2e3ebdSchin 				sym = '|';
2119da2e3ebdSchin 				break;
2120da2e3ebdSchin 			case SYMGT:
2121da2e3ebdSchin 				sym = '>';
2122da2e3ebdSchin 				break;
2123da2e3ebdSchin 			case SYMLPAR:
2124da2e3ebdSchin 				sym = LPAREN;
2125da2e3ebdSchin 				break;
2126da2e3ebdSchin 			case SYMSHARP:
2127da2e3ebdSchin 				sym = '#';
2128da2e3ebdSchin 				break;
21297c2fbfb3SApril Chin 			case SYMSEMI:
213034f9b3eeSRoland Mainz 				if(tok[0]=='<')
213134f9b3eeSRoland Mainz 					tok[n++] = '>';
21327c2fbfb3SApril Chin 				sym = ';';
21337c2fbfb3SApril Chin 				break;
2134da2e3ebdSchin 			default:
2135da2e3ebdSchin 				sym = 0;
2136da2e3ebdSchin 		}
213734f9b3eeSRoland Mainz 		tok[n++] = sym;
2138da2e3ebdSchin 	}
213934f9b3eeSRoland Mainz 	tok[n] = 0;
2140da2e3ebdSchin 	return(tok);
2141da2e3ebdSchin }
2142da2e3ebdSchin 
2143da2e3ebdSchin /*
2144da2e3ebdSchin  * print a bad syntax message
2145da2e3ebdSchin  */
2146da2e3ebdSchin 
sh_syntax(Lex_t * lp)21477c2fbfb3SApril Chin void	sh_syntax(Lex_t *lp)
2148da2e3ebdSchin {
21497c2fbfb3SApril Chin 	register Shell_t *shp = lp->sh;
2150da2e3ebdSchin 	register const char *cp = sh_translate(e_unexpected);
2151da2e3ebdSchin 	register char *tokstr;
21527c2fbfb3SApril Chin 	register int tok = lp->token;
2153da2e3ebdSchin 	char tokbuf[3];
2154da2e3ebdSchin 	Sfio_t *sp;
21557c2fbfb3SApril Chin 	if((tok==EOFSYM) && lp->lasttok)
2156da2e3ebdSchin 	{
21577c2fbfb3SApril Chin 		tok = lp->lasttok;
2158da2e3ebdSchin 		cp = sh_translate(e_unmatched);
2159da2e3ebdSchin 	}
2160da2e3ebdSchin 	else
21617c2fbfb3SApril Chin 		lp->lastline = shp->inlineno;
2162da2e3ebdSchin 	tokstr = fmttoken(lp,tok,tokbuf);
2163b30d1939SAndy Fiddaman 	VALIDATE_FD(shp, shp->infd);
2164da2e3ebdSchin 	if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
2165da2e3ebdSchin 	{
2166da2e3ebdSchin 		/* clear out any pending input */
2167da2e3ebdSchin 		register Sfio_t *top;
2168da2e3ebdSchin 		while(fcget()>0);
2169da2e3ebdSchin 		fcclose();
2170da2e3ebdSchin 		while(top=sfstack(sp,SF_POPSTACK))
2171da2e3ebdSchin 			sfclose(top);
2172da2e3ebdSchin 	}
2173da2e3ebdSchin 	else
2174da2e3ebdSchin 		fcclose();
21757c2fbfb3SApril Chin 	shp->inlineno = lp->inlineno;
21767c2fbfb3SApril Chin 	shp->st.firstline = lp->firstline;
2177da2e3ebdSchin #if KSHELL
2178da2e3ebdSchin 	if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
2179da2e3ebdSchin #else
2180da2e3ebdSchin 	if(shp->inlineno!=1)
2181da2e3ebdSchin #endif
21827c2fbfb3SApril Chin 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
2183da2e3ebdSchin 	else
2184da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
2185da2e3ebdSchin }
2186da2e3ebdSchin 
stack_shift(Stk_t * stkp,register char * sp,char * dp)21877c2fbfb3SApril Chin static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
2188da2e3ebdSchin {
2189da2e3ebdSchin 	register char *ep;
21907c2fbfb3SApril Chin 	register int offset = stktell(stkp);
21917c2fbfb3SApril Chin 	register int left = offset-(sp-stkptr(stkp,0));
2192da2e3ebdSchin 	register int shift = (dp+1-sp);
2193da2e3ebdSchin 	offset += shift;
21947c2fbfb3SApril Chin 	stkseek(stkp,offset);
21957c2fbfb3SApril Chin 	sp = stkptr(stkp,offset);
2196da2e3ebdSchin 	ep = sp - shift;
2197da2e3ebdSchin 	while(left--)
2198da2e3ebdSchin 		*--sp = *--ep;
2199da2e3ebdSchin 	return(sp);
2200da2e3ebdSchin }
2201da2e3ebdSchin 
2202da2e3ebdSchin /*
2203da2e3ebdSchin  * Assumes that current word is unfrozen on top of the stak
2204da2e3ebdSchin  * If <mode> is zero, gets rid of quoting and consider argument as string
2205da2e3ebdSchin  *    and returns pointer to frozen arg
2206da2e3ebdSchin  * If mode==1, just replace $"..." strings with international strings
2207da2e3ebdSchin  *    The result is left on the stak
2208da2e3ebdSchin  * If mode==2, the each $"" string is printed on standard output
2209da2e3ebdSchin  */
sh_endword(Shell_t * shp,int mode)22107c2fbfb3SApril Chin struct argnod *sh_endword(Shell_t *shp,int mode)
2211da2e3ebdSchin {
2212da2e3ebdSchin 	register const char *state = sh_lexstates[ST_NESTED];
2213da2e3ebdSchin 	register int n;
2214da2e3ebdSchin 	register char *sp,*dp;
2215da2e3ebdSchin 	register int inquote=0, inlit=0; /* set within quoted strings */
2216da2e3ebdSchin 	struct argnod* argp=0;
2217da2e3ebdSchin 	char	*ep=0, *xp=0;
2218da2e3ebdSchin 	int bracket=0;
22197c2fbfb3SApril Chin 	Stk_t		*stkp=shp->stk;
22207c2fbfb3SApril Chin 	sfputc(stkp,0);
22217c2fbfb3SApril Chin 	sp =  stkptr(stkp,ARGVAL);
2222da2e3ebdSchin #if SHOPT_MULTIBYTE
2223da2e3ebdSchin 	if(mbwide())
2224da2e3ebdSchin 	{
2225da2e3ebdSchin 		do
2226da2e3ebdSchin 		{
2227da2e3ebdSchin 			int len;
2228da2e3ebdSchin 			switch(len = mbsize(sp))
2229da2e3ebdSchin 			{
2230da2e3ebdSchin 			    case -1:	/* illegal multi-byte char */
2231da2e3ebdSchin 			    case 0:
2232da2e3ebdSchin 			    case 1:
2233da2e3ebdSchin 				n=state[*sp++];
2234da2e3ebdSchin 				break;
2235da2e3ebdSchin 			    default:
2236da2e3ebdSchin 				/*
2237da2e3ebdSchin 				 * None of the state tables contain
2238da2e3ebdSchin 				 * entries for multibyte characters,
2239da2e3ebdSchin 				 * however, they should be treated
2240da2e3ebdSchin 				 * the same as any other alph
2241da2e3ebdSchin 				 * character.  Therefore, we'll use
2242da2e3ebdSchin 				 * the state of the 'a' character.
2243da2e3ebdSchin 				 */
2244da2e3ebdSchin 				n=state['a'];
2245da2e3ebdSchin 				sp += len;
2246da2e3ebdSchin 			}
2247da2e3ebdSchin 		}
2248da2e3ebdSchin 		while(n == 0);
2249da2e3ebdSchin 	}
2250da2e3ebdSchin 	else
2251da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2252da2e3ebdSchin 	while((n=state[*sp++])==0);
2253da2e3ebdSchin 	dp = sp;
2254da2e3ebdSchin 	if(mode<0)
2255da2e3ebdSchin 		inquote = 1;
2256da2e3ebdSchin 	while(1)
2257da2e3ebdSchin 	{
2258da2e3ebdSchin 		switch(n)
2259da2e3ebdSchin 		{
2260da2e3ebdSchin 		    case S_EOF:
22617c2fbfb3SApril Chin 			stkseek(stkp,dp-stkptr(stkp,0));
2262da2e3ebdSchin 			if(mode<=0)
2263da2e3ebdSchin 			{
22647c2fbfb3SApril Chin 				argp = (struct argnod*)stkfreeze(stkp,0);
2265da2e3ebdSchin 				argp->argflag = ARG_RAW|ARG_QUOTED;
2266da2e3ebdSchin 			}
2267da2e3ebdSchin 			return(argp);
2268da2e3ebdSchin 		    case S_LIT:
2269da2e3ebdSchin 			if(!(inquote&1))
2270da2e3ebdSchin 			{
2271da2e3ebdSchin 				inlit = !inlit;
2272da2e3ebdSchin 				if(mode==0 || (mode<0 && bracket))
2273da2e3ebdSchin 				{
2274da2e3ebdSchin 					dp--;
2275da2e3ebdSchin 					if(ep)
2276da2e3ebdSchin 					{
2277da2e3ebdSchin 						*dp = 0;
2278b30d1939SAndy Fiddaman 						stresc(ep);
2279b30d1939SAndy Fiddaman 						dp = ep+ strlen(ep);
2280da2e3ebdSchin 					}
2281da2e3ebdSchin 					ep = 0;
2282da2e3ebdSchin 				}
2283da2e3ebdSchin 			}
2284da2e3ebdSchin 			break;
2285da2e3ebdSchin 		    case S_QUOTE:
2286da2e3ebdSchin 			if(mode<0 && !bracket)
2287da2e3ebdSchin 				break;
2288da2e3ebdSchin 			if(!inlit)
2289da2e3ebdSchin 			{
2290da2e3ebdSchin 				if(mode<=0)
2291da2e3ebdSchin 					dp--;
2292da2e3ebdSchin 				inquote = inquote^1;
2293da2e3ebdSchin 				if(ep)
2294da2e3ebdSchin 				{
2295da2e3ebdSchin 					char *msg;
2296da2e3ebdSchin 					if(mode==2)
2297da2e3ebdSchin 					{
2298da2e3ebdSchin 						sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
2299da2e3ebdSchin 						ep = 0;
2300da2e3ebdSchin 						break;
2301da2e3ebdSchin 					}
2302da2e3ebdSchin 					*--dp = 0;
2303da2e3ebdSchin #if ERROR_VERSION >= 20000317L
2304da2e3ebdSchin 					msg = ERROR_translate(0,error_info.id,0,ep);
2305da2e3ebdSchin #else
2306da2e3ebdSchin #   if ERROR_VERSION >= 20000101L
2307da2e3ebdSchin 					msg = ERROR_translate(error_info.id,ep);
2308da2e3ebdSchin #   else
2309da2e3ebdSchin 					msg = ERROR_translate(ep,2);
2310da2e3ebdSchin #   endif
2311da2e3ebdSchin #endif
2312da2e3ebdSchin 					n = strlen(msg);
2313da2e3ebdSchin 					dp = ep+n;
2314da2e3ebdSchin 					if(sp-dp <= 1)
2315da2e3ebdSchin 					{
23167c2fbfb3SApril Chin 						sp = stack_shift(stkp,sp,dp);
2317da2e3ebdSchin 						dp = sp-1;
2318da2e3ebdSchin 						ep = dp-n;
2319da2e3ebdSchin 					}
2320da2e3ebdSchin 					memmove(ep,msg,n);
2321da2e3ebdSchin 					*dp++ = '"';
2322da2e3ebdSchin 				}
2323da2e3ebdSchin 				ep = 0;
2324da2e3ebdSchin 			}
2325da2e3ebdSchin 			break;
2326da2e3ebdSchin 		    case S_DOL:	/* check for $'...'  and $"..." */
2327da2e3ebdSchin 			if(inlit)
2328da2e3ebdSchin 				break;
2329da2e3ebdSchin 			if(*sp==LPAREN || *sp==LBRACE)
2330da2e3ebdSchin 			{
2331da2e3ebdSchin 				inquote <<= 1;
2332da2e3ebdSchin 				break;
2333da2e3ebdSchin 			}
2334da2e3ebdSchin 			if(inquote&1)
2335da2e3ebdSchin 				break;
2336da2e3ebdSchin 			if(*sp=='\'' || *sp=='"')
2337da2e3ebdSchin 			{
2338da2e3ebdSchin 				if(*sp=='"')
2339da2e3ebdSchin 					inquote |= 1;
2340da2e3ebdSchin 				else
2341da2e3ebdSchin 					inlit = 1;
2342da2e3ebdSchin 				sp++;
2343da2e3ebdSchin 				if((mode==0||(mode<0&&bracket)) || (inquote&1))
2344da2e3ebdSchin 				{
2345da2e3ebdSchin 					if(mode==2)
2346da2e3ebdSchin 						ep = dp++;
2347da2e3ebdSchin 					else if(mode==1)
2348da2e3ebdSchin 						(ep=dp)[-1] = '"';
2349da2e3ebdSchin 					else
2350da2e3ebdSchin 						ep = --dp;
2351da2e3ebdSchin 				}
2352da2e3ebdSchin 			}
2353da2e3ebdSchin 			break;
2354da2e3ebdSchin 		    case S_ESC:
2355da2e3ebdSchin #if SHOPT_CRNL
2356da2e3ebdSchin 			if(*sp=='\r' && sp[1]=='\n')
2357da2e3ebdSchin 				sp++;
2358da2e3ebdSchin #endif /* SHOPT_CRNL */
2359da2e3ebdSchin 			if(inlit || mode>0)
2360da2e3ebdSchin 			{
2361da2e3ebdSchin 				if(mode<0)
2362da2e3ebdSchin 				{
2363da2e3ebdSchin 					if(dp>=sp)
2364da2e3ebdSchin 					{
23657c2fbfb3SApril Chin 						sp = stack_shift(stkp,sp,dp+1);
2366da2e3ebdSchin 						dp = sp-2;
2367da2e3ebdSchin 					}
2368da2e3ebdSchin 					*dp++ = '\\';
2369da2e3ebdSchin 				}
2370da2e3ebdSchin 				if(ep)
2371da2e3ebdSchin 					*dp++ = *sp++;
2372da2e3ebdSchin 				break;
2373da2e3ebdSchin 			}
2374da2e3ebdSchin 			n = *sp;
2375da2e3ebdSchin #if SHOPT_DOS
2376da2e3ebdSchin 			if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
2377da2e3ebdSchin 				break;
2378da2e3ebdSchin #endif /* SHOPT_DOS */
2379da2e3ebdSchin 			if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
2380da2e3ebdSchin 			{
2381da2e3ebdSchin 				if(n=='\n')
2382da2e3ebdSchin 					dp--;
2383da2e3ebdSchin 				else
2384da2e3ebdSchin 					dp[-1] = n;
2385da2e3ebdSchin 				sp++;
2386da2e3ebdSchin 			}
2387da2e3ebdSchin 			break;
2388da2e3ebdSchin 		    case S_POP:
2389da2e3ebdSchin 			if(sp[-1]!=RBRACT)
2390da2e3ebdSchin 				break;
2391da2e3ebdSchin 			if(!inlit && !(inquote&1))
2392da2e3ebdSchin 			{
2393da2e3ebdSchin 				inquote >>= 1;
2394da2e3ebdSchin 				if(xp)
2395da2e3ebdSchin 					dp = sh_checkid(xp,dp);
2396da2e3ebdSchin 				xp = 0;
2397da2e3ebdSchin 				if(--bracket<=0 && mode<0)
2398da2e3ebdSchin 					inquote = 1;
2399da2e3ebdSchin 			}
2400da2e3ebdSchin 			else if((inlit||inquote) && mode<0)
2401da2e3ebdSchin 			{
2402da2e3ebdSchin 				dp[-1] = '\\';
2403da2e3ebdSchin 				if(dp>=sp)
2404da2e3ebdSchin 				{
24057c2fbfb3SApril Chin 					sp = stack_shift(stkp,sp,dp);
2406da2e3ebdSchin 					dp = sp-1;
2407da2e3ebdSchin 				}
2408da2e3ebdSchin 				*dp++ = ']';
2409da2e3ebdSchin 			}
2410da2e3ebdSchin 			break;
2411da2e3ebdSchin 		    case S_BRACT:
2412da2e3ebdSchin 			if(dp[-2]=='.')
2413da2e3ebdSchin 				xp = dp;
2414da2e3ebdSchin 			if(mode<0)
2415da2e3ebdSchin 			{
2416da2e3ebdSchin 				if(inlit || (bracket&&inquote))
2417da2e3ebdSchin 				{
2418da2e3ebdSchin 					dp[-1] = '\\';
2419da2e3ebdSchin 					if(dp>=sp)
2420da2e3ebdSchin 					{
24217c2fbfb3SApril Chin 						sp = stack_shift(stkp,sp,dp);
2422da2e3ebdSchin 						dp = sp-1;
2423da2e3ebdSchin 					}
2424da2e3ebdSchin 					*dp++ = '[';
2425da2e3ebdSchin 				}
2426da2e3ebdSchin 				else if(bracket++==0)
2427da2e3ebdSchin 					inquote = 0;
2428da2e3ebdSchin 			}
2429da2e3ebdSchin 			break;
2430da2e3ebdSchin 		}
2431da2e3ebdSchin #if SHOPT_MULTIBYTE
2432da2e3ebdSchin 		if(mbwide())
2433da2e3ebdSchin 		{
2434da2e3ebdSchin 			do
2435da2e3ebdSchin 			{
2436da2e3ebdSchin 				int len;
2437da2e3ebdSchin 				switch(len = mbsize(sp))
2438da2e3ebdSchin 				{
2439da2e3ebdSchin 				    case -1: /* illegal multi-byte char */
2440da2e3ebdSchin 				    case 0:
2441da2e3ebdSchin 				    case 1:
2442da2e3ebdSchin 					n=state[*dp++ = *sp++];
2443da2e3ebdSchin 					break;
2444da2e3ebdSchin 				    default:
2445da2e3ebdSchin 					/*
2446da2e3ebdSchin 					 * None of the state tables contain
2447da2e3ebdSchin 					 * entries for multibyte characters,
2448da2e3ebdSchin 					 * however, they should be treated
2449da2e3ebdSchin 					 * the same as any other alph
2450da2e3ebdSchin 					 * character.  Therefore, we'll use
2451da2e3ebdSchin 					 * the state of the 'a' character.
2452da2e3ebdSchin 					 */
2453da2e3ebdSchin 					while(len--)
2454da2e3ebdSchin 						*dp++ = *sp++;
2455da2e3ebdSchin 					n=state['a'];
2456da2e3ebdSchin 				}
2457da2e3ebdSchin 			}
2458da2e3ebdSchin 			while(n == 0);
2459da2e3ebdSchin 		}
2460da2e3ebdSchin 		else
2461da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2462da2e3ebdSchin 		while((n=state[*dp++ = *sp++])==0);
2463da2e3ebdSchin 	}
2464da2e3ebdSchin }
2465da2e3ebdSchin 
2466da2e3ebdSchin struct alias
2467da2e3ebdSchin {
2468da2e3ebdSchin 	Sfdisc_t	disc;
2469da2e3ebdSchin 	Namval_t	*np;
2470da2e3ebdSchin 	int		nextc;
2471da2e3ebdSchin 	int		line;
2472da2e3ebdSchin 	char		buf[2];
2473da2e3ebdSchin 	Lex_t		*lp;
2474da2e3ebdSchin };
2475da2e3ebdSchin 
2476da2e3ebdSchin /*
2477da2e3ebdSchin  * This code gets called whenever an end of string is found with alias
2478da2e3ebdSchin  */
2479da2e3ebdSchin 
2480da2e3ebdSchin #ifndef SF_ATEXIT
2481da2e3ebdSchin #   define SF_ATEXIT	0
2482da2e3ebdSchin #endif
2483da2e3ebdSchin /*
2484da2e3ebdSchin  * This code gets called whenever an end of string is found with alias
2485da2e3ebdSchin  */
2486da2e3ebdSchin #ifdef SF_BUFCONST
alias_exceptf(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)2487da2e3ebdSchin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
2488da2e3ebdSchin #else
2489da2e3ebdSchin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
2490da2e3ebdSchin #endif
2491da2e3ebdSchin {
2492da2e3ebdSchin 	register struct alias *ap = (struct alias*)handle;
2493da2e3ebdSchin 	register Namval_t *np;
2494da2e3ebdSchin 	register Lex_t	*lp;
2495da2e3ebdSchin 	if(type==0 || type==SF_ATEXIT || !ap)
2496da2e3ebdSchin 		return(0);
2497da2e3ebdSchin 	lp = ap->lp;
2498da2e3ebdSchin 	np = ap->np;
2499da2e3ebdSchin 	if(type!=SF_READ)
2500da2e3ebdSchin 	{
2501da2e3ebdSchin 		if(type==SF_CLOSING)
2502da2e3ebdSchin 		{
2503da2e3ebdSchin 			register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
2504da2e3ebdSchin 			if(dp!=handle)
2505da2e3ebdSchin 				sfdisc(iop,dp);
2506da2e3ebdSchin 		}
2507da2e3ebdSchin 		else if(type==SF_FINAL)
2508da2e3ebdSchin 			free((void*)ap);
2509da2e3ebdSchin 		goto done;
2510da2e3ebdSchin 	}
2511da2e3ebdSchin 	if(ap->nextc)
2512da2e3ebdSchin 	{
2513da2e3ebdSchin 		/* if last character is a blank, then next work can be alias */
2514da2e3ebdSchin 		register int c = fcpeek(-1);
2515da2e3ebdSchin 		if(isblank(c))
25167c2fbfb3SApril Chin 			lp->aliasok = 1;
2517da2e3ebdSchin 		*ap->buf = ap->nextc;
2518da2e3ebdSchin 		ap->nextc = 0;
2519da2e3ebdSchin 		sfsetbuf(iop,ap->buf,1);
2520da2e3ebdSchin 		return(1);
2521da2e3ebdSchin 	}
2522da2e3ebdSchin done:
2523da2e3ebdSchin 	if(np)
2524da2e3ebdSchin 		nv_offattr(np,NV_NOEXPAND);
2525da2e3ebdSchin 	return(0);
2526da2e3ebdSchin }
2527da2e3ebdSchin 
2528da2e3ebdSchin 
setupalias(Lex_t * lp,const char * string,Namval_t * np)2529da2e3ebdSchin static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
2530da2e3ebdSchin {
2531da2e3ebdSchin 	register Sfio_t *iop, *base;
2532da2e3ebdSchin 	struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
2533da2e3ebdSchin 	ap->disc = alias_disc;
2534da2e3ebdSchin 	ap->lp = lp;
2535da2e3ebdSchin 	ap->buf[1] = 0;
2536da2e3ebdSchin 	if(ap->np = np)
2537da2e3ebdSchin 	{
2538da2e3ebdSchin #if SHOPT_KIA
25397c2fbfb3SApril Chin 		if(lp->kiafile)
2540da2e3ebdSchin 		{
2541da2e3ebdSchin 			unsigned long r;
25427c2fbfb3SApril Chin 			r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
25437c2fbfb3SApril Chin 			sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
2544da2e3ebdSchin 		}
2545da2e3ebdSchin #endif /* SHOPT_KIA */
2546da2e3ebdSchin 		if((ap->nextc=fcget())==0)
2547da2e3ebdSchin 			ap->nextc = ' ';
2548da2e3ebdSchin 	}
2549da2e3ebdSchin 	else
2550da2e3ebdSchin 		ap->nextc = 0;
2551da2e3ebdSchin 	iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
2552da2e3ebdSchin 	sfdisc(iop, &ap->disc);
25537c2fbfb3SApril Chin 	lp->lexd.nocopy++;
2554da2e3ebdSchin 	if(!(base=fcfile()))
2555da2e3ebdSchin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
2556da2e3ebdSchin 	fcclose();
2557da2e3ebdSchin 	sfstack(base,iop);
2558da2e3ebdSchin 	fcfopen(base);
25597c2fbfb3SApril Chin 	lp->lexd.nocopy--;
2560da2e3ebdSchin }
2561da2e3ebdSchin 
2562da2e3ebdSchin /*
2563da2e3ebdSchin  * grow storage stack for nested constructs by STACK_ARRAY
2564da2e3ebdSchin  */
stack_grow(Lex_t * lp)2565da2e3ebdSchin static int stack_grow(Lex_t *lp)
2566da2e3ebdSchin {
25677c2fbfb3SApril Chin 	lp->lexd.lex_max += STACK_ARRAY;
25687c2fbfb3SApril Chin 	if(lp->lexd.lex_match)
25697c2fbfb3SApril Chin 		lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
2570da2e3ebdSchin 	else
25717c2fbfb3SApril Chin 		lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
25727c2fbfb3SApril Chin 	return(lp->lexd.lex_match!=0);
2573da2e3ebdSchin }
2574da2e3ebdSchin 
2575