xref: /onnv-gate/usr/src/lib/libshell/common/sh/parse.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  * UNIX shell
234887Schin  *
244887Schin  * S. R. Bourne
254887Schin  * Rewritten by David Korn
264887Schin  * AT&T Labs
274887Schin  *
284887Schin  *  This is the parser for a shell language
294887Schin  */
304887Schin 
314887Schin #if KSHELL
324887Schin #include	"defs.h"
334887Schin #else
344887Schin #include	<shell.h>
3510898Sroland.mainz@nrubsig.org #include	<ctype.h>
364887Schin #endif
374887Schin #include	<fcin.h>
384887Schin #include	<error.h>
394887Schin #include	"shlex.h"
404887Schin #include	"history.h"
414887Schin #include	"builtins.h"
424887Schin #include	"test.h"
434887Schin #include	"history.h"
444887Schin 
454887Schin #define HERE_MEM	1024	/* size of here-docs kept in memory */
464887Schin 
474887Schin #define hash	nvlink.hl._hash
484887Schin 
494887Schin /* These routines are local to this module */
504887Schin 
518462SApril.Chin@Sun.COM static Shnode_t	*makeparent(Lex_t*, int, Shnode_t*);
528462SApril.Chin@Sun.COM static Shnode_t	*makelist(Lex_t*, int, Shnode_t*, Shnode_t*);
534887Schin static struct argnod	*qscan(struct comnod*, int);
548462SApril.Chin@Sun.COM static struct ionod	*inout(Lex_t*,struct ionod*, int);
558462SApril.Chin@Sun.COM static Shnode_t	*sh_cmd(Lex_t*,int,int);
568462SApril.Chin@Sun.COM static Shnode_t	*term(Lex_t*,int);
578462SApril.Chin@Sun.COM static Shnode_t	*list(Lex_t*,int);
588462SApril.Chin@Sun.COM static struct regnod	*syncase(Lex_t*,int);
598462SApril.Chin@Sun.COM static Shnode_t	*item(Lex_t*,int);
608462SApril.Chin@Sun.COM static Shnode_t	*simple(Lex_t*,int, struct ionod*);
618462SApril.Chin@Sun.COM static int	skipnl(Lex_t*,int);
628462SApril.Chin@Sun.COM static Shnode_t	*test_expr(Lex_t*,int);
638462SApril.Chin@Sun.COM static Shnode_t	*test_and(Lex_t*);
648462SApril.Chin@Sun.COM static Shnode_t	*test_or(Lex_t*);
658462SApril.Chin@Sun.COM static Shnode_t	*test_primary(Lex_t*);
664887Schin 
678462SApril.Chin@Sun.COM #define	sh_getlineno(lp)	(lp->lastline)
684887Schin 
694887Schin #ifndef NIL
704887Schin #   define NIL(type)	((type)0)
714887Schin #endif /* NIL */
724887Schin #define CNTL(x)		((x)&037)
734887Schin 
744887Schin 
754887Schin #if !KSHELL
764887Schin static struct stdata
774887Schin {
784887Schin 	struct slnod    *staklist;
794887Schin 	int	cmdline;
804887Schin } st;
814887Schin #endif
824887Schin 
838462SApril.Chin@Sun.COM static int		opt_get;
844887Schin static int		loop_level;
854887Schin static struct argnod	*label_list;
864887Schin static struct argnod	*label_last;
874887Schin 
884887Schin #define getnode(type)	((Shnode_t*)stakalloc(sizeof(struct type)))
894887Schin 
904887Schin #if SHOPT_KIA
914887Schin #include	"path.h"
924887Schin /*
934887Schin  * write out entities for each item in the list
944887Schin  * type=='V' for variable assignment lists
954887Schin  * Otherwise type is determined by the command */
writedefs(Lex_t * lexp,struct argnod * arglist,int line,int type,struct argnod * cmd)968462SApril.Chin@Sun.COM static unsigned long writedefs(Lex_t *lexp,struct argnod *arglist, int line, int type, struct argnod *cmd)
974887Schin {
984887Schin 	register struct argnod *argp = arglist;
994887Schin 	register char *cp;
1004887Schin 	register int n,eline;
1014887Schin 	int width=0;
1024887Schin 	unsigned long r=0;
1034887Schin 	static char atbuff[20];
1044887Schin 	int  justify=0;
1054887Schin 	char *attribute = atbuff;
1068462SApril.Chin@Sun.COM 	unsigned long parent=lexp->script;
1074887Schin 	if(type==0)
1084887Schin 	{
1098462SApril.Chin@Sun.COM 		parent = lexp->current;
1104887Schin 		type = 'v';
1114887Schin 		switch(*argp->argval)
1124887Schin 		{
1134887Schin 		    case 'a':
1144887Schin 			type='p';
1154887Schin 			justify = 'a';
1164887Schin 			break;
1174887Schin 		    case 'e':
1184887Schin 			*attribute++ =  'x';
1194887Schin 			break;
1204887Schin 		    case 'r':
1214887Schin 			*attribute++ = 'r';
1224887Schin 			break;
1234887Schin 		    case 'l':
1244887Schin 			break;
1254887Schin 		}
1264887Schin 		while(argp = argp->argnxt.ap)
1274887Schin 		{
1284887Schin 			if((n= *(cp=argp->argval))!='-' && n!='+')
1294887Schin 				break;
1304887Schin 			if(cp[1]==n)
1314887Schin 				break;
1324887Schin 			while((n= *++cp))
1334887Schin 			{
1344887Schin 				if(isdigit(n))
1354887Schin 					width = 10*width + n-'0';
1364887Schin 				else if(n=='L' || n=='R' || n =='Z')
1374887Schin 					justify=n;
1384887Schin 				else
1394887Schin 					*attribute++ = n;
1404887Schin 			}
1414887Schin 		}
1424887Schin 	}
1434887Schin 	else if(cmd)
1448462SApril.Chin@Sun.COM 		parent=kiaentity(lexp,sh_argstr(cmd),-1,'p',-1,-1,lexp->unknown,'b',0,"");
1454887Schin 	*attribute = 0;
1464887Schin 	while(argp)
1474887Schin 	{
1484887Schin 		if((cp=strchr(argp->argval,'='))||(cp=strchr(argp->argval,'?')))
1494887Schin 			n = cp-argp->argval;
1504887Schin 		else
1514887Schin 			n = strlen(argp->argval);
1528462SApril.Chin@Sun.COM 		eline = lexp->sh->inlineno-(lexp->token==NL);
1538462SApril.Chin@Sun.COM 		r=kiaentity(lexp,argp->argval,n,type,line,eline,parent,justify,width,atbuff);
1548462SApril.Chin@Sun.COM 		sfprintf(lexp->kiatmp,"p;%..64d;v;%..64d;%d;%d;s;\n",lexp->current,r,line,eline);
1554887Schin 		argp = argp->argnxt.ap;
1564887Schin 	}
1574887Schin 	return(r);
1584887Schin }
1594887Schin #endif /* SHOPT_KIA */
1608462SApril.Chin@Sun.COM 
typeset_order(const char * str,int line)1618462SApril.Chin@Sun.COM static void typeset_order(const char *str,int line)
1628462SApril.Chin@Sun.COM {
1638462SApril.Chin@Sun.COM 	register int		c,n=0;
1648462SApril.Chin@Sun.COM 	unsigned const char	*cp=(unsigned char*)str;
1658462SApril.Chin@Sun.COM 	static unsigned char	*table;
1668462SApril.Chin@Sun.COM 	if(*cp!='+' && *cp!='-')
1678462SApril.Chin@Sun.COM 		return;
1688462SApril.Chin@Sun.COM 	if(!table)
1698462SApril.Chin@Sun.COM 	{
1708462SApril.Chin@Sun.COM 		table = calloc(1,256);
1718462SApril.Chin@Sun.COM 		for(cp=(unsigned char*)"bflmnprstuxACHS";c = *cp; cp++)
1728462SApril.Chin@Sun.COM 			table[c] = 1;
1738462SApril.Chin@Sun.COM 		for(cp=(unsigned char*)"aiEFLRXhTZ";c = *cp; cp++)
1748462SApril.Chin@Sun.COM 			table[c] = 2;
1758462SApril.Chin@Sun.COM 		for(c='0'; c <='9'; c++)
1768462SApril.Chin@Sun.COM 			table[c] = 3;
1778462SApril.Chin@Sun.COM 	}
1788462SApril.Chin@Sun.COM 	for(cp=(unsigned char*)str; c= *cp++; n=table[c])
1798462SApril.Chin@Sun.COM 	{
1808462SApril.Chin@Sun.COM 		if(table[c] < n)
1818462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_warn(0),e_lextypeset,line,str);
1828462SApril.Chin@Sun.COM 	}
1838462SApril.Chin@Sun.COM }
1848462SApril.Chin@Sun.COM 
1858462SApril.Chin@Sun.COM /*
1868462SApril.Chin@Sun.COM  * add type definitions when compiling with -n
1878462SApril.Chin@Sun.COM  */
check_typedef(struct comnod * tp)1888462SApril.Chin@Sun.COM static void check_typedef(struct comnod *tp)
1898462SApril.Chin@Sun.COM {
1908462SApril.Chin@Sun.COM 	char	*cp=0;
1918462SApril.Chin@Sun.COM 	if(tp->comtyp&COMSCAN)
1928462SApril.Chin@Sun.COM 	{
1938462SApril.Chin@Sun.COM 		struct argnod *ap = tp->comarg;
1948462SApril.Chin@Sun.COM 		while(ap = ap->argnxt.ap)
1958462SApril.Chin@Sun.COM 		{
1968462SApril.Chin@Sun.COM 			if(!(ap->argflag&ARG_RAW) || memcmp(ap->argval,"--",2))
1978462SApril.Chin@Sun.COM 				break;
1988462SApril.Chin@Sun.COM 			if(sh_isoption(SH_NOEXEC))
1998462SApril.Chin@Sun.COM 				typeset_order(ap->argval,tp->comline);
2008462SApril.Chin@Sun.COM 			if(memcmp(ap->argval,"-T",2)==0)
2018462SApril.Chin@Sun.COM 			{
2028462SApril.Chin@Sun.COM 				if(ap->argval[2])
2038462SApril.Chin@Sun.COM 					cp = ap->argval+2;
2048462SApril.Chin@Sun.COM 				else if((ap->argnxt.ap)->argflag&ARG_RAW)
2058462SApril.Chin@Sun.COM 					cp = (ap->argnxt.ap)->argval;
2068462SApril.Chin@Sun.COM 				if(cp)
2078462SApril.Chin@Sun.COM 					break;
2088462SApril.Chin@Sun.COM 			}
2098462SApril.Chin@Sun.COM 		}
2108462SApril.Chin@Sun.COM 	}
2118462SApril.Chin@Sun.COM 	else
2128462SApril.Chin@Sun.COM 	{
2138462SApril.Chin@Sun.COM 		struct dolnod *dp = (struct dolnod*)tp->comarg;
2148462SApril.Chin@Sun.COM 		char **argv = dp->dolval + dp->dolbot+1;
2158462SApril.Chin@Sun.COM 		while((cp= *argv++) && memcmp(cp,"--",2))
2168462SApril.Chin@Sun.COM 		{
2178462SApril.Chin@Sun.COM 			if(sh_isoption(SH_NOEXEC))
2188462SApril.Chin@Sun.COM 				typeset_order(cp,tp->comline);
2198462SApril.Chin@Sun.COM 			if(memcmp(cp,"-T",2)==0)
2208462SApril.Chin@Sun.COM 			{
2218462SApril.Chin@Sun.COM 				if(cp[2])
2228462SApril.Chin@Sun.COM 					cp = cp+2;
2238462SApril.Chin@Sun.COM 				else
2248462SApril.Chin@Sun.COM 					cp = *argv;
2258462SApril.Chin@Sun.COM 				break;
2268462SApril.Chin@Sun.COM 			}
2278462SApril.Chin@Sun.COM 		}
2288462SApril.Chin@Sun.COM 	}
2298462SApril.Chin@Sun.COM 	if(cp)
2308462SApril.Chin@Sun.COM 	{
2318462SApril.Chin@Sun.COM 		Namval_t	*mp=(Namval_t*)tp->comnamp ,*bp;
2328462SApril.Chin@Sun.COM 		bp = sh_addbuiltin(cp,mp->nvalue.bfp, (void*)0);
2338462SApril.Chin@Sun.COM 		nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
2348462SApril.Chin@Sun.COM 	}
2358462SApril.Chin@Sun.COM }
2368462SApril.Chin@Sun.COM 
2374887Schin /*
2384887Schin  * Make a parent node for fork() or io-redirection
2394887Schin  */
makeparent(Lex_t * lp,int flag,Shnode_t * child)2408462SApril.Chin@Sun.COM static Shnode_t	*makeparent(Lex_t *lp, int flag, Shnode_t *child)
2414887Schin {
2424887Schin 	register Shnode_t	*par = getnode(forknod);
2434887Schin 	par->fork.forktyp = flag;
2444887Schin 	par->fork.forktre = child;
2454887Schin 	par->fork.forkio = 0;
2468462SApril.Chin@Sun.COM 	par->fork.forkline = sh_getlineno(lp)-1;
2474887Schin 	return(par);
2484887Schin }
2494887Schin 
paramsub(const char * str)250*12068SRoger.Faulkner@Oracle.COM static int paramsub(const char *str)
251*12068SRoger.Faulkner@Oracle.COM {
252*12068SRoger.Faulkner@Oracle.COM 	register int c,sub=0,lit=0;
253*12068SRoger.Faulkner@Oracle.COM 	while(c= *str++)
254*12068SRoger.Faulkner@Oracle.COM 	{
255*12068SRoger.Faulkner@Oracle.COM 		if(c=='$' && !lit)
256*12068SRoger.Faulkner@Oracle.COM 		{
257*12068SRoger.Faulkner@Oracle.COM 			if(*str=='(')
258*12068SRoger.Faulkner@Oracle.COM 				return(0);
259*12068SRoger.Faulkner@Oracle.COM 			if(sub)
260*12068SRoger.Faulkner@Oracle.COM 				continue;
261*12068SRoger.Faulkner@Oracle.COM 			if(*str=='{')
262*12068SRoger.Faulkner@Oracle.COM 				str++;
263*12068SRoger.Faulkner@Oracle.COM 			if(!isdigit(*str) && strchr("?#@*!$ ",*str)==0)
264*12068SRoger.Faulkner@Oracle.COM 				return(1);
265*12068SRoger.Faulkner@Oracle.COM 		}
266*12068SRoger.Faulkner@Oracle.COM 		else if(c=='`')
267*12068SRoger.Faulkner@Oracle.COM 			return(0);
268*12068SRoger.Faulkner@Oracle.COM 		else if(c=='[' && !lit)
269*12068SRoger.Faulkner@Oracle.COM 			sub++;
270*12068SRoger.Faulkner@Oracle.COM 		else if(c==']' && !lit)
271*12068SRoger.Faulkner@Oracle.COM 			sub--;
272*12068SRoger.Faulkner@Oracle.COM 		else if(c=='\'')
273*12068SRoger.Faulkner@Oracle.COM 			lit = !lit;
274*12068SRoger.Faulkner@Oracle.COM 	}
275*12068SRoger.Faulkner@Oracle.COM 	return(0);
276*12068SRoger.Faulkner@Oracle.COM }
277*12068SRoger.Faulkner@Oracle.COM 
getanode(Lex_t * lp,struct argnod * ap)2788462SApril.Chin@Sun.COM static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
2794887Schin {
2804887Schin 	register Shnode_t *t = getnode(arithnod);
2814887Schin 	t->ar.artyp = TARITH;
2828462SApril.Chin@Sun.COM 	t->ar.arline = sh_getlineno(lp);
2834887Schin 	t->ar.arexpr = ap;
2844887Schin 	if(ap->argflag&ARG_RAW)
2854887Schin 		t->ar.arcomp = sh_arithcomp(ap->argval);
2864887Schin 	else
287*12068SRoger.Faulkner@Oracle.COM 	{
288*12068SRoger.Faulkner@Oracle.COM 		if(sh_isoption(SH_NOEXEC) && (ap->argflag&ARG_MAC) && paramsub(ap->argval))
289*12068SRoger.Faulkner@Oracle.COM 			errormsg(SH_DICT,ERROR_warn(0),"%d: parameter substitution requires unnecessary string to number conversion",lp->sh->inlineno-(lp->token=='\n'));
2904887Schin 		t->ar.arcomp = 0;
291*12068SRoger.Faulkner@Oracle.COM 	}
2924887Schin 	return(t);
2934887Schin }
2944887Schin 
2954887Schin /*
2964887Schin  *  Make a node corresponding to a command list
2974887Schin  */
makelist(Lex_t * lexp,int type,Shnode_t * l,Shnode_t * r)2988462SApril.Chin@Sun.COM static Shnode_t	*makelist(Lex_t *lexp, int type, Shnode_t *l, Shnode_t *r)
2994887Schin {
3004887Schin 	register Shnode_t	*t;
3014887Schin 	if(!l || !r)
3028462SApril.Chin@Sun.COM 		sh_syntax(lexp);
3034887Schin 	else
3044887Schin 	{
3054887Schin 		if((type&COMMSK) == TTST)
3064887Schin 			t = getnode(tstnod);
3074887Schin 		else
3084887Schin 			t = getnode(lstnod);
3094887Schin 		t->lst.lsttyp = type;
3104887Schin 		t->lst.lstlef = l;
3114887Schin 		t->lst.lstrit = r;
3124887Schin 	}
3134887Schin 	return(t);
3144887Schin }
3154887Schin 
3164887Schin /*
3174887Schin  * entry to shell parser
3184887Schin  * Flag can be the union of SH_EOF|SH_NL
3194887Schin  */
3204887Schin 
sh_parse(Shell_t * shp,Sfio_t * iop,int flag)3214887Schin void	*sh_parse(Shell_t *shp, Sfio_t *iop, int flag)
3224887Schin {
3234887Schin 	register Shnode_t	*t;
3248462SApril.Chin@Sun.COM 	Lex_t			*lexp = (Lex_t*)shp->lex_context;
3254887Schin 	Fcin_t	sav_input;
3268462SApril.Chin@Sun.COM 	struct argnod *sav_arg = lexp->arg;
3274887Schin 	int	sav_prompt = shp->nextprompt;
32810898Sroland.mainz@nrubsig.org 	if(shp->binscript && (sffileno(iop)==shp->infd || (flag&SH_FUNEVAL)))
3298462SApril.Chin@Sun.COM 		return((void*)sh_trestore(shp,iop));
3304887Schin 	fcsave(&sav_input);
3314887Schin 	shp->st.staklist = 0;
3328462SApril.Chin@Sun.COM 	lexp->heredoc = 0;
3338462SApril.Chin@Sun.COM 	lexp->inlineno = shp->inlineno;
3348462SApril.Chin@Sun.COM 	lexp->firstline = shp->st.firstline;
3354887Schin 	shp->nextprompt = 1;
3364887Schin 	loop_level = 0;
3374887Schin 	label_list = label_last = 0;
3384887Schin 	if(sh_isoption(SH_INTERACTIVE))
3394887Schin 		sh_onstate(SH_INTERACTIVE);
3404887Schin 	if(sh_isoption(SH_VERBOSE))
3414887Schin 		sh_onstate(SH_VERBOSE);
3428462SApril.Chin@Sun.COM 	sh_lexopen(lexp,shp,0);
3434887Schin 	if(fcfopen(iop) < 0)
3444887Schin 		return(NIL(void*));
3454887Schin 	if(fcfile())
3464887Schin 	{
3474887Schin 		char *cp = fcfirst();
3484887Schin 		if( cp[0]==CNTL('k') &&  cp[1]==CNTL('s') && cp[2]==CNTL('h') && cp[3]==0)
3494887Schin 		{
3504887Schin 			int version;
3514887Schin 			fcseek(4);
3524887Schin 			fcgetc(version);
3534887Schin 			fcclose();
3544887Schin 			fcrestore(&sav_input);
3558462SApril.Chin@Sun.COM 			lexp->arg = sav_arg;
3564887Schin 			if(version > 3)
3574887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_lexversion);
35810898Sroland.mainz@nrubsig.org 			if(sffileno(iop)==shp->infd || (flag&SH_FUNEVAL))
3594887Schin 				shp->binscript = 1;
3604887Schin 			sfgetc(iop);
3618462SApril.Chin@Sun.COM 			return((void*)sh_trestore(shp,iop));
3624887Schin 		}
3634887Schin 	}
36410898Sroland.mainz@nrubsig.org 	flag &= ~SH_FUNEVAL;
3654887Schin 	if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0)
3664887Schin 		shp->inlineno=1;
3674887Schin #if KSHELL
3684887Schin 	shp->nextprompt = 2;
3694887Schin #endif
3708462SApril.Chin@Sun.COM 	t = sh_cmd(lexp,(flag&SH_EOF)?EOFSYM:'\n',SH_SEMI|SH_EMPTY|(flag&SH_NL));
3714887Schin 	fcclose();
3724887Schin 	fcrestore(&sav_input);
3738462SApril.Chin@Sun.COM 	lexp->arg = sav_arg;
3744887Schin 	/* unstack any completed alias expansions */
3754887Schin 	if((sfset(iop,0,0)&SF_STRING) && !sfreserve(iop,0,-1))
3764887Schin 	{
3774887Schin 		Sfio_t *sp = sfstack(iop,NULL);
3784887Schin 		if(sp)
3794887Schin 			sfclose(sp);
3804887Schin 	}
3814887Schin 	shp->nextprompt = sav_prompt;
3824887Schin 	if(flag&SH_NL)
3834887Schin 	{
3848462SApril.Chin@Sun.COM 		shp->st.firstline = lexp->firstline;
3858462SApril.Chin@Sun.COM 		shp->inlineno = lexp->inlineno;
3864887Schin 	}
3878462SApril.Chin@Sun.COM 	stkseek(shp->stk,0);
3884887Schin 	return((void*)t);
3894887Schin }
3904887Schin 
3914887Schin /*
3924887Schin  * This routine parses up the matching right parenthesis and returns
3934887Schin  * the parse tree
3944887Schin  */
sh_dolparen(Lex_t * lp)3958462SApril.Chin@Sun.COM Shnode_t *sh_dolparen(Lex_t* lp)
3964887Schin {
3974887Schin 	register Shnode_t *t=0;
3984887Schin 	Sfio_t *sp = fcfile();
3998462SApril.Chin@Sun.COM 	int line = lp->sh->inlineno;
4008462SApril.Chin@Sun.COM 	lp->sh->inlineno = error_info.line+lp->sh->st.firstline;
4018462SApril.Chin@Sun.COM 	sh_lexopen(lp,lp->sh,1);
4028462SApril.Chin@Sun.COM 	lp->comsub = 1;
4038462SApril.Chin@Sun.COM 	switch(sh_lex(lp))
4044887Schin 	{
4054887Schin 	    /* ((...)) arithmetic expression */
4064887Schin 	    case EXPRSYM:
4078462SApril.Chin@Sun.COM 		t = getanode(lp,lp->arg);
4084887Schin 		break;
4094887Schin 	    case LPAREN:
4108462SApril.Chin@Sun.COM 		t = sh_cmd(lp,RPAREN,SH_NL|SH_EMPTY);
4118462SApril.Chin@Sun.COM 		break;
4128462SApril.Chin@Sun.COM 	    case LBRACE:
4138462SApril.Chin@Sun.COM 		t = sh_cmd(lp,RBRACE,SH_NL|SH_EMPTY);
4144887Schin 		break;
4154887Schin 	}
4168462SApril.Chin@Sun.COM 	lp->comsub = 0;
4174887Schin 	if(!sp && (sp=fcfile()))
4184887Schin 	{
4194887Schin 		/*
4204887Schin 		 * This code handles the case where string has been converted
4214887Schin 		 * to a file by an alias setup
4224887Schin 		 */
4234887Schin 		register int c;
4244887Schin 		char *cp;
4254887Schin 		if(fcgetc(c) > 0)
4264887Schin 			fcseek(-1);
4274887Schin 		cp = fcseek(0);
4284887Schin 		fcclose();
4294887Schin 		fcsopen(cp);
4304887Schin 		sfclose(sp);
4314887Schin 	}
4328462SApril.Chin@Sun.COM 	lp->sh->inlineno = line;
4334887Schin 	return(t);
4344887Schin }
4354887Schin 
4364887Schin /*
4374887Schin  * remove temporary files and stacks
4384887Schin  */
4394887Schin 
sh_freeup(Shell_t * shp)4408462SApril.Chin@Sun.COM void	sh_freeup(Shell_t *shp)
4414887Schin {
4428462SApril.Chin@Sun.COM 	if(shp->st.staklist)
4438462SApril.Chin@Sun.COM 		sh_funstaks(shp->st.staklist,-1);
4448462SApril.Chin@Sun.COM 	shp->st.staklist = 0;
4454887Schin }
4464887Schin 
4474887Schin /*
4484887Schin  * increase reference count for each stack in function list when flag>0
4494887Schin  * decrease reference count for each stack in function list when flag<=0
4504887Schin  * stack is freed when reference count is zero
4514887Schin  */
4524887Schin 
sh_funstaks(register struct slnod * slp,int flag)4534887Schin void sh_funstaks(register struct slnod *slp,int flag)
4544887Schin {
4554887Schin 	register struct slnod *slpold;
4564887Schin 	while(slpold=slp)
4574887Schin 	{
4584887Schin 		if(slp->slchild)
4594887Schin 			sh_funstaks(slp->slchild,flag);
4604887Schin 		slp = slp->slnext;
4614887Schin 		if(flag<=0)
4624887Schin 			stakdelete(slpold->slptr);
4634887Schin 		else
4644887Schin 			staklink(slpold->slptr);
4654887Schin 	}
4664887Schin }
4674887Schin /*
4684887Schin  * cmd
4694887Schin  *	empty
4704887Schin  *	list
4714887Schin  *	list & [ cmd ]
4724887Schin  *	list [ ; cmd ]
4734887Schin  */
4744887Schin 
sh_cmd(Lex_t * lexp,register int sym,int flag)4758462SApril.Chin@Sun.COM static Shnode_t	*sh_cmd(Lex_t *lexp, register int sym, int flag)
4764887Schin {
4774887Schin 	register Shnode_t	*left, *right;
4784887Schin 	register int type = FINT|FAMP;
4794887Schin 	if(sym==NL)
4808462SApril.Chin@Sun.COM 		lexp->lasttok = 0;
4818462SApril.Chin@Sun.COM 	left = list(lexp,flag);
4828462SApril.Chin@Sun.COM 	if(lexp->token==NL)
4834887Schin 	{
4844887Schin 		if(flag&SH_NL)
4858462SApril.Chin@Sun.COM 			lexp->token=';';
4864887Schin 	}
4874887Schin 	else if(!left && !(flag&SH_EMPTY))
4888462SApril.Chin@Sun.COM 		sh_syntax(lexp);
4898462SApril.Chin@Sun.COM 	switch(lexp->token)
4904887Schin 	{
4914887Schin 	    case COOPSYM:		/* set up a cooperating process */
4924887Schin 		type |= (FPIN|FPOU|FPCL|FCOOP);
4934887Schin 		/* FALL THRU */
4944887Schin 	    case '&':
4954887Schin 		if(left)
4964887Schin 		{
4974887Schin 			/* (...)& -> {...;} & */
4984887Schin 			if(left->tre.tretyp==TPAR)
4994887Schin 				left = left->par.partre;
5008462SApril.Chin@Sun.COM 			left = makeparent(lexp,TFORK|type, left);
5014887Schin 		}
5024887Schin 		/* FALL THRU */
5034887Schin 	    case ';':
5044887Schin 		if(!left)
5058462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5068462SApril.Chin@Sun.COM 		if(right=sh_cmd(lexp,sym,flag|SH_EMPTY))
5078462SApril.Chin@Sun.COM 			left=makelist(lexp,TLST, left, right);
5084887Schin 		break;
5094887Schin 	    case EOFSYM:
5104887Schin 		if(sym==NL)
5114887Schin 			break;
5124887Schin 	    default:
5138462SApril.Chin@Sun.COM 		if(sym && sym!=lexp->token)
5144887Schin 		{
5158462SApril.Chin@Sun.COM 			if(sym!=ELSESYM || (lexp->token!=ELIFSYM && lexp->token!=FISYM))
5168462SApril.Chin@Sun.COM 				sh_syntax(lexp);
5174887Schin 		}
5184887Schin 	}
5194887Schin 	return(left);
5204887Schin }
5214887Schin 
5224887Schin /*
5234887Schin  * list
5244887Schin  *	term
5254887Schin  *	list && term
5264887Schin  *	list || term
5274887Schin  *      unfortunately, these are equal precedence
5284887Schin  */
list(Lex_t * lexp,register int flag)5298462SApril.Chin@Sun.COM static Shnode_t	*list(Lex_t *lexp, register int flag)
5304887Schin {
5318462SApril.Chin@Sun.COM 	register Shnode_t	*t = term(lexp,flag);
5324887Schin 	register int 	token;
5338462SApril.Chin@Sun.COM 	while(t && ((token=lexp->token)==ANDFSYM || token==ORFSYM))
5348462SApril.Chin@Sun.COM 		t = makelist(lexp,(token==ANDFSYM?TAND:TORF), t, term(lexp,SH_NL|SH_SEMI));
5354887Schin 	return(t);
5364887Schin }
5374887Schin 
5384887Schin /*
5394887Schin  * term
5404887Schin  *	item
5414887Schin  *	item | term
5424887Schin  */
term(Lex_t * lexp,register int flag)5438462SApril.Chin@Sun.COM static Shnode_t	*term(Lex_t *lexp,register int flag)
5444887Schin {
5454887Schin 	register Shnode_t	*t;
5464887Schin 	register int token;
5474887Schin 	if(flag&SH_NL)
5488462SApril.Chin@Sun.COM 		token = skipnl(lexp,flag);
5494887Schin 	else
5508462SApril.Chin@Sun.COM 		token = sh_lex(lexp);
5514887Schin 	/* check to see if pipeline is to be timed */
5524887Schin 	if(token==TIMESYM || token==NOTSYM)
5534887Schin 	{
5544887Schin 		t = getnode(parnod);
5554887Schin 		t->par.partyp=TTIME;
5568462SApril.Chin@Sun.COM 		if(lexp->token==NOTSYM)
5574887Schin 			t->par.partyp |= COMSCAN;
5588462SApril.Chin@Sun.COM 		t->par.partre = term(lexp,0);
5594887Schin 	}
5608462SApril.Chin@Sun.COM 	else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && lexp->token=='|')
5614887Schin 	{
5624887Schin 		register Shnode_t	*tt;
5634887Schin 		int showme = t->tre.tretyp&FSHOWME;
5648462SApril.Chin@Sun.COM 		t = makeparent(lexp,TFORK|FPOU,t);
5658462SApril.Chin@Sun.COM 		if(tt=term(lexp,SH_NL))
5664887Schin 		{
5674887Schin 			switch(tt->tre.tretyp&COMMSK)
5684887Schin 			{
5694887Schin 			    case TFORK:
5704887Schin 				tt->tre.tretyp |= FPIN|FPCL;
5714887Schin 				break;
5724887Schin 			    case TFIL:
5734887Schin 				tt->lst.lstlef->tre.tretyp |= FPIN|FPCL;
5744887Schin 				break;
5754887Schin 			    default:
5768462SApril.Chin@Sun.COM 				tt= makeparent(lexp,TSETIO|FPIN|FPCL,tt);
5774887Schin 			}
5788462SApril.Chin@Sun.COM 			t=makelist(lexp,TFIL,t,tt);
5794887Schin 			t->tre.tretyp |= showme;
5804887Schin 		}
5818462SApril.Chin@Sun.COM 		else if(lexp->token)
5828462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5834887Schin 	}
5844887Schin 	return(t);
5854887Schin }
5864887Schin 
5874887Schin /*
5884887Schin  * case statement
5894887Schin  */
syncase(Lex_t * lexp,register int esym)5908462SApril.Chin@Sun.COM static struct regnod*	syncase(Lex_t *lexp,register int esym)
5914887Schin {
5928462SApril.Chin@Sun.COM 	register int tok = skipnl(lexp,0);
5934887Schin 	register struct regnod	*r;
5944887Schin 	if(tok==esym)
5954887Schin 		return(NIL(struct regnod*));
5964887Schin 	r = (struct regnod*)stakalloc(sizeof(struct regnod));
5974887Schin 	r->regptr=0;
5984887Schin 	r->regflag=0;
5994887Schin 	if(tok==LPAREN)
6008462SApril.Chin@Sun.COM 		skipnl(lexp,0);
6014887Schin 	while(1)
6024887Schin 	{
6038462SApril.Chin@Sun.COM 		if(!lexp->arg)
6048462SApril.Chin@Sun.COM 			sh_syntax(lexp);
6058462SApril.Chin@Sun.COM 		lexp->arg->argnxt.ap=r->regptr;
6068462SApril.Chin@Sun.COM 		r->regptr = lexp->arg;
6078462SApril.Chin@Sun.COM 		if((tok=sh_lex(lexp))==RPAREN)
6084887Schin 			break;
6094887Schin 		else if(tok=='|')
6108462SApril.Chin@Sun.COM 			sh_lex(lexp);
6114887Schin 		else
6128462SApril.Chin@Sun.COM 			sh_syntax(lexp);
6134887Schin 	}
6148462SApril.Chin@Sun.COM 	r->regcom=sh_cmd(lexp,0,SH_NL|SH_EMPTY|SH_SEMI);
6158462SApril.Chin@Sun.COM 	if((tok=lexp->token)==BREAKCASESYM)
6168462SApril.Chin@Sun.COM 		r->regnxt=syncase(lexp,esym);
6174887Schin 	else if(tok==FALLTHRUSYM)
6184887Schin 	{
6194887Schin 		r->regflag++;
6208462SApril.Chin@Sun.COM 		r->regnxt=syncase(lexp,esym);
6214887Schin 	}
6224887Schin 	else
6234887Schin 	{
6244887Schin 		if(tok!=esym && tok!=EOFSYM)
6258462SApril.Chin@Sun.COM 			sh_syntax(lexp);
6264887Schin 		r->regnxt=0;
6274887Schin 	}
6288462SApril.Chin@Sun.COM 	if(lexp->token==EOFSYM)
6294887Schin 		return(NIL(struct regnod*));
6304887Schin 	return(r);
6314887Schin }
6324887Schin 
6334887Schin /*
6344887Schin  * This routine creates the parse tree for the arithmetic for
6354887Schin  * When called, shlex.arg contains the string inside ((...))
6364887Schin  * When the first argument is missing, a while node is returned
6374887Schin  * Otherise a list containing an arithmetic command and a while
6384887Schin  * is returned.
6394887Schin  */
arithfor(Lex_t * lexp,register Shnode_t * tf)6408462SApril.Chin@Sun.COM static Shnode_t	*arithfor(Lex_t *lexp,register Shnode_t *tf)
6414887Schin {
6424887Schin 	register Shnode_t	*t, *tw = tf;
6434887Schin 	register int	offset;
6444887Schin 	register struct argnod *argp;
6454887Schin 	register int n;
6468462SApril.Chin@Sun.COM 	Stk_t		*stkp = lexp->sh->stk;
6478462SApril.Chin@Sun.COM 	int argflag = lexp->arg->argflag;
6484887Schin 	/* save current input */
6494887Schin 	Fcin_t	sav_input;
6504887Schin 	fcsave(&sav_input);
6518462SApril.Chin@Sun.COM 	fcsopen(lexp->arg->argval);
6524887Schin 	/* split ((...)) into three expressions */
6534887Schin 	for(n=0; ; n++)
6544887Schin 	{
6554887Schin 		register int c;
6568462SApril.Chin@Sun.COM 		argp = (struct argnod*)stkseek(stkp,ARGVAL);
6574887Schin 		argp->argnxt.ap = 0;
6584887Schin 		argp->argchn.cp = 0;
6594887Schin 		argp->argflag = argflag;
6604887Schin 		if(n==2)
6614887Schin 			break;
6624887Schin 		/* copy up to ; onto the stack */
6638462SApril.Chin@Sun.COM 		sh_lexskip(lexp,';',1,ST_NESTED);
6648462SApril.Chin@Sun.COM 		offset = stktell(stkp)-1;
6654887Schin 		if((c=fcpeek(-1))!=';')
6664887Schin 			break;
6674887Schin 		/* remove trailing white space */
6688462SApril.Chin@Sun.COM 		while(offset>ARGVAL && ((c= *stkptr(stkp,offset-1)),isspace(c)))
6694887Schin 			offset--;
6704887Schin 		/* check for empty initialization expression  */
6714887Schin 		if(offset==ARGVAL && n==0)
6724887Schin 			continue;
6738462SApril.Chin@Sun.COM 		stkseek(stkp,offset);
6744887Schin 		/* check for empty condition and treat as while((1)) */
6754887Schin 		if(offset==ARGVAL)
6768462SApril.Chin@Sun.COM 			sfputc(stkp,'1');
6778462SApril.Chin@Sun.COM 		argp = (struct argnod*)stkfreeze(stkp,1);
6788462SApril.Chin@Sun.COM 		t = getanode(lexp,argp);
6794887Schin 		if(n==0)
6808462SApril.Chin@Sun.COM 			tf = makelist(lexp,TLST,t,tw);
6814887Schin 		else
6824887Schin 			tw->wh.whtre = t;
6834887Schin 	}
6844887Schin 	while((offset=fcpeek(0)) && isspace(offset))
6854887Schin 		fcseek(1);
6864887Schin 	stakputs(fcseek(0));
6874887Schin 	argp = (struct argnod*)stakfreeze(1);
6884887Schin 	fcrestore(&sav_input);
6894887Schin 	if(n<2)
6904887Schin 	{
6918462SApril.Chin@Sun.COM 		lexp->token = RPAREN|SYMREP;
6928462SApril.Chin@Sun.COM 		sh_syntax(lexp);
6934887Schin 	}
6944887Schin 	/* check whether the increment is present */
6954887Schin 	if(*argp->argval)
6964887Schin 	{
6978462SApril.Chin@Sun.COM 		t = getanode(lexp,argp);
6984887Schin 		tw->wh.whinc = (struct arithnod*)t;
6994887Schin 	}
7004887Schin 	else
7014887Schin 		tw->wh.whinc = 0;
7028462SApril.Chin@Sun.COM 	sh_lexopen(lexp, lexp->sh,1);
7038462SApril.Chin@Sun.COM 	if((n=sh_lex(lexp))==NL)
7048462SApril.Chin@Sun.COM 		n = skipnl(lexp,0);
7054887Schin 	else if(n==';')
7068462SApril.Chin@Sun.COM 		n = sh_lex(lexp);
7074887Schin 	if(n!=DOSYM && n!=LBRACE)
7088462SApril.Chin@Sun.COM 		sh_syntax(lexp);
7098462SApril.Chin@Sun.COM 	tw->wh.dotre = sh_cmd(lexp,n==DOSYM?DONESYM:RBRACE,SH_NL);
7104887Schin 	tw->wh.whtyp = TWH;
7114887Schin 	return(tf);
7124887Schin 
7134887Schin }
7144887Schin 
funct(Lex_t * lexp)7158462SApril.Chin@Sun.COM static Shnode_t *funct(Lex_t *lexp)
7164887Schin {
7178462SApril.Chin@Sun.COM 	Shell_t	*shp = lexp->sh;
7184887Schin 	register Shnode_t *t;
7194887Schin 	register int flag;
7204887Schin 	struct slnod *volatile slp=0;
7214887Schin 	Stak_t *savstak;
7224887Schin 	Sfoff_t	first, last;
7238462SApril.Chin@Sun.COM 	struct functnod *volatile fp;
7244887Schin 	Sfio_t *iop;
7254887Schin #if SHOPT_KIA
7268462SApril.Chin@Sun.COM 	unsigned long current = lexp->current;
7274887Schin #endif /* SHOPT_KIA */
7284887Schin 	int jmpval, saveloop=loop_level;
7294887Schin 	struct argnod *savelabel = label_last;
7304887Schin 	struct  checkpt buff;
7318462SApril.Chin@Sun.COM 	int save_optget = opt_get;
7328462SApril.Chin@Sun.COM 	void	*in_mktype = shp->mktype;
7338462SApril.Chin@Sun.COM 	shp->mktype = 0;
7348462SApril.Chin@Sun.COM 	opt_get = 0;
7354887Schin 	t = getnode(functnod);
7368462SApril.Chin@Sun.COM 	t->funct.functline = shp->inlineno;
7374887Schin 	t->funct.functtyp=TFUN;
7384887Schin 	t->funct.functargs = 0;
7398462SApril.Chin@Sun.COM 	if(!(flag = (lexp->token==FUNCTSYM)))
7404887Schin 		t->funct.functtyp |= FPOSIX;
7418462SApril.Chin@Sun.COM 	else if(sh_lex(lexp))
7428462SApril.Chin@Sun.COM 		sh_syntax(lexp);
7434887Schin 	if(!(iop=fcfile()))
7444887Schin 	{
7454887Schin 		iop = sfopen(NIL(Sfio_t*),fcseek(0),"s");
7464887Schin 		fcclose();
7474887Schin 		fcfopen(iop);
7484887Schin 	}
7494887Schin 	t->funct.functloc = first = fctell();
7508462SApril.Chin@Sun.COM 	if(!shp->st.filename || sffileno(iop)<0)
7514887Schin 	{
7524887Schin 		if(fcfill() >= 0)
7534887Schin 			fcseek(-1);
75410898Sroland.mainz@nrubsig.org 		if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
7558462SApril.Chin@Sun.COM 			t->funct.functloc = sfseek(shp->hist_ptr->histfp,(off_t)0,SEEK_CUR);
7564887Schin 		else
7574887Schin 		{
7584887Schin 			/* copy source to temporary file */
7594887Schin 			t->funct.functloc = 0;
7608462SApril.Chin@Sun.COM 			if(lexp->sh->heredocs)
7618462SApril.Chin@Sun.COM 				t->funct.functloc = sfseek(lexp->sh->heredocs,(Sfoff_t)0, SEEK_END);
7624887Schin 			else
7638462SApril.Chin@Sun.COM 				lexp->sh->heredocs = sftmp(HERE_MEM);
7648462SApril.Chin@Sun.COM 			lexp->sh->funlog = lexp->sh->heredocs;
7654887Schin 			t->funct.functtyp |= FPIN;
7664887Schin 		}
7674887Schin 	}
7688462SApril.Chin@Sun.COM 	t->funct.functnam= (char*)lexp->arg->argval;
7694887Schin #if SHOPT_KIA
7708462SApril.Chin@Sun.COM 	if(lexp->kiafile)
7718462SApril.Chin@Sun.COM 		lexp->current = kiaentity(lexp,t->funct.functnam,-1,'p',-1,-1,lexp->script,'p',0,"");
7724887Schin #endif /* SHOPT_KIA */
7734887Schin 	if(flag)
7744887Schin 	{
7758462SApril.Chin@Sun.COM 		lexp->token = sh_lex(lexp);
7764887Schin #if SHOPT_BASH
7778462SApril.Chin@Sun.COM 		if(lexp->token == LPAREN)
7784887Schin 		{
7798462SApril.Chin@Sun.COM 			if((lexp->token = sh_lex(lexp)) == RPAREN)
7804887Schin 				t->funct.functtyp |= FPOSIX;
7814887Schin 			else
7828462SApril.Chin@Sun.COM 				sh_syntax(lexp);
7834887Schin 		}
7844887Schin #endif
7854887Schin 	}
7864887Schin 	if(t->funct.functtyp&FPOSIX)
7878462SApril.Chin@Sun.COM 		skipnl(lexp,0);
7884887Schin 	else
7894887Schin 	{
7908462SApril.Chin@Sun.COM 		if(lexp->token==0)
7918462SApril.Chin@Sun.COM 			t->funct.functargs = (struct comnod*)simple(lexp,SH_NOIO|SH_FUNDEF,NIL(struct ionod*));
7928462SApril.Chin@Sun.COM 		while(lexp->token==NL)
7938462SApril.Chin@Sun.COM 			lexp->token = sh_lex(lexp);
7944887Schin 	}
7958462SApril.Chin@Sun.COM 	if((flag && lexp->token!=LBRACE) || lexp->token==EOFSYM)
7968462SApril.Chin@Sun.COM 		sh_syntax(lexp);
7974887Schin 	sh_pushcontext(&buff,1);
7984887Schin 	jmpval = sigsetjmp(buff.buff,0);
7994887Schin 	if(jmpval == 0)
8004887Schin 	{
8014887Schin 		/* create a new stak frame to compile the command */
8024887Schin 		savstak = stakcreate(STAK_SMALL);
8034887Schin 		savstak = stakinstall(savstak, 0);
8044887Schin 		slp = (struct slnod*)stakalloc(sizeof(struct slnod)+sizeof(struct functnod));
8054887Schin 		slp->slchild = 0;
8068462SApril.Chin@Sun.COM 		slp->slnext = shp->st.staklist;
8078462SApril.Chin@Sun.COM 		shp->st.staklist = 0;
8084887Schin 		t->funct.functstak = (struct slnod*)slp;
8094887Schin 		/*
8104887Schin 		 * store the pathname of function definition file on stack
8114887Schin 		 * in name field of fake for node
8124887Schin 		 */
8134887Schin 		fp = (struct functnod*)(slp+1);
8144887Schin 		fp->functtyp = TFUN|FAMP;
8154887Schin 		fp->functnam = 0;
8164887Schin 		fp->functline = t->funct.functline;
8178462SApril.Chin@Sun.COM 		if(shp->st.filename)
8188462SApril.Chin@Sun.COM 			fp->functnam = stakcopy(shp->st.filename);
8194887Schin 		loop_level = 0;
8204887Schin 		label_last = label_list;
8218462SApril.Chin@Sun.COM 		if(!flag && lexp->token==0)
8224887Schin 		{
8234887Schin 			/* copy current word token to current stak frame */
8244887Schin 			struct argnod *ap;
8258462SApril.Chin@Sun.COM 			flag = ARGVAL + strlen(lexp->arg->argval);
8264887Schin 			ap = (struct argnod*)stakalloc(flag);
8278462SApril.Chin@Sun.COM 			memcpy(ap,lexp->arg,flag);
8288462SApril.Chin@Sun.COM 			lexp->arg = ap;
8294887Schin 		}
8308462SApril.Chin@Sun.COM 		t->funct.functtre = item(lexp,SH_NOIO);
8314887Schin 	}
832*12068SRoger.Faulkner@Oracle.COM 	else if(shp->shcomp)
833*12068SRoger.Faulkner@Oracle.COM 		exit(1);
8344887Schin 	sh_popcontext(&buff);
8354887Schin 	loop_level = saveloop;
8364887Schin 	label_last = savelabel;
8374887Schin 	/* restore the old stack */
8384887Schin 	if(slp)
8394887Schin 	{
8404887Schin 		slp->slptr =  stakinstall(savstak,0);
8418462SApril.Chin@Sun.COM 		slp->slchild = shp->st.staklist;
8424887Schin 	}
8434887Schin #if SHOPT_KIA
8448462SApril.Chin@Sun.COM 	lexp->current = current;
8454887Schin #endif /* SHOPT_KIA */
8464887Schin 	if(jmpval)
8474887Schin 	{
8484887Schin 		if(slp && slp->slptr)
8494887Schin 		{
8508462SApril.Chin@Sun.COM 			shp->st.staklist = slp->slnext;
8514887Schin 			stakdelete(slp->slptr);
8524887Schin 		}
8538462SApril.Chin@Sun.COM 		siglongjmp(*shp->jmplist,jmpval);
8544887Schin 	}
8558462SApril.Chin@Sun.COM 	shp->st.staklist = (struct slnod*)slp;
8564887Schin 	last = fctell();
8574887Schin 	fp->functline = (last-first);
8584887Schin 	fp->functtre = t;
8598462SApril.Chin@Sun.COM 	shp->mktype = in_mktype;
8608462SApril.Chin@Sun.COM 	if(lexp->sh->funlog)
8614887Schin 	{
8624887Schin 		if(fcfill()>0)
8634887Schin 			fcseek(-1);
8648462SApril.Chin@Sun.COM 		lexp->sh->funlog = 0;
8654887Schin 	}
8664887Schin #if 	SHOPT_KIA
8678462SApril.Chin@Sun.COM 	if(lexp->kiafile)
8688462SApril.Chin@Sun.COM 		kiaentity(lexp,t->funct.functnam,-1,'p',t->funct.functline,shp->inlineno-1,lexp->current,'p',0,"");
8694887Schin #endif /* SHOPT_KIA */
8708462SApril.Chin@Sun.COM 	t->funct.functtyp |= opt_get;
8718462SApril.Chin@Sun.COM 	opt_get = save_optget;
8724887Schin 	return(t);
8734887Schin }
8744887Schin 
8754887Schin /*
8764887Schin  * Compound assignment
8774887Schin  */
assign(Lex_t * lexp,register struct argnod * ap,int tdef)8788462SApril.Chin@Sun.COM static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int tdef)
8794887Schin {
8804887Schin 	register int n;
8814887Schin 	register Shnode_t *t, **tp;
8824887Schin 	register struct comnod *ac;
8838462SApril.Chin@Sun.COM 	Stk_t	*stkp = lexp->sh->stk;
8844887Schin 	int array=0;
8854887Schin 	Namval_t *np;
8864887Schin 	n = strlen(ap->argval)-1;
8874887Schin 	if(ap->argval[n]!='=')
8888462SApril.Chin@Sun.COM 		sh_syntax(lexp);
8894887Schin 	if(ap->argval[n-1]=='+')
8904887Schin 	{
8914887Schin 		ap->argval[n--]=0;
8924887Schin 		array = ARG_APPEND;
8934887Schin 	}
8944887Schin 	/* shift right */
8954887Schin 	while(n > 0)
8964887Schin 	{
8974887Schin 		ap->argval[n] = ap->argval[n-1];
8984887Schin 		n--;
8994887Schin 	}
9004887Schin 	*ap->argval=0;
9014887Schin 	t = getnode(fornod);
9024887Schin 	t->for_.fornam = (char*)(ap->argval+1);
9038462SApril.Chin@Sun.COM 	t->for_.fortyp = sh_getlineno(lexp);
9044887Schin 	tp = &t->for_.fortre;
9054887Schin 	ap->argchn.ap = (struct argnod*)t;
9064887Schin 	ap->argflag &= ARG_QUOTED;
9074887Schin 	ap->argflag |= array;
9088462SApril.Chin@Sun.COM 	lexp->assignok = SH_ASSIGN;
9098462SApril.Chin@Sun.COM 	lexp->aliasok = 1;
9104887Schin 	array=0;
9118462SApril.Chin@Sun.COM 	if((n=skipnl(lexp,0))==RPAREN || n==LPAREN)
9124887Schin 	{
9134887Schin 		int index= 0;
9144887Schin 		struct argnod **settail;
9154887Schin 		ac = (struct comnod*)getnode(comnod);
9164887Schin 		settail= &ac->comset;
9174887Schin 		memset((void*)ac,0,sizeof(*ac));
9188462SApril.Chin@Sun.COM 		ac->comline = sh_getlineno(lexp);
9194887Schin 		while(n==LPAREN)
9204887Schin 		{
9214887Schin 			struct argnod *ap;
9228462SApril.Chin@Sun.COM 			ap = (struct argnod*)stkseek(stkp,ARGVAL);
9234887Schin 			ap->argflag= ARG_ASSIGN;
9248462SApril.Chin@Sun.COM 			sfprintf(stkp,"[%d]=",index++);
9258462SApril.Chin@Sun.COM 			ap = (struct argnod*)stkfreeze(stkp,1);
9264887Schin 			ap->argnxt.ap = 0;
9278462SApril.Chin@Sun.COM 			ap = assign(lexp,ap,0);
9284887Schin 			ap->argflag |= ARG_MESSAGE;
9294887Schin 			*settail = ap;
9304887Schin 			settail = &(ap->argnxt.ap);
9318462SApril.Chin@Sun.COM 			while((n = skipnl(lexp,0))==0)
9328462SApril.Chin@Sun.COM 			{
9338462SApril.Chin@Sun.COM 				ap = (struct argnod*)stkseek(stkp,ARGVAL);
9348462SApril.Chin@Sun.COM 				ap->argflag= ARG_ASSIGN;
9358462SApril.Chin@Sun.COM 				sfprintf(stkp,"[%d]=",index++);
9368462SApril.Chin@Sun.COM 				stakputs(lexp->arg->argval);
9378462SApril.Chin@Sun.COM 				ap = (struct argnod*)stkfreeze(stkp,1);
9388462SApril.Chin@Sun.COM 				ap->argnxt.ap = 0;
9398462SApril.Chin@Sun.COM 				ap->argflag = lexp->arg->argflag;
9408462SApril.Chin@Sun.COM 				*settail = ap;
9418462SApril.Chin@Sun.COM 				settail = &(ap->argnxt.ap);
9428462SApril.Chin@Sun.COM 			}
9434887Schin 		}
9444887Schin 	}
9458462SApril.Chin@Sun.COM 	else if(n && n!=FUNCTSYM)
9468462SApril.Chin@Sun.COM 		sh_syntax(lexp);
9478462SApril.Chin@Sun.COM 	else if(n!=FUNCTSYM && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)|| np==SYSDOT)))
9488462SApril.Chin@Sun.COM 	{
9494887Schin 		array=SH_ARRAY;
9508462SApril.Chin@Sun.COM 		if(fcgetc(n)==LPAREN)
9518462SApril.Chin@Sun.COM 		{
9528462SApril.Chin@Sun.COM 			int c;
9538462SApril.Chin@Sun.COM 			if(fcgetc(c)==RPAREN)
9548462SApril.Chin@Sun.COM 			{
9558462SApril.Chin@Sun.COM 				lexp->token =  SYMRES;
9568462SApril.Chin@Sun.COM 				array = 0;
9578462SApril.Chin@Sun.COM 			}
9588462SApril.Chin@Sun.COM 			else
9598462SApril.Chin@Sun.COM 				fcseek(-2);
9608462SApril.Chin@Sun.COM 		}
9618462SApril.Chin@Sun.COM 		else if(n>0)
9628462SApril.Chin@Sun.COM 			fcseek(-1);
9638462SApril.Chin@Sun.COM 		if(array && tdef)
9648462SApril.Chin@Sun.COM 			sh_syntax(lexp);
9658462SApril.Chin@Sun.COM 	}
9664887Schin 	while(1)
9674887Schin 	{
9688462SApril.Chin@Sun.COM 		if((n=lexp->token)==RPAREN)
9694887Schin 			break;
9704887Schin 		if(n==FUNCTSYM || n==SYMRES)
9718462SApril.Chin@Sun.COM 			ac = (struct comnod*)funct(lexp);
9724887Schin 		else
9738462SApril.Chin@Sun.COM 			ac = (struct comnod*)simple(lexp,SH_NOIO|SH_ASSIGN|array,NIL(struct ionod*));
9748462SApril.Chin@Sun.COM 		if((n=lexp->token)==RPAREN)
9754887Schin 			break;
9764887Schin 		if(n!=NL && n!=';')
9778462SApril.Chin@Sun.COM 			sh_syntax(lexp);
9788462SApril.Chin@Sun.COM 		lexp->assignok = SH_ASSIGN;
9798462SApril.Chin@Sun.COM 		if((n=skipnl(lexp,0)) || array)
9804887Schin 		{
9814887Schin 			if(n==RPAREN)
9824887Schin 				break;
9834887Schin 			if(array ||  n!=FUNCTSYM)
9848462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9854887Schin 		}
9868462SApril.Chin@Sun.COM 		if((n!=FUNCTSYM) && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)||np==SYSDOT)))
9874887Schin 		{
9888462SApril.Chin@Sun.COM 			struct argnod *arg = lexp->arg;
9894887Schin 			if(n!=0)
9908462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9914887Schin 			/* check for sys5 style function */
9928462SApril.Chin@Sun.COM 			if(sh_lex(lexp)!=LPAREN || sh_lex(lexp)!=RPAREN)
9934887Schin 			{
9948462SApril.Chin@Sun.COM 				lexp->arg = arg;
9958462SApril.Chin@Sun.COM 				lexp->token = 0;
9968462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9974887Schin 			}
9988462SApril.Chin@Sun.COM 			lexp->arg = arg;
9998462SApril.Chin@Sun.COM 			lexp->token = SYMRES;
10004887Schin 		}
10018462SApril.Chin@Sun.COM 		t = makelist(lexp,TLST,(Shnode_t*)ac,t);
10024887Schin 		*tp = t;
10034887Schin 		tp = &t->lst.lstrit;
10044887Schin 	}
10054887Schin 	*tp = (Shnode_t*)ac;
10068462SApril.Chin@Sun.COM 	lexp->assignok = 0;
10074887Schin 	return(ap);
10084887Schin }
10094887Schin 
10104887Schin /*
10114887Schin  * item
10124887Schin  *
10134887Schin  *	( cmd ) [ < in ] [ > out ]
10144887Schin  *	word word* [ < in ] [ > out ]
10154887Schin  *	if ... then ... else ... fi
10164887Schin  *	for ... while ... do ... done
10174887Schin  *	case ... in ... esac
10184887Schin  *	begin ... end
10194887Schin  */
10204887Schin 
item(Lex_t * lexp,int flag)10218462SApril.Chin@Sun.COM static Shnode_t	*item(Lex_t *lexp,int flag)
10224887Schin {
10234887Schin 	register Shnode_t	*t;
10244887Schin 	register struct ionod	*io;
10258462SApril.Chin@Sun.COM 	register int tok = (lexp->token&0xff);
10268462SApril.Chin@Sun.COM 	int savwdval = lexp->lasttok;
10278462SApril.Chin@Sun.COM 	int savline = lexp->lastline;
10288462SApril.Chin@Sun.COM 	int showme=0, comsub;
10298462SApril.Chin@Sun.COM 	if(!(flag&SH_NOIO) && (tok=='<' || tok=='>' || lexp->token==IOVNAME))
10308462SApril.Chin@Sun.COM 		io=inout(lexp,NIL(struct ionod*),1);
10314887Schin 	else
10324887Schin 		io=0;
10338462SApril.Chin@Sun.COM 	if((tok=lexp->token) && tok!=EOFSYM && tok!=FUNCTSYM)
10344887Schin 	{
10358462SApril.Chin@Sun.COM 		lexp->lastline =  sh_getlineno(lexp);
10368462SApril.Chin@Sun.COM 		lexp->lasttok = lexp->token;
10374887Schin 	}
10384887Schin 	switch(tok)
10394887Schin 	{
10404887Schin 	    /* [[ ... ]] test expression */
10414887Schin 	    case BTESTSYM:
10428462SApril.Chin@Sun.COM 		t = test_expr(lexp,ETESTSYM);
10434887Schin 		t->tre.tretyp &= ~TTEST;
10444887Schin 		break;
10454887Schin 	    /* ((...)) arithmetic expression */
10464887Schin 	    case EXPRSYM:
10478462SApril.Chin@Sun.COM 		t = getanode(lexp,lexp->arg);
10488462SApril.Chin@Sun.COM 		sh_lex(lexp);
10494887Schin 		goto done;
10504887Schin 
10514887Schin 	    /* case statement */
10524887Schin 	    case CASESYM:
10534887Schin 	    {
10548462SApril.Chin@Sun.COM 		int savetok = lexp->lasttok;
10558462SApril.Chin@Sun.COM 		int saveline = lexp->lastline;
10564887Schin 		t = getnode(swnod);
10578462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
10588462SApril.Chin@Sun.COM 			sh_syntax(lexp);
10598462SApril.Chin@Sun.COM 		t->sw.swarg=lexp->arg;
10604887Schin 		t->sw.swtyp=TSW;
10614887Schin 		t->sw.swio = 0;
10624887Schin 		t->sw.swtyp |= FLINENO;
10638462SApril.Chin@Sun.COM 		t->sw.swline =  lexp->sh->inlineno;
10648462SApril.Chin@Sun.COM 		if((tok=skipnl(lexp,0))!=INSYM && tok!=LBRACE)
10658462SApril.Chin@Sun.COM 			sh_syntax(lexp);
10668462SApril.Chin@Sun.COM 		if(!(t->sw.swlst=syncase(lexp,tok==INSYM?ESACSYM:RBRACE)) && lexp->token==EOFSYM)
10674887Schin 		{
10688462SApril.Chin@Sun.COM 			lexp->lasttok = savetok;
10698462SApril.Chin@Sun.COM 			lexp->lastline = saveline;
10708462SApril.Chin@Sun.COM 			sh_syntax(lexp);
10714887Schin 		}
10724887Schin 		break;
10734887Schin 	    }
10744887Schin 
10754887Schin 	    /* if statement */
10764887Schin 	    case IFSYM:
10774887Schin 	    {
10784887Schin 		register Shnode_t	*tt;
10794887Schin 		t = getnode(ifnod);
10804887Schin 		t->if_.iftyp=TIF;
10818462SApril.Chin@Sun.COM 		t->if_.iftre=sh_cmd(lexp,THENSYM,SH_NL);
10828462SApril.Chin@Sun.COM 		t->if_.thtre=sh_cmd(lexp,ELSESYM,SH_NL|SH_SEMI);
10838462SApril.Chin@Sun.COM 		tok = lexp->token;
10848462SApril.Chin@Sun.COM 		t->if_.eltre=(tok==ELSESYM?sh_cmd(lexp,FISYM,SH_NL|SH_SEMI):
10858462SApril.Chin@Sun.COM 			(tok==ELIFSYM?(lexp->token=IFSYM, tt=item(lexp,SH_NOIO)):0));
10864887Schin 		if(tok==ELIFSYM)
10874887Schin 		{
10884887Schin 			if(!tt || tt->tre.tretyp!=TSETIO)
10894887Schin 				goto done;
10904887Schin 			t->if_.eltre = tt->fork.forktre;
10914887Schin 			tt->fork.forktre = t;
10924887Schin 			t = tt;
10934887Schin 			goto done;
10944887Schin 		}
10954887Schin 		break;
10964887Schin 	    }
10974887Schin 
10984887Schin 	    /* for and select statement */
10994887Schin 	    case FORSYM:
11004887Schin 	    case SELECTSYM:
11014887Schin 	    {
11024887Schin 		t = getnode(fornod);
11038462SApril.Chin@Sun.COM 		t->for_.fortyp=(lexp->token==FORSYM?TFOR:TSELECT);
11044887Schin 		t->for_.forlst=0;
11058462SApril.Chin@Sun.COM 		t->for_.forline =  lexp->sh->inlineno;
11068462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
11074887Schin 		{
11088462SApril.Chin@Sun.COM 			if(lexp->token!=EXPRSYM || t->for_.fortyp!=TFOR)
11098462SApril.Chin@Sun.COM 				sh_syntax(lexp);
11104887Schin 			/* arithmetic for */
11118462SApril.Chin@Sun.COM 			t = arithfor(lexp,t);
11124887Schin 			break;
11134887Schin 		}
11148462SApril.Chin@Sun.COM 		t->for_.fornam=(char*) lexp->arg->argval;
11154887Schin 		t->for_.fortyp |= FLINENO;
11164887Schin #if SHOPT_KIA
11178462SApril.Chin@Sun.COM 		if(lexp->kiafile)
11188462SApril.Chin@Sun.COM 			writedefs(lexp,lexp->arg,lexp->sh->inlineno,'v',NIL(struct argnod*));
11194887Schin #endif /* SHOPT_KIA */
11208462SApril.Chin@Sun.COM 		while((tok=sh_lex(lexp))==NL);
11214887Schin 		if(tok==INSYM)
11224887Schin 		{
11238462SApril.Chin@Sun.COM 			if(sh_lex(lexp))
11244887Schin 			{
11258462SApril.Chin@Sun.COM 				if(lexp->token != NL && lexp->token !=';')
11268462SApril.Chin@Sun.COM 					sh_syntax(lexp);
11274887Schin 				/* some Linux scripts assume this */
11284887Schin 				if(sh_isoption(SH_NOEXEC))
11298462SApril.Chin@Sun.COM 					errormsg(SH_DICT,ERROR_warn(0),e_lexemptyfor,lexp->sh->inlineno-(lexp->token=='\n'));
11304887Schin 				t->for_.forlst = (struct comnod*)getnode(comnod);
11314887Schin 				(t->for_.forlst)->comarg = 0;
11324887Schin 				(t->for_.forlst)->comset = 0;
11334887Schin 				(t->for_.forlst)->comnamp = 0;
11344887Schin 				(t->for_.forlst)->comnamq = 0;
11354887Schin 				(t->for_.forlst)->comstate = 0;
11364887Schin 				(t->for_.forlst)->comio = 0;
11374887Schin 				(t->for_.forlst)->comtyp = 0;
11384887Schin 			}
11394887Schin 			else
11408462SApril.Chin@Sun.COM 				t->for_.forlst=(struct comnod*)simple(lexp,SH_NOIO,NIL(struct ionod*));
11418462SApril.Chin@Sun.COM 			if(lexp->token != NL && lexp->token !=';')
11428462SApril.Chin@Sun.COM 				sh_syntax(lexp);
11438462SApril.Chin@Sun.COM 			tok = skipnl(lexp,0);
11444887Schin 		}
11454887Schin 		/* 'for i;do cmd' is valid syntax */
11464887Schin 		else if(tok==';')
11478462SApril.Chin@Sun.COM 			tok=sh_lex(lexp);
11484887Schin 		if(tok!=DOSYM && tok!=LBRACE)
11498462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11504887Schin 		loop_level++;
11518462SApril.Chin@Sun.COM 		t->for_.fortre=sh_cmd(lexp,tok==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
11524887Schin 		if(--loop_level==0)
11534887Schin 			label_last = label_list;
11544887Schin 		break;
11554887Schin 	    }
11564887Schin 
11574887Schin 	    /* This is the code for parsing function definitions */
11584887Schin 	    case FUNCTSYM:
11598462SApril.Chin@Sun.COM 		return(funct(lexp));
11604887Schin 
11614887Schin #if SHOPT_NAMESPACE
11624887Schin 	    case NSPACESYM:
11634887Schin 		t = getnode(fornod);
11644887Schin 		t->for_.fortyp=TNSPACE;
11654887Schin 		t->for_.forlst=0;
11668462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
11678462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11688462SApril.Chin@Sun.COM 		t->for_.fornam=(char*) lexp->arg->argval;
11698462SApril.Chin@Sun.COM 		while((tok=sh_lex(lexp))==NL);
11704887Schin 		if(tok!=LBRACE)
11718462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11728462SApril.Chin@Sun.COM 		t->for_.fortre = sh_cmd(lexp,RBRACE,SH_NL);
11734887Schin 		break;
11744887Schin #endif /* SHOPT_NAMESPACE */
11754887Schin 
11764887Schin 	    /* while and until */
11774887Schin 	    case WHILESYM:
11784887Schin 	    case UNTILSYM:
11794887Schin 		t = getnode(whnod);
11808462SApril.Chin@Sun.COM 		t->wh.whtyp=(lexp->token==WHILESYM ? TWH : TUN);
11814887Schin 		loop_level++;
11828462SApril.Chin@Sun.COM 		t->wh.whtre = sh_cmd(lexp,DOSYM,SH_NL);
11838462SApril.Chin@Sun.COM 		t->wh.dotre = sh_cmd(lexp,DONESYM,SH_NL|SH_SEMI);
11844887Schin 		if(--loop_level==0)
11854887Schin 			label_last = label_list;
11864887Schin 		t->wh.whinc = 0;
11874887Schin 		break;
11884887Schin 
11894887Schin 	    case LABLSYM:
11904887Schin 	    {
11914887Schin 		register struct argnod *argp = label_list;
11924887Schin 		while(argp)
11934887Schin 		{
11948462SApril.Chin@Sun.COM 			if(strcmp(argp->argval,lexp->arg->argval)==0)
11958462SApril.Chin@Sun.COM 				errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax3,lexp->sh->inlineno,argp->argval);
11964887Schin 			argp = argp->argnxt.ap;
11974887Schin 		}
11988462SApril.Chin@Sun.COM 		lexp->arg->argnxt.ap = label_list;
11998462SApril.Chin@Sun.COM 		label_list = lexp->arg;
12008462SApril.Chin@Sun.COM 		label_list->argchn.len = sh_getlineno(lexp);
12014887Schin 		label_list->argflag = loop_level;
12028462SApril.Chin@Sun.COM 		skipnl(lexp,flag);
12038462SApril.Chin@Sun.COM 		if(!(t = item(lexp,SH_NL)))
12048462SApril.Chin@Sun.COM 			sh_syntax(lexp);
12054887Schin 		tok = (t->tre.tretyp&(COMSCAN|COMSCAN-1));
12064887Schin 		if(sh_isoption(SH_NOEXEC) && tok!=TWH && tok!=TUN && tok!=TFOR && tok!=TSELECT)
12074887Schin 			errormsg(SH_DICT,ERROR_warn(0),e_lexlabignore,label_list->argchn.len,label_list->argval);
12084887Schin 		return(t);
12094887Schin 	    }
12104887Schin 
12114887Schin 	    /* command group with {...} */
12124887Schin 	    case LBRACE:
12138462SApril.Chin@Sun.COM 		comsub = lexp->comsub;
12148462SApril.Chin@Sun.COM 		lexp->comsub = 0;
121510898Sroland.mainz@nrubsig.org 		t = sh_cmd(lexp,RBRACE,SH_NL|SH_SEMI);
12168462SApril.Chin@Sun.COM 		lexp->comsub = comsub;
12174887Schin 		break;
12184887Schin 
12194887Schin 	    case LPAREN:
12204887Schin 		t = getnode(parnod);
122110898Sroland.mainz@nrubsig.org 		t->par.partre=sh_cmd(lexp,RPAREN,SH_NL|SH_SEMI);
12224887Schin 		t->par.partyp=TPAR;
12234887Schin 		break;
12244887Schin 
12254887Schin 	    default:
12264887Schin 		if(io==0)
12274887Schin 			return(0);
12284887Schin 
12294887Schin 	    case ';':
12304887Schin 		if(io==0)
12314887Schin 		{
12324887Schin 			if(!(flag&SH_SEMI))
12334887Schin 				return(0);
12348462SApril.Chin@Sun.COM 			if(sh_lex(lexp)==';')
12358462SApril.Chin@Sun.COM 				sh_syntax(lexp);
12364887Schin 			showme =  FSHOWME;
12374887Schin 		}
12384887Schin 	    /* simple command */
12394887Schin 	    case 0:
12408462SApril.Chin@Sun.COM 		t = (Shnode_t*)simple(lexp,flag,io);
12418462SApril.Chin@Sun.COM 		if(t->com.comarg && lexp->intypeset && (lexp->sh->shcomp || sh_isoption(SH_NOEXEC) || sh.dot_depth))
12428462SApril.Chin@Sun.COM 			check_typedef(&t->com);
12438462SApril.Chin@Sun.COM 		lexp->intypeset = 0;
12448462SApril.Chin@Sun.COM 		lexp->inexec = 0;
12454887Schin 		t->tre.tretyp |= showme;
12464887Schin 		return(t);
12474887Schin 	}
12488462SApril.Chin@Sun.COM 	sh_lex(lexp);
12498462SApril.Chin@Sun.COM 	if(io=inout(lexp,io,0))
12504887Schin 	{
12514887Schin 		if((tok=t->tre.tretyp&COMMSK) != TFORK)
12524887Schin 			tok = TSETIO;
12538462SApril.Chin@Sun.COM 		t=makeparent(lexp,tok,t);
12544887Schin 		t->tre.treio=io;
12554887Schin 	}
12564887Schin done:
12578462SApril.Chin@Sun.COM 	lexp->lasttok = savwdval;
12588462SApril.Chin@Sun.COM 	lexp->lastline = savline;
12594887Schin 	return(t);
12604887Schin }
12614887Schin 
process_sub(Lex_t * lexp,int tok)126210898Sroland.mainz@nrubsig.org static struct argnod *process_sub(Lex_t *lexp,int tok)
126310898Sroland.mainz@nrubsig.org {
126410898Sroland.mainz@nrubsig.org 	struct argnod *argp;
126510898Sroland.mainz@nrubsig.org 	Shnode_t *t;
126610898Sroland.mainz@nrubsig.org 	int mode = (tok==OPROCSYM);
126710898Sroland.mainz@nrubsig.org 	t = sh_cmd(lexp,RPAREN,SH_NL);
126810898Sroland.mainz@nrubsig.org 	argp = (struct argnod*)stkalloc(lexp->sh->stk,sizeof(struct argnod));
126910898Sroland.mainz@nrubsig.org 	*argp->argval = 0;
127010898Sroland.mainz@nrubsig.org 	argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t);
127110898Sroland.mainz@nrubsig.org 	argp->argflag =  (ARG_EXP|mode);
127210898Sroland.mainz@nrubsig.org 	return(argp);
127310898Sroland.mainz@nrubsig.org }
127410898Sroland.mainz@nrubsig.org 
127510898Sroland.mainz@nrubsig.org 
12764887Schin /*
12774887Schin  * This is for a simple command, for list, or compound assignment
12784887Schin  */
simple(Lex_t * lexp,int flag,struct ionod * io)12798462SApril.Chin@Sun.COM static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
12804887Schin {
12814887Schin 	register struct comnod *t;
12824887Schin 	register struct argnod	*argp;
12834887Schin 	register int tok;
12848462SApril.Chin@Sun.COM 	Stk_t		*stkp = lexp->sh->stk;
12854887Schin 	struct argnod	**argtail;
12864887Schin 	struct argnod	**settail;
12878462SApril.Chin@Sun.COM 	int	cmdarg=0;
12888462SApril.Chin@Sun.COM 	int	argno = 0, argmax=0;
12894887Schin 	int	assignment = 0;
12904887Schin 	int	key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
12914887Schin 	int	associative=0;
12928462SApril.Chin@Sun.COM 	if((argp=lexp->arg) && (argp->argflag&ARG_ASSIGN) && argp->argval[0]=='[')
12934887Schin 	{
12944887Schin 		flag |= SH_ARRAY;
12954887Schin 		associative = 1;
12964887Schin 	}
12974887Schin 	t = (struct comnod*)getnode(comnod);
12984887Schin 	t->comio=io; /*initial io chain*/
12994887Schin 	/* set command line number for error messages */
13008462SApril.Chin@Sun.COM 	t->comline = sh_getlineno(lexp);
13014887Schin 	argtail = &(t->comarg);
13024887Schin 	t->comset = 0;
13034887Schin 	t->comnamp = 0;
13044887Schin 	t->comnamq = 0;
13054887Schin 	t->comstate = 0;
13064887Schin 	settail = &(t->comset);
13078462SApril.Chin@Sun.COM 	while(lexp->token==0)
13084887Schin 	{
13098462SApril.Chin@Sun.COM 		argp = lexp->arg;
13104887Schin 		if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
13114887Schin 		{
13128462SApril.Chin@Sun.COM 			lexp->token = LBRACE;
13134887Schin 			break;
13144887Schin 		}
13154887Schin 		if(associative && argp->argval[0]!='[')
13168462SApril.Chin@Sun.COM 			sh_syntax(lexp);
13174887Schin 		/* check for assignment argument */
13184887Schin 		if((argp->argflag&ARG_ASSIGN) && assignment!=2)
13194887Schin 		{
13204887Schin 			*settail = argp;
13214887Schin 			settail = &(argp->argnxt.ap);
13228462SApril.Chin@Sun.COM 			lexp->assignok = (flag&SH_ASSIGN)?SH_ASSIGN:1;
13234887Schin 			if(assignment)
13244887Schin 			{
13254887Schin 				struct argnod *ap=argp;
13264887Schin 				char *last, *cp;
13274887Schin 				if(assignment==1)
13284887Schin 				{
13294887Schin 					last = strchr(argp->argval,'=');
133010898Sroland.mainz@nrubsig.org 					if(last && (last[-1]==']'|| (last[-1]=='+' && last[-2]==']')) && (cp=strchr(argp->argval,'[')) && (cp < last))
13314887Schin 						last = cp;
13328462SApril.Chin@Sun.COM 					stkseek(stkp,ARGVAL);
13338462SApril.Chin@Sun.COM 					sfwrite(stkp,argp->argval,last-argp->argval);
13348462SApril.Chin@Sun.COM 					ap=(struct argnod*)stkfreeze(stkp,1);
13354887Schin 					ap->argflag = ARG_RAW;
13364887Schin 					ap->argchn.ap = 0;
13374887Schin 				}
13384887Schin 				*argtail = ap;
13394887Schin 				argtail = &(ap->argnxt.ap);
13404887Schin 				if(argno>=0)
13414887Schin 					argno++;
13424887Schin 			}
13434887Schin 			else /* alias substitutions allowed */
13448462SApril.Chin@Sun.COM 				lexp->aliasok = 1;
13454887Schin 		}
13464887Schin 		else
13474887Schin 		{
13484887Schin 			if(!(argp->argflag&ARG_RAW))
13498462SApril.Chin@Sun.COM 			{
13508462SApril.Chin@Sun.COM 				if(argno>0)
13518462SApril.Chin@Sun.COM 					argmax = argno;
13524887Schin 				argno = -1;
13538462SApril.Chin@Sun.COM 			}
13548462SApril.Chin@Sun.COM 			if(argno>=0 && argno++==cmdarg && !(flag&SH_ARRAY) && *argp->argval!='/')
13554887Schin 			{
13564887Schin 				/* check for builtin command */
13578462SApril.Chin@Sun.COM 				Namval_t *np=nv_bfsearch(argp->argval,lexp->sh->fun_tree, (Namval_t**)&t->comnamq,(char**)0);
13588462SApril.Chin@Sun.COM 				if(cmdarg==0)
13598462SApril.Chin@Sun.COM 					t->comnamp = (void*)np;
13608462SApril.Chin@Sun.COM 				if(np && is_abuiltin(np))
13614887Schin 				{
13628462SApril.Chin@Sun.COM 					if(nv_isattr(np,BLT_DCL))
13638462SApril.Chin@Sun.COM 					{
13648462SApril.Chin@Sun.COM 						assignment = 1+(*argp->argval=='a');
13658462SApril.Chin@Sun.COM 						if(np==SYSTYPESET)
13668462SApril.Chin@Sun.COM 							lexp->intypeset = 1;
13678462SApril.Chin@Sun.COM 						key_on = 1;
13688462SApril.Chin@Sun.COM 					}
13698462SApril.Chin@Sun.COM 					else if(np==SYSCOMMAND)
13708462SApril.Chin@Sun.COM 						cmdarg++;
13718462SApril.Chin@Sun.COM 					else if(np==SYSEXEC)
13728462SApril.Chin@Sun.COM 						lexp->inexec = 1;
13738462SApril.Chin@Sun.COM 					else if(np->nvalue.bfp==b_getopts)
13748462SApril.Chin@Sun.COM 						opt_get |= FOPTGET;
13754887Schin 				}
13764887Schin 			}
13774887Schin 			*argtail = argp;
13784887Schin 			argtail = &(argp->argnxt.ap);
13798462SApril.Chin@Sun.COM 			if(!(lexp->assignok=key_on)  && !(flag&SH_NOIO) && sh_isoption(SH_NOEXEC))
13808462SApril.Chin@Sun.COM 				lexp->assignok = SH_COMPASSIGN;
13818462SApril.Chin@Sun.COM 			lexp->aliasok = 0;
13824887Schin 		}
13834887Schin 	retry:
13848462SApril.Chin@Sun.COM 		tok = sh_lex(lexp);
13858462SApril.Chin@Sun.COM 		if(tok==LABLSYM && (flag&SH_ASSIGN))
13868462SApril.Chin@Sun.COM 			lexp->token = tok = 0;
13874887Schin #if SHOPT_DEVFD
13884887Schin 		if((tok==IPROCSYM || tok==OPROCSYM))
13894887Schin 		{
139010898Sroland.mainz@nrubsig.org 			argp = process_sub(lexp,tok);
13918462SApril.Chin@Sun.COM 			argmax = 0;
13924887Schin 			argno = -1;
13934887Schin 			*argtail = argp;
13944887Schin 			argtail = &(argp->argnxt.ap);
13954887Schin 			goto retry;
13964887Schin 		}
13974887Schin #endif	/* SHOPT_DEVFD */
13984887Schin 		if(tok==LPAREN)
13994887Schin 		{
14004887Schin 			if(argp->argflag&ARG_ASSIGN)
14014887Schin 			{
14028462SApril.Chin@Sun.COM 				int intypeset = lexp->intypeset;
14038462SApril.Chin@Sun.COM 				int tdef = 0;
14048462SApril.Chin@Sun.COM 				lexp->intypeset = 0;
14058462SApril.Chin@Sun.COM 				if(t->comnamp==SYSTYPESET && t->comarg->argnxt.ap && strcmp(t->comarg->argnxt.ap->argval,"-T")==0)
14068462SApril.Chin@Sun.COM 					tdef = 1;
14078462SApril.Chin@Sun.COM 				argp = assign(lexp,argp,tdef);
14088462SApril.Chin@Sun.COM 				lexp->intypeset = intypeset;
14094887Schin 				if(associative)
14108462SApril.Chin@Sun.COM 					lexp->assignok |= SH_ASSIGN;
14114887Schin 				goto retry;
14124887Schin 			}
14134887Schin 			else if(argno==1 && !t->comset)
14144887Schin 			{
14154887Schin 				/* SVR2 style function */
14168462SApril.Chin@Sun.COM 				if(sh_lex(lexp) == RPAREN)
14174887Schin 				{
14188462SApril.Chin@Sun.COM 					lexp->arg = argp;
14198462SApril.Chin@Sun.COM 					return(funct(lexp));
14204887Schin 				}
14218462SApril.Chin@Sun.COM 				lexp->token = LPAREN;
14224887Schin 			}
14234887Schin 		}
14244887Schin 		else if(flag&SH_ASSIGN)
14254887Schin 		{
14264887Schin 			if(tok==RPAREN)
14274887Schin 				break;
14284887Schin 			else if(tok==NL && (flag&SH_ARRAY))
14298462SApril.Chin@Sun.COM 			{
14308462SApril.Chin@Sun.COM 				lexp->comp_assign = 2;
14314887Schin 				goto retry;
14328462SApril.Chin@Sun.COM 			}
14338462SApril.Chin@Sun.COM 
14344887Schin 		}
14354887Schin 		if(!(flag&SH_NOIO))
14364887Schin 		{
14374887Schin 			if(io)
14384887Schin 			{
14394887Schin 				while(io->ionxt)
14404887Schin 					io = io->ionxt;
14418462SApril.Chin@Sun.COM 				io->ionxt = inout(lexp,(struct ionod*)0,0);
14424887Schin 			}
14434887Schin 			else
14448462SApril.Chin@Sun.COM 				t->comio = io = inout(lexp,(struct ionod*)0,0);
14454887Schin 		}
14464887Schin 	}
14474887Schin 	*argtail = 0;
14488462SApril.Chin@Sun.COM 	if(argno>0)
14498462SApril.Chin@Sun.COM 		argmax = argno;
1450*12068SRoger.Faulkner@Oracle.COM 	t->comtyp = TCOM;
14514887Schin #if SHOPT_KIA
14528462SApril.Chin@Sun.COM 	if(lexp->kiafile && !(flag&SH_NOIO))
14534887Schin 	{
14544887Schin 		register Namval_t *np=(Namval_t*)t->comnamp;
14554887Schin 		unsigned long r=0;
14564887Schin 		int line = t->comline;
14574887Schin 		argp = t->comarg;
14584887Schin 		if(np)
14598462SApril.Chin@Sun.COM 			r = kiaentity(lexp,nv_name(np),-1,'p',-1,0,lexp->unknown,'b',0,"");
14604887Schin 		else if(argp)
14618462SApril.Chin@Sun.COM 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',-1,0,lexp->unknown,'c',0,"");
14624887Schin 		if(r>0)
14638462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;c;\n",lexp->current,r,line,line);
14644887Schin 		if(t->comset && argno==0)
14658462SApril.Chin@Sun.COM 			writedefs(lexp,t->comset,line,'v',t->comarg);
14664887Schin 		else if(np && nv_isattr(np,BLT_DCL))
14678462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
14684887Schin 		else if(argp && strcmp(argp->argval,"read")==0)
14698462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
14704887Schin #if 0
14714887Schin 		else if(argp && strcmp(argp->argval,"unset")==0)
14728462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,'u',NIL(struct argnod*));
14734887Schin #endif
14744887Schin 		else if(argp && *argp->argval=='.' && argp->argval[1]==0 && (argp=argp->argnxt.ap))
14754887Schin 		{
14768462SApril.Chin@Sun.COM 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',0,0,lexp->script,'d',0,"");
14778462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;d;\n",lexp->current,r,line,line);
14784887Schin 		}
14794887Schin 	}
14804887Schin #endif /* SHOPT_KIA */
14814887Schin 	if(t->comnamp && (argp=t->comarg->argnxt.ap))
14824887Schin 	{
14834887Schin 		Namval_t *np=(Namval_t*)t->comnamp;
14844887Schin 		if((np==SYSBREAK || np==SYSCONT) && (argp->argflag&ARG_RAW) && !isdigit(*argp->argval))
14854887Schin 		{
14864887Schin 			register char *cp = argp->argval;
14874887Schin 			/* convert break/continue labels to numbers */
14884887Schin 			tok = 0;
14894887Schin 			for(argp=label_list;argp!=label_last;argp=argp->argnxt.ap)
14904887Schin 			{
14914887Schin 				if(strcmp(cp,argp->argval))
14924887Schin 					continue;
14934887Schin 				tok = loop_level-argp->argflag;
14944887Schin 				if(tok>=1)
14954887Schin 				{
14964887Schin 					argp = t->comarg->argnxt.ap;
14974887Schin 					if(tok>9)
14984887Schin 					{
14994887Schin 						argp->argval[1] = '0'+tok%10;
15004887Schin 						argp->argval[2] = 0;
15014887Schin 						tok /= 10;
15024887Schin 					}
15034887Schin 					else
15044887Schin 						argp->argval[1] = 0;
15054887Schin 					*argp->argval = '0'+tok;
15064887Schin 				}
15074887Schin 				break;
15084887Schin 			}
15094887Schin 			if(sh_isoption(SH_NOEXEC) && tok==0)
15108462SApril.Chin@Sun.COM 				errormsg(SH_DICT,ERROR_warn(0),e_lexlabunknown,lexp->sh->inlineno-(lexp->token=='\n'),cp);
15114887Schin 		}
15124887Schin 		else if(sh_isoption(SH_NOEXEC) && np==SYSSET && ((tok= *argp->argval)=='-'||tok=='+') &&
15134887Schin 			(argp->argval[1]==0||strchr(argp->argval,'k')))
15148462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete5,lexp->sh->inlineno-(lexp->token=='\n'),argp->argval);
15154887Schin 	}
15164887Schin 	/* expand argument list if possible */
15174887Schin 	if(argno>0)
15184887Schin 		t->comarg = qscan(t,argno);
15194887Schin 	else if(t->comarg)
15204887Schin 		t->comtyp |= COMSCAN;
15218462SApril.Chin@Sun.COM 	lexp->aliasok = 0;
15224887Schin 	return((Shnode_t*)t);
15234887Schin }
15244887Schin 
15254887Schin /*
15264887Schin  * skip past newlines but issue prompt if interactive
15274887Schin  */
skipnl(Lex_t * lexp,int flag)15288462SApril.Chin@Sun.COM static int	skipnl(Lex_t *lexp,int flag)
15294887Schin {
15304887Schin 	register int token;
15318462SApril.Chin@Sun.COM 	while((token=sh_lex(lexp))==NL);
15324887Schin 	if(token==';' && !(flag&SH_SEMI))
15338462SApril.Chin@Sun.COM 		sh_syntax(lexp);
15344887Schin 	return(token);
15354887Schin }
15364887Schin 
15374887Schin /*
15384887Schin  * check for and process and i/o redirections
15394887Schin  * if flag>0 then an alias can be in the next word
15404887Schin  * if flag<0 only one redirection will be processed
15414887Schin  */
inout(Lex_t * lexp,struct ionod * lastio,int flag)15428462SApril.Chin@Sun.COM static struct ionod	*inout(Lex_t *lexp,struct ionod *lastio,int flag)
15434887Schin {
15448462SApril.Chin@Sun.COM 	register int 		iof = lexp->digits, token=lexp->token;
15454887Schin 	register struct ionod	*iop;
15468462SApril.Chin@Sun.COM 	Stk_t			*stkp = lexp->sh->stk;
15474887Schin 	char *iovname=0;
15484887Schin 	register int		errout=0;
15494887Schin 	if(token==IOVNAME)
15504887Schin 	{
15518462SApril.Chin@Sun.COM 		iovname=lexp->arg->argval+1;
15528462SApril.Chin@Sun.COM 		token= sh_lex(lexp);
15534887Schin 		iof = 0;
15544887Schin 	}
15554887Schin 	switch(token&0xff)
15564887Schin 	{
15574887Schin 	    case '<':
15584887Schin 		if(token==IODOCSYM)
15594887Schin 			iof |= (IODOC|IORAW);
15604887Schin 		else if(token==IOMOV0SYM)
15614887Schin 			iof |= IOMOV;
156210898Sroland.mainz@nrubsig.org 		else if(token==IORDWRSYMT)
156310898Sroland.mainz@nrubsig.org 			iof |= IORDW|IOREWRITE;
15644887Schin 		else if(token==IORDWRSYM)
15654887Schin 			iof |= IORDW;
15664887Schin 		else if((token&SYMSHARP) == SYMSHARP)
15674887Schin 		{
15684887Schin 			int n;
15694887Schin 			iof |= IOLSEEK;
15704887Schin 			if(fcgetc(n)=='#')
15714887Schin 				iof |= IOCOPY;
15724887Schin 			else if(n>0)
15734887Schin 				fcseek(-1);
15744887Schin 		}
15754887Schin 		break;
15764887Schin 
15774887Schin 	    case '>':
15784887Schin 		if(iof<0)
15794887Schin 		{
15804887Schin 			errout = 1;
15814887Schin 			iof = 1;
15824887Schin 		}
15834887Schin 		iof |= IOPUT;
15844887Schin 		if(token==IOAPPSYM)
15854887Schin 			iof |= IOAPP;
15864887Schin 		else if(token==IOMOV1SYM)
15874887Schin 			iof |= IOMOV;
15884887Schin 		else if(token==IOCLOBSYM)
15894887Schin 			iof |= IOCLOB;
15904887Schin 		else if((token&SYMSHARP) == SYMSHARP)
15914887Schin 			iof |= IOLSEEK;
15928462SApril.Chin@Sun.COM 		else if((token&SYMSEMI) == SYMSEMI)
15938462SApril.Chin@Sun.COM 			iof |= IOREWRITE;
15944887Schin 		break;
15954887Schin 
15964887Schin 	    default:
15974887Schin 		return(lastio);
15984887Schin 	}
15998462SApril.Chin@Sun.COM 	lexp->digits=0;
16008462SApril.Chin@Sun.COM 	iop=(struct ionod*) stkalloc(stkp,sizeof(struct ionod));
16014887Schin 	iop->iodelim = 0;
16028462SApril.Chin@Sun.COM 	if(token=sh_lex(lexp))
16034887Schin 	{
16048462SApril.Chin@Sun.COM 		if(token==RPAREN && (iof&IOLSEEK) && lexp->comsub)
16054887Schin 		{
16068462SApril.Chin@Sun.COM 			lexp->arg = (struct argnod*)stkalloc(stkp,sizeof(struct argnod)+3);
16078462SApril.Chin@Sun.COM 			strcpy(lexp->arg->argval,"CUR");
16088462SApril.Chin@Sun.COM 			lexp->arg->argflag = ARG_RAW;
16094887Schin 			iof |= IOARITH;
16104887Schin 			fcseek(-1);
16114887Schin 		}
16124887Schin 		else if(token==EXPRSYM && (iof&IOLSEEK))
16134887Schin 			iof |= IOARITH;
161410898Sroland.mainz@nrubsig.org 		else if(((token==IPROCSYM && !(iof&IOPUT)) || (token==OPROCSYM && (iof&IOPUT))) && !(iof&(IOLSEEK|IOREWRITE|IOMOV|IODOC)))
161510898Sroland.mainz@nrubsig.org 		{
161610898Sroland.mainz@nrubsig.org 			lexp->arg = process_sub(lexp,token);
161710898Sroland.mainz@nrubsig.org 			iof |= IOPROCSUB;
161810898Sroland.mainz@nrubsig.org 		}
16194887Schin 		else
16208462SApril.Chin@Sun.COM 			sh_syntax(lexp);
16214887Schin 	}
162210898Sroland.mainz@nrubsig.org 	if( (iof&IOPROCSUB) && !(iof&IOLSEEK))
162310898Sroland.mainz@nrubsig.org 		iop->ioname= (char*)lexp->arg->argchn.ap;
162410898Sroland.mainz@nrubsig.org 	else
162510898Sroland.mainz@nrubsig.org 		iop->ioname=lexp->arg->argval;
16264887Schin 	iop->iovname = iovname;
16274887Schin 	if(iof&IODOC)
16284887Schin 	{
16298462SApril.Chin@Sun.COM 		if(lexp->digits==2)
16304887Schin 		{
16314887Schin 			iof |= IOSTRG;
16328462SApril.Chin@Sun.COM 			if(!(lexp->arg->argflag&ARG_RAW))
16334887Schin 				iof &= ~IORAW;
16344887Schin 		}
16354887Schin 		else
16364887Schin 		{
16378462SApril.Chin@Sun.COM 			if(!lexp->sh->heredocs)
16388462SApril.Chin@Sun.COM 				lexp->sh->heredocs = sftmp(HERE_MEM);
16398462SApril.Chin@Sun.COM 			iop->iolst=lexp->heredoc;
16408462SApril.Chin@Sun.COM 			lexp->heredoc=iop;
16418462SApril.Chin@Sun.COM 			if(lexp->arg->argflag&ARG_QUOTED)
16424887Schin 				iof |= IOQUOTE;
16438462SApril.Chin@Sun.COM 			if(lexp->digits==3)
16444887Schin 				iof |= IOLSEEK;
16458462SApril.Chin@Sun.COM 			if(lexp->digits)
16464887Schin 				iof |= IOSTRIP;
16474887Schin 		}
16484887Schin 	}
16494887Schin 	else
16504887Schin 	{
16514887Schin 		iop->iolst = 0;
16528462SApril.Chin@Sun.COM 		if(lexp->arg->argflag&ARG_RAW)
16534887Schin 			iof |= IORAW;
16544887Schin 	}
16554887Schin 	iop->iofile=iof;
16564887Schin 	if(flag>0)
16574887Schin 		/* allow alias substitutions and parameter assignments */
16588462SApril.Chin@Sun.COM 		lexp->aliasok = lexp->assignok = 1;
16594887Schin #if SHOPT_KIA
16608462SApril.Chin@Sun.COM 	if(lexp->kiafile)
16614887Schin 	{
16628462SApril.Chin@Sun.COM 		int n = lexp->sh->inlineno-(lexp->token=='\n');
16634887Schin 		if(!(iof&IOMOV))
16644887Schin 		{
16658462SApril.Chin@Sun.COM 			unsigned long r=kiaentity(lexp,(iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,lexp->script,'f',0,"");
16668462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;%c;%d\n",lexp->current,r,n,n,(iof&IOPUT)?((iof&IOAPP)?'a':'w'):((iof&IODOC)?'h':'r'),iof&IOUFD);
16674887Schin 		}
16684887Schin 	}
16694887Schin #endif /* SHOPT_KIA */
16704887Schin 	if(flag>=0)
16714887Schin 	{
16724887Schin 		struct ionod *ioq=iop;
16738462SApril.Chin@Sun.COM 		sh_lex(lexp);
16744887Schin 		if(errout)
16754887Schin 		{
16764887Schin 			/* redirect standard output to standard error */
16778462SApril.Chin@Sun.COM 			ioq = (struct ionod*)stkalloc(stkp,sizeof(struct ionod));
167810898Sroland.mainz@nrubsig.org 			memset(ioq,0,sizeof(*ioq));
16794887Schin 			ioq->ioname = "1";
16804887Schin 			ioq->iolst = 0;
16814887Schin 			ioq->iodelim = 0;
16824887Schin 			ioq->iofile = IORAW|IOPUT|IOMOV|2;
16834887Schin 			iop->ionxt=ioq;
16844887Schin 		}
16858462SApril.Chin@Sun.COM 		ioq->ionxt=inout(lexp,lastio,flag);
16864887Schin 	}
16874887Schin 	else
16884887Schin 		iop->ionxt=0;
16894887Schin 	return(iop);
16904887Schin }
16914887Schin 
16924887Schin /*
16934887Schin  * convert argument chain to argument list when no special arguments
16944887Schin  */
16954887Schin 
qscan(struct comnod * ac,int argn)16964887Schin static struct argnod *qscan(struct comnod *ac,int argn)
16974887Schin {
16984887Schin 	register char **cp;
16994887Schin 	register struct argnod *ap;
17004887Schin 	register struct dolnod* dp;
17014887Schin 	register int special=0;
17024887Schin 	/* special hack for test -t compatibility */
17034887Schin 	if((Namval_t*)ac->comnamp==SYSTEST)
17044887Schin 		special = 2;
17054887Schin 	else if(*(ac->comarg->argval)=='[' && ac->comarg->argval[1]==0)
17064887Schin 		special = 3;
17074887Schin 	if(special)
17084887Schin 	{
17094887Schin 		ap = ac->comarg->argnxt.ap;
17104887Schin 		if(argn==(special+1) && ap->argval[1]==0 && *ap->argval=='!')
17114887Schin 			ap = ap->argnxt.ap;
17124887Schin 		else if(argn!=special)
17134887Schin 			special=0;
17144887Schin 	}
17154887Schin 	if(special)
17164887Schin 	{
17174887Schin 		const char *message;
17184887Schin 		if(strcmp(ap->argval,"-t"))
17194887Schin 		{
17204887Schin 			message = "line %d: Invariant test";
17214887Schin 			special=0;
17224887Schin 		}
17234887Schin 		else
17244887Schin 		{
17254887Schin 			message = "line %d: -t requires argument";
17264887Schin 			argn++;
17274887Schin 		}
17284887Schin 		if(sh_isoption(SH_NOEXEC))
17294887Schin 			errormsg(SH_DICT,ERROR_warn(0),message,ac->comline);
17304887Schin 	}
17314887Schin 	/* leave space for an extra argument at the front */
17324887Schin 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
17334887Schin 	cp = dp->dolval+ARG_SPARE;
17344887Schin 	dp->dolnum = argn;
17354887Schin 	dp->dolbot = ARG_SPARE;
17364887Schin 	ap = ac->comarg;
17374887Schin 	while(ap)
17384887Schin 	{
17394887Schin 		*cp++ = ap->argval;
17404887Schin 		ap = ap->argnxt.ap;
17414887Schin 	}
17424887Schin 	if(special==3)
17434887Schin 	{
17444887Schin 		cp[0] = cp[-1];
17454887Schin 		cp[-1] = "1";
17464887Schin 		cp++;
17474887Schin 	}
17484887Schin 	else if(special)
17494887Schin 		*cp++ = "1";
17504887Schin 	*cp = 0;
17514887Schin 	return((struct argnod*)dp);
17524887Schin }
17534887Schin 
test_expr(Lex_t * lp,int sym)17548462SApril.Chin@Sun.COM static Shnode_t *test_expr(Lex_t *lp,int sym)
17554887Schin {
17568462SApril.Chin@Sun.COM 	register Shnode_t *t = test_or(lp);
17578462SApril.Chin@Sun.COM 	if(lp->token!=sym)
17588462SApril.Chin@Sun.COM 		sh_syntax(lp);
17594887Schin 	return(t);
17604887Schin }
17614887Schin 
test_or(Lex_t * lp)17628462SApril.Chin@Sun.COM static Shnode_t *test_or(Lex_t *lp)
17634887Schin {
17648462SApril.Chin@Sun.COM 	register Shnode_t *t = test_and(lp);
17658462SApril.Chin@Sun.COM 	while(lp->token==ORFSYM)
17668462SApril.Chin@Sun.COM 		t = makelist(lp,TORF|TTEST,t,test_and(lp));
17674887Schin 	return(t);
17684887Schin }
17694887Schin 
test_and(Lex_t * lp)17708462SApril.Chin@Sun.COM static Shnode_t *test_and(Lex_t *lp)
17714887Schin {
17728462SApril.Chin@Sun.COM 	register Shnode_t *t = test_primary(lp);
17738462SApril.Chin@Sun.COM 	while(lp->token==ANDFSYM)
17748462SApril.Chin@Sun.COM 		t = makelist(lp,TAND|TTEST,t,test_primary(lp));
17754887Schin 	return(t);
17764887Schin }
17774887Schin 
17784887Schin /*
17794887Schin  * convert =~ into == ~(E)
17804887Schin  */
ere_match(void)17814887Schin static void ere_match(void)
17824887Schin {
17834887Schin 	Sfio_t *base, *iop = sfopen((Sfio_t*)0," ~(E)","s");
17844887Schin 	register int c;
17854887Schin 	while( fcgetc(c),(c==' ' || c=='\t'));
17864887Schin 	if(c)
17874887Schin 		fcseek(-1);
17884887Schin 	if(!(base=fcfile()))
17894887Schin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
17904887Schin 	fcclose();
17914887Schin         sfstack(base,iop);
17924887Schin         fcfopen(base);
17934887Schin }
17944887Schin 
test_primary(Lex_t * lexp)17958462SApril.Chin@Sun.COM static Shnode_t *test_primary(Lex_t *lexp)
17964887Schin {
17974887Schin 	register struct argnod *arg;
17984887Schin 	register Shnode_t *t;
17994887Schin 	register int num,token;
18008462SApril.Chin@Sun.COM 	token = skipnl(lexp,0);
18018462SApril.Chin@Sun.COM 	num = lexp->digits;
18024887Schin 	switch(token)
18034887Schin 	{
18044887Schin 	    case '(':
18058462SApril.Chin@Sun.COM 		t = test_expr(lexp,')');
18068462SApril.Chin@Sun.COM 		t = makelist(lexp,TTST|TTEST|TPAREN ,t, (Shnode_t*)pointerof(lexp->sh->inlineno));
18074887Schin 		break;
18084887Schin 	    case '!':
18098462SApril.Chin@Sun.COM 		if(!(t = test_primary(lexp)))
18108462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18114887Schin 		t->tre.tretyp |= TNEGATE;
18124887Schin 		return(t);
18134887Schin 	    case TESTUNOP:
18148462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
18158462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18164887Schin #if SHOPT_KIA
18178462SApril.Chin@Sun.COM 		if(lexp->kiafile && !strchr("sntzoOG",num))
18184887Schin 		{
18198462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno- (lexp->token==NL);
18204887Schin 			unsigned long r;
18218462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->script,'t',0,"");
18228462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
18234887Schin 		}
18244887Schin #endif /* SHOPT_KIA */
18258462SApril.Chin@Sun.COM 		t = makelist(lexp,TTST|TTEST|TUNARY|(num<<TSHIFT),
18268462SApril.Chin@Sun.COM 			(Shnode_t*)lexp->arg,(Shnode_t*)lexp->arg);
18278462SApril.Chin@Sun.COM 		t->tst.tstline =  lexp->sh->inlineno;
18284887Schin 		break;
18294887Schin 	    /* binary test operators */
18304887Schin 	    case 0:
18318462SApril.Chin@Sun.COM 		arg = lexp->arg;
18328462SApril.Chin@Sun.COM 		if((token=sh_lex(lexp))==TESTBINOP)
18334887Schin 		{
18348462SApril.Chin@Sun.COM 			num = lexp->digits;
18354887Schin 			if(num==TEST_REP)
18364887Schin 			{
18374887Schin 				ere_match();
18384887Schin 				num = TEST_PEQ;
18394887Schin 			}
18404887Schin 		}
18414887Schin 		else if(token=='<')
18424887Schin 			num = TEST_SLT;
18434887Schin 		else if(token=='>')
18444887Schin 			num = TEST_SGT;
18454887Schin 		else if(token==ANDFSYM||token==ORFSYM||token==ETESTSYM||token==RPAREN)
18464887Schin 		{
18478462SApril.Chin@Sun.COM 			t = makelist(lexp,TTST|TTEST|TUNARY|('n'<<TSHIFT),
18484887Schin 				(Shnode_t*)arg,(Shnode_t*)arg);
18498462SApril.Chin@Sun.COM 			t->tst.tstline =  lexp->sh->inlineno;
18504887Schin 			return(t);
18514887Schin 		}
18524887Schin 		else
18538462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18544887Schin #if SHOPT_KIA
18558462SApril.Chin@Sun.COM 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
18564887Schin 		{
18578462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno- (lexp->token==NL);
18584887Schin 			unsigned long r;
18598462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
18608462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
18614887Schin 		}
18624887Schin #endif /* SHOPT_KIA */
18638462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
18648462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18654887Schin 		if(num&TEST_PATTERN)
18664887Schin 		{
18678462SApril.Chin@Sun.COM 			if(lexp->arg->argflag&(ARG_EXP|ARG_MAC))
18684887Schin 				num &= ~TEST_PATTERN;
18694887Schin 		}
18704887Schin 		t = getnode(tstnod);
18714887Schin 		t->lst.lsttyp = TTST|TTEST|TBINARY|(num<<TSHIFT);
18724887Schin 		t->lst.lstlef = (Shnode_t*)arg;
18738462SApril.Chin@Sun.COM 		t->lst.lstrit = (Shnode_t*)lexp->arg;
18748462SApril.Chin@Sun.COM 		t->tst.tstline =  lexp->sh->inlineno;
18754887Schin #if SHOPT_KIA
18768462SApril.Chin@Sun.COM 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
18774887Schin 		{
18788462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno-(lexp->token==NL);
18794887Schin 			unsigned long r;
18808462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
18818462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
18824887Schin 		}
18834887Schin #endif /* SHOPT_KIA */
18844887Schin 		break;
18854887Schin 	    default:
18864887Schin 		return(0);
18874887Schin 	}
18888462SApril.Chin@Sun.COM 	skipnl(lexp,0);
18894887Schin 	return(t);
18904887Schin }
18914887Schin 
18924887Schin #if SHOPT_KIA
18934887Schin /*
18944887Schin  * return an entity checksum
18954887Schin  * The entity is created if it doesn't exist
18964887Schin  */
kiaentity(Lex_t * lexp,const char * name,int len,int type,int first,int last,unsigned long parent,int pkind,int width,const char * attr)18978462SApril.Chin@Sun.COM unsigned long kiaentity(Lex_t *lexp,const char *name,int len,int type,int first,int last,unsigned long parent, int pkind, int width, const char *attr)
18984887Schin {
18998462SApril.Chin@Sun.COM 	Stk_t	*stkp = lexp->sh->stk;
19004887Schin 	Namval_t *np;
19018462SApril.Chin@Sun.COM 	long offset = stktell(stkp);
19028462SApril.Chin@Sun.COM 	sfputc(stkp,type);
19034887Schin 	if(len>0)
19048462SApril.Chin@Sun.COM 		sfwrite(stkp,name,len);
19054887Schin 	else
19064887Schin 	{
19074887Schin 		if(type=='p')
19088462SApril.Chin@Sun.COM 			sfputr(stkp,path_basename(name),0);
19094887Schin 		else
19108462SApril.Chin@Sun.COM 			sfputr(stkp,name,0);
19114887Schin 	}
19128462SApril.Chin@Sun.COM 	np = nv_search(stakptr(offset),lexp->entity_tree,NV_ADD);
19138462SApril.Chin@Sun.COM 	stkseek(stkp,offset);
19144887Schin 	np->nvalue.i = pkind;
19154887Schin 	nv_setsize(np,width);
19164887Schin 	if(!nv_isattr(np,NV_TAGGED) && first>=0)
19174887Schin 	{
19184887Schin 		nv_onattr(np,NV_TAGGED);
19194887Schin 		if(!pkind)
19204887Schin 			pkind = '0';
19214887Schin 		if(len>0)
19228462SApril.Chin@Sun.COM 			sfprintf(lexp->kiafile,"%..64d;%c;%.*s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,len,name,first,last,parent,lexp->fscript,pkind,width,attr);
19234887Schin 		else
19248462SApril.Chin@Sun.COM 			sfprintf(lexp->kiafile,"%..64d;%c;%s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,name,first,last,parent,lexp->fscript,pkind,width,attr);
19254887Schin 	}
19264887Schin 	return(np->hash);
19274887Schin }
19284887Schin 
kia_add(register Namval_t * np,void * data)19294887Schin static void kia_add(register Namval_t *np, void *data)
19304887Schin {
19314887Schin 	char *name = nv_name(np);
19328462SApril.Chin@Sun.COM 	Lex_t	*lp = (Lex_t*)data;
19334887Schin 	NOT_USED(data);
19348462SApril.Chin@Sun.COM 	kiaentity(lp,name+1,-1,*name,0,-1,(*name=='p'?lp->unknown:lp->script),np->nvalue.i,nv_size(np),"");
19354887Schin }
19364887Schin 
kiaclose(Lex_t * lexp)19378462SApril.Chin@Sun.COM int kiaclose(Lex_t *lexp)
19384887Schin {
19394887Schin 	register off_t off1,off2;
19404887Schin 	register int n;
19418462SApril.Chin@Sun.COM 	if(lexp->kiafile)
19424887Schin 	{
19438462SApril.Chin@Sun.COM 		unsigned long r = kiaentity(lexp,lexp->scriptname,-1,'p',-1,lexp->sh->inlineno-1,0,'s',0,"");
19448462SApril.Chin@Sun.COM 		kiaentity(lexp,lexp->scriptname,-1,'p',1,lexp->sh->inlineno-1,r,'s',0,"");
19458462SApril.Chin@Sun.COM 		kiaentity(lexp,lexp->scriptname,-1,'f',1,lexp->sh->inlineno-1,r,'s',0,"");
19468462SApril.Chin@Sun.COM 		nv_scan(lexp->entity_tree,kia_add,(void*)lexp,NV_TAGGED,0);
19478462SApril.Chin@Sun.COM 		off1 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
19488462SApril.Chin@Sun.COM 		sfseek(lexp->kiatmp,(off_t)0,SEEK_SET);
19498462SApril.Chin@Sun.COM 		sfmove(lexp->kiatmp,lexp->kiafile,SF_UNBOUND,-1);
19508462SApril.Chin@Sun.COM 		off2 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
19514887Schin #ifdef SF_BUFCONST
19524887Schin 		if(off2==off1)
19538462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin));
19544887Schin 		else
19558462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nRELATIONSHIP;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin),(Sflong_t)off1,(size_t)(off2-off1));
19564887Schin 		if(off2 >= INT_MAX)
19574887Schin 			off2 = -(n+12);
19588462SApril.Chin@Sun.COM 		sfprintf(lexp->kiafile,"%010.10lld;%010d\n",(Sflong_t)off2+10, n+12);
19594887Schin #else
19604887Schin 		if(off2==off1)
19618462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin);
19624887Schin 		else
19638462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin,off1,off2-off1);
19648462SApril.Chin@Sun.COM 		sfprintf(lexp->kiafile,"%010d;%010d\n",off2+10, n+12);
19654887Schin #endif
19664887Schin 	}
19678462SApril.Chin@Sun.COM 	return(sfclose(lexp->kiafile));
19684887Schin }
19694887Schin #endif /* SHOPT_KIA */
1970