xref: /onnv-gate/usr/src/lib/libshell/common/sh/lex.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * KornShell  lexical analyzer
234887Schin  *
244887Schin  * Written by David Korn
254887Schin  * AT&T Labs
264887Schin  *
274887Schin  */
284887Schin 
294887Schin #include	<ast.h>
304887Schin #include	<stak.h>
314887Schin #include	<fcin.h>
324887Schin #include	<nval.h>
334887Schin #include	"FEATURE/options"
344887Schin 
354887Schin #if KSHELL
364887Schin #   include	"defs.h"
374887Schin #else
384887Schin #   include	<shell.h>
394887Schin #   define	nv_getval(np)	((np)->nvalue)
404887Schin     Shell_t sh  =  {1};
414887Schin #endif /* KSHELL */
424887Schin 
434887Schin #include	"argnod.h"
444887Schin #include	"test.h"
454887Schin #include	"lexstates.h"
464887Schin #include	"io.h"
474887Schin 
484887Schin #define TEST_RE		3
494887Schin #define SYNBAD		3	/* exit value for syntax errors */
504887Schin #define STACK_ARRAY	3	/* size of depth match stack growth */
514887Schin 
524887Schin #if _lib_iswblank < 0	/* set in lexstates.h to enable this code */
534887Schin 
544887Schin int
local_iswblank(wchar_t wc)554887Schin local_iswblank(wchar_t wc)
564887Schin {
574887Schin 	static int      initialized;
584887Schin 	static wctype_t wt;
594887Schin 
604887Schin 	if (!initialized)
614887Schin 	{
624887Schin 		initialized = 1;
634887Schin 		wt = wctype("blank");
644887Schin 	}
654887Schin 	return(iswctype(wc, wt));
664887Schin }
674887Schin 
684887Schin #endif
694887Schin 
704887Schin /*
714887Schin  * This structure allows for arbitrary depth nesting of (...), {...}, [...]
724887Schin  */
734887Schin struct lexstate
744887Schin {
754887Schin 	char		incase;		/* 1 for case pattern, 2 after case */
764887Schin 	char		intest;		/* 1 inside [[...]] */
774887Schin 	char		testop1;	/* 1 when unary test op legal */
784887Schin 	char		testop2;	/* 1 when binary test op legal */
794887Schin 	char		reservok;	/* >0 for reserved word legal */
804887Schin 	char		skipword;	/* next word can't be reserved */
814887Schin 	char		last_quote;	/* last multi-line quote character */
824887Schin };
834887Schin 
844887Schin struct lexdata
854887Schin {
864887Schin 	char		nocopy;
874887Schin 	char		paren;
884887Schin 	char		dolparen;
894887Schin 	char		nest;
904887Schin 	char		docword;
914887Schin 	char 		*docend;
924887Schin 	char		noarg;
934887Schin 	char		balance;
944887Schin 	char		warn;
954887Schin 	char		message;
964887Schin 	char		arith;
974887Schin 	char 		*first;
984887Schin 	int		level;
994887Schin 	int		lastc;
1004887Schin 	int		lex_max;
1014887Schin 	int		*lex_match;
1024887Schin 	int		lex_state;
10310898Sroland.mainz@nrubsig.org 	int		docextra;
1044887Schin #if SHOPT_KIA
1054887Schin 	off_t		kiaoff;
1064887Schin #endif
1074887Schin };
1084887Schin 
1094887Schin #define _SHLEX_PRIVATE \
1108462SApril.Chin@Sun.COM 	struct lexdata  lexd; \
1118462SApril.Chin@Sun.COM 	struct lexstate  lex;
1124887Schin 
1134887Schin #include	"shlex.h"
1144887Schin 
1154887Schin 
1168462SApril.Chin@Sun.COM #define	pushlevel(lp,c,s)	((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\
1178462SApril.Chin@Sun.COM 				((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\
1188462SApril.Chin@Sun.COM 				lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
1198462SApril.Chin@Sun.COM #define oldmode(lp)	(lp->lexd.lastc>>CHAR_BIT)
1208462SApril.Chin@Sun.COM #define endchar(lp)	(lp->lexd.lastc&0xff)
1218462SApril.Chin@Sun.COM #define setchar(lp,c)	(lp->lexd.lastc = ((lp->lexd.lastc&~0xff)|(c)))
1228462SApril.Chin@Sun.COM #define poplevel(lp)	(lp->lexd.lastc=lp->lexd.lex_match[--lp->lexd.level])
1234887Schin 
1244887Schin static char		*fmttoken(Lex_t*, int, char*);
1254887Schin #ifdef SF_BUFCONST
1264887Schin     static int          alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
1274887Schin #else
1284887Schin     static int 		alias_exceptf(Sfio_t*, int, Sfdisc_t*);
1294887Schin #endif
1304887Schin static void		setupalias(Lex_t*,const char*, Namval_t*);
1318462SApril.Chin@Sun.COM static int		comsub(Lex_t*,int);
1324887Schin static void		nested_here(Lex_t*);
1334887Schin static int		here_copy(Lex_t*, struct ionod*);
1344887Schin static int 		stack_grow(Lex_t*);
1354887Schin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL };
1364887Schin 
1374887Schin #if SHOPT_KIA
1384887Schin 
refvar(Lex_t * lp,int type)1398462SApril.Chin@Sun.COM static void refvar(Lex_t *lp, int type)
1404887Schin {
1418462SApril.Chin@Sun.COM 	register Shell_t *shp = lp->sh;
1428462SApril.Chin@Sun.COM 	register Stk_t	*stkp = shp->stk;
1438462SApril.Chin@Sun.COM 	off_t off = (fcseek(0)-(type+1))-(lp->lexd.first?lp->lexd.first:fcfirst());
1444887Schin 	unsigned long r;
1458462SApril.Chin@Sun.COM 	if(lp->lexd.first)
1464887Schin 	{
1478462SApril.Chin@Sun.COM 		off = (fcseek(0)-(type+1)) - lp->lexd.first;
1488462SApril.Chin@Sun.COM 		r=kiaentity(lp,lp->lexd.first+lp->lexd.kiaoff+type,off-lp->lexd.kiaoff,'v',-1,-1,lp->current,'v',0,"");
1494887Schin 	}
1504887Schin 	else
1514887Schin 	{
1528462SApril.Chin@Sun.COM 		int n,offset = stktell(stkp);
1534887Schin 		char *savptr,*begin;
1544887Schin 		off = offset + (fcseek(0)-(type+1)) - fcfirst();
1558462SApril.Chin@Sun.COM 		if(lp->lexd.kiaoff < offset)
1564887Schin 		{
1574887Schin 			/* variable starts on stak, copy remainder */
1584887Schin 			if(off>offset)
1598462SApril.Chin@Sun.COM 				sfwrite(stkp,fcfirst()+type,off-offset);
1608462SApril.Chin@Sun.COM 			n = stktell(stkp)-lp->lexd.kiaoff;
1618462SApril.Chin@Sun.COM 			begin = stkptr(stkp,lp->lexd.kiaoff);
1624887Schin 		}
1634887Schin 		else
1644887Schin 		{
1654887Schin 			/* variable in data buffer */
1668462SApril.Chin@Sun.COM 			begin = fcfirst()+(type+lp->lexd.kiaoff-offset);
1678462SApril.Chin@Sun.COM 			n = off-lp->lexd.kiaoff;
1684887Schin 		}
1698462SApril.Chin@Sun.COM 		savptr = stkfreeze(stkp,0);
1708462SApril.Chin@Sun.COM 		r=kiaentity(lp,begin,n,'v',-1,-1,lp->current,'v',0,"");
1718462SApril.Chin@Sun.COM 		stkset(stkp,savptr,offset);
1724887Schin 	}
1738462SApril.Chin@Sun.COM 	sfprintf(lp->kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",lp->current,r,shp->inlineno,shp->inlineno);
1744887Schin }
1754887Schin #endif /* SHOPT_KIA */
1764887Schin 
1774887Schin /*
1784887Schin  * This routine gets called when reading across a buffer boundary
1794887Schin  * If lexd.nocopy is off, then current token is saved on the stack
1804887Schin  */
lex_advance(Sfio_t * iop,const char * buff,register int size,void * context)1818462SApril.Chin@Sun.COM static void lex_advance(Sfio_t *iop, const char *buff, register int size, void *context)
1824887Schin {
1838462SApril.Chin@Sun.COM 	register Lex_t		*lp = (Lex_t*)context;
1848462SApril.Chin@Sun.COM 	register Shell_t	*shp = lp->sh;
1858462SApril.Chin@Sun.COM 	register Sfio_t		*log= shp->funlog;
1868462SApril.Chin@Sun.COM 	Stk_t			*stkp = shp->stk;
1874887Schin #if KSHELL
1884887Schin 	/* write to history file and to stderr if necessary */
1894887Schin 	if(iop && !sfstacked(iop))
1904887Schin 	{
1914887Schin 		if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
1924887Schin 			log = shp->hist_ptr->histfp;
1934887Schin 		sfwrite(log, (void*)buff, size);
1944887Schin 		if(sh_isstate(SH_VERBOSE))
1954887Schin 			sfwrite(sfstderr, buff, size);
1964887Schin 	}
1974887Schin #endif
1988462SApril.Chin@Sun.COM 	if(lp->lexd.nocopy)
1994887Schin 		return;
20010898Sroland.mainz@nrubsig.org 	if(lp->lexd.dolparen && lp->lexd.docword)
20110898Sroland.mainz@nrubsig.org 	{
20210898Sroland.mainz@nrubsig.org 		int n = size - (lp->lexd.docend-(char*)buff);
20310898Sroland.mainz@nrubsig.org 		sfwrite(shp->strbuf,lp->lexd.docend,n);
20410898Sroland.mainz@nrubsig.org 		lp->lexd.docextra  += n;
20510898Sroland.mainz@nrubsig.org 	}
2068462SApril.Chin@Sun.COM 	if(lp->lexd.first)
2074887Schin 	{
2088462SApril.Chin@Sun.COM 		size -= (lp->lexd.first-(char*)buff);
2098462SApril.Chin@Sun.COM 		buff = lp->lexd.first;
2108462SApril.Chin@Sun.COM 		if(!lp->lexd.noarg)
2118462SApril.Chin@Sun.COM 			lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
2124887Schin #if SHOPT_KIA
2138462SApril.Chin@Sun.COM 		lp->lexd.kiaoff += ARGVAL;
2144887Schin #endif /* SHOPT_KIA */
2154887Schin 	}
2168462SApril.Chin@Sun.COM 	if(size>0 && (lp->arg||lp->lexd.noarg))
2174887Schin 	{
2188462SApril.Chin@Sun.COM 		sfwrite(stkp,buff,size);
2198462SApril.Chin@Sun.COM 		lp->lexd.first = 0;
2204887Schin 	}
2214887Schin }
2224887Schin 
2234887Schin /*
2244887Schin  * fill up another input buffer
2254887Schin  * preserves lexical state
2264887Schin  */
lexfill(Lex_t * lp)2278462SApril.Chin@Sun.COM static int lexfill(Lex_t *lp)
2284887Schin {
2294887Schin 	register int c;
2308462SApril.Chin@Sun.COM 	Lex_t savelex;
2314887Schin 	struct argnod *ap;
23210898Sroland.mainz@nrubsig.org 	int aok,docextra;
2338462SApril.Chin@Sun.COM 	savelex = *lp;
2348462SApril.Chin@Sun.COM 	ap = lp->arg;
2354887Schin 	c = fcfill();
2364887Schin 	if(ap)
2378462SApril.Chin@Sun.COM 		lp->arg = ap;
23810898Sroland.mainz@nrubsig.org 	docextra = lp->lexd.docextra;
2398462SApril.Chin@Sun.COM 	lp->lex = savelex.lex;
2408462SApril.Chin@Sun.COM 	lp->lexd = savelex.lexd;
2418462SApril.Chin@Sun.COM 	if(fcfile() ||  c)
2428462SApril.Chin@Sun.COM 		lp->lexd.first = 0;
2438462SApril.Chin@Sun.COM 	aok= lp->aliasok;
2448462SApril.Chin@Sun.COM 	ap = lp->arg;
2458462SApril.Chin@Sun.COM 	memcpy(lp, &savelex, offsetof(Lex_t,lexd));
2468462SApril.Chin@Sun.COM 	lp->arg = ap;
2478462SApril.Chin@Sun.COM 	lp->aliasok = aok;
24810898Sroland.mainz@nrubsig.org 	if(lp->lexd.docword && docextra)
24910898Sroland.mainz@nrubsig.org 	{
25010898Sroland.mainz@nrubsig.org 		lp->lexd.docextra = docextra;
25110898Sroland.mainz@nrubsig.org 		lp->lexd.docend = fcseek(0)-1;
25210898Sroland.mainz@nrubsig.org 	}
2534887Schin 	return(c);
2544887Schin }
2554887Schin 
2564887Schin /*
2574887Schin  * mode=1 for reinitialization
2584887Schin  */
sh_lexopen(Lex_t * lp,Shell_t * sp,int mode)2594887Schin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode)
2604887Schin {
2614887Schin 	if(!lp)
2624887Schin 	{
2634887Schin 		lp = (Lex_t*)newof(0,Lex_t,1,0);
2648462SApril.Chin@Sun.COM 		lp->sh = sp;
2654887Schin 	}
2668462SApril.Chin@Sun.COM 	fcnotify(lex_advance,lp);
2678462SApril.Chin@Sun.COM 	lp->lex.intest = lp->lex.incase = lp->lex.skipword = lp->lexd.warn = 0;
2688462SApril.Chin@Sun.COM 	lp->comp_assign = 0;
2698462SApril.Chin@Sun.COM 	lp->lex.reservok = 1;
2704887Schin 	if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC))
2718462SApril.Chin@Sun.COM 		lp->lexd.warn=1;
2724887Schin 	if(!mode)
2734887Schin 	{
2748462SApril.Chin@Sun.COM 		lp->lexd.noarg = lp->lexd.level= lp->lexd.dolparen = lp->lexd.balance = 0;
2758462SApril.Chin@Sun.COM 		lp->lexd.nocopy = lp->lexd.docword = lp->lexd.nest = lp->lexd.paren = 0;
276*12068SRoger.Faulkner@Oracle.COM 		lp->lexd.lex_state = lp->lexd.lastc=0;
2774887Schin 	}
2788462SApril.Chin@Sun.COM 	lp->comsub = 0;
2794887Schin 	return(lp);
2804887Schin }
2814887Schin 
2824887Schin #ifdef DBUG
2838462SApril.Chin@Sun.COM extern int lextoken(Lex_t*);
sh_lex(Lex_t * lp)2848462SApril.Chin@Sun.COM int sh_lex(Lex_t *lp)
2854887Schin {
2868462SApril.Chin@Sun.COM 	Shell_t *shp = lp->sh;
2874887Schin 	register int flag;
2884887Schin 	char *quoted, *macro, *split, *expand;
2894887Schin 	char tokstr[3];
2904887Schin 	register int tok = lextoken();
2914887Schin 	quoted = macro = split = expand = "";
2928462SApril.Chin@Sun.COM 	if(tok==0 && (flag=lp->arg->argflag))
2934887Schin 	{
2944887Schin 		if(flag&ARG_MAC)
2954887Schin 			macro = "macro:";
2964887Schin 		if(flag&ARG_EXP)
2974887Schin 			expand = "expand:";
2984887Schin 		if(flag&ARG_QUOTED)
2994887Schin 			quoted = "quoted:";
3004887Schin 	}
3014887Schin 	sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted,
3024887Schin 		macro, split, expand, fmttoken(lp,tok,tokstr));
3034887Schin 	return(tok);
3044887Schin }
3054887Schin #define sh_lex	lextoken
3064887Schin #endif
3074887Schin 
3084887Schin /*
3094887Schin  * Get the next word and put it on the top of the stak
3108462SApril.Chin@Sun.COM  * A pointer to the current word is stored in lp->arg
3114887Schin  * Returns the token type
3124887Schin  */
sh_lex(Lex_t * lp)3138462SApril.Chin@Sun.COM int sh_lex(Lex_t* lp)
3144887Schin {
3158462SApril.Chin@Sun.COM 	register Shell_t *shp = lp->sh;
3164887Schin 	register const char	*state;
3178462SApril.Chin@Sun.COM 	register int		n, c, mode=ST_BEGIN, wordflags=0;
3188462SApril.Chin@Sun.COM 	Stk_t			*stkp = shp->stk;
3198462SApril.Chin@Sun.COM 	int		inlevel=lp->lexd.level, assignment=0, ingrave=0;
3204887Schin 	Sfio_t *sp;
3214887Schin #if SHOPT_MULTIBYTE
3224887Schin 	LEN=1;
3234887Schin #endif /* SHOPT_MULTIBYTE */
3248462SApril.Chin@Sun.COM 	if(lp->lexd.paren)
3254887Schin 	{
3268462SApril.Chin@Sun.COM 		lp->lexd.paren = 0;
3278462SApril.Chin@Sun.COM 		return(lp->token=LPAREN);
3284887Schin 	}
3298462SApril.Chin@Sun.COM 	if(lp->lex.incase)
3308462SApril.Chin@Sun.COM 		lp->assignok = 0;
3314887Schin 	else
3328462SApril.Chin@Sun.COM 		lp->assignok |= lp->lex.reservok;
3338462SApril.Chin@Sun.COM 	if(lp->comp_assign==2)
3348462SApril.Chin@Sun.COM 		lp->comp_assign = lp->lex.reservok = 0;
3358462SApril.Chin@Sun.COM 	lp->lexd.arith = (lp->lexd.nest==1);
3368462SApril.Chin@Sun.COM 	if(lp->lexd.nest)
3374887Schin 	{
3388462SApril.Chin@Sun.COM 		pushlevel(lp,lp->lexd.nest,ST_NONE);
3398462SApril.Chin@Sun.COM 		lp->lexd.nest = 0;
3408462SApril.Chin@Sun.COM 		mode = lp->lexd.lex_state;
3414887Schin 	}
3428462SApril.Chin@Sun.COM 	else if(lp->lexd.docword)
3434887Schin 	{
3444887Schin 		if(fcgetc(c)=='-' || c=='#')
3454887Schin 		{
3468462SApril.Chin@Sun.COM 			lp->lexd.docword++;
3478462SApril.Chin@Sun.COM 			lp->digits=(c=='#'?3:1);
3484887Schin 		}
3494887Schin 		else if(c=='<')
3504887Schin 		{
3518462SApril.Chin@Sun.COM 			lp->digits=2;
3528462SApril.Chin@Sun.COM 			lp->lexd.docword=0;
3534887Schin 		}
3544887Schin 		else if(c>0)
3554887Schin 			fcseek(-1);
3564887Schin 	}
3578462SApril.Chin@Sun.COM 	if(!lp->lexd.dolparen)
3584887Schin 	{
3598462SApril.Chin@Sun.COM 		lp->arg = 0;
3604887Schin 		if(mode!=ST_BEGIN)
3618462SApril.Chin@Sun.COM 			lp->lexd.first = fcseek(0);
3624887Schin 		else
3638462SApril.Chin@Sun.COM 			lp->lexd.first = 0;
3644887Schin 	}
3658462SApril.Chin@Sun.COM 	lp->lastline = lp->sh->inlineno;
3664887Schin 	while(1)
3674887Schin 	{
3684887Schin 		/* skip over characters in the current state */
3694887Schin 		state = sh_lexstates[mode];
3704887Schin 		while((n=STATE(state,c))==0);
3714887Schin 		switch(n)
3724887Schin 		{
3734887Schin 			case S_BREAK:
3744887Schin 				fcseek(-1);
3754887Schin 				goto breakloop;
3764887Schin 			case S_EOF:
3774887Schin 				sp = fcfile();
3788462SApril.Chin@Sun.COM 				if((n=lexfill(lp)) > 0)
3794887Schin 				{
3804887Schin 					fcseek(-1);
3814887Schin 					continue;
3824887Schin 				}
3834887Schin 				/* check for zero byte in file */
3844887Schin 				if(n==0 && fcfile())
3854887Schin 				{
3864887Schin 					if(shp->readscript)
3874887Schin 					{
3884887Schin 						char *cp = error_info.id;
3894887Schin 						errno = ENOEXEC;
3904887Schin 						error_info.id = shp->readscript;
3914887Schin 						errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp);
3924887Schin 					}
3934887Schin 					else
3944887Schin 					{
3958462SApril.Chin@Sun.COM 						lp->token = -1;
3968462SApril.Chin@Sun.COM 						sh_syntax(lp);
3974887Schin 					}
3984887Schin 				}
3994887Schin 				/* end-of-file */
4004887Schin 				if(mode==ST_BEGIN)
4018462SApril.Chin@Sun.COM 					return(lp->token=EOFSYM);
4028462SApril.Chin@Sun.COM 				if(mode >ST_NORM && lp->lexd.level>0)
4034887Schin 				{
4048462SApril.Chin@Sun.COM 					switch(c=endchar(lp))
4054887Schin 					{
4064887Schin 						case '$':
4074887Schin 							if(mode==ST_LIT)
4084887Schin 							{
4094887Schin 								c = '\'';
4104887Schin 								break;
4114887Schin 							}
4128462SApril.Chin@Sun.COM 							mode = oldmode(lp);
4138462SApril.Chin@Sun.COM 							poplevel(lp);
4144887Schin 							continue;
4154887Schin 						case RBRACT:
4164887Schin 							c = LBRACT;
4174887Schin 							break;
4184887Schin 						case 1:	/* for ((...)) */
4194887Schin 						case RPAREN:
4204887Schin 							c = LPAREN;
4214887Schin 							break;
4224887Schin 						default:
4234887Schin 							c = LBRACE;
4244887Schin 							break;
4254887Schin 						case '"': case '`': case '\'':
4268462SApril.Chin@Sun.COM 							lp->lexd.balance = c;
4274887Schin 							break;
4284887Schin 					}
4294887Schin 					if(sp && !(sfset(sp,0,0)&SF_STRING))
4304887Schin 					{
4318462SApril.Chin@Sun.COM 						lp->lasttok = c;
4328462SApril.Chin@Sun.COM 						lp->token = EOFSYM;
4338462SApril.Chin@Sun.COM 						sh_syntax(lp);
4344887Schin 					}
4358462SApril.Chin@Sun.COM 					lp->lexd.balance = c;
4364887Schin 				}
4374887Schin 				goto breakloop;
4384887Schin 			case S_COM:
4394887Schin 				/* skip one or more comment line(s) */
4408462SApril.Chin@Sun.COM 				lp->lex.reservok = !lp->lex.intest;
4418462SApril.Chin@Sun.COM 				if((n=lp->lexd.nocopy) && lp->lexd.dolparen)
4428462SApril.Chin@Sun.COM 					lp->lexd.nocopy--;
4434887Schin 				do
4444887Schin 				{
4454887Schin 					while(fcgetc(c)>0 && c!='\n');
4468462SApril.Chin@Sun.COM 					if(c<=0 || lp->heredoc)
4474887Schin 						break;
4484887Schin 					while(shp->inlineno++,fcpeek(0)=='\n')
4494887Schin 						fcseek(1);
4504887Schin 					while(state[c=fcpeek(0)]==0)
4514887Schin 						fcseek(1);
4524887Schin 				}
4534887Schin 				while(c=='#');
4548462SApril.Chin@Sun.COM 				lp->lexd.nocopy = n;
4554887Schin 				if(c<0)
4568462SApril.Chin@Sun.COM 					return(lp->token=EOFSYM);
4574887Schin 				n = S_NLTOK;
4584887Schin 				shp->inlineno--;
4594887Schin 				/* FALL THRU */
4604887Schin 			case S_NLTOK:
4614887Schin 				/* check for here-document */
4628462SApril.Chin@Sun.COM 				if(lp->heredoc)
4634887Schin 				{
4648462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen)
4658462SApril.Chin@Sun.COM 						lp->lexd.nocopy++;
4664887Schin 					c = shp->inlineno;
4678462SApril.Chin@Sun.COM 					if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok)
4684887Schin 					{
4698462SApril.Chin@Sun.COM 						lp->lasttok = IODOCSYM;
4708462SApril.Chin@Sun.COM 						lp->token = EOFSYM;
4718462SApril.Chin@Sun.COM 						lp->lastline = c;
4728462SApril.Chin@Sun.COM 						sh_syntax(lp);
4734887Schin 					}
4748462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen)
4758462SApril.Chin@Sun.COM 						lp->lexd.nocopy--;
4768462SApril.Chin@Sun.COM 					lp->heredoc = 0;
4774887Schin 				}
4788462SApril.Chin@Sun.COM 				lp->lex.reservok = !lp->lex.intest;
4798462SApril.Chin@Sun.COM 				lp->lex.skipword = 0;
4804887Schin 				/* FALL THRU */
4814887Schin 			case S_NL:
4824887Schin 				/* skip over new-lines */
4838462SApril.Chin@Sun.COM 				lp->lex.last_quote = 0;
4844887Schin 				while(shp->inlineno++,fcget()=='\n');
4854887Schin 				fcseek(-1);
4864887Schin 				if(n==S_NLTOK)
4874887Schin 				{
4888462SApril.Chin@Sun.COM 					lp->comp_assign = 0;
4898462SApril.Chin@Sun.COM 					return(lp->token='\n');
4904887Schin 				}
4914887Schin 			case S_BLNK:
4928462SApril.Chin@Sun.COM 				if(lp->lex.incase<=TEST_RE)
4934887Schin 					continue;
4944887Schin 				/* implicit RPAREN for =~ test operator */
4958462SApril.Chin@Sun.COM 				if(inlevel+1==lp->lexd.level)
4964887Schin 				{
4978462SApril.Chin@Sun.COM 					if(lp->lex.intest)
4988462SApril.Chin@Sun.COM 						fcseek(-1);
4994887Schin 					c = RPAREN;
5004887Schin 					goto do_pop;
5014887Schin 				}
5024887Schin 				continue;
5034887Schin 			case S_OP:
5044887Schin 				/* return operator token */
5054887Schin 				if(c=='<' || c=='>')
5064887Schin 				{
5078462SApril.Chin@Sun.COM 					if(lp->lex.testop2)
5088462SApril.Chin@Sun.COM 						lp->lex.testop2 = 0;
5094887Schin 					else
5104887Schin 					{
5118462SApril.Chin@Sun.COM 						lp->digits = (c=='>');
5128462SApril.Chin@Sun.COM 						lp->lex.skipword = 1;
5138462SApril.Chin@Sun.COM 						lp->aliasok = lp->lex.reservok;
5148462SApril.Chin@Sun.COM 						lp->lex.reservok = 0;
5154887Schin 					}
5164887Schin 				}
5174887Schin 				else
5184887Schin 				{
5198462SApril.Chin@Sun.COM 					lp->lex.reservok = !lp->lex.intest;
5204887Schin 					if(c==RPAREN)
5214887Schin 					{
5228462SApril.Chin@Sun.COM 						if(!lp->lexd.dolparen)
5238462SApril.Chin@Sun.COM 							lp->lex.incase = 0;
5248462SApril.Chin@Sun.COM 						return(lp->token=c);
5254887Schin 					}
5268462SApril.Chin@Sun.COM 					lp->lex.testop1 = lp->lex.intest;
5274887Schin 				}
5284887Schin 				if(fcgetc(n)>0)
5294887Schin 					fcseek(-1);
5304887Schin 				if(state[n]==S_OP || n=='#')
5314887Schin 				{
5324887Schin 					if(n==c)
5334887Schin 					{
5344887Schin 						if(c=='<')
5358462SApril.Chin@Sun.COM 							lp->lexd.docword=1;
5364887Schin 						else if(n==LPAREN)
5374887Schin 						{
5388462SApril.Chin@Sun.COM 							lp->lexd.nest=1;
5398462SApril.Chin@Sun.COM 							lp->lastline = shp->inlineno;
5408462SApril.Chin@Sun.COM 							lp->lexd.lex_state = ST_NESTED;
5414887Schin 							fcseek(1);
5428462SApril.Chin@Sun.COM 							return(sh_lex(lp));
5434887Schin 						}
5444887Schin 						c  |= SYMREP;
5454887Schin 					}
5464887Schin 					else if(c=='(' || c==')')
5478462SApril.Chin@Sun.COM 						return(lp->token=c);
5484887Schin 					else if(c=='&')
5494887Schin 					{
55010898Sroland.mainz@nrubsig.org 						if(!sh_isoption(SH_POSIX) && n=='>' && (sh_isoption(SH_BASH) || sh_isstate(SH_PROFILE)))
5514887Schin 						{
55210898Sroland.mainz@nrubsig.org 							if(!sh_isoption(SH_BASH) && !lp->nonstandard)
55310898Sroland.mainz@nrubsig.org 							{
55410898Sroland.mainz@nrubsig.org 								lp->nonstandard = 1;
55510898Sroland.mainz@nrubsig.org 								errormsg(SH_DICT,ERROR_warn(0),e_lexnonstandard,shp->inlineno);
55610898Sroland.mainz@nrubsig.org 							}
5578462SApril.Chin@Sun.COM 							lp->digits = -1;
5584887Schin 							c = '>';
5594887Schin 						}
5604887Schin 						else
5614887Schin 							n = 0;
5624887Schin 					}
5634887Schin 					else if(n=='&')
5644887Schin 						c  |= SYMAMP;
5654887Schin 					else if(c!='<' && c!='>')
5664887Schin 						n = 0;
5674887Schin 					else if(n==LPAREN)
5684887Schin 					{
5694887Schin 						c  |= SYMLPAR;
5708462SApril.Chin@Sun.COM 						lp->lex.reservok = 1;
5718462SApril.Chin@Sun.COM 						lp->lex.skipword = 0;
5724887Schin 					}
5734887Schin 					else if(n=='|')
5744887Schin 						c  |= SYMPIPE;
5754887Schin 					else if(c=='<' && n=='>')
57610898Sroland.mainz@nrubsig.org 					{
57710898Sroland.mainz@nrubsig.org 						lp->digits = 1;
5784887Schin 						c = IORDWRSYM;
57910898Sroland.mainz@nrubsig.org 						fcgetc(n);
58010898Sroland.mainz@nrubsig.org 						if(fcgetc(n)==';')
58110898Sroland.mainz@nrubsig.org 						{
58210898Sroland.mainz@nrubsig.org 							lp->token = c = IORDWRSYMT;
58310898Sroland.mainz@nrubsig.org 							if(lp->inexec)
58410898Sroland.mainz@nrubsig.org 								sh_syntax(lp);
58510898Sroland.mainz@nrubsig.org 						}
58610898Sroland.mainz@nrubsig.org 						else if(n>0)
58710898Sroland.mainz@nrubsig.org 							fcseek(-1);
58810898Sroland.mainz@nrubsig.org 						n= 0;
58910898Sroland.mainz@nrubsig.org 					}
5904887Schin 					else if(n=='#' && (c=='<'||c=='>'))
5914887Schin 						c |= SYMSHARP;
5928462SApril.Chin@Sun.COM 					else if(n==';' && c=='>')
5938462SApril.Chin@Sun.COM 					{
5948462SApril.Chin@Sun.COM 						c |= SYMSEMI;
5958462SApril.Chin@Sun.COM 						if(lp->inexec)
5968462SApril.Chin@Sun.COM 						{
5978462SApril.Chin@Sun.COM 							lp->token = c;
5988462SApril.Chin@Sun.COM 							sh_syntax(lp);
5998462SApril.Chin@Sun.COM 						}
6008462SApril.Chin@Sun.COM 					}
6014887Schin 					else
6024887Schin 						n = 0;
6034887Schin 					if(n)
6044887Schin 					{
6054887Schin 						fcseek(1);
6068462SApril.Chin@Sun.COM 						lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM);
6074887Schin 					}
6084887Schin 					else
6094887Schin 					{
61010898Sroland.mainz@nrubsig.org 						if(lp->lexd.warn && (n=fcpeek(0))!=RPAREN && n!=' ' && n!='\t')
6114887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n);
6124887Schin 					}
6134887Schin 				}
6148462SApril.Chin@Sun.COM 				if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase)
6158462SApril.Chin@Sun.COM 					lp->comp_assign = 2;
6164887Schin 				else
6178462SApril.Chin@Sun.COM 					lp->comp_assign = 0;
6188462SApril.Chin@Sun.COM 				return(lp->token=c);
6194887Schin 			case S_ESC:
6204887Schin 				/* check for \<new-line> */
6214887Schin 				fcgetc(n);
6224887Schin 				c=2;
6234887Schin #if SHOPT_CRNL
6244887Schin 				if(n=='\r')
6254887Schin 				{
6264887Schin 					if(fcgetc(n)=='\n')
6274887Schin 						c=3;
6284887Schin 					else
6294887Schin 					{
6304887Schin 						n='\r';
6314887Schin 						fcseek(-1);
6324887Schin 					}
6334887Schin 				}
6344887Schin #endif /* SHOPT_CRNL */
6354887Schin 				if(n=='\n')
6364887Schin 				{
6374887Schin 					Sfio_t *sp;
6384887Schin 					struct argnod *ap;
6394887Schin 					shp->inlineno++;
6404887Schin 					/* synchronize */
6414887Schin 					if(!(sp=fcfile()))
6424887Schin 						state=fcseek(0);
6434887Schin 					fcclose();
6448462SApril.Chin@Sun.COM 					ap = lp->arg;
6454887Schin 					if(sp)
6464887Schin 						fcfopen(sp);
6474887Schin 					else
6484887Schin 						fcsopen((char*)state);
6494887Schin 					/* remove \new-line */
6508462SApril.Chin@Sun.COM 					n = stktell(stkp)-c;
6518462SApril.Chin@Sun.COM 					stkseek(stkp,n);
6528462SApril.Chin@Sun.COM 					lp->arg = ap;
6534887Schin 					if(n<=ARGVAL)
6544887Schin 					{
6554887Schin 						mode = 0;
6568462SApril.Chin@Sun.COM 						lp->lexd.first = 0;
6574887Schin 					}
6584887Schin 					continue;
6594887Schin 				}
6604887Schin 				wordflags |= ARG_QUOTED;
6614887Schin 				if(mode==ST_DOL)
6624887Schin 					goto err;
6634887Schin #ifndef STR_MAXIMAL
6648462SApril.Chin@Sun.COM 				else if(mode==ST_NESTED && lp->lexd.warn &&
6658462SApril.Chin@Sun.COM 					endchar(lp)==RBRACE &&
6664887Schin 					sh_lexstates[ST_DOL][n]==S_DIG
6674887Schin 				)
6684887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n);
6694887Schin #endif /* STR_MAXIMAL */
6704887Schin 				break;
6714887Schin 			case S_NAME:
6728462SApril.Chin@Sun.COM 				if(!lp->lex.skipword)
6738462SApril.Chin@Sun.COM 					lp->lex.reservok *= 2;
6744887Schin 				/* FALL THRU */
6754887Schin 			case S_TILDE:
6764887Schin 			case S_RES:
6778462SApril.Chin@Sun.COM 				if(!lp->lexd.dolparen)
6788462SApril.Chin@Sun.COM 					lp->lexd.first = fcseek(0)-LEN;
6798462SApril.Chin@Sun.COM 				else if(lp->lexd.docword)
6808462SApril.Chin@Sun.COM 					lp->lexd.docend = fcseek(0)-LEN;
6814887Schin 				mode = ST_NAME;
6824887Schin 				if(c=='.')
6834887Schin 					fcseek(-1);
6844887Schin 				if(n!=S_TILDE)
6854887Schin 					continue;
6864887Schin 				fcgetc(n);
6874887Schin 				if(n>0)
6888462SApril.Chin@Sun.COM 				{
6898462SApril.Chin@Sun.COM 					if(c=='~' && n==LPAREN && lp->lex.incase)
6908462SApril.Chin@Sun.COM 						lp->lex.incase = TEST_RE;
6914887Schin 					fcseek(-1);
6928462SApril.Chin@Sun.COM 				}
6934887Schin 				if(n==LPAREN)
6944887Schin 					goto epat;
6954887Schin 				wordflags = ARG_MAC;
6964887Schin 				mode = ST_NORM;
6974887Schin 				continue;
6984887Schin 			case S_REG:
6994887Schin 				if(mode==ST_BEGIN)
7004887Schin 				{
7018462SApril.Chin@Sun.COM 				do_reg:
7024887Schin 					/* skip new-line joining */
7034887Schin 					if(c=='\\' && fcpeek(0)=='\n')
7044887Schin 					{
7054887Schin 						shp->inlineno++;
7064887Schin 						fcseek(1);
7074887Schin 						continue;
7084887Schin 					}
7094887Schin 					fcseek(-1);
7108462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen)
7118462SApril.Chin@Sun.COM 						lp->lexd.first = fcseek(0);
7128462SApril.Chin@Sun.COM 					else if(lp->lexd.docword)
7138462SApril.Chin@Sun.COM 						lp->lexd.docend = fcseek(0);
7148462SApril.Chin@Sun.COM 					if(c=='[' && lp->assignok>=SH_ASSIGN)
7154887Schin 					{
7164887Schin 						mode = ST_NAME;
7174887Schin 						continue;
7184887Schin 					}
7194887Schin 				}
7204887Schin 				mode = ST_NORM;
7214887Schin 				continue;
7224887Schin 			case S_LIT:
7238462SApril.Chin@Sun.COM 				if(oldmode(lp)==ST_NONE && !lp->lexd.noarg)	/*  in ((...)) */
7244887Schin 				{
7254887Schin 					if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']')
7264887Schin 					{
7274887Schin 						if(fcpeek(1)=='\'')
7284887Schin 							fcseek(2);
7294887Schin 					}
7304887Schin 					continue;
7314887Schin 				}
7324887Schin 				wordflags |= ARG_QUOTED;
7334887Schin 				if(mode==ST_DOL)
7344887Schin 				{
7358462SApril.Chin@Sun.COM 					if(endchar(lp)!='$')
7364887Schin 						goto err;
7378462SApril.Chin@Sun.COM 					if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */
7384887Schin 					{
7398462SApril.Chin@Sun.COM 						if(lp->lexd.warn)
7404887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
7414887Schin 						mode = ST_LIT;
7424887Schin 					}
7434887Schin 				}
7444887Schin 				if(mode!=ST_LIT)
7454887Schin 				{
7468462SApril.Chin@Sun.COM 					if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
7478462SApril.Chin@Sun.COM 						errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
7488462SApril.Chin@Sun.COM 					lp->lex.last_quote = 0;
7498462SApril.Chin@Sun.COM 					lp->lastline = shp->inlineno;
7504887Schin 					if(mode!=ST_DOL)
7518462SApril.Chin@Sun.COM 						pushlevel(lp,'\'',mode);
7524887Schin 					mode = ST_LIT;
7534887Schin 					continue;
7544887Schin 				}
7554887Schin 				/* check for multi-line single-quoted string */
7568462SApril.Chin@Sun.COM 				else if(shp->inlineno > lp->lastline)
7578462SApril.Chin@Sun.COM 					lp->lex.last_quote = '\'';
7588462SApril.Chin@Sun.COM 				mode = oldmode(lp);
7598462SApril.Chin@Sun.COM 				poplevel(lp);
7604887Schin 				break;
7614887Schin 			case S_ESC2:
7624887Schin 				/* \ inside '' */
7638462SApril.Chin@Sun.COM 				if(endchar(lp)=='$')
7644887Schin 				{
7654887Schin 					fcgetc(n);
7664887Schin 					if(n=='\n')
7674887Schin 						shp->inlineno++;
7684887Schin 				}
7694887Schin 				continue;
7704887Schin 			case S_GRAVE:
7718462SApril.Chin@Sun.COM 				if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`'))
7724887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno);
7734887Schin 				wordflags |=(ARG_MAC|ARG_EXP);
7744887Schin 				if(mode==ST_QUOTE)
7754887Schin 					ingrave = !ingrave;
7764887Schin 				/* FALL THRU */
7774887Schin 			case S_QUOTE:
7788462SApril.Chin@Sun.COM 				if(oldmode(lp)==ST_NONE && lp->lexd.arith)	/*  in ((...)) */
7798462SApril.Chin@Sun.COM 				{
7808462SApril.Chin@Sun.COM 					if(n!=S_GRAVE || fcpeek(0)=='\'')
7818462SApril.Chin@Sun.COM 						continue;
7828462SApril.Chin@Sun.COM 				}
7834887Schin 				if(n==S_QUOTE)
7844887Schin 					wordflags |=ARG_QUOTED;
7854887Schin 				if(mode!=ST_QUOTE)
7864887Schin 				{
7874887Schin 					if(c!='"' || mode!=ST_QNEST)
7884887Schin 					{
7898462SApril.Chin@Sun.COM 						if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
7908462SApril.Chin@Sun.COM 							errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
7918462SApril.Chin@Sun.COM 						lp->lex.last_quote=0;
7928462SApril.Chin@Sun.COM 						lp->lastline = shp->inlineno;
7938462SApril.Chin@Sun.COM 						pushlevel(lp,c,mode);
7944887Schin 					}
79510898Sroland.mainz@nrubsig.org 					ingrave ^= (c=='`');
7964887Schin 					mode = ST_QUOTE;
7974887Schin 					continue;
7984887Schin 				}
7998462SApril.Chin@Sun.COM 				else if((n=endchar(lp))==c)
8004887Schin 				{
8018462SApril.Chin@Sun.COM 					if(shp->inlineno > lp->lastline)
8028462SApril.Chin@Sun.COM 						lp->lex.last_quote = c;
8038462SApril.Chin@Sun.COM 					mode = oldmode(lp);
8048462SApril.Chin@Sun.COM 					poplevel(lp);
8054887Schin 				}
8064887Schin 				else if(c=='"' && n==RBRACE)
8074887Schin 					mode = ST_QNEST;
8084887Schin 				break;
8094887Schin 			case S_DOL:
8104887Schin 				/* don't check syntax inside `` */
8114887Schin 				if(mode==ST_QUOTE && ingrave)
8124887Schin 					continue;
8134887Schin #if SHOPT_KIA
8148462SApril.Chin@Sun.COM 				if(lp->lexd.first)
8158462SApril.Chin@Sun.COM 					lp->lexd.kiaoff = fcseek(0)-lp->lexd.first;
8164887Schin 				else
8178462SApril.Chin@Sun.COM 					lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst();
8184887Schin #endif /* SHOPT_KIA */
8198462SApril.Chin@Sun.COM 				pushlevel(lp,'$',mode);
8204887Schin 				mode = ST_DOL;
8214887Schin 				continue;
8224887Schin 			case S_PAR:
8238462SApril.Chin@Sun.COM 			do_comsub:
8244887Schin 				wordflags |= ARG_MAC;
8258462SApril.Chin@Sun.COM 				mode = oldmode(lp);
8268462SApril.Chin@Sun.COM 				poplevel(lp);
8274887Schin 				fcseek(-1);
8288462SApril.Chin@Sun.COM 				wordflags |= comsub(lp,c);
8294887Schin 				continue;
8304887Schin 			case S_RBRA:
8318462SApril.Chin@Sun.COM 				if((n=endchar(lp)) == '$')
8324887Schin 					goto err;
8334887Schin 				if(mode!=ST_QUOTE || n==RBRACE)
8344887Schin 				{
8358462SApril.Chin@Sun.COM 					mode = oldmode(lp);
8368462SApril.Chin@Sun.COM 					poplevel(lp);
8374887Schin 				}
8384887Schin 				break;
8394887Schin 			case S_EDOL:
8404887Schin 				/* end $identifier */
8414887Schin #if SHOPT_KIA
8428462SApril.Chin@Sun.COM 				if(lp->kiafile)
8438462SApril.Chin@Sun.COM 					refvar(lp,0);
8444887Schin #endif /* SHOPT_KIA */
8458462SApril.Chin@Sun.COM 				if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED)
8464887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno);
8474887Schin 				fcseek(-1);
8488462SApril.Chin@Sun.COM 				mode = oldmode(lp);
8498462SApril.Chin@Sun.COM 				poplevel(lp);
8504887Schin 				break;
8514887Schin 			case S_DOT:
8524887Schin 				/* make sure next character is alpha */
8534887Schin 				if(fcgetc(n)>0)
8548462SApril.Chin@Sun.COM 				{
8558462SApril.Chin@Sun.COM 					if(n=='.')
8568462SApril.Chin@Sun.COM 						fcgetc(n);
8578462SApril.Chin@Sun.COM 					if(n>0)
8588462SApril.Chin@Sun.COM 						fcseek(-1);
8598462SApril.Chin@Sun.COM 				}
8604887Schin 				if(isaletter(n) || n==LBRACT)
8614887Schin 					continue;
8624887Schin 				if(mode==ST_NAME)
8634887Schin 				{
8644887Schin 					if(n=='=')
8654887Schin 						continue;
8664887Schin 					break;
8674887Schin 				}
8684887Schin 				else if(n==RBRACE)
8694887Schin 					continue;
8704887Schin 				if(isastchar(n))
8714887Schin 					continue;
8724887Schin 				goto err;
8734887Schin 			case S_SPC1:
8744887Schin 				wordflags |= ARG_MAC;
8758462SApril.Chin@Sun.COM 				if(endchar(lp)==RBRACE)
8764887Schin 				{
8778462SApril.Chin@Sun.COM 					setchar(lp,c);
8784887Schin 					continue;
8794887Schin 				}
8804887Schin 				/* FALL THRU */
8814887Schin 			case S_ALP:
8828462SApril.Chin@Sun.COM 				if(c=='.' && endchar(lp)=='$')
8834887Schin 					goto err;
8844887Schin 			case S_SPC2:
8854887Schin 			case S_DIG:
8864887Schin 				wordflags |= ARG_MAC;
8878462SApril.Chin@Sun.COM 				switch(endchar(lp))
8884887Schin 				{
8894887Schin 					case '$':
8904887Schin 						if(n==S_ALP) /* $identifier */
8914887Schin 							mode = ST_DOLNAME;
8924887Schin 						else
8934887Schin 						{
8948462SApril.Chin@Sun.COM 							mode = oldmode(lp);
8958462SApril.Chin@Sun.COM 							poplevel(lp);
8964887Schin 						}
8974887Schin 						break;
8984887Schin #if SHOPT_TYPEDEF
8994887Schin 					case '@':
9004887Schin #endif /* SHOPT_TYPEDEF */
9014887Schin 					case '!':
9024887Schin 						if(n!=S_ALP)
9034887Schin 							goto dolerr;
9044887Schin 					case '#':
9054887Schin 					case RBRACE:
9064887Schin 						if(n==S_ALP)
9074887Schin 						{
9088462SApril.Chin@Sun.COM 							setchar(lp,RBRACE);
9094887Schin 							if(c=='.')
9104887Schin 								fcseek(-1);
9114887Schin 							mode = ST_BRACE;
9124887Schin 						}
9134887Schin 						else
9144887Schin 						{
9154887Schin 							if(fcgetc(c)>0)
9164887Schin 								fcseek(-1);
9174887Schin 							if(state[c]==S_ALP)
9184887Schin 								goto err;
9194887Schin 							if(n==S_DIG)
9208462SApril.Chin@Sun.COM 								setchar(lp,'0');
9214887Schin 							else
9228462SApril.Chin@Sun.COM 								setchar(lp,'!');
9234887Schin 						}
9244887Schin 						break;
9254887Schin 					case '0':
9264887Schin 						if(n==S_DIG)
9274887Schin 							break;
9284887Schin 					default:
9294887Schin 						goto dolerr;
9304887Schin 				}
9314887Schin 				break;
9324887Schin 			dolerr:
9334887Schin 			case S_ERR:
9348462SApril.Chin@Sun.COM 				if((n=endchar(lp)) == '$')
9354887Schin 					goto err;
9364887Schin 				if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2)
9374887Schin 				{
9384887Schin 					/* see whether inside `...` */
9398462SApril.Chin@Sun.COM 					mode = oldmode(lp);
9408462SApril.Chin@Sun.COM 					poplevel(lp);
9418462SApril.Chin@Sun.COM 					if((n = endchar(lp)) != '`')
9424887Schin 						goto err;
9438462SApril.Chin@Sun.COM 					pushlevel(lp,RBRACE,mode);
9444887Schin 				}
9454887Schin 				else
9468462SApril.Chin@Sun.COM 					setchar(lp,RBRACE);
9474887Schin 				mode = ST_NESTED;
9484887Schin 				continue;
9494887Schin 			case S_MOD1:
9508462SApril.Chin@Sun.COM 				if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE)
9514887Schin 				{
9524887Schin 					/* allow ' inside "${...}" */
9534887Schin 					if(c==':' && fcgetc(n)>0)
9544887Schin 					{
9554887Schin 						n = state[n];
9564887Schin 						fcseek(-1);
9574887Schin 					}
9584887Schin 					if(n==S_MOD1)
9594887Schin 					{
9604887Schin 						mode = ST_QUOTE;
9614887Schin 						continue;
9624887Schin 					}
9634887Schin 				}
9644887Schin 				/* FALL THRU */
9654887Schin 			case S_MOD2:
9664887Schin #if SHOPT_KIA
9678462SApril.Chin@Sun.COM 				if(lp->kiafile)
9688462SApril.Chin@Sun.COM 					refvar(lp,1);
9694887Schin #endif /* SHOPT_KIA */
9704887Schin 				if(c!=':' && fcgetc(n)>0)
9714887Schin 				{
9724887Schin 					if(n!=c)
9734887Schin 						c = 0;
9744887Schin 					if(!c || (fcgetc(n)>0))
9754887Schin 					{
9764887Schin 						fcseek(-1);
9774887Schin 						if(n==LPAREN)
9784887Schin 						{
9794887Schin 							if(c!='%')
9804887Schin 							{
9818462SApril.Chin@Sun.COM 								lp->token = n;
9828462SApril.Chin@Sun.COM 								sh_syntax(lp);
9834887Schin 							}
9848462SApril.Chin@Sun.COM 							else if(lp->lexd.warn)
9854887Schin 								errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%');
9864887Schin 						}
9874887Schin 					}
9884887Schin 				}
9894887Schin 				mode = ST_NESTED;
9904887Schin 				continue;
9914887Schin 			case S_LBRA:
9928462SApril.Chin@Sun.COM 				if((c=endchar(lp)) == '$')
9934887Schin 				{
9944887Schin 					if(fcgetc(c)>0)
9954887Schin 						fcseek(-1);
9968462SApril.Chin@Sun.COM 					setchar(lp,RBRACE);
9974887Schin 					if(state[c]!=S_ERR && c!=RBRACE)
9984887Schin 						continue;
9998462SApril.Chin@Sun.COM 					if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK)
10008462SApril.Chin@Sun.COM 					{
10018462SApril.Chin@Sun.COM 						c = LBRACE;
10028462SApril.Chin@Sun.COM 						goto do_comsub;
10038462SApril.Chin@Sun.COM 					}
10044887Schin 				}
10054887Schin 			err:
10068462SApril.Chin@Sun.COM 				n = endchar(lp);
10078462SApril.Chin@Sun.COM 				mode = oldmode(lp);
10088462SApril.Chin@Sun.COM 				poplevel(lp);
10094887Schin 				if(n!='$')
10104887Schin 				{
10118462SApril.Chin@Sun.COM 					lp->token = c;
10128462SApril.Chin@Sun.COM 					sh_syntax(lp);
10134887Schin 				}
10144887Schin 				else
10154887Schin 				{
10168462SApril.Chin@Sun.COM 					if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE))
10174887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
101810898Sroland.mainz@nrubsig.org 					else if(c=='"' && mode!=ST_QUOTE && !ingrave)
10194887Schin 						wordflags |= ARG_MESSAGE;
10204887Schin 					fcseek(-1);
10214887Schin 				}
10224887Schin 				continue;
10234887Schin 			case S_META:
10248462SApril.Chin@Sun.COM 				if(lp->lexd.warn && endchar(lp)==RBRACE)
10254887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
10264887Schin 				continue;
10274887Schin 			case S_PUSH:
10288462SApril.Chin@Sun.COM 				pushlevel(lp,RPAREN,mode);
10294887Schin 				mode = ST_NESTED;
10304887Schin 				continue;
10314887Schin 			case S_POP:
10324887Schin 			do_pop:
10338462SApril.Chin@Sun.COM 				if(lp->lexd.level <= inlevel)
10344887Schin 					break;
10358462SApril.Chin@Sun.COM 				if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest)
10368462SApril.Chin@Sun.COM 				{
10378462SApril.Chin@Sun.COM 					fcseek(-1);
10388462SApril.Chin@Sun.COM 					goto breakloop;
10398462SApril.Chin@Sun.COM 				}
10408462SApril.Chin@Sun.COM 				n = endchar(lp);
10414887Schin 				if(c==RBRACT  && !(n==RBRACT || n==RPAREN))
10424887Schin 					continue;
10434887Schin 				if((c==RBRACE||c==RPAREN) && n==RPAREN)
10444887Schin 				{
10454887Schin 					if(fcgetc(n)==LPAREN)
10464887Schin 					{
10474887Schin 						if(c!=RPAREN)
10484887Schin 							fcseek(-1);
10494887Schin 						continue;
10504887Schin 					}
10514887Schin 					if(n>0)
10524887Schin 						fcseek(-1);
10534887Schin 					n = RPAREN;
10544887Schin 				}
10554887Schin 				if(c==';' && n!=';')
10564887Schin 				{
10578462SApril.Chin@Sun.COM 					if(lp->lexd.warn && n==RBRACE)
10584887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
10594887Schin 					continue;
10604887Schin 				}
10614887Schin 				if(mode==ST_QNEST)
10624887Schin 				{
10638462SApril.Chin@Sun.COM 					if(lp->lexd.warn)
10644887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c);
10654887Schin 					continue;
10664887Schin 				}
10678462SApril.Chin@Sun.COM 				mode = oldmode(lp);
10688462SApril.Chin@Sun.COM 				poplevel(lp);
10694887Schin 				/* quotes in subscript need expansion */
10704887Schin 				if(mode==ST_NAME && (wordflags&ARG_QUOTED))
10714887Schin 					wordflags |= ARG_MAC;
10724887Schin 				/* check for ((...)) */
10734887Schin 				if(n==1 && c==RPAREN)
10744887Schin 				{
10754887Schin 					if(fcgetc(n)==RPAREN)
10764887Schin 					{
10778462SApril.Chin@Sun.COM 						if(mode==ST_NONE && !lp->lexd.dolparen)
10784887Schin 							goto breakloop;
10798462SApril.Chin@Sun.COM 						lp->lex.reservok = 1;
10808462SApril.Chin@Sun.COM 						lp->lex.skipword = 0;
10818462SApril.Chin@Sun.COM 						return(lp->token=EXPRSYM);
10824887Schin 					}
10834887Schin 					/* backward compatibility */
10844887Schin 					{
10858462SApril.Chin@Sun.COM 						if(lp->lexd.warn)
10864887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
10878462SApril.Chin@Sun.COM 						if(!(state=lp->lexd.first))
10884887Schin 							state = fcfirst();
10894887Schin 						fcseek(state-fcseek(0));
10908462SApril.Chin@Sun.COM 						if(lp->arg)
10914887Schin 						{
10928462SApril.Chin@Sun.COM 							lp->arg = (struct argnod*)stkfreeze(stkp,1);
10938462SApril.Chin@Sun.COM 							setupalias(lp,lp->arg->argval,NIL(Namval_t*));
10944887Schin 						}
10958462SApril.Chin@Sun.COM 						lp->lexd.paren = 1;
10964887Schin 					}
10978462SApril.Chin@Sun.COM 					return(lp->token=LPAREN);
10984887Schin 				}
10994887Schin 				if(mode==ST_NONE)
11004887Schin 					return(0);
11014887Schin 				if(c!=n)
11024887Schin 				{
11038462SApril.Chin@Sun.COM 					lp->token = c;
11048462SApril.Chin@Sun.COM 					sh_syntax(lp);
11054887Schin 				}
11064887Schin 				if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
11074887Schin 					goto epat;
11084887Schin 				continue;
11094887Schin 			case S_EQ:
11108462SApril.Chin@Sun.COM 				assignment = lp->assignok;
11114887Schin 				/* FALL THRU */
11124887Schin 			case S_COLON:
11134887Schin 				if(assignment)
11144887Schin 				{
11154887Schin 					if((c=fcget())=='~')
11164887Schin 						wordflags |= ARG_MAC;
11174887Schin 					else if(c!=LPAREN && assignment==SH_COMPASSIGN)
11184887Schin 						assignment = 0;
11194887Schin 					fcseek(-1);
11204887Schin 				}
11214887Schin 				break;
11224887Schin 			case S_LABEL:
11238462SApril.Chin@Sun.COM 				if(lp->lex.reservok && !lp->lex.incase)
11244887Schin 				{
11254887Schin 					c = fcget();
11264887Schin 					fcseek(-1);
11274887Schin 					if(state[c]==S_BREAK)
11284887Schin 					{
11294887Schin 						assignment = -1;
11304887Schin 						goto breakloop;
11314887Schin 					}
11324887Schin 				}
11334887Schin 				break;
11344887Schin 			case S_BRACT:
11354887Schin 				/* check for possible subscript */
11368462SApril.Chin@Sun.COM 				if((n=endchar(lp))==RBRACT || n==RPAREN ||
11374887Schin 					(mode==ST_BRACE) ||
11388462SApril.Chin@Sun.COM 					(oldmode(lp)==ST_NONE) ||
11398462SApril.Chin@Sun.COM 					(mode==ST_NAME && (lp->assignok||lp->lexd.level)))
11404887Schin 				{
114110898Sroland.mainz@nrubsig.org 					if(mode==ST_NAME)
114210898Sroland.mainz@nrubsig.org 					{
114310898Sroland.mainz@nrubsig.org 						fcgetc(n);
114410898Sroland.mainz@nrubsig.org 						if(n>0)
114510898Sroland.mainz@nrubsig.org 						{
114610898Sroland.mainz@nrubsig.org 							if(n==']')
114710898Sroland.mainz@nrubsig.org 								errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript");
114810898Sroland.mainz@nrubsig.org 							fcseek(-1);
114910898Sroland.mainz@nrubsig.org 						}
115010898Sroland.mainz@nrubsig.org 					}
11518462SApril.Chin@Sun.COM 					pushlevel(lp,RBRACT,mode);
11524887Schin 					wordflags |= ARG_QUOTED;
11534887Schin 					mode = ST_NESTED;
11544887Schin 					continue;
11554887Schin 				}
11564887Schin 				wordflags |= ARG_EXP;
11574887Schin 				break;
11584887Schin 			case S_BRACE:
11594887Schin 			{
11604887Schin 				int isfirst;
11618462SApril.Chin@Sun.COM 				if(lp->lexd.dolparen)
11628462SApril.Chin@Sun.COM 				{
11638462SApril.Chin@Sun.COM 					if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub))
11648462SApril.Chin@Sun.COM 					{
11658462SApril.Chin@Sun.COM 						fcgetc(n);
11668462SApril.Chin@Sun.COM 						if(n>0)
11678462SApril.Chin@Sun.COM 							fcseek(-1);
11688462SApril.Chin@Sun.COM 						else
11698462SApril.Chin@Sun.COM 							n = '\n';
11708462SApril.Chin@Sun.COM 						if(n==RBRACT || sh_lexstates[ST_NORM][n])
11718462SApril.Chin@Sun.COM 							return(lp->token=c);
11728462SApril.Chin@Sun.COM 					}
11734887Schin 					break;
11748462SApril.Chin@Sun.COM 				}
11758462SApril.Chin@Sun.COM 				else if(mode==ST_BEGIN)
11768462SApril.Chin@Sun.COM 				{
11778462SApril.Chin@Sun.COM 					if(lp->comsub && c==RBRACE)
11788462SApril.Chin@Sun.COM 						return(lp->token=c);
11798462SApril.Chin@Sun.COM 					goto do_reg;
11808462SApril.Chin@Sun.COM 				}
11818462SApril.Chin@Sun.COM 				isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1);
11824887Schin 				fcgetc(n);
11834887Schin 				/* check for {} */
11844887Schin 				if(c==LBRACE && n==RBRACE)
11854887Schin 					break;
11864887Schin 				if(n>0)
11874887Schin 					fcseek(-1);
11888462SApril.Chin@Sun.COM 				else if(lp->lex.reservok)
11894887Schin 					break;
11904887Schin 				/* check for reserved word { or } */
11918462SApril.Chin@Sun.COM 				if(lp->lex.reservok && state[n]==S_BREAK && isfirst)
11924887Schin 					break;
11934887Schin 				if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
11948462SApril.Chin@Sun.COM 					&& !lp->lex.incase && !lp->lex.intest
11958462SApril.Chin@Sun.COM 					&& !lp->lex.skipword)
11964887Schin 				{
11974887Schin 					wordflags |= ARG_EXP;
11984887Schin 				}
11994887Schin 				if(c==RBRACE && n==LPAREN)
12004887Schin 					goto epat;
12014887Schin 				break;
12024887Schin 			}
12034887Schin 			case S_PAT:
12044887Schin 				wordflags |= ARG_EXP;
12054887Schin 				/* FALL THRU */
12064887Schin 			case S_EPAT:
12074887Schin 			epat:
12084887Schin 				if(fcgetc(n)==LPAREN)
12094887Schin 				{
12108462SApril.Chin@Sun.COM 					if(lp->lex.incase==TEST_RE)
12114887Schin 					{
12128462SApril.Chin@Sun.COM 						lp->lex.incase++;
12138462SApril.Chin@Sun.COM 						pushlevel(lp,RPAREN,ST_NORM);
12144887Schin 						mode = ST_NESTED;
12154887Schin 					}
12164887Schin 					wordflags |= ARG_EXP;
12178462SApril.Chin@Sun.COM 					pushlevel(lp,RPAREN,mode);
12184887Schin 					mode = ST_NESTED;
12194887Schin 					continue;
12204887Schin 				}
12214887Schin 				if(n>0)
12224887Schin 					fcseek(-1);
12234887Schin 				if(n=='=' && c=='+' && mode==ST_NAME)
12244887Schin 					continue;
12254887Schin 				break;
12264887Schin 		}
12278462SApril.Chin@Sun.COM 		lp->comp_assign = 0;
12284887Schin 		if(mode==ST_NAME)
12294887Schin 			mode = ST_NORM;
12304887Schin 		else if(mode==ST_NONE)
12314887Schin 			return(0);
12324887Schin 	}
12334887Schin breakloop:
12348462SApril.Chin@Sun.COM 	if(lp->lexd.nocopy)
12354887Schin 	{
12368462SApril.Chin@Sun.COM 		lp->lexd.balance = 0;
12378462SApril.Chin@Sun.COM 		return(0);
12388462SApril.Chin@Sun.COM 	}
12398462SApril.Chin@Sun.COM 	if(lp->lexd.dolparen)
12408462SApril.Chin@Sun.COM 	{
12418462SApril.Chin@Sun.COM 		lp->lexd.balance = 0;
12428462SApril.Chin@Sun.COM 		if(lp->lexd.docword)
12434887Schin 			nested_here(lp);
12448462SApril.Chin@Sun.COM 		lp->lexd.message = (wordflags&ARG_MESSAGE);
12458462SApril.Chin@Sun.COM 		return(lp->token=0);
12464887Schin 	}
12478462SApril.Chin@Sun.COM 	if(!(state=lp->lexd.first))
12484887Schin 		state = fcfirst();
12494887Schin 	n = fcseek(0)-(char*)state;
12508462SApril.Chin@Sun.COM 	if(!lp->arg)
12518462SApril.Chin@Sun.COM 		lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
12524887Schin 	if(n>0)
12538462SApril.Chin@Sun.COM 		sfwrite(stkp,state,n);
12544887Schin 	/* add balancing character if necessary */
12558462SApril.Chin@Sun.COM 	if(lp->lexd.balance)
12564887Schin 	{
12578462SApril.Chin@Sun.COM 		sfputc(stkp,lp->lexd.balance);
12588462SApril.Chin@Sun.COM 		lp->lexd.balance = 0;
12594887Schin 	}
12608462SApril.Chin@Sun.COM 	sfputc(stkp,0);
12618462SApril.Chin@Sun.COM 	stkseek(stkp,stktell(stkp)-1);
12628462SApril.Chin@Sun.COM 	state = stkptr(stkp,ARGVAL);
12638462SApril.Chin@Sun.COM 	n = stktell(stkp)-ARGVAL;
12648462SApril.Chin@Sun.COM 	lp->lexd.first=0;
12654887Schin 	if(n==1)
12664887Schin 	{
12674887Schin 		/* check for numbered redirection */
12684887Schin 		n = state[0];
12694887Schin 		if((c=='<' || c=='>') && isadigit(n))
12704887Schin 		{
12718462SApril.Chin@Sun.COM 			c = sh_lex(lp);
12728462SApril.Chin@Sun.COM 			lp->digits = (n-'0');
12734887Schin 			return(c);
12744887Schin 		}
12754887Schin 		if(n==LBRACT)
12764887Schin 			c = 0;
12778462SApril.Chin@Sun.COM 		else if(n==RBRACE && lp->comsub)
12788462SApril.Chin@Sun.COM 			return(lp->token=n);
12794887Schin 		else if(n=='~')
12804887Schin 			c = ARG_MAC;
12814887Schin 		else
12824887Schin 			c = (wordflags&ARG_EXP);
12834887Schin 		n = 1;
12844887Schin 	}
12858462SApril.Chin@Sun.COM 	else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
12864887Schin 	{
12874887Schin 		if(!strchr(state,','))
12884887Schin 		{
12898462SApril.Chin@Sun.COM 			stkseek(stkp,stktell(stkp)-1);
12908462SApril.Chin@Sun.COM 			lp->arg = (struct argnod*)stkfreeze(stkp,1);
12918462SApril.Chin@Sun.COM 			return(lp->token=IOVNAME);
12924887Schin 		}
12934887Schin 		c = wordflags;
12944887Schin 	}
12954887Schin 	else
12964887Schin 		c = wordflags;
12974887Schin 	if(assignment<0)
12984887Schin 	{
12998462SApril.Chin@Sun.COM 		stkseek(stkp,stktell(stkp)-1);
13008462SApril.Chin@Sun.COM 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
13018462SApril.Chin@Sun.COM 		lp->lex.reservok = 1;
13028462SApril.Chin@Sun.COM 		return(lp->token=LABLSYM);
13034887Schin 	}
13048462SApril.Chin@Sun.COM 	if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE)
13054887Schin 		c &= ~ARG_EXP;
13064887Schin 	if((c&ARG_EXP) && (c&ARG_QUOTED))
13074887Schin 		c |= ARG_MAC;
13084887Schin 	if(mode==ST_NONE)
13094887Schin 	{
13104887Schin 		/* eliminate trailing )) */
13118462SApril.Chin@Sun.COM 		stkseek(stkp,stktell(stkp)-2);
13124887Schin 	}
13134887Schin 	if(c&ARG_MESSAGE)
13144887Schin 	{
13154887Schin 		if(sh_isoption(SH_DICTIONARY))
13168462SApril.Chin@Sun.COM 			lp->arg = sh_endword(shp,2);
13174887Schin 		if(!sh_isoption(SH_NOEXEC))
13184887Schin 		{
13198462SApril.Chin@Sun.COM 			lp->arg = sh_endword(shp,1);
13204887Schin 			c &= ~ARG_MESSAGE;
13214887Schin 		}
13224887Schin 	}
13238462SApril.Chin@Sun.COM 	if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lp->lexd.warn && !lp->lexd.docword))
13244887Schin 	{
13258462SApril.Chin@Sun.COM 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
13268462SApril.Chin@Sun.COM 		lp->arg->argflag = (c?c:ARG_RAW);
13274887Schin 	}
13284887Schin 	else if(mode==ST_NONE)
13298462SApril.Chin@Sun.COM 		lp->arg = sh_endword(shp,-1);
13304887Schin 	else
13318462SApril.Chin@Sun.COM 		lp->arg = sh_endword(shp,0);
13328462SApril.Chin@Sun.COM 	state = lp->arg->argval;
13338462SApril.Chin@Sun.COM 	lp->comp_assign = assignment;
13344887Schin 	if(assignment)
13358462SApril.Chin@Sun.COM 		lp->arg->argflag |= ARG_ASSIGN;
13368462SApril.Chin@Sun.COM 	else if(!lp->lex.skipword)
13378462SApril.Chin@Sun.COM 		lp->assignok = 0;
13388462SApril.Chin@Sun.COM 	lp->arg->argchn.cp = 0;
13398462SApril.Chin@Sun.COM 	lp->arg->argnxt.ap = 0;
13404887Schin 	if(mode==ST_NONE)
13418462SApril.Chin@Sun.COM 		return(lp->token=EXPRSYM);
13428462SApril.Chin@Sun.COM 	if(lp->lex.intest)
13434887Schin 	{
13448462SApril.Chin@Sun.COM 		if(lp->lex.testop1)
13454887Schin 		{
13468462SApril.Chin@Sun.COM 			lp->lex.testop1 = 0;
13474887Schin 			if(n==2 && state[0]=='-' && state[2]==0 &&
13484887Schin 				strchr(test_opchars,state[1]))
13494887Schin 			{
13508462SApril.Chin@Sun.COM 				if(lp->lexd.warn && state[1]=='a')
13514887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
13528462SApril.Chin@Sun.COM 				lp->digits = state[1];
13538462SApril.Chin@Sun.COM 				lp->token = TESTUNOP;
13544887Schin 			}
13554887Schin 			else if(n==1 && state[0]=='!' && state[1]==0)
13564887Schin 			{
13578462SApril.Chin@Sun.COM 				lp->lex.testop1 = 1;
13588462SApril.Chin@Sun.COM 				lp->token = '!';
13594887Schin 			}
13604887Schin 			else
13614887Schin 			{
13628462SApril.Chin@Sun.COM 				lp->lex.testop2 = 1;
13638462SApril.Chin@Sun.COM 				lp->token = 0;
13644887Schin 			}
13658462SApril.Chin@Sun.COM 			return(lp->token);
13664887Schin 		}
13678462SApril.Chin@Sun.COM 		lp->lex.incase = 0;
13684887Schin 		c = sh_lookup(state,shtab_testops);
13694887Schin 		switch(c)
13704887Schin 		{
13714887Schin 		case TEST_END:
13728462SApril.Chin@Sun.COM 			lp->lex.testop2 = lp->lex.intest = 0;
13738462SApril.Chin@Sun.COM 			lp->lex.reservok = 1;
13748462SApril.Chin@Sun.COM 			lp->token = ETESTSYM;
13758462SApril.Chin@Sun.COM 			return(lp->token);
13764887Schin 
13774887Schin 		case TEST_SEQ:
13788462SApril.Chin@Sun.COM 			if(lp->lexd.warn && state[1]==0)
13794887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
13804887Schin 			/* FALL THRU */
13814887Schin 		default:
13828462SApril.Chin@Sun.COM 			if(lp->lex.testop2)
13834887Schin 			{
13848462SApril.Chin@Sun.COM 				if(lp->lexd.warn && (c&TEST_ARITH))
13854887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
13864887Schin 				if(c&TEST_PATTERN)
13878462SApril.Chin@Sun.COM 					lp->lex.incase = 1;
13884887Schin 				else if(c==TEST_REP)
13898462SApril.Chin@Sun.COM 					lp->lex.incase = TEST_RE;
13908462SApril.Chin@Sun.COM 				lp->lex.testop2 = 0;
13918462SApril.Chin@Sun.COM 				lp->digits = c;
13928462SApril.Chin@Sun.COM 				lp->token = TESTBINOP;
13938462SApril.Chin@Sun.COM 				return(lp->token);
13944887Schin 			}
13954887Schin 
13964887Schin 		case TEST_OR: case TEST_AND:
13974887Schin 		case 0:
13988462SApril.Chin@Sun.COM 			return(lp->token=0);
13994887Schin 		}
14004887Schin 	}
14018462SApril.Chin@Sun.COM 	if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2)
14024887Schin 	{
14034887Schin 		/* check for {, }, ! */
14044887Schin 		c = state[0];
14054887Schin 		if(n==1 && (c=='{' || c=='}' || c=='!'))
14064887Schin 		{
14078462SApril.Chin@Sun.COM 			if(lp->lexd.warn && c=='{' && lp->lex.incase==2)
14084887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
14098462SApril.Chin@Sun.COM 			if(lp->lex.incase==1 && c==RBRACE)
14108462SApril.Chin@Sun.COM 				lp->lex.incase = 0;
14118462SApril.Chin@Sun.COM 			return(lp->token=c);
14124887Schin 		}
14138462SApril.Chin@Sun.COM 		else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT)
14144887Schin 		{
14158462SApril.Chin@Sun.COM 			lp->lex.intest = lp->lex.testop1 = 1;
14168462SApril.Chin@Sun.COM 			lp->lex.testop2 = lp->lex.reservok = 0;
14178462SApril.Chin@Sun.COM 			return(lp->token=BTESTSYM);
14184887Schin 		}
14194887Schin 	}
14204887Schin 	c = 0;
14218462SApril.Chin@Sun.COM 	if(!lp->lex.skipword)
14224887Schin 	{
14238462SApril.Chin@Sun.COM 		if(n>1 && lp->lex.reservok==1 && mode==ST_NAME &&
14244887Schin 			(c=sh_lookup(state,shtab_reserved)))
14254887Schin 		{
14268462SApril.Chin@Sun.COM 			if(lp->lex.incase)
14274887Schin 			{
14288462SApril.Chin@Sun.COM 				if(lp->lex.incase >1)
14298462SApril.Chin@Sun.COM 					lp->lex.incase = 1;
14304887Schin 				else if(c==ESACSYM)
14318462SApril.Chin@Sun.COM 					lp->lex.incase = 0;
14324887Schin 				else
14334887Schin 					c = 0;
14344887Schin 			}
14354887Schin 			else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
14364887Schin 			{
14378462SApril.Chin@Sun.COM 				lp->lex.skipword = 1;
14388462SApril.Chin@Sun.COM 				lp->lex.incase = 2*(c==CASESYM);
14394887Schin 			}
14404887Schin 			else
14418462SApril.Chin@Sun.COM 				lp->lex.skipword = 0;
14424887Schin 			if(c==INSYM)
14438462SApril.Chin@Sun.COM 				lp->lex.reservok = 0;
14444887Schin 			else if(c==TIMESYM)
14454887Schin 			{
14464887Schin 				/* yech - POSIX requires time -p */
14474887Schin 				while(fcgetc(n)==' ' || n=='\t');
14484887Schin 				if(n>0)
14494887Schin 					fcseek(-1);
14504887Schin 				if(n=='-')
14514887Schin 					c=0;
14524887Schin 			}
14538462SApril.Chin@Sun.COM 			return(lp->token=c);
14544887Schin 		}
14558462SApril.Chin@Sun.COM 		if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok))
14564887Schin 		{
14574887Schin 			/* check for aliases */
14584887Schin 			Namval_t* np;
14598462SApril.Chin@Sun.COM 			if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN &&
14604887Schin 				(np=nv_search(state,shp->alias_tree,HASH_SCOPE))
14614887Schin 				&& !nv_isattr(np,NV_NOEXPAND)
14624887Schin #if KSHELL
14634887Schin 				&& (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
14644887Schin #endif /* KSHELL */
14654887Schin 				&& (state=nv_getval(np)))
14664887Schin 			{
14674887Schin 				setupalias(lp,state,np);
14684887Schin 				nv_onattr(np,NV_NOEXPAND);
14698462SApril.Chin@Sun.COM 				lp->lex.reservok = 1;
14708462SApril.Chin@Sun.COM 				lp->assignok |= lp->lex.reservok;
14718462SApril.Chin@Sun.COM 				return(sh_lex(lp));
14724887Schin 			}
14734887Schin 		}
14748462SApril.Chin@Sun.COM 		lp->lex.reservok = 0;
14754887Schin 	}
14768462SApril.Chin@Sun.COM 	lp->lex.skipword = lp->lexd.docword = 0;
14778462SApril.Chin@Sun.COM 	return(lp->token=c);
14784887Schin }
14794887Schin 
14804887Schin /*
14814887Schin  * read to end of command substitution
14824887Schin  */
comsub(register Lex_t * lp,int endtok)14838462SApril.Chin@Sun.COM static int comsub(register Lex_t *lp, int endtok)
14844887Schin {
14854887Schin 	register int	n,c,count=1;
14868462SApril.Chin@Sun.COM 	register int	line=lp->sh->inlineno;
14874887Schin 	char word[5];
1488*12068SRoger.Faulkner@Oracle.COM 	int off, messages=0, assignok=lp->assignok, csub;
14894887Schin 	struct lexstate	save;
14908462SApril.Chin@Sun.COM 	save = lp->lex;
14918462SApril.Chin@Sun.COM 	csub = lp->comsub;
14928462SApril.Chin@Sun.COM 	sh_lexopen(lp,lp->sh,1);
14938462SApril.Chin@Sun.COM 	lp->lexd.dolparen++;
14948462SApril.Chin@Sun.COM 	lp->lex.incase=0;
14958462SApril.Chin@Sun.COM 	pushlevel(lp,0,0);
14968462SApril.Chin@Sun.COM 	lp->comsub = (endtok==LBRACE);
1497*12068SRoger.Faulkner@Oracle.COM 	off = fcseek(0) - lp->lexd.first;
14988462SApril.Chin@Sun.COM 	if(sh_lex(lp)==endtok)
14994887Schin 	{
1500*12068SRoger.Faulkner@Oracle.COM 		if(endtok==LPAREN && fcseek(0)==lp->lexd.first)
1501*12068SRoger.Faulkner@Oracle.COM 		{
1502*12068SRoger.Faulkner@Oracle.COM 			count++;
1503*12068SRoger.Faulkner@Oracle.COM 			lp->lexd.paren = 0;
1504*12068SRoger.Faulkner@Oracle.COM 			fcseek(off+2);
1505*12068SRoger.Faulkner@Oracle.COM 		}
15064887Schin 		while(1)
15074887Schin 		{
15084887Schin 			/* look for case and esac */
15094887Schin 			n=0;
15104887Schin 			while(1)
15114887Schin 			{
15124887Schin 				fcgetc(c);
15134887Schin 				/* skip leading white space */
15144887Schin 				if(n==0 && !sh_lexstates[ST_BEGIN][c])
15154887Schin 					continue;
15164887Schin 				if(n==4)
15174887Schin 					break;
15184887Schin 				if(sh_lexstates[ST_NAME][c])
15194887Schin 					goto skip;
15204887Schin 				word[n++] = c;
15214887Schin 			}
15224887Schin 			if(sh_lexstates[ST_NAME][c]==S_BREAK)
15234887Schin 			{
15244887Schin 				if(memcmp(word,"case",4)==0)
15258462SApril.Chin@Sun.COM 					lp->lex.incase=1;
15264887Schin 				else if(memcmp(word,"esac",4)==0)
15278462SApril.Chin@Sun.COM 					lp->lex.incase=0;
15284887Schin 			}
15294887Schin 		skip:
15304887Schin 			if(c && (c!='#' || n==0))
15314887Schin 				fcseek(-1);
15328462SApril.Chin@Sun.COM 			if(c==RBRACE && lp->lex.incase)
15338462SApril.Chin@Sun.COM 				lp->lex.incase=0;
15348462SApril.Chin@Sun.COM 			switch(c=sh_lex(lp))
15354887Schin 			{
15368462SApril.Chin@Sun.COM 			    case LBRACE:
15378462SApril.Chin@Sun.COM 				if(endtok==LBRACE && !lp->lex.incase)
15388462SApril.Chin@Sun.COM 				{
15398462SApril.Chin@Sun.COM 					lp->comsub = 0;
15408462SApril.Chin@Sun.COM 					count++;
15418462SApril.Chin@Sun.COM 				}
15428462SApril.Chin@Sun.COM 				break;
15438462SApril.Chin@Sun.COM 			    case RBRACE:
15448462SApril.Chin@Sun.COM 			    rbrace:
15458462SApril.Chin@Sun.COM 				if(endtok==LBRACE && --count<=0)
15468462SApril.Chin@Sun.COM 					goto done;
15478462SApril.Chin@Sun.COM 				lp->comsub = (count==1);
15488462SApril.Chin@Sun.COM 				break;
15498462SApril.Chin@Sun.COM 			    case IPROCSYM:	case OPROCSYM:
15508462SApril.Chin@Sun.COM 			    case LPAREN:
15518462SApril.Chin@Sun.COM 				if(endtok==LPAREN && !lp->lex.incase)
15524887Schin 					count++;
15534887Schin 				break;
15544887Schin 			    case RPAREN:
15558462SApril.Chin@Sun.COM 				if(lp->lex.incase)
15568462SApril.Chin@Sun.COM 					lp->lex.incase=0;
15578462SApril.Chin@Sun.COM 				else if(endtok==LPAREN && --count<=0)
15584887Schin 					goto done;
15594887Schin 				break;
15604887Schin 			    case EOFSYM:
15618462SApril.Chin@Sun.COM 				lp->lastline = line;
15628462SApril.Chin@Sun.COM 				lp->lasttok = endtok;
15638462SApril.Chin@Sun.COM 				sh_syntax(lp);
15644887Schin 			    case IOSEEKSYM:
15654887Schin 				if(fcgetc(c)!='#' && c>0)
15664887Schin 					fcseek(-1);
15674887Schin 				break;
15684887Schin 			    case IODOCSYM:
156910898Sroland.mainz@nrubsig.org 				lp->lexd.docextra = 0;
15708462SApril.Chin@Sun.COM 				sh_lex(lp);
15714887Schin 				break;
15724887Schin 			    case 0:
15738462SApril.Chin@Sun.COM 				lp->lex.reservok = 0;
15748462SApril.Chin@Sun.COM 				messages |= lp->lexd.message;
15758462SApril.Chin@Sun.COM 				break;
15768462SApril.Chin@Sun.COM 			    case ';':
15778462SApril.Chin@Sun.COM 				fcgetc(c);
15788462SApril.Chin@Sun.COM 				if(c==RBRACE && endtok==LBRACE)
15798462SApril.Chin@Sun.COM 					goto rbrace;
15808462SApril.Chin@Sun.COM 				if(c>0)
15818462SApril.Chin@Sun.COM 					fcseek(-1);
15828462SApril.Chin@Sun.COM 				/* fall through*/
15838462SApril.Chin@Sun.COM 			    default:
15848462SApril.Chin@Sun.COM 				lp->lex.reservok = 1;
15854887Schin 			}
15864887Schin 		}
15874887Schin 	}
15884887Schin done:
15898462SApril.Chin@Sun.COM 	poplevel(lp);
15908462SApril.Chin@Sun.COM 	lp->comsub = csub;
15918462SApril.Chin@Sun.COM 	lp->lastline = line;
15928462SApril.Chin@Sun.COM 	lp->lexd.dolparen--;
15938462SApril.Chin@Sun.COM 	lp->lex = save;
15948462SApril.Chin@Sun.COM 	lp->assignok = (endchar(lp)==RBRACT?assignok:0);
15954887Schin 	return(messages);
15964887Schin }
15974887Schin 
15984887Schin /*
15994887Schin  * here-doc nested in $(...)
16004887Schin  * allocate ionode with delimiter filled in without disturbing stak
16014887Schin  */
nested_here(register Lex_t * lp)16024887Schin static void nested_here(register Lex_t *lp)
16034887Schin {
16048462SApril.Chin@Sun.COM 	register struct ionod	*iop;
16058462SApril.Chin@Sun.COM 	register int		n,offset;
16068462SApril.Chin@Sun.COM 	struct argnod		*arg = lp->arg;
16078462SApril.Chin@Sun.COM 	Stk_t			*stkp = lp->sh->stk;
16088462SApril.Chin@Sun.COM 	char			*base;
16098462SApril.Chin@Sun.COM 	if(offset=stktell(stkp))
16108462SApril.Chin@Sun.COM 		base = stkfreeze(stkp,0);
16118462SApril.Chin@Sun.COM 	n = fcseek(0)-lp->lexd.docend;
161210898Sroland.mainz@nrubsig.org 	iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL);
16138462SApril.Chin@Sun.COM 	iop->iolst = lp->heredoc;
16148462SApril.Chin@Sun.COM 	stkseek(stkp,ARGVAL);
161510898Sroland.mainz@nrubsig.org 	if(lp->lexd.docextra)
161610898Sroland.mainz@nrubsig.org 	{
161710898Sroland.mainz@nrubsig.org 		sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
161810898Sroland.mainz@nrubsig.org 		sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1);
161910898Sroland.mainz@nrubsig.org 	}
16208462SApril.Chin@Sun.COM 	sfwrite(stkp,lp->lexd.docend,n);
16218462SApril.Chin@Sun.COM 	lp->arg = sh_endword(lp->sh,0);
16224887Schin 	iop->ioname = (char*)(iop+1);
16238462SApril.Chin@Sun.COM 	strcpy(iop->ioname,lp->arg->argval);
16244887Schin 	iop->iofile = (IODOC|IORAW);
16258462SApril.Chin@Sun.COM 	if(lp->lexd.docword>1)
16264887Schin 		iop->iofile |= IOSTRIP;
16278462SApril.Chin@Sun.COM 	lp->heredoc = iop;
16288462SApril.Chin@Sun.COM 	lp->arg = arg;
16298462SApril.Chin@Sun.COM 	lp->lexd.docword = 0;
16304887Schin 	if(offset)
16318462SApril.Chin@Sun.COM 		stkset(stkp,base,offset);
16324887Schin 	else
16338462SApril.Chin@Sun.COM 		stkseek(stkp,0);
16344887Schin }
16354887Schin 
16364887Schin /*
16374887Schin  * skip to <close> character
16384887Schin  * if <copy> is non,zero, then the characters are copied to the stack
16394887Schin  * <state> is the initial lexical state
16404887Schin  */
sh_lexskip(Lex_t * lp,int close,register int copy,int state)16418462SApril.Chin@Sun.COM void sh_lexskip(Lex_t *lp,int close, register int copy, int  state)
16424887Schin {
16434887Schin 	register char	*cp;
16448462SApril.Chin@Sun.COM 	lp->lexd.nest = close;
16458462SApril.Chin@Sun.COM 	lp->lexd.lex_state = state;
16468462SApril.Chin@Sun.COM 	lp->lexd.noarg = 1;
16474887Schin 	if(copy)
16488462SApril.Chin@Sun.COM 		fcnotify(lex_advance,lp);
16494887Schin 	else
16508462SApril.Chin@Sun.COM 		lp->lexd.nocopy++;
16518462SApril.Chin@Sun.COM 	sh_lex(lp);
16528462SApril.Chin@Sun.COM 	lp->lexd.noarg = 0;
16534887Schin 	if(copy)
16544887Schin 	{
16558462SApril.Chin@Sun.COM 		fcnotify(0,lp);
16568462SApril.Chin@Sun.COM 		if(!(cp=lp->lexd.first))
16574887Schin 			cp = fcfirst();
16584887Schin 		if((copy = fcseek(0)-cp) > 0)
16598462SApril.Chin@Sun.COM 			sfwrite(lp->sh->stk,cp,copy);
16604887Schin 	}
16614887Schin 	else
16628462SApril.Chin@Sun.COM 		lp->lexd.nocopy--;
16634887Schin }
16644887Schin 
16654887Schin #if SHOPT_CRNL
_sfwrite(Sfio_t * sp,const Void_t * buff,size_t n)16664887Schin     ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
16674887Schin     {
16684887Schin 	const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
16694887Schin 	int m=0,k;
16704887Schin 	while(next = (const char*)memchr(next,'\r',ep-next))
16714887Schin 		if(*++next=='\n')
16724887Schin 		{
16734887Schin 			if(k=next-cp-1)
16744887Schin 			{
16754887Schin 				if((k=sfwrite(sp,cp,k)) < 0)
16764887Schin 					return(m>0?m:-1);
16774887Schin 				m += k;
16784887Schin 			}
16794887Schin 			cp = next;
16804887Schin 		}
16814887Schin 	if((k=sfwrite(sp,cp,ep-cp)) < 0)
16824887Schin 		return(m>0?m:-1);
16834887Schin 	return(m+k);
16844887Schin     }
16854887Schin #   define sfwrite	_sfwrite
16864887Schin #endif /* SHOPT_CRNL */
16874887Schin 
16884887Schin /*
16894887Schin  * read in here-document from script
16904887Schin  * quoted here documents, and here-documents without special chars are
16914887Schin  * noted with the IOQUOTE flag
16924887Schin  * returns 1 for complete here-doc, 0 for EOF
16934887Schin  */
16944887Schin 
here_copy(Lex_t * lp,register struct ionod * iop)16954887Schin static int here_copy(Lex_t *lp,register struct ionod *iop)
16964887Schin {
16974887Schin 	register const char	*state;
16984887Schin 	register int		c,n;
16994887Schin 	register char		*bufp,*cp;
17008462SApril.Chin@Sun.COM 	register Sfio_t		*sp=lp->sh->heredocs, *funlog;
17014887Schin 	int			stripcol=0,stripflg, nsave, special=0;
17028462SApril.Chin@Sun.COM 	if(funlog=lp->sh->funlog)
17034887Schin 	{
17044887Schin 		if(fcfill()>0)
17054887Schin 			fcseek(-1);
17068462SApril.Chin@Sun.COM 		lp->sh->funlog = 0;
17074887Schin 	}
17084887Schin 	if(iop->iolst)
17094887Schin 		here_copy(lp,iop->iolst);
17104887Schin 	iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
17114887Schin 	iop->iosize = 0;
17124887Schin 	iop->iodelim=iop->ioname;
17134887Schin 	/* check for and strip quoted characters in delimiter string */
17144887Schin 	if(stripflg=iop->iofile&IOSTRIP)
17154887Schin 	{
17164887Schin 		while(*iop->iodelim=='\t')
17174887Schin 			iop->iodelim++;
17184887Schin 		/* skip over leading tabs in document */
17194887Schin 		if(iop->iofile&IOLSEEK)
17204887Schin 		{
17214887Schin 			iop->iofile &= ~IOLSEEK;
17224887Schin 			while(fcgetc(c)=='\t' || c==' ')
17234887Schin 			{
17244887Schin 				if(c==' ')
17254887Schin 					stripcol++;
17264887Schin 				else
17274887Schin 					stripcol += 8 - stripcol%8;
17284887Schin 			}
17294887Schin 		}
17304887Schin 		else
17314887Schin 			while(fcgetc(c)=='\t');
17324887Schin 		if(c>0)
17334887Schin 			fcseek(-1);
17344887Schin 	}
17354887Schin 	if(iop->iofile&IOQUOTE)
17364887Schin 		state = sh_lexstates[ST_LIT];
17374887Schin 	else
17384887Schin 		state = sh_lexstates[ST_QUOTE];
17394887Schin 	bufp = fcseek(0);
17404887Schin 	n = S_NL;
17414887Schin 	while(1)
17424887Schin 	{
17434887Schin 		if(n!=S_NL)
17444887Schin 		{
17454887Schin 			/* skip over regular characters */
17464887Schin 			while((n=STATE(state,c))==0);
17474887Schin 		}
17484887Schin 		if(n==S_EOF || !(c=fcget()))
17494887Schin 		{
17508462SApril.Chin@Sun.COM 			if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp))
17514887Schin 			{
17524887Schin 				if(n==S_ESC)
17534887Schin 					c--;
17544887Schin 				if((c=sfwrite(sp,bufp,c))>0)
17554887Schin 					iop->iosize += c;
17564887Schin 			}
17578462SApril.Chin@Sun.COM 			if((c=lexfill(lp))<=0)
17584887Schin 				break;
17594887Schin 			if(n==S_ESC)
17604887Schin 			{
17614887Schin #if SHOPT_CRNL
17624887Schin 				if(c=='\r' && (c=fcget())!=NL)
17634887Schin 					fcseek(-1);
17644887Schin #endif /* SHOPT_CRNL */
17654887Schin 				if(c==NL)
17664887Schin 					fcseek(1);
17674887Schin 				else
17684887Schin 					sfputc(sp,'\\');
17694887Schin 			}
17704887Schin 			bufp = fcseek(-1);
17714887Schin 		}
17724887Schin 		else
17734887Schin 			fcseek(-1);
17744887Schin 		switch(n)
17754887Schin 		{
17764887Schin 		    case S_NL:
17778462SApril.Chin@Sun.COM 			lp->sh->inlineno++;
17784887Schin 			if((stripcol && c==' ') || (stripflg && c=='\t'))
17794887Schin 			{
17808462SApril.Chin@Sun.COM 				if(!lp->lexd.dolparen)
17814887Schin 				{
17824887Schin 					/* write out line */
17834887Schin 					n = fcseek(0)-bufp;
17844887Schin 					if((n=sfwrite(sp,bufp,n))>0)
17854887Schin 						iop->iosize += n;
17864887Schin 				}
17874887Schin 				/* skip over tabs */
17884887Schin 				if(stripcol)
17894887Schin 				{
17904887Schin 					int col=0;
17914887Schin 					do
17924887Schin 					{
17934887Schin 						fcgetc(c);
17944887Schin 						if(c==' ')
17954887Schin 							col++;
17964887Schin 						else
17974887Schin 							col += 8 - col%8;
17984887Schin 						if(col>stripcol)
17994887Schin 							break;
18004887Schin 					}
18014887Schin 					while (c==' ' || c=='\t');
18024887Schin 				}
18034887Schin 				else while(c=='\t')
18044887Schin 					fcgetc(c);
18054887Schin 				if(c<=0)
18064887Schin 					goto done;
18074887Schin 				bufp = fcseek(-1);
18084887Schin 			}
18094887Schin 			if(c!=iop->iodelim[0])
18104887Schin 				break;
18114887Schin 			cp = fcseek(0);
18124887Schin 			nsave = n = 0;
18134887Schin 			while(1)
18144887Schin 			{
18154887Schin 				if(!(c=fcget()))
18164887Schin 				{
18178462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen && (c=cp-bufp))
18184887Schin 					{
18194887Schin 						if((c=sfwrite(sp,cp=bufp,c))>0)
18204887Schin 							iop->iosize+=c;
18214887Schin 					}
18224887Schin 					nsave = n;
18238462SApril.Chin@Sun.COM 					if((c=lexfill(lp))<=0)
18244887Schin 					{
18254887Schin 						c = iop->iodelim[n]==0;
18264887Schin 						goto done;
18274887Schin 					}
18284887Schin 				}
18294887Schin #if SHOPT_CRNL
18304887Schin 				if(c=='\r' && (c=fcget())!=NL)
18314887Schin 				{
18324887Schin 					if(c)
18334887Schin 						fcseek(-1);
18344887Schin 					c='\r';
18354887Schin 				}
18364887Schin #endif /* SHOPT_CRNL */
18374887Schin 				if(c==NL)
18388462SApril.Chin@Sun.COM 					lp->sh->inlineno++;
18394887Schin 				if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
18404887Schin 				{
18418462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen && (n=cp-bufp))
18424887Schin 					{
18434887Schin 						if((n=sfwrite(sp,bufp,n))>0)
18444887Schin 							iop->iosize += n;
18454887Schin 					}
18468462SApril.Chin@Sun.COM 					lp->sh->inlineno--;
18474887Schin 					if(c==RPAREN)
18484887Schin 						fcseek(-1);
18494887Schin 					goto done;
18504887Schin 				}
18514887Schin 				if(iop->iodelim[n++]!=c)
18524887Schin 				{
18534887Schin 					/*
18544887Schin 					 * The match for delimiter failed.
18554887Schin 					 * nsave>0 only when a buffer boundary
18564887Schin 					 * was crossed while checking the
18574887Schin 					 * delimiter
18584887Schin 					 */
18598462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen && nsave>0)
18604887Schin 					{
18614887Schin 						if((n=sfwrite(sp,bufp,nsave))>0)
18624887Schin 							iop->iosize += n;
18634887Schin 						bufp = fcfirst();
18644887Schin 					}
18654887Schin 					if(c==NL)
18664887Schin 						fcseek(-1);
18674887Schin 					break;
18684887Schin 				}
18694887Schin 			}
18704887Schin 			break;
18714887Schin 		    case S_ESC:
18724887Schin 			n=1;
18734887Schin #if SHOPT_CRNL
18744887Schin 			if(c=='\r')
18754887Schin 			{
18764887Schin 				fcseek(1);
18774887Schin 				if(c=fcget())
18784887Schin 					fcseek(-1);
18794887Schin 				if(c==NL)
18804887Schin 					n=2;
18814887Schin 				else
18824887Schin 				{
18834887Schin 					special++;
18844887Schin 					break;
18854887Schin 				}
18864887Schin 			}
18874887Schin #endif /* SHOPT_CRNL */
18884887Schin 			if(c==NL)
18894887Schin 			{
18904887Schin 				/* new-line joining */
18918462SApril.Chin@Sun.COM 				lp->sh->inlineno++;
189210898Sroland.mainz@nrubsig.org 				if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0)
18934887Schin 				{
189410898Sroland.mainz@nrubsig.org 					if(n && (n=sfwrite(sp,bufp,n))>0)
18954887Schin 						iop->iosize += n;
18964887Schin 					bufp = fcseek(0)+1;
18974887Schin 				}
18984887Schin 			}
18994887Schin 			else
19004887Schin 				special++;
19014887Schin 			fcget();
19024887Schin 			break;
19034887Schin 
19044887Schin 		    case S_GRAVE:
19054887Schin 		    case S_DOL:
19064887Schin 			special++;
19074887Schin 			break;
19084887Schin 		}
19094887Schin 		n=0;
19104887Schin 	}
19114887Schin done:
19128462SApril.Chin@Sun.COM 	lp->sh->funlog = funlog;
19138462SApril.Chin@Sun.COM 	if(lp->lexd.dolparen)
19144887Schin 		free((void*)iop);
19154887Schin 	else if(!special)
19164887Schin 		iop->iofile |= IOQUOTE;
19174887Schin 	return(c);
19184887Schin }
19194887Schin 
19204887Schin /*
19214887Schin  * generates string for given token
19224887Schin  */
fmttoken(Lex_t * lp,register int sym,char * tok)19234887Schin static char	*fmttoken(Lex_t *lp, register int sym, char *tok)
19244887Schin {
192510898Sroland.mainz@nrubsig.org 	int n=1;
19264887Schin 	if(sym < 0)
19274887Schin 		return((char*)sh_translate(e_lexzerobyte));
19284887Schin 	if(sym==0)
19298462SApril.Chin@Sun.COM 		return(lp->arg?lp->arg->argval:"?");
19308462SApril.Chin@Sun.COM 	if(lp->lex.intest && lp->arg && *lp->arg->argval)
19318462SApril.Chin@Sun.COM 		return(lp->arg->argval);
19324887Schin 	if(sym&SYMRES)
19334887Schin 	{
19344887Schin 		register const Shtable_t *tp=shtab_reserved;
19354887Schin 		while(tp->sh_number && tp->sh_number!=sym)
19364887Schin 			tp++;
19374887Schin 		return((char*)tp->sh_name);
19384887Schin 	}
19394887Schin 	if(sym==EOFSYM)
19404887Schin 		return((char*)sh_translate(e_endoffile));
19414887Schin 	if(sym==NL)
19424887Schin 		return((char*)sh_translate(e_newline));
19434887Schin 	tok[0] = sym;
19444887Schin 	if(sym&SYMREP)
194510898Sroland.mainz@nrubsig.org 		tok[n++] = sym;
19464887Schin 	else
19474887Schin 	{
19484887Schin 		switch(sym&SYMMASK)
19494887Schin 		{
19504887Schin 			case SYMAMP:
19514887Schin 				sym = '&';
19524887Schin 				break;
19534887Schin 			case SYMPIPE:
19544887Schin 				sym = '|';
19554887Schin 				break;
19564887Schin 			case SYMGT:
19574887Schin 				sym = '>';
19584887Schin 				break;
19594887Schin 			case SYMLPAR:
19604887Schin 				sym = LPAREN;
19614887Schin 				break;
19624887Schin 			case SYMSHARP:
19634887Schin 				sym = '#';
19644887Schin 				break;
19658462SApril.Chin@Sun.COM 			case SYMSEMI:
196610898Sroland.mainz@nrubsig.org 				if(tok[0]=='<')
196710898Sroland.mainz@nrubsig.org 					tok[n++] = '>';
19688462SApril.Chin@Sun.COM 				sym = ';';
19698462SApril.Chin@Sun.COM 				break;
19704887Schin 			default:
19714887Schin 				sym = 0;
19724887Schin 		}
197310898Sroland.mainz@nrubsig.org 		tok[n++] = sym;
19744887Schin 	}
197510898Sroland.mainz@nrubsig.org 	tok[n] = 0;
19764887Schin 	return(tok);
19774887Schin }
19784887Schin 
19794887Schin /*
19804887Schin  * print a bad syntax message
19814887Schin  */
19824887Schin 
sh_syntax(Lex_t * lp)19838462SApril.Chin@Sun.COM void	sh_syntax(Lex_t *lp)
19844887Schin {
19858462SApril.Chin@Sun.COM 	register Shell_t *shp = lp->sh;
19864887Schin 	register const char *cp = sh_translate(e_unexpected);
19874887Schin 	register char *tokstr;
19888462SApril.Chin@Sun.COM 	register int tok = lp->token;
19894887Schin 	char tokbuf[3];
19904887Schin 	Sfio_t *sp;
19918462SApril.Chin@Sun.COM 	if((tok==EOFSYM) && lp->lasttok)
19924887Schin 	{
19938462SApril.Chin@Sun.COM 		tok = lp->lasttok;
19944887Schin 		cp = sh_translate(e_unmatched);
19954887Schin 	}
19964887Schin 	else
19978462SApril.Chin@Sun.COM 		lp->lastline = shp->inlineno;
19984887Schin 	tokstr = fmttoken(lp,tok,tokbuf);
19994887Schin 	if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
20004887Schin 	{
20014887Schin 		/* clear out any pending input */
20024887Schin 		register Sfio_t *top;
20034887Schin 		while(fcget()>0);
20044887Schin 		fcclose();
20054887Schin 		while(top=sfstack(sp,SF_POPSTACK))
20064887Schin 			sfclose(top);
20074887Schin 	}
20084887Schin 	else
20094887Schin 		fcclose();
20108462SApril.Chin@Sun.COM 	shp->inlineno = lp->inlineno;
20118462SApril.Chin@Sun.COM 	shp->st.firstline = lp->firstline;
20124887Schin #if KSHELL
20134887Schin 	if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
20144887Schin #else
20154887Schin 	if(shp->inlineno!=1)
20164887Schin #endif
20178462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
20184887Schin 	else
20194887Schin 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
20204887Schin }
20214887Schin 
stack_shift(Stk_t * stkp,register char * sp,char * dp)20228462SApril.Chin@Sun.COM static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
20234887Schin {
20244887Schin 	register char *ep;
20258462SApril.Chin@Sun.COM 	register int offset = stktell(stkp);
20268462SApril.Chin@Sun.COM 	register int left = offset-(sp-stkptr(stkp,0));
20274887Schin 	register int shift = (dp+1-sp);
20284887Schin 	offset += shift;
20298462SApril.Chin@Sun.COM 	stkseek(stkp,offset);
20308462SApril.Chin@Sun.COM 	sp = stkptr(stkp,offset);
20314887Schin 	ep = sp - shift;
20324887Schin 	while(left--)
20334887Schin 		*--sp = *--ep;
20344887Schin 	return(sp);
20354887Schin }
20364887Schin 
20374887Schin /*
20384887Schin  * Assumes that current word is unfrozen on top of the stak
20394887Schin  * If <mode> is zero, gets rid of quoting and consider argument as string
20404887Schin  *    and returns pointer to frozen arg
20414887Schin  * If mode==1, just replace $"..." strings with international strings
20424887Schin  *    The result is left on the stak
20434887Schin  * If mode==2, the each $"" string is printed on standard output
20444887Schin  */
sh_endword(Shell_t * shp,int mode)20458462SApril.Chin@Sun.COM struct argnod *sh_endword(Shell_t *shp,int mode)
20464887Schin {
20474887Schin 	register const char *state = sh_lexstates[ST_NESTED];
20484887Schin 	register int n;
20494887Schin 	register char *sp,*dp;
20504887Schin 	register int inquote=0, inlit=0; /* set within quoted strings */
20514887Schin 	struct argnod* argp=0;
20524887Schin 	char	*ep=0, *xp=0;
20534887Schin 	int bracket=0;
20548462SApril.Chin@Sun.COM 	Stk_t		*stkp=shp->stk;
20558462SApril.Chin@Sun.COM 	sfputc(stkp,0);
20568462SApril.Chin@Sun.COM 	sp =  stkptr(stkp,ARGVAL);
20574887Schin #if SHOPT_MULTIBYTE
20584887Schin 	if(mbwide())
20594887Schin 	{
20604887Schin 		do
20614887Schin 		{
20624887Schin 			int len;
20634887Schin 			switch(len = mbsize(sp))
20644887Schin 			{
20654887Schin 			    case -1:	/* illegal multi-byte char */
20664887Schin 			    case 0:
20674887Schin 			    case 1:
20684887Schin 				n=state[*sp++];
20694887Schin 				break;
20704887Schin 			    default:
20714887Schin 				/*
20724887Schin 				 * None of the state tables contain
20734887Schin 				 * entries for multibyte characters,
20744887Schin 				 * however, they should be treated
20754887Schin 				 * the same as any other alph
20764887Schin 				 * character.  Therefore, we'll use
20774887Schin 				 * the state of the 'a' character.
20784887Schin 				 */
20794887Schin 				n=state['a'];
20804887Schin 				sp += len;
20814887Schin 			}
20824887Schin 		}
20834887Schin 		while(n == 0);
20844887Schin 	}
20854887Schin 	else
20864887Schin #endif /* SHOPT_MULTIBYTE */
20874887Schin 	while((n=state[*sp++])==0);
20884887Schin 	dp = sp;
20894887Schin 	if(mode<0)
20904887Schin 		inquote = 1;
20914887Schin 	while(1)
20924887Schin 	{
20934887Schin 		switch(n)
20944887Schin 		{
20954887Schin 		    case S_EOF:
20968462SApril.Chin@Sun.COM 			stkseek(stkp,dp-stkptr(stkp,0));
20974887Schin 			if(mode<=0)
20984887Schin 			{
20998462SApril.Chin@Sun.COM 				argp = (struct argnod*)stkfreeze(stkp,0);
21004887Schin 				argp->argflag = ARG_RAW|ARG_QUOTED;
21014887Schin 			}
21024887Schin 			return(argp);
21034887Schin 		    case S_LIT:
21044887Schin 			if(!(inquote&1))
21054887Schin 			{
21064887Schin 				inlit = !inlit;
21074887Schin 				if(mode==0 || (mode<0 && bracket))
21084887Schin 				{
21094887Schin 					dp--;
21104887Schin 					if(ep)
21114887Schin 					{
21124887Schin 						*dp = 0;
21134887Schin 						dp = ep+stresc(ep);
21144887Schin 					}
21154887Schin 					ep = 0;
21164887Schin 				}
21174887Schin 			}
21184887Schin 			break;
21194887Schin 		    case S_QUOTE:
21204887Schin 			if(mode<0 && !bracket)
21214887Schin 				break;
21224887Schin 			if(!inlit)
21234887Schin 			{
21244887Schin 				if(mode<=0)
21254887Schin 					dp--;
21264887Schin 				inquote = inquote^1;
21274887Schin 				if(ep)
21284887Schin 				{
21294887Schin 					char *msg;
21304887Schin 					if(mode==2)
21314887Schin 					{
21324887Schin 						sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
21334887Schin 						ep = 0;
21344887Schin 						break;
21354887Schin 					}
21364887Schin 					*--dp = 0;
21374887Schin #if ERROR_VERSION >= 20000317L
21384887Schin 					msg = ERROR_translate(0,error_info.id,0,ep);
21394887Schin #else
21404887Schin #   if ERROR_VERSION >= 20000101L
21414887Schin 					msg = ERROR_translate(error_info.id,ep);
21424887Schin #   else
21434887Schin 					msg = ERROR_translate(ep,2);
21444887Schin #   endif
21454887Schin #endif
21464887Schin 					n = strlen(msg);
21474887Schin 					dp = ep+n;
21484887Schin 					if(sp-dp <= 1)
21494887Schin 					{
21508462SApril.Chin@Sun.COM 						sp = stack_shift(stkp,sp,dp);
21514887Schin 						dp = sp-1;
21524887Schin 						ep = dp-n;
21534887Schin 					}
21544887Schin 					memmove(ep,msg,n);
21554887Schin 					*dp++ = '"';
21564887Schin 				}
21574887Schin 				ep = 0;
21584887Schin 			}
21594887Schin 			break;
21604887Schin 		    case S_DOL:	/* check for $'...'  and $"..." */
21614887Schin 			if(inlit)
21624887Schin 				break;
21634887Schin 			if(*sp==LPAREN || *sp==LBRACE)
21644887Schin 			{
21654887Schin 				inquote <<= 1;
21664887Schin 				break;
21674887Schin 			}
21684887Schin 			if(inquote&1)
21694887Schin 				break;
21704887Schin 			if(*sp=='\'' || *sp=='"')
21714887Schin 			{
21724887Schin 				if(*sp=='"')
21734887Schin 					inquote |= 1;
21744887Schin 				else
21754887Schin 					inlit = 1;
21764887Schin 				sp++;
21774887Schin 				if((mode==0||(mode<0&&bracket)) || (inquote&1))
21784887Schin 				{
21794887Schin 					if(mode==2)
21804887Schin 						ep = dp++;
21814887Schin 					else if(mode==1)
21824887Schin 						(ep=dp)[-1] = '"';
21834887Schin 					else
21844887Schin 						ep = --dp;
21854887Schin 				}
21864887Schin 			}
21874887Schin 			break;
21884887Schin 		    case S_ESC:
21894887Schin #if SHOPT_CRNL
21904887Schin 			if(*sp=='\r' && sp[1]=='\n')
21914887Schin 				sp++;
21924887Schin #endif /* SHOPT_CRNL */
21934887Schin 			if(inlit || mode>0)
21944887Schin 			{
21954887Schin 				if(mode<0)
21964887Schin 				{
21974887Schin 					if(dp>=sp)
21984887Schin 					{
21998462SApril.Chin@Sun.COM 						sp = stack_shift(stkp,sp,dp+1);
22004887Schin 						dp = sp-2;
22014887Schin 					}
22024887Schin 					*dp++ = '\\';
22034887Schin 				}
22044887Schin 				if(ep)
22054887Schin 					*dp++ = *sp++;
22064887Schin 				break;
22074887Schin 			}
22084887Schin 			n = *sp;
22094887Schin #if SHOPT_DOS
22104887Schin 			if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
22114887Schin 				break;
22124887Schin #endif /* SHOPT_DOS */
22134887Schin 			if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
22144887Schin 			{
22154887Schin 				if(n=='\n')
22164887Schin 					dp--;
22174887Schin 				else
22184887Schin 					dp[-1] = n;
22194887Schin 				sp++;
22204887Schin 			}
22214887Schin 			break;
22224887Schin 		    case S_POP:
22234887Schin 			if(sp[-1]!=RBRACT)
22244887Schin 				break;
22254887Schin 			if(!inlit && !(inquote&1))
22264887Schin 			{
22274887Schin 				inquote >>= 1;
22284887Schin 				if(xp)
22294887Schin 					dp = sh_checkid(xp,dp);
22304887Schin 				xp = 0;
22314887Schin 				if(--bracket<=0 && mode<0)
22324887Schin 					inquote = 1;
22334887Schin 			}
22344887Schin 			else if((inlit||inquote) && mode<0)
22354887Schin 			{
22364887Schin 				dp[-1] = '\\';
22374887Schin 				if(dp>=sp)
22384887Schin 				{
22398462SApril.Chin@Sun.COM 					sp = stack_shift(stkp,sp,dp);
22404887Schin 					dp = sp-1;
22414887Schin 				}
22424887Schin 				*dp++ = ']';
22434887Schin 			}
22444887Schin 			break;
22454887Schin 		    case S_BRACT:
22464887Schin 			if(dp[-2]=='.')
22474887Schin 				xp = dp;
22484887Schin 			if(mode<0)
22494887Schin 			{
22504887Schin 				if(inlit || (bracket&&inquote))
22514887Schin 				{
22524887Schin 					dp[-1] = '\\';
22534887Schin 					if(dp>=sp)
22544887Schin 					{
22558462SApril.Chin@Sun.COM 						sp = stack_shift(stkp,sp,dp);
22564887Schin 						dp = sp-1;
22574887Schin 					}
22584887Schin 					*dp++ = '[';
22594887Schin 				}
22604887Schin 				else if(bracket++==0)
22614887Schin 					inquote = 0;
22624887Schin 			}
22634887Schin 			break;
22644887Schin 		}
22654887Schin #if SHOPT_MULTIBYTE
22664887Schin 		if(mbwide())
22674887Schin 		{
22684887Schin 			do
22694887Schin 			{
22704887Schin 				int len;
22714887Schin 				switch(len = mbsize(sp))
22724887Schin 				{
22734887Schin 				    case -1: /* illegal multi-byte char */
22744887Schin 				    case 0:
22754887Schin 				    case 1:
22764887Schin 					n=state[*dp++ = *sp++];
22774887Schin 					break;
22784887Schin 				    default:
22794887Schin 					/*
22804887Schin 					 * None of the state tables contain
22814887Schin 					 * entries for multibyte characters,
22824887Schin 					 * however, they should be treated
22834887Schin 					 * the same as any other alph
22844887Schin 					 * character.  Therefore, we'll use
22854887Schin 					 * the state of the 'a' character.
22864887Schin 					 */
22874887Schin 					while(len--)
22884887Schin 						*dp++ = *sp++;
22894887Schin 					n=state['a'];
22904887Schin 				}
22914887Schin 			}
22924887Schin 			while(n == 0);
22934887Schin 		}
22944887Schin 		else
22954887Schin #endif /* SHOPT_MULTIBYTE */
22964887Schin 		while((n=state[*dp++ = *sp++])==0);
22974887Schin 	}
22984887Schin }
22994887Schin 
23004887Schin struct alias
23014887Schin {
23024887Schin 	Sfdisc_t	disc;
23034887Schin 	Namval_t	*np;
23044887Schin 	int		nextc;
23054887Schin 	int		line;
23064887Schin 	char		buf[2];
23074887Schin 	Lex_t		*lp;
23084887Schin };
23094887Schin 
23104887Schin /*
23114887Schin  * This code gets called whenever an end of string is found with alias
23124887Schin  */
23134887Schin 
23144887Schin #ifndef SF_ATEXIT
23154887Schin #   define SF_ATEXIT	0
23164887Schin #endif
23174887Schin /*
23184887Schin  * This code gets called whenever an end of string is found with alias
23194887Schin  */
23204887Schin #ifdef SF_BUFCONST
alias_exceptf(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)23214887Schin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
23224887Schin #else
23234887Schin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
23244887Schin #endif
23254887Schin {
23264887Schin 	register struct alias *ap = (struct alias*)handle;
23274887Schin 	register Namval_t *np;
23284887Schin 	register Lex_t	*lp;
23294887Schin 	if(type==0 || type==SF_ATEXIT || !ap)
23304887Schin 		return(0);
23314887Schin 	lp = ap->lp;
23324887Schin 	np = ap->np;
23334887Schin 	if(type!=SF_READ)
23344887Schin 	{
23354887Schin 		if(type==SF_CLOSING)
23364887Schin 		{
23374887Schin 			register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
23384887Schin 			if(dp!=handle)
23394887Schin 				sfdisc(iop,dp);
23404887Schin 		}
23414887Schin 		else if(type==SF_FINAL)
23424887Schin 			free((void*)ap);
23434887Schin 		goto done;
23444887Schin 	}
23454887Schin 	if(ap->nextc)
23464887Schin 	{
23474887Schin 		/* if last character is a blank, then next work can be alias */
23484887Schin 		register int c = fcpeek(-1);
23494887Schin 		if(isblank(c))
23508462SApril.Chin@Sun.COM 			lp->aliasok = 1;
23514887Schin 		*ap->buf = ap->nextc;
23524887Schin 		ap->nextc = 0;
23534887Schin 		sfsetbuf(iop,ap->buf,1);
23544887Schin 		return(1);
23554887Schin 	}
23564887Schin done:
23574887Schin 	if(np)
23584887Schin 		nv_offattr(np,NV_NOEXPAND);
23594887Schin 	return(0);
23604887Schin }
23614887Schin 
23624887Schin 
setupalias(Lex_t * lp,const char * string,Namval_t * np)23634887Schin static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
23644887Schin {
23654887Schin 	register Sfio_t *iop, *base;
23664887Schin 	struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
23674887Schin 	ap->disc = alias_disc;
23684887Schin 	ap->lp = lp;
23694887Schin 	ap->buf[1] = 0;
23704887Schin 	if(ap->np = np)
23714887Schin 	{
23724887Schin #if SHOPT_KIA
23738462SApril.Chin@Sun.COM 		if(lp->kiafile)
23744887Schin 		{
23754887Schin 			unsigned long r;
23768462SApril.Chin@Sun.COM 			r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
23778462SApril.Chin@Sun.COM 			sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
23784887Schin 		}
23794887Schin #endif /* SHOPT_KIA */
23804887Schin 		if((ap->nextc=fcget())==0)
23814887Schin 			ap->nextc = ' ';
23824887Schin 	}
23834887Schin 	else
23844887Schin 		ap->nextc = 0;
23854887Schin 	iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
23864887Schin 	sfdisc(iop, &ap->disc);
23878462SApril.Chin@Sun.COM 	lp->lexd.nocopy++;
23884887Schin 	if(!(base=fcfile()))
23894887Schin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
23904887Schin 	fcclose();
23914887Schin 	sfstack(base,iop);
23924887Schin 	fcfopen(base);
23938462SApril.Chin@Sun.COM 	lp->lexd.nocopy--;
23944887Schin }
23954887Schin 
23964887Schin /*
23974887Schin  * grow storage stack for nested constructs by STACK_ARRAY
23984887Schin  */
stack_grow(Lex_t * lp)23994887Schin static int stack_grow(Lex_t *lp)
24004887Schin {
24018462SApril.Chin@Sun.COM 	lp->lexd.lex_max += STACK_ARRAY;
24028462SApril.Chin@Sun.COM 	if(lp->lexd.lex_match)
24038462SApril.Chin@Sun.COM 		lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
24044887Schin 	else
24058462SApril.Chin@Sun.COM 		lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
24068462SApril.Chin@Sun.COM 	return(lp->lexd.lex_match!=0);
24074887Schin }
24084887Schin 
2409