14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1982-2009 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>
35*10898Sroland.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 */
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 
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  */
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  */
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 
2508462SApril.Chin@Sun.COM static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
2514887Schin {
2524887Schin 	register Shnode_t *t = getnode(arithnod);
2534887Schin 	t->ar.artyp = TARITH;
2548462SApril.Chin@Sun.COM 	t->ar.arline = sh_getlineno(lp);
2554887Schin 	t->ar.arexpr = ap;
2564887Schin 	if(ap->argflag&ARG_RAW)
2574887Schin 		t->ar.arcomp = sh_arithcomp(ap->argval);
2584887Schin 	else
2594887Schin 		t->ar.arcomp = 0;
2604887Schin 	return(t);
2614887Schin }
2624887Schin 
2634887Schin /*
2644887Schin  *  Make a node corresponding to a command list
2654887Schin  */
2668462SApril.Chin@Sun.COM static Shnode_t	*makelist(Lex_t *lexp, int type, Shnode_t *l, Shnode_t *r)
2674887Schin {
2684887Schin 	register Shnode_t	*t;
2694887Schin 	if(!l || !r)
2708462SApril.Chin@Sun.COM 		sh_syntax(lexp);
2714887Schin 	else
2724887Schin 	{
2734887Schin 		if((type&COMMSK) == TTST)
2744887Schin 			t = getnode(tstnod);
2754887Schin 		else
2764887Schin 			t = getnode(lstnod);
2774887Schin 		t->lst.lsttyp = type;
2784887Schin 		t->lst.lstlef = l;
2794887Schin 		t->lst.lstrit = r;
2804887Schin 	}
2814887Schin 	return(t);
2824887Schin }
2834887Schin 
2844887Schin /*
2854887Schin  * entry to shell parser
2864887Schin  * Flag can be the union of SH_EOF|SH_NL
2874887Schin  */
2884887Schin 
2894887Schin void	*sh_parse(Shell_t *shp, Sfio_t *iop, int flag)
2904887Schin {
2914887Schin 	register Shnode_t	*t;
2928462SApril.Chin@Sun.COM 	Lex_t			*lexp = (Lex_t*)shp->lex_context;
2934887Schin 	Fcin_t	sav_input;
2948462SApril.Chin@Sun.COM 	struct argnod *sav_arg = lexp->arg;
2954887Schin 	int	sav_prompt = shp->nextprompt;
296*10898Sroland.mainz@nrubsig.org 	if(shp->binscript && (sffileno(iop)==shp->infd || (flag&SH_FUNEVAL)))
2978462SApril.Chin@Sun.COM 		return((void*)sh_trestore(shp,iop));
2984887Schin 	fcsave(&sav_input);
2994887Schin 	shp->st.staklist = 0;
3008462SApril.Chin@Sun.COM 	lexp->heredoc = 0;
3018462SApril.Chin@Sun.COM 	lexp->inlineno = shp->inlineno;
3028462SApril.Chin@Sun.COM 	lexp->firstline = shp->st.firstline;
3034887Schin 	shp->nextprompt = 1;
3044887Schin 	loop_level = 0;
3054887Schin 	label_list = label_last = 0;
3064887Schin 	if(sh_isoption(SH_INTERACTIVE))
3074887Schin 		sh_onstate(SH_INTERACTIVE);
3084887Schin 	if(sh_isoption(SH_VERBOSE))
3094887Schin 		sh_onstate(SH_VERBOSE);
3108462SApril.Chin@Sun.COM 	sh_lexopen(lexp,shp,0);
3114887Schin 	if(fcfopen(iop) < 0)
3124887Schin 		return(NIL(void*));
3134887Schin 	if(fcfile())
3144887Schin 	{
3154887Schin 		char *cp = fcfirst();
3164887Schin 		if( cp[0]==CNTL('k') &&  cp[1]==CNTL('s') && cp[2]==CNTL('h') && cp[3]==0)
3174887Schin 		{
3184887Schin 			int version;
3194887Schin 			fcseek(4);
3204887Schin 			fcgetc(version);
3214887Schin 			fcclose();
3224887Schin 			fcrestore(&sav_input);
3238462SApril.Chin@Sun.COM 			lexp->arg = sav_arg;
3244887Schin 			if(version > 3)
3254887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_lexversion);
326*10898Sroland.mainz@nrubsig.org 			if(sffileno(iop)==shp->infd || (flag&SH_FUNEVAL))
3274887Schin 				shp->binscript = 1;
3284887Schin 			sfgetc(iop);
3298462SApril.Chin@Sun.COM 			return((void*)sh_trestore(shp,iop));
3304887Schin 		}
3314887Schin 	}
332*10898Sroland.mainz@nrubsig.org 	flag &= ~SH_FUNEVAL;
3334887Schin 	if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0)
3344887Schin 		shp->inlineno=1;
3354887Schin #if KSHELL
3364887Schin 	shp->nextprompt = 2;
3374887Schin #endif
3388462SApril.Chin@Sun.COM 	t = sh_cmd(lexp,(flag&SH_EOF)?EOFSYM:'\n',SH_SEMI|SH_EMPTY|(flag&SH_NL));
3394887Schin 	fcclose();
3404887Schin 	fcrestore(&sav_input);
3418462SApril.Chin@Sun.COM 	lexp->arg = sav_arg;
3424887Schin 	/* unstack any completed alias expansions */
3434887Schin 	if((sfset(iop,0,0)&SF_STRING) && !sfreserve(iop,0,-1))
3444887Schin 	{
3454887Schin 		Sfio_t *sp = sfstack(iop,NULL);
3464887Schin 		if(sp)
3474887Schin 			sfclose(sp);
3484887Schin 	}
3494887Schin 	shp->nextprompt = sav_prompt;
3504887Schin 	if(flag&SH_NL)
3514887Schin 	{
3528462SApril.Chin@Sun.COM 		shp->st.firstline = lexp->firstline;
3538462SApril.Chin@Sun.COM 		shp->inlineno = lexp->inlineno;
3544887Schin 	}
3558462SApril.Chin@Sun.COM 	stkseek(shp->stk,0);
3564887Schin 	return((void*)t);
3574887Schin }
3584887Schin 
3594887Schin /*
3604887Schin  * This routine parses up the matching right parenthesis and returns
3614887Schin  * the parse tree
3624887Schin  */
3638462SApril.Chin@Sun.COM Shnode_t *sh_dolparen(Lex_t* lp)
3644887Schin {
3654887Schin 	register Shnode_t *t=0;
3664887Schin 	Sfio_t *sp = fcfile();
3678462SApril.Chin@Sun.COM 	int line = lp->sh->inlineno;
3688462SApril.Chin@Sun.COM 	lp->sh->inlineno = error_info.line+lp->sh->st.firstline;
3698462SApril.Chin@Sun.COM 	sh_lexopen(lp,lp->sh,1);
3708462SApril.Chin@Sun.COM 	lp->comsub = 1;
3718462SApril.Chin@Sun.COM 	switch(sh_lex(lp))
3724887Schin 	{
3734887Schin 	    /* ((...)) arithmetic expression */
3744887Schin 	    case EXPRSYM:
3758462SApril.Chin@Sun.COM 		t = getanode(lp,lp->arg);
3764887Schin 		break;
3774887Schin 	    case LPAREN:
3788462SApril.Chin@Sun.COM 		t = sh_cmd(lp,RPAREN,SH_NL|SH_EMPTY);
3798462SApril.Chin@Sun.COM 		break;
3808462SApril.Chin@Sun.COM 	    case LBRACE:
3818462SApril.Chin@Sun.COM 		t = sh_cmd(lp,RBRACE,SH_NL|SH_EMPTY);
3824887Schin 		break;
3834887Schin 	}
3848462SApril.Chin@Sun.COM 	lp->comsub = 0;
3854887Schin 	if(!sp && (sp=fcfile()))
3864887Schin 	{
3874887Schin 		/*
3884887Schin 		 * This code handles the case where string has been converted
3894887Schin 		 * to a file by an alias setup
3904887Schin 		 */
3914887Schin 		register int c;
3924887Schin 		char *cp;
3934887Schin 		if(fcgetc(c) > 0)
3944887Schin 			fcseek(-1);
3954887Schin 		cp = fcseek(0);
3964887Schin 		fcclose();
3974887Schin 		fcsopen(cp);
3984887Schin 		sfclose(sp);
3994887Schin 	}
4008462SApril.Chin@Sun.COM 	lp->sh->inlineno = line;
4014887Schin 	return(t);
4024887Schin }
4034887Schin 
4044887Schin /*
4054887Schin  * remove temporary files and stacks
4064887Schin  */
4074887Schin 
4088462SApril.Chin@Sun.COM void	sh_freeup(Shell_t *shp)
4094887Schin {
4108462SApril.Chin@Sun.COM 	if(shp->st.staklist)
4118462SApril.Chin@Sun.COM 		sh_funstaks(shp->st.staklist,-1);
4128462SApril.Chin@Sun.COM 	shp->st.staklist = 0;
4134887Schin }
4144887Schin 
4154887Schin /*
4164887Schin  * increase reference count for each stack in function list when flag>0
4174887Schin  * decrease reference count for each stack in function list when flag<=0
4184887Schin  * stack is freed when reference count is zero
4194887Schin  */
4204887Schin 
4214887Schin void sh_funstaks(register struct slnod *slp,int flag)
4224887Schin {
4234887Schin 	register struct slnod *slpold;
4244887Schin 	while(slpold=slp)
4254887Schin 	{
4264887Schin 		if(slp->slchild)
4274887Schin 			sh_funstaks(slp->slchild,flag);
4284887Schin 		slp = slp->slnext;
4294887Schin 		if(flag<=0)
4304887Schin 			stakdelete(slpold->slptr);
4314887Schin 		else
4324887Schin 			staklink(slpold->slptr);
4334887Schin 	}
4344887Schin }
4354887Schin /*
4364887Schin  * cmd
4374887Schin  *	empty
4384887Schin  *	list
4394887Schin  *	list & [ cmd ]
4404887Schin  *	list [ ; cmd ]
4414887Schin  */
4424887Schin 
4438462SApril.Chin@Sun.COM static Shnode_t	*sh_cmd(Lex_t *lexp, register int sym, int flag)
4444887Schin {
4454887Schin 	register Shnode_t	*left, *right;
4464887Schin 	register int type = FINT|FAMP;
4474887Schin 	if(sym==NL)
4488462SApril.Chin@Sun.COM 		lexp->lasttok = 0;
4498462SApril.Chin@Sun.COM 	left = list(lexp,flag);
4508462SApril.Chin@Sun.COM 	if(lexp->token==NL)
4514887Schin 	{
4524887Schin 		if(flag&SH_NL)
4538462SApril.Chin@Sun.COM 			lexp->token=';';
4544887Schin 	}
4554887Schin 	else if(!left && !(flag&SH_EMPTY))
4568462SApril.Chin@Sun.COM 		sh_syntax(lexp);
4578462SApril.Chin@Sun.COM 	switch(lexp->token)
4584887Schin 	{
4594887Schin 	    case COOPSYM:		/* set up a cooperating process */
4604887Schin 		type |= (FPIN|FPOU|FPCL|FCOOP);
4614887Schin 		/* FALL THRU */
4624887Schin 	    case '&':
4634887Schin 		if(left)
4644887Schin 		{
4654887Schin 			/* (...)& -> {...;} & */
4664887Schin 			if(left->tre.tretyp==TPAR)
4674887Schin 				left = left->par.partre;
4688462SApril.Chin@Sun.COM 			left = makeparent(lexp,TFORK|type, left);
4694887Schin 		}
4704887Schin 		/* FALL THRU */
4714887Schin 	    case ';':
4724887Schin 		if(!left)
4738462SApril.Chin@Sun.COM 			sh_syntax(lexp);
4748462SApril.Chin@Sun.COM 		if(right=sh_cmd(lexp,sym,flag|SH_EMPTY))
4758462SApril.Chin@Sun.COM 			left=makelist(lexp,TLST, left, right);
4764887Schin 		break;
4774887Schin 	    case EOFSYM:
4784887Schin 		if(sym==NL)
4794887Schin 			break;
4804887Schin 	    default:
4818462SApril.Chin@Sun.COM 		if(sym && sym!=lexp->token)
4824887Schin 		{
4838462SApril.Chin@Sun.COM 			if(sym!=ELSESYM || (lexp->token!=ELIFSYM && lexp->token!=FISYM))
4848462SApril.Chin@Sun.COM 				sh_syntax(lexp);
4854887Schin 		}
4864887Schin 	}
4874887Schin 	return(left);
4884887Schin }
4894887Schin 
4904887Schin /*
4914887Schin  * list
4924887Schin  *	term
4934887Schin  *	list && term
4944887Schin  *	list || term
4954887Schin  *      unfortunately, these are equal precedence
4964887Schin  */
4978462SApril.Chin@Sun.COM static Shnode_t	*list(Lex_t *lexp, register int flag)
4984887Schin {
4998462SApril.Chin@Sun.COM 	register Shnode_t	*t = term(lexp,flag);
5004887Schin 	register int 	token;
5018462SApril.Chin@Sun.COM 	while(t && ((token=lexp->token)==ANDFSYM || token==ORFSYM))
5028462SApril.Chin@Sun.COM 		t = makelist(lexp,(token==ANDFSYM?TAND:TORF), t, term(lexp,SH_NL|SH_SEMI));
5034887Schin 	return(t);
5044887Schin }
5054887Schin 
5064887Schin /*
5074887Schin  * term
5084887Schin  *	item
5094887Schin  *	item | term
5104887Schin  */
5118462SApril.Chin@Sun.COM static Shnode_t	*term(Lex_t *lexp,register int flag)
5124887Schin {
5134887Schin 	register Shnode_t	*t;
5144887Schin 	register int token;
5154887Schin 	if(flag&SH_NL)
5168462SApril.Chin@Sun.COM 		token = skipnl(lexp,flag);
5174887Schin 	else
5188462SApril.Chin@Sun.COM 		token = sh_lex(lexp);
5194887Schin 	/* check to see if pipeline is to be timed */
5204887Schin 	if(token==TIMESYM || token==NOTSYM)
5214887Schin 	{
5224887Schin 		t = getnode(parnod);
5234887Schin 		t->par.partyp=TTIME;
5248462SApril.Chin@Sun.COM 		if(lexp->token==NOTSYM)
5254887Schin 			t->par.partyp |= COMSCAN;
5268462SApril.Chin@Sun.COM 		t->par.partre = term(lexp,0);
5274887Schin 	}
5288462SApril.Chin@Sun.COM 	else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && lexp->token=='|')
5294887Schin 	{
5304887Schin 		register Shnode_t	*tt;
5314887Schin 		int showme = t->tre.tretyp&FSHOWME;
5328462SApril.Chin@Sun.COM 		t = makeparent(lexp,TFORK|FPOU,t);
5338462SApril.Chin@Sun.COM 		if(tt=term(lexp,SH_NL))
5344887Schin 		{
5354887Schin 			switch(tt->tre.tretyp&COMMSK)
5364887Schin 			{
5374887Schin 			    case TFORK:
5384887Schin 				tt->tre.tretyp |= FPIN|FPCL;
5394887Schin 				break;
5404887Schin 			    case TFIL:
5414887Schin 				tt->lst.lstlef->tre.tretyp |= FPIN|FPCL;
5424887Schin 				break;
5434887Schin 			    default:
5448462SApril.Chin@Sun.COM 				tt= makeparent(lexp,TSETIO|FPIN|FPCL,tt);
5454887Schin 			}
5468462SApril.Chin@Sun.COM 			t=makelist(lexp,TFIL,t,tt);
5474887Schin 			t->tre.tretyp |= showme;
5484887Schin 		}
5498462SApril.Chin@Sun.COM 		else if(lexp->token)
5508462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5514887Schin 	}
5524887Schin 	return(t);
5534887Schin }
5544887Schin 
5554887Schin /*
5564887Schin  * case statement
5574887Schin  */
5588462SApril.Chin@Sun.COM static struct regnod*	syncase(Lex_t *lexp,register int esym)
5594887Schin {
5608462SApril.Chin@Sun.COM 	register int tok = skipnl(lexp,0);
5614887Schin 	register struct regnod	*r;
5624887Schin 	if(tok==esym)
5634887Schin 		return(NIL(struct regnod*));
5644887Schin 	r = (struct regnod*)stakalloc(sizeof(struct regnod));
5654887Schin 	r->regptr=0;
5664887Schin 	r->regflag=0;
5674887Schin 	if(tok==LPAREN)
5688462SApril.Chin@Sun.COM 		skipnl(lexp,0);
5694887Schin 	while(1)
5704887Schin 	{
5718462SApril.Chin@Sun.COM 		if(!lexp->arg)
5728462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5738462SApril.Chin@Sun.COM 		lexp->arg->argnxt.ap=r->regptr;
5748462SApril.Chin@Sun.COM 		r->regptr = lexp->arg;
5758462SApril.Chin@Sun.COM 		if((tok=sh_lex(lexp))==RPAREN)
5764887Schin 			break;
5774887Schin 		else if(tok=='|')
5788462SApril.Chin@Sun.COM 			sh_lex(lexp);
5794887Schin 		else
5808462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5814887Schin 	}
5828462SApril.Chin@Sun.COM 	r->regcom=sh_cmd(lexp,0,SH_NL|SH_EMPTY|SH_SEMI);
5838462SApril.Chin@Sun.COM 	if((tok=lexp->token)==BREAKCASESYM)
5848462SApril.Chin@Sun.COM 		r->regnxt=syncase(lexp,esym);
5854887Schin 	else if(tok==FALLTHRUSYM)
5864887Schin 	{
5874887Schin 		r->regflag++;
5888462SApril.Chin@Sun.COM 		r->regnxt=syncase(lexp,esym);
5894887Schin 	}
5904887Schin 	else
5914887Schin 	{
5924887Schin 		if(tok!=esym && tok!=EOFSYM)
5938462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5944887Schin 		r->regnxt=0;
5954887Schin 	}
5968462SApril.Chin@Sun.COM 	if(lexp->token==EOFSYM)
5974887Schin 		return(NIL(struct regnod*));
5984887Schin 	return(r);
5994887Schin }
6004887Schin 
6014887Schin /*
6024887Schin  * This routine creates the parse tree for the arithmetic for
6034887Schin  * When called, shlex.arg contains the string inside ((...))
6044887Schin  * When the first argument is missing, a while node is returned
6054887Schin  * Otherise a list containing an arithmetic command and a while
6064887Schin  * is returned.
6074887Schin  */
6088462SApril.Chin@Sun.COM static Shnode_t	*arithfor(Lex_t *lexp,register Shnode_t *tf)
6094887Schin {
6104887Schin 	register Shnode_t	*t, *tw = tf;
6114887Schin 	register int	offset;
6124887Schin 	register struct argnod *argp;
6134887Schin 	register int n;
6148462SApril.Chin@Sun.COM 	Stk_t		*stkp = lexp->sh->stk;
6158462SApril.Chin@Sun.COM 	int argflag = lexp->arg->argflag;
6164887Schin 	/* save current input */
6174887Schin 	Fcin_t	sav_input;
6184887Schin 	fcsave(&sav_input);
6198462SApril.Chin@Sun.COM 	fcsopen(lexp->arg->argval);
6204887Schin 	/* split ((...)) into three expressions */
6214887Schin 	for(n=0; ; n++)
6224887Schin 	{
6234887Schin 		register int c;
6248462SApril.Chin@Sun.COM 		argp = (struct argnod*)stkseek(stkp,ARGVAL);
6254887Schin 		argp->argnxt.ap = 0;
6264887Schin 		argp->argchn.cp = 0;
6274887Schin 		argp->argflag = argflag;
6284887Schin 		if(n==2)
6294887Schin 			break;
6304887Schin 		/* copy up to ; onto the stack */
6318462SApril.Chin@Sun.COM 		sh_lexskip(lexp,';',1,ST_NESTED);
6328462SApril.Chin@Sun.COM 		offset = stktell(stkp)-1;
6334887Schin 		if((c=fcpeek(-1))!=';')
6344887Schin 			break;
6354887Schin 		/* remove trailing white space */
6368462SApril.Chin@Sun.COM 		while(offset>ARGVAL && ((c= *stkptr(stkp,offset-1)),isspace(c)))
6374887Schin 			offset--;
6384887Schin 		/* check for empty initialization expression  */
6394887Schin 		if(offset==ARGVAL && n==0)
6404887Schin 			continue;
6418462SApril.Chin@Sun.COM 		stkseek(stkp,offset);
6424887Schin 		/* check for empty condition and treat as while((1)) */
6434887Schin 		if(offset==ARGVAL)
6448462SApril.Chin@Sun.COM 			sfputc(stkp,'1');
6458462SApril.Chin@Sun.COM 		argp = (struct argnod*)stkfreeze(stkp,1);
6468462SApril.Chin@Sun.COM 		t = getanode(lexp,argp);
6474887Schin 		if(n==0)
6488462SApril.Chin@Sun.COM 			tf = makelist(lexp,TLST,t,tw);
6494887Schin 		else
6504887Schin 			tw->wh.whtre = t;
6514887Schin 	}
6524887Schin 	while((offset=fcpeek(0)) && isspace(offset))
6534887Schin 		fcseek(1);
6544887Schin 	stakputs(fcseek(0));
6554887Schin 	argp = (struct argnod*)stakfreeze(1);
6564887Schin 	fcrestore(&sav_input);
6574887Schin 	if(n<2)
6584887Schin 	{
6598462SApril.Chin@Sun.COM 		lexp->token = RPAREN|SYMREP;
6608462SApril.Chin@Sun.COM 		sh_syntax(lexp);
6614887Schin 	}
6624887Schin 	/* check whether the increment is present */
6634887Schin 	if(*argp->argval)
6644887Schin 	{
6658462SApril.Chin@Sun.COM 		t = getanode(lexp,argp);
6664887Schin 		tw->wh.whinc = (struct arithnod*)t;
6674887Schin 	}
6684887Schin 	else
6694887Schin 		tw->wh.whinc = 0;
6708462SApril.Chin@Sun.COM 	sh_lexopen(lexp, lexp->sh,1);
6718462SApril.Chin@Sun.COM 	if((n=sh_lex(lexp))==NL)
6728462SApril.Chin@Sun.COM 		n = skipnl(lexp,0);
6734887Schin 	else if(n==';')
6748462SApril.Chin@Sun.COM 		n = sh_lex(lexp);
6754887Schin 	if(n!=DOSYM && n!=LBRACE)
6768462SApril.Chin@Sun.COM 		sh_syntax(lexp);
6778462SApril.Chin@Sun.COM 	tw->wh.dotre = sh_cmd(lexp,n==DOSYM?DONESYM:RBRACE,SH_NL);
6784887Schin 	tw->wh.whtyp = TWH;
6794887Schin 	return(tf);
6804887Schin 
6814887Schin }
6824887Schin 
6838462SApril.Chin@Sun.COM static Shnode_t *funct(Lex_t *lexp)
6844887Schin {
6858462SApril.Chin@Sun.COM 	Shell_t	*shp = lexp->sh;
6864887Schin 	register Shnode_t *t;
6874887Schin 	register int flag;
6884887Schin 	struct slnod *volatile slp=0;
6894887Schin 	Stak_t *savstak;
6904887Schin 	Sfoff_t	first, last;
6918462SApril.Chin@Sun.COM 	struct functnod *volatile fp;
6924887Schin 	Sfio_t *iop;
6934887Schin #if SHOPT_KIA
6948462SApril.Chin@Sun.COM 	unsigned long current = lexp->current;
6954887Schin #endif /* SHOPT_KIA */
6964887Schin 	int jmpval, saveloop=loop_level;
6974887Schin 	struct argnod *savelabel = label_last;
6984887Schin 	struct  checkpt buff;
6998462SApril.Chin@Sun.COM 	int save_optget = opt_get;
7008462SApril.Chin@Sun.COM 	void	*in_mktype = shp->mktype;
7018462SApril.Chin@Sun.COM 	shp->mktype = 0;
7028462SApril.Chin@Sun.COM 	opt_get = 0;
7034887Schin 	t = getnode(functnod);
7048462SApril.Chin@Sun.COM 	t->funct.functline = shp->inlineno;
7054887Schin 	t->funct.functtyp=TFUN;
7064887Schin 	t->funct.functargs = 0;
7078462SApril.Chin@Sun.COM 	if(!(flag = (lexp->token==FUNCTSYM)))
7084887Schin 		t->funct.functtyp |= FPOSIX;
7098462SApril.Chin@Sun.COM 	else if(sh_lex(lexp))
7108462SApril.Chin@Sun.COM 		sh_syntax(lexp);
7114887Schin 	if(!(iop=fcfile()))
7124887Schin 	{
7134887Schin 		iop = sfopen(NIL(Sfio_t*),fcseek(0),"s");
7144887Schin 		fcclose();
7154887Schin 		fcfopen(iop);
7164887Schin 	}
7174887Schin 	t->funct.functloc = first = fctell();
7188462SApril.Chin@Sun.COM 	if(!shp->st.filename || sffileno(iop)<0)
7194887Schin 	{
7204887Schin 		if(fcfill() >= 0)
7214887Schin 			fcseek(-1);
722*10898Sroland.mainz@nrubsig.org 		if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
7238462SApril.Chin@Sun.COM 			t->funct.functloc = sfseek(shp->hist_ptr->histfp,(off_t)0,SEEK_CUR);
7244887Schin 		else
7254887Schin 		{
7264887Schin 			/* copy source to temporary file */
7274887Schin 			t->funct.functloc = 0;
7288462SApril.Chin@Sun.COM 			if(lexp->sh->heredocs)
7298462SApril.Chin@Sun.COM 				t->funct.functloc = sfseek(lexp->sh->heredocs,(Sfoff_t)0, SEEK_END);
7304887Schin 			else
7318462SApril.Chin@Sun.COM 				lexp->sh->heredocs = sftmp(HERE_MEM);
7328462SApril.Chin@Sun.COM 			lexp->sh->funlog = lexp->sh->heredocs;
7334887Schin 			t->funct.functtyp |= FPIN;
7344887Schin 		}
7354887Schin 	}
7368462SApril.Chin@Sun.COM 	t->funct.functnam= (char*)lexp->arg->argval;
7374887Schin #if SHOPT_KIA
7388462SApril.Chin@Sun.COM 	if(lexp->kiafile)
7398462SApril.Chin@Sun.COM 		lexp->current = kiaentity(lexp,t->funct.functnam,-1,'p',-1,-1,lexp->script,'p',0,"");
7404887Schin #endif /* SHOPT_KIA */
7414887Schin 	if(flag)
7424887Schin 	{
7438462SApril.Chin@Sun.COM 		lexp->token = sh_lex(lexp);
7444887Schin #if SHOPT_BASH
7458462SApril.Chin@Sun.COM 		if(lexp->token == LPAREN)
7464887Schin 		{
7478462SApril.Chin@Sun.COM 			if((lexp->token = sh_lex(lexp)) == RPAREN)
7484887Schin 				t->funct.functtyp |= FPOSIX;
7494887Schin 			else
7508462SApril.Chin@Sun.COM 				sh_syntax(lexp);
7514887Schin 		}
7524887Schin #endif
7534887Schin 	}
7544887Schin 	if(t->funct.functtyp&FPOSIX)
7558462SApril.Chin@Sun.COM 		skipnl(lexp,0);
7564887Schin 	else
7574887Schin 	{
7588462SApril.Chin@Sun.COM 		if(lexp->token==0)
7598462SApril.Chin@Sun.COM 			t->funct.functargs = (struct comnod*)simple(lexp,SH_NOIO|SH_FUNDEF,NIL(struct ionod*));
7608462SApril.Chin@Sun.COM 		while(lexp->token==NL)
7618462SApril.Chin@Sun.COM 			lexp->token = sh_lex(lexp);
7624887Schin 	}
7638462SApril.Chin@Sun.COM 	if((flag && lexp->token!=LBRACE) || lexp->token==EOFSYM)
7648462SApril.Chin@Sun.COM 		sh_syntax(lexp);
7654887Schin 	sh_pushcontext(&buff,1);
7664887Schin 	jmpval = sigsetjmp(buff.buff,0);
7674887Schin 	if(jmpval == 0)
7684887Schin 	{
7694887Schin 		/* create a new stak frame to compile the command */
7704887Schin 		savstak = stakcreate(STAK_SMALL);
7714887Schin 		savstak = stakinstall(savstak, 0);
7724887Schin 		slp = (struct slnod*)stakalloc(sizeof(struct slnod)+sizeof(struct functnod));
7734887Schin 		slp->slchild = 0;
7748462SApril.Chin@Sun.COM 		slp->slnext = shp->st.staklist;
7758462SApril.Chin@Sun.COM 		shp->st.staklist = 0;
7764887Schin 		t->funct.functstak = (struct slnod*)slp;
7774887Schin 		/*
7784887Schin 		 * store the pathname of function definition file on stack
7794887Schin 		 * in name field of fake for node
7804887Schin 		 */
7814887Schin 		fp = (struct functnod*)(slp+1);
7824887Schin 		fp->functtyp = TFUN|FAMP;
7834887Schin 		fp->functnam = 0;
7844887Schin 		fp->functline = t->funct.functline;
7858462SApril.Chin@Sun.COM 		if(shp->st.filename)
7868462SApril.Chin@Sun.COM 			fp->functnam = stakcopy(shp->st.filename);
7874887Schin 		loop_level = 0;
7884887Schin 		label_last = label_list;
7898462SApril.Chin@Sun.COM 		if(!flag && lexp->token==0)
7904887Schin 		{
7914887Schin 			/* copy current word token to current stak frame */
7924887Schin 			struct argnod *ap;
7938462SApril.Chin@Sun.COM 			flag = ARGVAL + strlen(lexp->arg->argval);
7944887Schin 			ap = (struct argnod*)stakalloc(flag);
7958462SApril.Chin@Sun.COM 			memcpy(ap,lexp->arg,flag);
7968462SApril.Chin@Sun.COM 			lexp->arg = ap;
7974887Schin 		}
7988462SApril.Chin@Sun.COM 		t->funct.functtre = item(lexp,SH_NOIO);
7994887Schin 	}
8004887Schin 	sh_popcontext(&buff);
8014887Schin 	loop_level = saveloop;
8024887Schin 	label_last = savelabel;
8034887Schin 	/* restore the old stack */
8044887Schin 	if(slp)
8054887Schin 	{
8064887Schin 		slp->slptr =  stakinstall(savstak,0);
8078462SApril.Chin@Sun.COM 		slp->slchild = shp->st.staklist;
8084887Schin 	}
8094887Schin #if SHOPT_KIA
8108462SApril.Chin@Sun.COM 	lexp->current = current;
8114887Schin #endif /* SHOPT_KIA */
8124887Schin 	if(jmpval)
8134887Schin 	{
8144887Schin 		if(slp && slp->slptr)
8154887Schin 		{
8168462SApril.Chin@Sun.COM 			shp->st.staklist = slp->slnext;
8174887Schin 			stakdelete(slp->slptr);
8184887Schin 		}
8198462SApril.Chin@Sun.COM 		siglongjmp(*shp->jmplist,jmpval);
8204887Schin 	}
8218462SApril.Chin@Sun.COM 	shp->st.staklist = (struct slnod*)slp;
8224887Schin 	last = fctell();
8234887Schin 	fp->functline = (last-first);
8244887Schin 	fp->functtre = t;
8258462SApril.Chin@Sun.COM 	shp->mktype = in_mktype;
8268462SApril.Chin@Sun.COM 	if(lexp->sh->funlog)
8274887Schin 	{
8284887Schin 		if(fcfill()>0)
8294887Schin 			fcseek(-1);
8308462SApril.Chin@Sun.COM 		lexp->sh->funlog = 0;
8314887Schin 	}
8324887Schin #if 	SHOPT_KIA
8338462SApril.Chin@Sun.COM 	if(lexp->kiafile)
8348462SApril.Chin@Sun.COM 		kiaentity(lexp,t->funct.functnam,-1,'p',t->funct.functline,shp->inlineno-1,lexp->current,'p',0,"");
8354887Schin #endif /* SHOPT_KIA */
8368462SApril.Chin@Sun.COM 	t->funct.functtyp |= opt_get;
8378462SApril.Chin@Sun.COM 	opt_get = save_optget;
8384887Schin 	return(t);
8394887Schin }
8404887Schin 
8414887Schin /*
8424887Schin  * Compound assignment
8434887Schin  */
8448462SApril.Chin@Sun.COM static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int tdef)
8454887Schin {
8464887Schin 	register int n;
8474887Schin 	register Shnode_t *t, **tp;
8484887Schin 	register struct comnod *ac;
8498462SApril.Chin@Sun.COM 	Stk_t	*stkp = lexp->sh->stk;
8504887Schin 	int array=0;
8514887Schin 	Namval_t *np;
8524887Schin 	n = strlen(ap->argval)-1;
8534887Schin 	if(ap->argval[n]!='=')
8548462SApril.Chin@Sun.COM 		sh_syntax(lexp);
8554887Schin 	if(ap->argval[n-1]=='+')
8564887Schin 	{
8574887Schin 		ap->argval[n--]=0;
8584887Schin 		array = ARG_APPEND;
8594887Schin 	}
8604887Schin 	/* shift right */
8614887Schin 	while(n > 0)
8624887Schin 	{
8634887Schin 		ap->argval[n] = ap->argval[n-1];
8644887Schin 		n--;
8654887Schin 	}
8664887Schin 	*ap->argval=0;
8674887Schin 	t = getnode(fornod);
8684887Schin 	t->for_.fornam = (char*)(ap->argval+1);
8698462SApril.Chin@Sun.COM 	t->for_.fortyp = sh_getlineno(lexp);
8704887Schin 	tp = &t->for_.fortre;
8714887Schin 	ap->argchn.ap = (struct argnod*)t;
8724887Schin 	ap->argflag &= ARG_QUOTED;
8734887Schin 	ap->argflag |= array;
8748462SApril.Chin@Sun.COM 	lexp->assignok = SH_ASSIGN;
8758462SApril.Chin@Sun.COM 	lexp->aliasok = 1;
8764887Schin 	array=0;
8778462SApril.Chin@Sun.COM 	if((n=skipnl(lexp,0))==RPAREN || n==LPAREN)
8784887Schin 	{
8794887Schin 		int index= 0;
8804887Schin 		struct argnod **settail;
8814887Schin 		ac = (struct comnod*)getnode(comnod);
8824887Schin 		settail= &ac->comset;
8834887Schin 		memset((void*)ac,0,sizeof(*ac));
8848462SApril.Chin@Sun.COM 		ac->comline = sh_getlineno(lexp);
8854887Schin 		while(n==LPAREN)
8864887Schin 		{
8874887Schin 			struct argnod *ap;
8888462SApril.Chin@Sun.COM 			ap = (struct argnod*)stkseek(stkp,ARGVAL);
8894887Schin 			ap->argflag= ARG_ASSIGN;
8908462SApril.Chin@Sun.COM 			sfprintf(stkp,"[%d]=",index++);
8918462SApril.Chin@Sun.COM 			ap = (struct argnod*)stkfreeze(stkp,1);
8924887Schin 			ap->argnxt.ap = 0;
8938462SApril.Chin@Sun.COM 			ap = assign(lexp,ap,0);
8944887Schin 			ap->argflag |= ARG_MESSAGE;
8954887Schin 			*settail = ap;
8964887Schin 			settail = &(ap->argnxt.ap);
8978462SApril.Chin@Sun.COM 			while((n = skipnl(lexp,0))==0)
8988462SApril.Chin@Sun.COM 			{
8998462SApril.Chin@Sun.COM 				ap = (struct argnod*)stkseek(stkp,ARGVAL);
9008462SApril.Chin@Sun.COM 				ap->argflag= ARG_ASSIGN;
9018462SApril.Chin@Sun.COM 				sfprintf(stkp,"[%d]=",index++);
9028462SApril.Chin@Sun.COM 				stakputs(lexp->arg->argval);
9038462SApril.Chin@Sun.COM 				ap = (struct argnod*)stkfreeze(stkp,1);
9048462SApril.Chin@Sun.COM 				ap->argnxt.ap = 0;
9058462SApril.Chin@Sun.COM 				ap->argflag = lexp->arg->argflag;
9068462SApril.Chin@Sun.COM 				*settail = ap;
9078462SApril.Chin@Sun.COM 				settail = &(ap->argnxt.ap);
9088462SApril.Chin@Sun.COM 			}
9094887Schin 		}
9104887Schin 	}
9118462SApril.Chin@Sun.COM 	else if(n && n!=FUNCTSYM)
9128462SApril.Chin@Sun.COM 		sh_syntax(lexp);
9138462SApril.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)))
9148462SApril.Chin@Sun.COM 	{
9154887Schin 		array=SH_ARRAY;
9168462SApril.Chin@Sun.COM 		if(fcgetc(n)==LPAREN)
9178462SApril.Chin@Sun.COM 		{
9188462SApril.Chin@Sun.COM 			int c;
9198462SApril.Chin@Sun.COM 			if(fcgetc(c)==RPAREN)
9208462SApril.Chin@Sun.COM 			{
9218462SApril.Chin@Sun.COM 				lexp->token =  SYMRES;
9228462SApril.Chin@Sun.COM 				array = 0;
9238462SApril.Chin@Sun.COM 			}
9248462SApril.Chin@Sun.COM 			else
9258462SApril.Chin@Sun.COM 				fcseek(-2);
9268462SApril.Chin@Sun.COM 		}
9278462SApril.Chin@Sun.COM 		else if(n>0)
9288462SApril.Chin@Sun.COM 			fcseek(-1);
9298462SApril.Chin@Sun.COM 		if(array && tdef)
9308462SApril.Chin@Sun.COM 			sh_syntax(lexp);
9318462SApril.Chin@Sun.COM 	}
9324887Schin 	while(1)
9334887Schin 	{
9348462SApril.Chin@Sun.COM 		if((n=lexp->token)==RPAREN)
9354887Schin 			break;
9364887Schin 		if(n==FUNCTSYM || n==SYMRES)
9378462SApril.Chin@Sun.COM 			ac = (struct comnod*)funct(lexp);
9384887Schin 		else
9398462SApril.Chin@Sun.COM 			ac = (struct comnod*)simple(lexp,SH_NOIO|SH_ASSIGN|array,NIL(struct ionod*));
9408462SApril.Chin@Sun.COM 		if((n=lexp->token)==RPAREN)
9414887Schin 			break;
9424887Schin 		if(n!=NL && n!=';')
9438462SApril.Chin@Sun.COM 			sh_syntax(lexp);
9448462SApril.Chin@Sun.COM 		lexp->assignok = SH_ASSIGN;
9458462SApril.Chin@Sun.COM 		if((n=skipnl(lexp,0)) || array)
9464887Schin 		{
9474887Schin 			if(n==RPAREN)
9484887Schin 				break;
9494887Schin 			if(array ||  n!=FUNCTSYM)
9508462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9514887Schin 		}
9528462SApril.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)))
9534887Schin 		{
9548462SApril.Chin@Sun.COM 			struct argnod *arg = lexp->arg;
9554887Schin 			if(n!=0)
9568462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9574887Schin 			/* check for sys5 style function */
9588462SApril.Chin@Sun.COM 			if(sh_lex(lexp)!=LPAREN || sh_lex(lexp)!=RPAREN)
9594887Schin 			{
9608462SApril.Chin@Sun.COM 				lexp->arg = arg;
9618462SApril.Chin@Sun.COM 				lexp->token = 0;
9628462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9634887Schin 			}
9648462SApril.Chin@Sun.COM 			lexp->arg = arg;
9658462SApril.Chin@Sun.COM 			lexp->token = SYMRES;
9664887Schin 		}
9678462SApril.Chin@Sun.COM 		t = makelist(lexp,TLST,(Shnode_t*)ac,t);
9684887Schin 		*tp = t;
9694887Schin 		tp = &t->lst.lstrit;
9704887Schin 	}
9714887Schin 	*tp = (Shnode_t*)ac;
9728462SApril.Chin@Sun.COM 	lexp->assignok = 0;
9734887Schin 	return(ap);
9744887Schin }
9754887Schin 
9764887Schin /*
9774887Schin  * item
9784887Schin  *
9794887Schin  *	( cmd ) [ < in ] [ > out ]
9804887Schin  *	word word* [ < in ] [ > out ]
9814887Schin  *	if ... then ... else ... fi
9824887Schin  *	for ... while ... do ... done
9834887Schin  *	case ... in ... esac
9844887Schin  *	begin ... end
9854887Schin  */
9864887Schin 
9878462SApril.Chin@Sun.COM static Shnode_t	*item(Lex_t *lexp,int flag)
9884887Schin {
9894887Schin 	register Shnode_t	*t;
9904887Schin 	register struct ionod	*io;
9918462SApril.Chin@Sun.COM 	register int tok = (lexp->token&0xff);
9928462SApril.Chin@Sun.COM 	int savwdval = lexp->lasttok;
9938462SApril.Chin@Sun.COM 	int savline = lexp->lastline;
9948462SApril.Chin@Sun.COM 	int showme=0, comsub;
9958462SApril.Chin@Sun.COM 	if(!(flag&SH_NOIO) && (tok=='<' || tok=='>' || lexp->token==IOVNAME))
9968462SApril.Chin@Sun.COM 		io=inout(lexp,NIL(struct ionod*),1);
9974887Schin 	else
9984887Schin 		io=0;
9998462SApril.Chin@Sun.COM 	if((tok=lexp->token) && tok!=EOFSYM && tok!=FUNCTSYM)
10004887Schin 	{
10018462SApril.Chin@Sun.COM 		lexp->lastline =  sh_getlineno(lexp);
10028462SApril.Chin@Sun.COM 		lexp->lasttok = lexp->token;
10034887Schin 	}
10044887Schin 	switch(tok)
10054887Schin 	{
10064887Schin 	    /* [[ ... ]] test expression */
10074887Schin 	    case BTESTSYM:
10088462SApril.Chin@Sun.COM 		t = test_expr(lexp,ETESTSYM);
10094887Schin 		t->tre.tretyp &= ~TTEST;
10104887Schin 		break;
10114887Schin 	    /* ((...)) arithmetic expression */
10124887Schin 	    case EXPRSYM:
10138462SApril.Chin@Sun.COM 		t = getanode(lexp,lexp->arg);
10148462SApril.Chin@Sun.COM 		sh_lex(lexp);
10154887Schin 		goto done;
10164887Schin 
10174887Schin 	    /* case statement */
10184887Schin 	    case CASESYM:
10194887Schin 	    {
10208462SApril.Chin@Sun.COM 		int savetok = lexp->lasttok;
10218462SApril.Chin@Sun.COM 		int saveline = lexp->lastline;
10224887Schin 		t = getnode(swnod);
10238462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
10248462SApril.Chin@Sun.COM 			sh_syntax(lexp);
10258462SApril.Chin@Sun.COM 		t->sw.swarg=lexp->arg;
10264887Schin 		t->sw.swtyp=TSW;
10274887Schin 		t->sw.swio = 0;
10284887Schin 		t->sw.swtyp |= FLINENO;
10298462SApril.Chin@Sun.COM 		t->sw.swline =  lexp->sh->inlineno;
10308462SApril.Chin@Sun.COM 		if((tok=skipnl(lexp,0))!=INSYM && tok!=LBRACE)
10318462SApril.Chin@Sun.COM 			sh_syntax(lexp);
10328462SApril.Chin@Sun.COM 		if(!(t->sw.swlst=syncase(lexp,tok==INSYM?ESACSYM:RBRACE)) && lexp->token==EOFSYM)
10334887Schin 		{
10348462SApril.Chin@Sun.COM 			lexp->lasttok = savetok;
10358462SApril.Chin@Sun.COM 			lexp->lastline = saveline;
10368462SApril.Chin@Sun.COM 			sh_syntax(lexp);
10374887Schin 		}
10384887Schin 		break;
10394887Schin 	    }
10404887Schin 
10414887Schin 	    /* if statement */
10424887Schin 	    case IFSYM:
10434887Schin 	    {
10444887Schin 		register Shnode_t	*tt;
10454887Schin 		t = getnode(ifnod);
10464887Schin 		t->if_.iftyp=TIF;
10478462SApril.Chin@Sun.COM 		t->if_.iftre=sh_cmd(lexp,THENSYM,SH_NL);
10488462SApril.Chin@Sun.COM 		t->if_.thtre=sh_cmd(lexp,ELSESYM,SH_NL|SH_SEMI);
10498462SApril.Chin@Sun.COM 		tok = lexp->token;
10508462SApril.Chin@Sun.COM 		t->if_.eltre=(tok==ELSESYM?sh_cmd(lexp,FISYM,SH_NL|SH_SEMI):
10518462SApril.Chin@Sun.COM 			(tok==ELIFSYM?(lexp->token=IFSYM, tt=item(lexp,SH_NOIO)):0));
10524887Schin 		if(tok==ELIFSYM)
10534887Schin 		{
10544887Schin 			if(!tt || tt->tre.tretyp!=TSETIO)
10554887Schin 				goto done;
10564887Schin 			t->if_.eltre = tt->fork.forktre;
10574887Schin 			tt->fork.forktre = t;
10584887Schin 			t = tt;
10594887Schin 			goto done;
10604887Schin 		}
10614887Schin 		break;
10624887Schin 	    }
10634887Schin 
10644887Schin 	    /* for and select statement */
10654887Schin 	    case FORSYM:
10664887Schin 	    case SELECTSYM:
10674887Schin 	    {
10684887Schin 		t = getnode(fornod);
10698462SApril.Chin@Sun.COM 		t->for_.fortyp=(lexp->token==FORSYM?TFOR:TSELECT);
10704887Schin 		t->for_.forlst=0;
10718462SApril.Chin@Sun.COM 		t->for_.forline =  lexp->sh->inlineno;
10728462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
10734887Schin 		{
10748462SApril.Chin@Sun.COM 			if(lexp->token!=EXPRSYM || t->for_.fortyp!=TFOR)
10758462SApril.Chin@Sun.COM 				sh_syntax(lexp);
10764887Schin 			/* arithmetic for */
10778462SApril.Chin@Sun.COM 			t = arithfor(lexp,t);
10784887Schin 			break;
10794887Schin 		}
10808462SApril.Chin@Sun.COM 		t->for_.fornam=(char*) lexp->arg->argval;
10814887Schin 		t->for_.fortyp |= FLINENO;
10824887Schin #if SHOPT_KIA
10838462SApril.Chin@Sun.COM 		if(lexp->kiafile)
10848462SApril.Chin@Sun.COM 			writedefs(lexp,lexp->arg,lexp->sh->inlineno,'v',NIL(struct argnod*));
10854887Schin #endif /* SHOPT_KIA */
10868462SApril.Chin@Sun.COM 		while((tok=sh_lex(lexp))==NL);
10874887Schin 		if(tok==INSYM)
10884887Schin 		{
10898462SApril.Chin@Sun.COM 			if(sh_lex(lexp))
10904887Schin 			{
10918462SApril.Chin@Sun.COM 				if(lexp->token != NL && lexp->token !=';')
10928462SApril.Chin@Sun.COM 					sh_syntax(lexp);
10934887Schin 				/* some Linux scripts assume this */
10944887Schin 				if(sh_isoption(SH_NOEXEC))
10958462SApril.Chin@Sun.COM 					errormsg(SH_DICT,ERROR_warn(0),e_lexemptyfor,lexp->sh->inlineno-(lexp->token=='\n'));
10964887Schin 				t->for_.forlst = (struct comnod*)getnode(comnod);
10974887Schin 				(t->for_.forlst)->comarg = 0;
10984887Schin 				(t->for_.forlst)->comset = 0;
10994887Schin 				(t->for_.forlst)->comnamp = 0;
11004887Schin 				(t->for_.forlst)->comnamq = 0;
11014887Schin 				(t->for_.forlst)->comstate = 0;
11024887Schin 				(t->for_.forlst)->comio = 0;
11034887Schin 				(t->for_.forlst)->comtyp = 0;
11044887Schin 			}
11054887Schin 			else
11068462SApril.Chin@Sun.COM 				t->for_.forlst=(struct comnod*)simple(lexp,SH_NOIO,NIL(struct ionod*));
11078462SApril.Chin@Sun.COM 			if(lexp->token != NL && lexp->token !=';')
11088462SApril.Chin@Sun.COM 				sh_syntax(lexp);
11098462SApril.Chin@Sun.COM 			tok = skipnl(lexp,0);
11104887Schin 		}
11114887Schin 		/* 'for i;do cmd' is valid syntax */
11124887Schin 		else if(tok==';')
11138462SApril.Chin@Sun.COM 			tok=sh_lex(lexp);
11144887Schin 		if(tok!=DOSYM && tok!=LBRACE)
11158462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11164887Schin 		loop_level++;
11178462SApril.Chin@Sun.COM 		t->for_.fortre=sh_cmd(lexp,tok==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
11184887Schin 		if(--loop_level==0)
11194887Schin 			label_last = label_list;
11204887Schin 		break;
11214887Schin 	    }
11224887Schin 
11234887Schin 	    /* This is the code for parsing function definitions */
11244887Schin 	    case FUNCTSYM:
11258462SApril.Chin@Sun.COM 		return(funct(lexp));
11264887Schin 
11274887Schin #if SHOPT_NAMESPACE
11284887Schin 	    case NSPACESYM:
11294887Schin 		t = getnode(fornod);
11304887Schin 		t->for_.fortyp=TNSPACE;
11314887Schin 		t->for_.forlst=0;
11328462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
11338462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11348462SApril.Chin@Sun.COM 		t->for_.fornam=(char*) lexp->arg->argval;
11358462SApril.Chin@Sun.COM 		while((tok=sh_lex(lexp))==NL);
11364887Schin 		if(tok!=LBRACE)
11378462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11388462SApril.Chin@Sun.COM 		t->for_.fortre = sh_cmd(lexp,RBRACE,SH_NL);
11394887Schin 		break;
11404887Schin #endif /* SHOPT_NAMESPACE */
11414887Schin 
11424887Schin 	    /* while and until */
11434887Schin 	    case WHILESYM:
11444887Schin 	    case UNTILSYM:
11454887Schin 		t = getnode(whnod);
11468462SApril.Chin@Sun.COM 		t->wh.whtyp=(lexp->token==WHILESYM ? TWH : TUN);
11474887Schin 		loop_level++;
11488462SApril.Chin@Sun.COM 		t->wh.whtre = sh_cmd(lexp,DOSYM,SH_NL);
11498462SApril.Chin@Sun.COM 		t->wh.dotre = sh_cmd(lexp,DONESYM,SH_NL|SH_SEMI);
11504887Schin 		if(--loop_level==0)
11514887Schin 			label_last = label_list;
11524887Schin 		t->wh.whinc = 0;
11534887Schin 		break;
11544887Schin 
11554887Schin 	    case LABLSYM:
11564887Schin 	    {
11574887Schin 		register struct argnod *argp = label_list;
11584887Schin 		while(argp)
11594887Schin 		{
11608462SApril.Chin@Sun.COM 			if(strcmp(argp->argval,lexp->arg->argval)==0)
11618462SApril.Chin@Sun.COM 				errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax3,lexp->sh->inlineno,argp->argval);
11624887Schin 			argp = argp->argnxt.ap;
11634887Schin 		}
11648462SApril.Chin@Sun.COM 		lexp->arg->argnxt.ap = label_list;
11658462SApril.Chin@Sun.COM 		label_list = lexp->arg;
11668462SApril.Chin@Sun.COM 		label_list->argchn.len = sh_getlineno(lexp);
11674887Schin 		label_list->argflag = loop_level;
11688462SApril.Chin@Sun.COM 		skipnl(lexp,flag);
11698462SApril.Chin@Sun.COM 		if(!(t = item(lexp,SH_NL)))
11708462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11714887Schin 		tok = (t->tre.tretyp&(COMSCAN|COMSCAN-1));
11724887Schin 		if(sh_isoption(SH_NOEXEC) && tok!=TWH && tok!=TUN && tok!=TFOR && tok!=TSELECT)
11734887Schin 			errormsg(SH_DICT,ERROR_warn(0),e_lexlabignore,label_list->argchn.len,label_list->argval);
11744887Schin 		return(t);
11754887Schin 	    }
11764887Schin 
11774887Schin 	    /* command group with {...} */
11784887Schin 	    case LBRACE:
11798462SApril.Chin@Sun.COM 		comsub = lexp->comsub;
11808462SApril.Chin@Sun.COM 		lexp->comsub = 0;
1181*10898Sroland.mainz@nrubsig.org 		t = sh_cmd(lexp,RBRACE,SH_NL|SH_SEMI);
11828462SApril.Chin@Sun.COM 		lexp->comsub = comsub;
11834887Schin 		break;
11844887Schin 
11854887Schin 	    case LPAREN:
11864887Schin 		t = getnode(parnod);
1187*10898Sroland.mainz@nrubsig.org 		t->par.partre=sh_cmd(lexp,RPAREN,SH_NL|SH_SEMI);
11884887Schin 		t->par.partyp=TPAR;
11894887Schin 		break;
11904887Schin 
11914887Schin 	    default:
11924887Schin 		if(io==0)
11934887Schin 			return(0);
11944887Schin 
11954887Schin 	    case ';':
11964887Schin 		if(io==0)
11974887Schin 		{
11984887Schin 			if(!(flag&SH_SEMI))
11994887Schin 				return(0);
12008462SApril.Chin@Sun.COM 			if(sh_lex(lexp)==';')
12018462SApril.Chin@Sun.COM 				sh_syntax(lexp);
12024887Schin 			showme =  FSHOWME;
12034887Schin 		}
12044887Schin 	    /* simple command */
12054887Schin 	    case 0:
12068462SApril.Chin@Sun.COM 		t = (Shnode_t*)simple(lexp,flag,io);
12078462SApril.Chin@Sun.COM 		if(t->com.comarg && lexp->intypeset && (lexp->sh->shcomp || sh_isoption(SH_NOEXEC) || sh.dot_depth))
12088462SApril.Chin@Sun.COM 			check_typedef(&t->com);
12098462SApril.Chin@Sun.COM 		lexp->intypeset = 0;
12108462SApril.Chin@Sun.COM 		lexp->inexec = 0;
12114887Schin 		t->tre.tretyp |= showme;
12124887Schin 		return(t);
12134887Schin 	}
12148462SApril.Chin@Sun.COM 	sh_lex(lexp);
12158462SApril.Chin@Sun.COM 	if(io=inout(lexp,io,0))
12164887Schin 	{
12174887Schin 		if((tok=t->tre.tretyp&COMMSK) != TFORK)
12184887Schin 			tok = TSETIO;
12198462SApril.Chin@Sun.COM 		t=makeparent(lexp,tok,t);
12204887Schin 		t->tre.treio=io;
12214887Schin 	}
12224887Schin done:
12238462SApril.Chin@Sun.COM 	lexp->lasttok = savwdval;
12248462SApril.Chin@Sun.COM 	lexp->lastline = savline;
12254887Schin 	return(t);
12264887Schin }
12274887Schin 
1228*10898Sroland.mainz@nrubsig.org static struct argnod *process_sub(Lex_t *lexp,int tok)
1229*10898Sroland.mainz@nrubsig.org {
1230*10898Sroland.mainz@nrubsig.org 	struct argnod *argp;
1231*10898Sroland.mainz@nrubsig.org 	Shnode_t *t;
1232*10898Sroland.mainz@nrubsig.org 	int mode = (tok==OPROCSYM);
1233*10898Sroland.mainz@nrubsig.org 	t = sh_cmd(lexp,RPAREN,SH_NL);
1234*10898Sroland.mainz@nrubsig.org 	argp = (struct argnod*)stkalloc(lexp->sh->stk,sizeof(struct argnod));
1235*10898Sroland.mainz@nrubsig.org 	*argp->argval = 0;
1236*10898Sroland.mainz@nrubsig.org 	argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t);
1237*10898Sroland.mainz@nrubsig.org 	argp->argflag =  (ARG_EXP|mode);
1238*10898Sroland.mainz@nrubsig.org 	return(argp);
1239*10898Sroland.mainz@nrubsig.org }
1240*10898Sroland.mainz@nrubsig.org 
1241*10898Sroland.mainz@nrubsig.org 
12424887Schin /*
12434887Schin  * This is for a simple command, for list, or compound assignment
12444887Schin  */
12458462SApril.Chin@Sun.COM static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
12464887Schin {
12474887Schin 	register struct comnod *t;
12484887Schin 	register struct argnod	*argp;
12494887Schin 	register int tok;
12508462SApril.Chin@Sun.COM 	Stk_t		*stkp = lexp->sh->stk;
12514887Schin 	struct argnod	**argtail;
12524887Schin 	struct argnod	**settail;
12538462SApril.Chin@Sun.COM 	int	cmdarg=0;
12548462SApril.Chin@Sun.COM 	int	argno = 0, argmax=0;
12554887Schin 	int	assignment = 0;
12564887Schin 	int	key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
12574887Schin 	int	associative=0;
12588462SApril.Chin@Sun.COM 	if((argp=lexp->arg) && (argp->argflag&ARG_ASSIGN) && argp->argval[0]=='[')
12594887Schin 	{
12604887Schin 		flag |= SH_ARRAY;
12614887Schin 		associative = 1;
12624887Schin 	}
12634887Schin 	t = (struct comnod*)getnode(comnod);
12644887Schin 	t->comio=io; /*initial io chain*/
12654887Schin 	/* set command line number for error messages */
12668462SApril.Chin@Sun.COM 	t->comline = sh_getlineno(lexp);
12674887Schin 	argtail = &(t->comarg);
12684887Schin 	t->comset = 0;
12694887Schin 	t->comnamp = 0;
12704887Schin 	t->comnamq = 0;
12714887Schin 	t->comstate = 0;
12724887Schin 	settail = &(t->comset);
12738462SApril.Chin@Sun.COM 	while(lexp->token==0)
12744887Schin 	{
12758462SApril.Chin@Sun.COM 		argp = lexp->arg;
12764887Schin 		if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
12774887Schin 		{
12788462SApril.Chin@Sun.COM 			lexp->token = LBRACE;
12794887Schin 			break;
12804887Schin 		}
12814887Schin 		if(associative && argp->argval[0]!='[')
12828462SApril.Chin@Sun.COM 			sh_syntax(lexp);
12834887Schin 		/* check for assignment argument */
12844887Schin 		if((argp->argflag&ARG_ASSIGN) && assignment!=2)
12854887Schin 		{
12864887Schin 			*settail = argp;
12874887Schin 			settail = &(argp->argnxt.ap);
12888462SApril.Chin@Sun.COM 			lexp->assignok = (flag&SH_ASSIGN)?SH_ASSIGN:1;
12894887Schin 			if(assignment)
12904887Schin 			{
12914887Schin 				struct argnod *ap=argp;
12924887Schin 				char *last, *cp;
12934887Schin 				if(assignment==1)
12944887Schin 				{
12954887Schin 					last = strchr(argp->argval,'=');
1296*10898Sroland.mainz@nrubsig.org 					if(last && (last[-1]==']'|| (last[-1]=='+' && last[-2]==']')) && (cp=strchr(argp->argval,'[')) && (cp < last))
12974887Schin 						last = cp;
12988462SApril.Chin@Sun.COM 					stkseek(stkp,ARGVAL);
12998462SApril.Chin@Sun.COM 					sfwrite(stkp,argp->argval,last-argp->argval);
13008462SApril.Chin@Sun.COM 					ap=(struct argnod*)stkfreeze(stkp,1);
13014887Schin 					ap->argflag = ARG_RAW;
13024887Schin 					ap->argchn.ap = 0;
13034887Schin 				}
13044887Schin 				*argtail = ap;
13054887Schin 				argtail = &(ap->argnxt.ap);
13064887Schin 				if(argno>=0)
13074887Schin 					argno++;
13084887Schin 			}
13094887Schin 			else /* alias substitutions allowed */
13108462SApril.Chin@Sun.COM 				lexp->aliasok = 1;
13114887Schin 		}
13124887Schin 		else
13134887Schin 		{
13144887Schin 			if(!(argp->argflag&ARG_RAW))
13158462SApril.Chin@Sun.COM 			{
13168462SApril.Chin@Sun.COM 				if(argno>0)
13178462SApril.Chin@Sun.COM 					argmax = argno;
13184887Schin 				argno = -1;
13198462SApril.Chin@Sun.COM 			}
13208462SApril.Chin@Sun.COM 			if(argno>=0 && argno++==cmdarg && !(flag&SH_ARRAY) && *argp->argval!='/')
13214887Schin 			{
13224887Schin 				/* check for builtin command */
13238462SApril.Chin@Sun.COM 				Namval_t *np=nv_bfsearch(argp->argval,lexp->sh->fun_tree, (Namval_t**)&t->comnamq,(char**)0);
13248462SApril.Chin@Sun.COM 				if(cmdarg==0)
13258462SApril.Chin@Sun.COM 					t->comnamp = (void*)np;
13268462SApril.Chin@Sun.COM 				if(np && is_abuiltin(np))
13274887Schin 				{
13288462SApril.Chin@Sun.COM 					if(nv_isattr(np,BLT_DCL))
13298462SApril.Chin@Sun.COM 					{
13308462SApril.Chin@Sun.COM 						assignment = 1+(*argp->argval=='a');
13318462SApril.Chin@Sun.COM 						if(np==SYSTYPESET)
13328462SApril.Chin@Sun.COM 							lexp->intypeset = 1;
13338462SApril.Chin@Sun.COM 						key_on = 1;
13348462SApril.Chin@Sun.COM 					}
13358462SApril.Chin@Sun.COM 					else if(np==SYSCOMMAND)
13368462SApril.Chin@Sun.COM 						cmdarg++;
13378462SApril.Chin@Sun.COM 					else if(np==SYSEXEC)
13388462SApril.Chin@Sun.COM 						lexp->inexec = 1;
13398462SApril.Chin@Sun.COM 					else if(np->nvalue.bfp==b_getopts)
13408462SApril.Chin@Sun.COM 						opt_get |= FOPTGET;
13414887Schin 				}
13424887Schin 			}
13434887Schin 			*argtail = argp;
13444887Schin 			argtail = &(argp->argnxt.ap);
13458462SApril.Chin@Sun.COM 			if(!(lexp->assignok=key_on)  && !(flag&SH_NOIO) && sh_isoption(SH_NOEXEC))
13468462SApril.Chin@Sun.COM 				lexp->assignok = SH_COMPASSIGN;
13478462SApril.Chin@Sun.COM 			lexp->aliasok = 0;
13484887Schin 		}
13494887Schin 	retry:
13508462SApril.Chin@Sun.COM 		tok = sh_lex(lexp);
13518462SApril.Chin@Sun.COM 		if(tok==LABLSYM && (flag&SH_ASSIGN))
13528462SApril.Chin@Sun.COM 			lexp->token = tok = 0;
13534887Schin #if SHOPT_DEVFD
13544887Schin 		if((tok==IPROCSYM || tok==OPROCSYM))
13554887Schin 		{
1356*10898Sroland.mainz@nrubsig.org 			argp = process_sub(lexp,tok);
13578462SApril.Chin@Sun.COM 			argmax = 0;
13584887Schin 			argno = -1;
13594887Schin 			*argtail = argp;
13604887Schin 			argtail = &(argp->argnxt.ap);
13614887Schin 			goto retry;
13624887Schin 		}
13634887Schin #endif	/* SHOPT_DEVFD */
13644887Schin 		if(tok==LPAREN)
13654887Schin 		{
13664887Schin 			if(argp->argflag&ARG_ASSIGN)
13674887Schin 			{
13688462SApril.Chin@Sun.COM 				int intypeset = lexp->intypeset;
13698462SApril.Chin@Sun.COM 				int tdef = 0;
13708462SApril.Chin@Sun.COM 				lexp->intypeset = 0;
13718462SApril.Chin@Sun.COM 				if(t->comnamp==SYSTYPESET && t->comarg->argnxt.ap && strcmp(t->comarg->argnxt.ap->argval,"-T")==0)
13728462SApril.Chin@Sun.COM 					tdef = 1;
13738462SApril.Chin@Sun.COM 				argp = assign(lexp,argp,tdef);
13748462SApril.Chin@Sun.COM 				lexp->intypeset = intypeset;
13754887Schin 				if(associative)
13768462SApril.Chin@Sun.COM 					lexp->assignok |= SH_ASSIGN;
13774887Schin 				goto retry;
13784887Schin 			}
13794887Schin 			else if(argno==1 && !t->comset)
13804887Schin 			{
13814887Schin 				/* SVR2 style function */
13828462SApril.Chin@Sun.COM 				if(sh_lex(lexp) == RPAREN)
13834887Schin 				{
13848462SApril.Chin@Sun.COM 					lexp->arg = argp;
13858462SApril.Chin@Sun.COM 					return(funct(lexp));
13864887Schin 				}
13878462SApril.Chin@Sun.COM 				lexp->token = LPAREN;
13884887Schin 			}
13894887Schin 		}
13904887Schin 		else if(flag&SH_ASSIGN)
13914887Schin 		{
13924887Schin 			if(tok==RPAREN)
13934887Schin 				break;
13944887Schin 			else if(tok==NL && (flag&SH_ARRAY))
13958462SApril.Chin@Sun.COM 			{
13968462SApril.Chin@Sun.COM 				lexp->comp_assign = 2;
13974887Schin 				goto retry;
13988462SApril.Chin@Sun.COM 			}
13998462SApril.Chin@Sun.COM 
14004887Schin 		}
14014887Schin 		if(!(flag&SH_NOIO))
14024887Schin 		{
14034887Schin 			if(io)
14044887Schin 			{
14054887Schin 				while(io->ionxt)
14064887Schin 					io = io->ionxt;
14078462SApril.Chin@Sun.COM 				io->ionxt = inout(lexp,(struct ionod*)0,0);
14084887Schin 			}
14094887Schin 			else
14108462SApril.Chin@Sun.COM 				t->comio = io = inout(lexp,(struct ionod*)0,0);
14114887Schin 		}
14124887Schin 	}
14134887Schin 	*argtail = 0;
14148462SApril.Chin@Sun.COM 	if(argno>0)
14158462SApril.Chin@Sun.COM 		argmax = argno;
14168462SApril.Chin@Sun.COM 	t->comtyp = TCOM | (argmax<<(COMBITS+2));
14174887Schin #if SHOPT_KIA
14188462SApril.Chin@Sun.COM 	if(lexp->kiafile && !(flag&SH_NOIO))
14194887Schin 	{
14204887Schin 		register Namval_t *np=(Namval_t*)t->comnamp;
14214887Schin 		unsigned long r=0;
14224887Schin 		int line = t->comline;
14234887Schin 		argp = t->comarg;
14244887Schin 		if(np)
14258462SApril.Chin@Sun.COM 			r = kiaentity(lexp,nv_name(np),-1,'p',-1,0,lexp->unknown,'b',0,"");
14264887Schin 		else if(argp)
14278462SApril.Chin@Sun.COM 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',-1,0,lexp->unknown,'c',0,"");
14284887Schin 		if(r>0)
14298462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;c;\n",lexp->current,r,line,line);
14304887Schin 		if(t->comset && argno==0)
14318462SApril.Chin@Sun.COM 			writedefs(lexp,t->comset,line,'v',t->comarg);
14324887Schin 		else if(np && nv_isattr(np,BLT_DCL))
14338462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
14344887Schin 		else if(argp && strcmp(argp->argval,"read")==0)
14358462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
14364887Schin #if 0
14374887Schin 		else if(argp && strcmp(argp->argval,"unset")==0)
14388462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,'u',NIL(struct argnod*));
14394887Schin #endif
14404887Schin 		else if(argp && *argp->argval=='.' && argp->argval[1]==0 && (argp=argp->argnxt.ap))
14414887Schin 		{
14428462SApril.Chin@Sun.COM 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',0,0,lexp->script,'d',0,"");
14438462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;d;\n",lexp->current,r,line,line);
14444887Schin 		}
14454887Schin 	}
14464887Schin #endif /* SHOPT_KIA */
14474887Schin 	if(t->comnamp && (argp=t->comarg->argnxt.ap))
14484887Schin 	{
14494887Schin 		Namval_t *np=(Namval_t*)t->comnamp;
14504887Schin 		if((np==SYSBREAK || np==SYSCONT) && (argp->argflag&ARG_RAW) && !isdigit(*argp->argval))
14514887Schin 		{
14524887Schin 			register char *cp = argp->argval;
14534887Schin 			/* convert break/continue labels to numbers */
14544887Schin 			tok = 0;
14554887Schin 			for(argp=label_list;argp!=label_last;argp=argp->argnxt.ap)
14564887Schin 			{
14574887Schin 				if(strcmp(cp,argp->argval))
14584887Schin 					continue;
14594887Schin 				tok = loop_level-argp->argflag;
14604887Schin 				if(tok>=1)
14614887Schin 				{
14624887Schin 					argp = t->comarg->argnxt.ap;
14634887Schin 					if(tok>9)
14644887Schin 					{
14654887Schin 						argp->argval[1] = '0'+tok%10;
14664887Schin 						argp->argval[2] = 0;
14674887Schin 						tok /= 10;
14684887Schin 					}
14694887Schin 					else
14704887Schin 						argp->argval[1] = 0;
14714887Schin 					*argp->argval = '0'+tok;
14724887Schin 				}
14734887Schin 				break;
14744887Schin 			}
14754887Schin 			if(sh_isoption(SH_NOEXEC) && tok==0)
14768462SApril.Chin@Sun.COM 				errormsg(SH_DICT,ERROR_warn(0),e_lexlabunknown,lexp->sh->inlineno-(lexp->token=='\n'),cp);
14774887Schin 		}
14784887Schin 		else if(sh_isoption(SH_NOEXEC) && np==SYSSET && ((tok= *argp->argval)=='-'||tok=='+') &&
14794887Schin 			(argp->argval[1]==0||strchr(argp->argval,'k')))
14808462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete5,lexp->sh->inlineno-(lexp->token=='\n'),argp->argval);
14814887Schin 	}
14824887Schin 	/* expand argument list if possible */
14834887Schin 	if(argno>0)
14844887Schin 		t->comarg = qscan(t,argno);
14854887Schin 	else if(t->comarg)
14864887Schin 		t->comtyp |= COMSCAN;
14878462SApril.Chin@Sun.COM 	lexp->aliasok = 0;
14884887Schin 	return((Shnode_t*)t);
14894887Schin }
14904887Schin 
14914887Schin /*
14924887Schin  * skip past newlines but issue prompt if interactive
14934887Schin  */
14948462SApril.Chin@Sun.COM static int	skipnl(Lex_t *lexp,int flag)
14954887Schin {
14964887Schin 	register int token;
14978462SApril.Chin@Sun.COM 	while((token=sh_lex(lexp))==NL);
14984887Schin 	if(token==';' && !(flag&SH_SEMI))
14998462SApril.Chin@Sun.COM 		sh_syntax(lexp);
15004887Schin 	return(token);
15014887Schin }
15024887Schin 
15034887Schin /*
15044887Schin  * check for and process and i/o redirections
15054887Schin  * if flag>0 then an alias can be in the next word
15064887Schin  * if flag<0 only one redirection will be processed
15074887Schin  */
15088462SApril.Chin@Sun.COM static struct ionod	*inout(Lex_t *lexp,struct ionod *lastio,int flag)
15094887Schin {
15108462SApril.Chin@Sun.COM 	register int 		iof = lexp->digits, token=lexp->token;
15114887Schin 	register struct ionod	*iop;
15128462SApril.Chin@Sun.COM 	Stk_t			*stkp = lexp->sh->stk;
15134887Schin 	char *iovname=0;
15144887Schin 	register int		errout=0;
15154887Schin 	if(token==IOVNAME)
15164887Schin 	{
15178462SApril.Chin@Sun.COM 		iovname=lexp->arg->argval+1;
15188462SApril.Chin@Sun.COM 		token= sh_lex(lexp);
15194887Schin 		iof = 0;
15204887Schin 	}
15214887Schin 	switch(token&0xff)
15224887Schin 	{
15234887Schin 	    case '<':
15244887Schin 		if(token==IODOCSYM)
15254887Schin 			iof |= (IODOC|IORAW);
15264887Schin 		else if(token==IOMOV0SYM)
15274887Schin 			iof |= IOMOV;
1528*10898Sroland.mainz@nrubsig.org 		else if(token==IORDWRSYMT)
1529*10898Sroland.mainz@nrubsig.org 			iof |= IORDW|IOREWRITE;
15304887Schin 		else if(token==IORDWRSYM)
15314887Schin 			iof |= IORDW;
15324887Schin 		else if((token&SYMSHARP) == SYMSHARP)
15334887Schin 		{
15344887Schin 			int n;
15354887Schin 			iof |= IOLSEEK;
15364887Schin 			if(fcgetc(n)=='#')
15374887Schin 				iof |= IOCOPY;
15384887Schin 			else if(n>0)
15394887Schin 				fcseek(-1);
15404887Schin 		}
15414887Schin 		break;
15424887Schin 
15434887Schin 	    case '>':
15444887Schin 		if(iof<0)
15454887Schin 		{
15464887Schin 			errout = 1;
15474887Schin 			iof = 1;
15484887Schin 		}
15494887Schin 		iof |= IOPUT;
15504887Schin 		if(token==IOAPPSYM)
15514887Schin 			iof |= IOAPP;
15524887Schin 		else if(token==IOMOV1SYM)
15534887Schin 			iof |= IOMOV;
15544887Schin 		else if(token==IOCLOBSYM)
15554887Schin 			iof |= IOCLOB;
15564887Schin 		else if((token&SYMSHARP) == SYMSHARP)
15574887Schin 			iof |= IOLSEEK;
15588462SApril.Chin@Sun.COM 		else if((token&SYMSEMI) == SYMSEMI)
15598462SApril.Chin@Sun.COM 			iof |= IOREWRITE;
15604887Schin 		break;
15614887Schin 
15624887Schin 	    default:
15634887Schin 		return(lastio);
15644887Schin 	}
15658462SApril.Chin@Sun.COM 	lexp->digits=0;
15668462SApril.Chin@Sun.COM 	iop=(struct ionod*) stkalloc(stkp,sizeof(struct ionod));
15674887Schin 	iop->iodelim = 0;
15688462SApril.Chin@Sun.COM 	if(token=sh_lex(lexp))
15694887Schin 	{
15708462SApril.Chin@Sun.COM 		if(token==RPAREN && (iof&IOLSEEK) && lexp->comsub)
15714887Schin 		{
15728462SApril.Chin@Sun.COM 			lexp->arg = (struct argnod*)stkalloc(stkp,sizeof(struct argnod)+3);
15738462SApril.Chin@Sun.COM 			strcpy(lexp->arg->argval,"CUR");
15748462SApril.Chin@Sun.COM 			lexp->arg->argflag = ARG_RAW;
15754887Schin 			iof |= IOARITH;
15764887Schin 			fcseek(-1);
15774887Schin 		}
15784887Schin 		else if(token==EXPRSYM && (iof&IOLSEEK))
15794887Schin 			iof |= IOARITH;
1580*10898Sroland.mainz@nrubsig.org 		else if(((token==IPROCSYM && !(iof&IOPUT)) || (token==OPROCSYM && (iof&IOPUT))) && !(iof&(IOLSEEK|IOREWRITE|IOMOV|IODOC)))
1581*10898Sroland.mainz@nrubsig.org 		{
1582*10898Sroland.mainz@nrubsig.org 			lexp->arg = process_sub(lexp,token);
1583*10898Sroland.mainz@nrubsig.org 			iof |= IOPROCSUB;
1584*10898Sroland.mainz@nrubsig.org 		}
15854887Schin 		else
15868462SApril.Chin@Sun.COM 			sh_syntax(lexp);
15874887Schin 	}
1588*10898Sroland.mainz@nrubsig.org 	if( (iof&IOPROCSUB) && !(iof&IOLSEEK))
1589*10898Sroland.mainz@nrubsig.org 		iop->ioname= (char*)lexp->arg->argchn.ap;
1590*10898Sroland.mainz@nrubsig.org 	else
1591*10898Sroland.mainz@nrubsig.org 		iop->ioname=lexp->arg->argval;
15924887Schin 	iop->iovname = iovname;
15934887Schin 	if(iof&IODOC)
15944887Schin 	{
15958462SApril.Chin@Sun.COM 		if(lexp->digits==2)
15964887Schin 		{
15974887Schin 			iof |= IOSTRG;
15988462SApril.Chin@Sun.COM 			if(!(lexp->arg->argflag&ARG_RAW))
15994887Schin 				iof &= ~IORAW;
16004887Schin 		}
16014887Schin 		else
16024887Schin 		{
16038462SApril.Chin@Sun.COM 			if(!lexp->sh->heredocs)
16048462SApril.Chin@Sun.COM 				lexp->sh->heredocs = sftmp(HERE_MEM);
16058462SApril.Chin@Sun.COM 			iop->iolst=lexp->heredoc;
16068462SApril.Chin@Sun.COM 			lexp->heredoc=iop;
16078462SApril.Chin@Sun.COM 			if(lexp->arg->argflag&ARG_QUOTED)
16084887Schin 				iof |= IOQUOTE;
16098462SApril.Chin@Sun.COM 			if(lexp->digits==3)
16104887Schin 				iof |= IOLSEEK;
16118462SApril.Chin@Sun.COM 			if(lexp->digits)
16124887Schin 				iof |= IOSTRIP;
16134887Schin 		}
16144887Schin 	}
16154887Schin 	else
16164887Schin 	{
16174887Schin 		iop->iolst = 0;
16188462SApril.Chin@Sun.COM 		if(lexp->arg->argflag&ARG_RAW)
16194887Schin 			iof |= IORAW;
16204887Schin 	}
16214887Schin 	iop->iofile=iof;
16224887Schin 	if(flag>0)
16234887Schin 		/* allow alias substitutions and parameter assignments */
16248462SApril.Chin@Sun.COM 		lexp->aliasok = lexp->assignok = 1;
16254887Schin #if SHOPT_KIA
16268462SApril.Chin@Sun.COM 	if(lexp->kiafile)
16274887Schin 	{
16288462SApril.Chin@Sun.COM 		int n = lexp->sh->inlineno-(lexp->token=='\n');
16294887Schin 		if(!(iof&IOMOV))
16304887Schin 		{
16318462SApril.Chin@Sun.COM 			unsigned long r=kiaentity(lexp,(iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,lexp->script,'f',0,"");
16328462SApril.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);
16334887Schin 		}
16344887Schin 	}
16354887Schin #endif /* SHOPT_KIA */
16364887Schin 	if(flag>=0)
16374887Schin 	{
16384887Schin 		struct ionod *ioq=iop;
16398462SApril.Chin@Sun.COM 		sh_lex(lexp);
16404887Schin 		if(errout)
16414887Schin 		{
16424887Schin 			/* redirect standard output to standard error */
16438462SApril.Chin@Sun.COM 			ioq = (struct ionod*)stkalloc(stkp,sizeof(struct ionod));
1644*10898Sroland.mainz@nrubsig.org 			memset(ioq,0,sizeof(*ioq));
16454887Schin 			ioq->ioname = "1";
16464887Schin 			ioq->iolst = 0;
16474887Schin 			ioq->iodelim = 0;
16484887Schin 			ioq->iofile = IORAW|IOPUT|IOMOV|2;
16494887Schin 			iop->ionxt=ioq;
16504887Schin 		}
16518462SApril.Chin@Sun.COM 		ioq->ionxt=inout(lexp,lastio,flag);
16524887Schin 	}
16534887Schin 	else
16544887Schin 		iop->ionxt=0;
16554887Schin 	return(iop);
16564887Schin }
16574887Schin 
16584887Schin /*
16594887Schin  * convert argument chain to argument list when no special arguments
16604887Schin  */
16614887Schin 
16624887Schin static struct argnod *qscan(struct comnod *ac,int argn)
16634887Schin {
16644887Schin 	register char **cp;
16654887Schin 	register struct argnod *ap;
16664887Schin 	register struct dolnod* dp;
16674887Schin 	register int special=0;
16684887Schin 	/* special hack for test -t compatibility */
16694887Schin 	if((Namval_t*)ac->comnamp==SYSTEST)
16704887Schin 		special = 2;
16714887Schin 	else if(*(ac->comarg->argval)=='[' && ac->comarg->argval[1]==0)
16724887Schin 		special = 3;
16734887Schin 	if(special)
16744887Schin 	{
16754887Schin 		ap = ac->comarg->argnxt.ap;
16764887Schin 		if(argn==(special+1) && ap->argval[1]==0 && *ap->argval=='!')
16774887Schin 			ap = ap->argnxt.ap;
16784887Schin 		else if(argn!=special)
16794887Schin 			special=0;
16804887Schin 	}
16814887Schin 	if(special)
16824887Schin 	{
16834887Schin 		const char *message;
16844887Schin 		if(strcmp(ap->argval,"-t"))
16854887Schin 		{
16864887Schin 			message = "line %d: Invariant test";
16874887Schin 			special=0;
16884887Schin 		}
16894887Schin 		else
16904887Schin 		{
16914887Schin 			message = "line %d: -t requires argument";
16924887Schin 			argn++;
16934887Schin 		}
16944887Schin 		if(sh_isoption(SH_NOEXEC))
16954887Schin 			errormsg(SH_DICT,ERROR_warn(0),message,ac->comline);
16964887Schin 	}
16974887Schin 	/* leave space for an extra argument at the front */
16984887Schin 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
16994887Schin 	cp = dp->dolval+ARG_SPARE;
17004887Schin 	dp->dolnum = argn;
17014887Schin 	dp->dolbot = ARG_SPARE;
17024887Schin 	ap = ac->comarg;
17034887Schin 	while(ap)
17044887Schin 	{
17054887Schin 		*cp++ = ap->argval;
17064887Schin 		ap = ap->argnxt.ap;
17074887Schin 	}
17084887Schin 	if(special==3)
17094887Schin 	{
17104887Schin 		cp[0] = cp[-1];
17114887Schin 		cp[-1] = "1";
17124887Schin 		cp++;
17134887Schin 	}
17144887Schin 	else if(special)
17154887Schin 		*cp++ = "1";
17164887Schin 	*cp = 0;
17174887Schin 	return((struct argnod*)dp);
17184887Schin }
17194887Schin 
17208462SApril.Chin@Sun.COM static Shnode_t *test_expr(Lex_t *lp,int sym)
17214887Schin {
17228462SApril.Chin@Sun.COM 	register Shnode_t *t = test_or(lp);
17238462SApril.Chin@Sun.COM 	if(lp->token!=sym)
17248462SApril.Chin@Sun.COM 		sh_syntax(lp);
17254887Schin 	return(t);
17264887Schin }
17274887Schin 
17288462SApril.Chin@Sun.COM static Shnode_t *test_or(Lex_t *lp)
17294887Schin {
17308462SApril.Chin@Sun.COM 	register Shnode_t *t = test_and(lp);
17318462SApril.Chin@Sun.COM 	while(lp->token==ORFSYM)
17328462SApril.Chin@Sun.COM 		t = makelist(lp,TORF|TTEST,t,test_and(lp));
17334887Schin 	return(t);
17344887Schin }
17354887Schin 
17368462SApril.Chin@Sun.COM static Shnode_t *test_and(Lex_t *lp)
17374887Schin {
17388462SApril.Chin@Sun.COM 	register Shnode_t *t = test_primary(lp);
17398462SApril.Chin@Sun.COM 	while(lp->token==ANDFSYM)
17408462SApril.Chin@Sun.COM 		t = makelist(lp,TAND|TTEST,t,test_primary(lp));
17414887Schin 	return(t);
17424887Schin }
17434887Schin 
17444887Schin /*
17454887Schin  * convert =~ into == ~(E)
17464887Schin  */
17474887Schin static void ere_match(void)
17484887Schin {
17494887Schin 	Sfio_t *base, *iop = sfopen((Sfio_t*)0," ~(E)","s");
17504887Schin 	register int c;
17514887Schin 	while( fcgetc(c),(c==' ' || c=='\t'));
17524887Schin 	if(c)
17534887Schin 		fcseek(-1);
17544887Schin 	if(!(base=fcfile()))
17554887Schin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
17564887Schin 	fcclose();
17574887Schin         sfstack(base,iop);
17584887Schin         fcfopen(base);
17594887Schin }
17604887Schin 
17618462SApril.Chin@Sun.COM static Shnode_t *test_primary(Lex_t *lexp)
17624887Schin {
17634887Schin 	register struct argnod *arg;
17644887Schin 	register Shnode_t *t;
17654887Schin 	register int num,token;
17668462SApril.Chin@Sun.COM 	token = skipnl(lexp,0);
17678462SApril.Chin@Sun.COM 	num = lexp->digits;
17684887Schin 	switch(token)
17694887Schin 	{
17704887Schin 	    case '(':
17718462SApril.Chin@Sun.COM 		t = test_expr(lexp,')');
17728462SApril.Chin@Sun.COM 		t = makelist(lexp,TTST|TTEST|TPAREN ,t, (Shnode_t*)pointerof(lexp->sh->inlineno));
17734887Schin 		break;
17744887Schin 	    case '!':
17758462SApril.Chin@Sun.COM 		if(!(t = test_primary(lexp)))
17768462SApril.Chin@Sun.COM 			sh_syntax(lexp);
17774887Schin 		t->tre.tretyp |= TNEGATE;
17784887Schin 		return(t);
17794887Schin 	    case TESTUNOP:
17808462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
17818462SApril.Chin@Sun.COM 			sh_syntax(lexp);
17824887Schin #if SHOPT_KIA
17838462SApril.Chin@Sun.COM 		if(lexp->kiafile && !strchr("sntzoOG",num))
17844887Schin 		{
17858462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno- (lexp->token==NL);
17864887Schin 			unsigned long r;
17878462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->script,'t',0,"");
17888462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
17894887Schin 		}
17904887Schin #endif /* SHOPT_KIA */
17918462SApril.Chin@Sun.COM 		t = makelist(lexp,TTST|TTEST|TUNARY|(num<<TSHIFT),
17928462SApril.Chin@Sun.COM 			(Shnode_t*)lexp->arg,(Shnode_t*)lexp->arg);
17938462SApril.Chin@Sun.COM 		t->tst.tstline =  lexp->sh->inlineno;
17944887Schin 		break;
17954887Schin 	    /* binary test operators */
17964887Schin 	    case 0:
17978462SApril.Chin@Sun.COM 		arg = lexp->arg;
17988462SApril.Chin@Sun.COM 		if((token=sh_lex(lexp))==TESTBINOP)
17994887Schin 		{
18008462SApril.Chin@Sun.COM 			num = lexp->digits;
18014887Schin 			if(num==TEST_REP)
18024887Schin 			{
18034887Schin 				ere_match();
18044887Schin 				num = TEST_PEQ;
18054887Schin 			}
18064887Schin 		}
18074887Schin 		else if(token=='<')
18084887Schin 			num = TEST_SLT;
18094887Schin 		else if(token=='>')
18104887Schin 			num = TEST_SGT;
18114887Schin 		else if(token==ANDFSYM||token==ORFSYM||token==ETESTSYM||token==RPAREN)
18124887Schin 		{
18138462SApril.Chin@Sun.COM 			t = makelist(lexp,TTST|TTEST|TUNARY|('n'<<TSHIFT),
18144887Schin 				(Shnode_t*)arg,(Shnode_t*)arg);
18158462SApril.Chin@Sun.COM 			t->tst.tstline =  lexp->sh->inlineno;
18164887Schin 			return(t);
18174887Schin 		}
18184887Schin 		else
18198462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18204887Schin #if SHOPT_KIA
18218462SApril.Chin@Sun.COM 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
18224887Schin 		{
18238462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno- (lexp->token==NL);
18244887Schin 			unsigned long r;
18258462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
18268462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
18274887Schin 		}
18284887Schin #endif /* SHOPT_KIA */
18298462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
18308462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18314887Schin 		if(num&TEST_PATTERN)
18324887Schin 		{
18338462SApril.Chin@Sun.COM 			if(lexp->arg->argflag&(ARG_EXP|ARG_MAC))
18344887Schin 				num &= ~TEST_PATTERN;
18354887Schin 		}
18364887Schin 		t = getnode(tstnod);
18374887Schin 		t->lst.lsttyp = TTST|TTEST|TBINARY|(num<<TSHIFT);
18384887Schin 		t->lst.lstlef = (Shnode_t*)arg;
18398462SApril.Chin@Sun.COM 		t->lst.lstrit = (Shnode_t*)lexp->arg;
18408462SApril.Chin@Sun.COM 		t->tst.tstline =  lexp->sh->inlineno;
18414887Schin #if SHOPT_KIA
18428462SApril.Chin@Sun.COM 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
18434887Schin 		{
18448462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno-(lexp->token==NL);
18454887Schin 			unsigned long r;
18468462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
18478462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
18484887Schin 		}
18494887Schin #endif /* SHOPT_KIA */
18504887Schin 		break;
18514887Schin 	    default:
18524887Schin 		return(0);
18534887Schin 	}
18548462SApril.Chin@Sun.COM 	skipnl(lexp,0);
18554887Schin 	return(t);
18564887Schin }
18574887Schin 
18584887Schin #if SHOPT_KIA
18594887Schin /*
18604887Schin  * return an entity checksum
18614887Schin  * The entity is created if it doesn't exist
18624887Schin  */
18638462SApril.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)
18644887Schin {
18658462SApril.Chin@Sun.COM 	Stk_t	*stkp = lexp->sh->stk;
18664887Schin 	Namval_t *np;
18678462SApril.Chin@Sun.COM 	long offset = stktell(stkp);
18688462SApril.Chin@Sun.COM 	sfputc(stkp,type);
18694887Schin 	if(len>0)
18708462SApril.Chin@Sun.COM 		sfwrite(stkp,name,len);
18714887Schin 	else
18724887Schin 	{
18734887Schin 		if(type=='p')
18748462SApril.Chin@Sun.COM 			sfputr(stkp,path_basename(name),0);
18754887Schin 		else
18768462SApril.Chin@Sun.COM 			sfputr(stkp,name,0);
18774887Schin 	}
18788462SApril.Chin@Sun.COM 	np = nv_search(stakptr(offset),lexp->entity_tree,NV_ADD);
18798462SApril.Chin@Sun.COM 	stkseek(stkp,offset);
18804887Schin 	np->nvalue.i = pkind;
18814887Schin 	nv_setsize(np,width);
18824887Schin 	if(!nv_isattr(np,NV_TAGGED) && first>=0)
18834887Schin 	{
18844887Schin 		nv_onattr(np,NV_TAGGED);
18854887Schin 		if(!pkind)
18864887Schin 			pkind = '0';
18874887Schin 		if(len>0)
18888462SApril.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);
18894887Schin 		else
18908462SApril.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);
18914887Schin 	}
18924887Schin 	return(np->hash);
18934887Schin }
18944887Schin 
18954887Schin static void kia_add(register Namval_t *np, void *data)
18964887Schin {
18974887Schin 	char *name = nv_name(np);
18988462SApril.Chin@Sun.COM 	Lex_t	*lp = (Lex_t*)data;
18994887Schin 	NOT_USED(data);
19008462SApril.Chin@Sun.COM 	kiaentity(lp,name+1,-1,*name,0,-1,(*name=='p'?lp->unknown:lp->script),np->nvalue.i,nv_size(np),"");
19014887Schin }
19024887Schin 
19038462SApril.Chin@Sun.COM int kiaclose(Lex_t *lexp)
19044887Schin {
19054887Schin 	register off_t off1,off2;
19064887Schin 	register int n;
19078462SApril.Chin@Sun.COM 	if(lexp->kiafile)
19084887Schin 	{
19098462SApril.Chin@Sun.COM 		unsigned long r = kiaentity(lexp,lexp->scriptname,-1,'p',-1,lexp->sh->inlineno-1,0,'s',0,"");
19108462SApril.Chin@Sun.COM 		kiaentity(lexp,lexp->scriptname,-1,'p',1,lexp->sh->inlineno-1,r,'s',0,"");
19118462SApril.Chin@Sun.COM 		kiaentity(lexp,lexp->scriptname,-1,'f',1,lexp->sh->inlineno-1,r,'s',0,"");
19128462SApril.Chin@Sun.COM 		nv_scan(lexp->entity_tree,kia_add,(void*)lexp,NV_TAGGED,0);
19138462SApril.Chin@Sun.COM 		off1 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
19148462SApril.Chin@Sun.COM 		sfseek(lexp->kiatmp,(off_t)0,SEEK_SET);
19158462SApril.Chin@Sun.COM 		sfmove(lexp->kiatmp,lexp->kiafile,SF_UNBOUND,-1);
19168462SApril.Chin@Sun.COM 		off2 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
19174887Schin #ifdef SF_BUFCONST
19184887Schin 		if(off2==off1)
19198462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin));
19204887Schin 		else
19218462SApril.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));
19224887Schin 		if(off2 >= INT_MAX)
19234887Schin 			off2 = -(n+12);
19248462SApril.Chin@Sun.COM 		sfprintf(lexp->kiafile,"%010.10lld;%010d\n",(Sflong_t)off2+10, n+12);
19254887Schin #else
19264887Schin 		if(off2==off1)
19278462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin);
19284887Schin 		else
19298462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin,off1,off2-off1);
19308462SApril.Chin@Sun.COM 		sfprintf(lexp->kiafile,"%010d;%010d\n",off2+10, n+12);
19314887Schin #endif
19324887Schin 	}
19338462SApril.Chin@Sun.COM 	return(sfclose(lexp->kiafile));
19344887Schin }
19354887Schin #endif /* SHOPT_KIA */
1936