1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4b30d1939SAndy Fiddaman *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * UNIX shell
23da2e3ebdSchin  *
24da2e3ebdSchin  * S. R. Bourne
25da2e3ebdSchin  * Rewritten by David Korn
26da2e3ebdSchin  * AT&T Labs
27da2e3ebdSchin  *
28da2e3ebdSchin  *  This is the parser for a shell language
29da2e3ebdSchin  */
30da2e3ebdSchin 
31da2e3ebdSchin #if KSHELL
32da2e3ebdSchin #include	"defs.h"
33da2e3ebdSchin #else
34da2e3ebdSchin #include	<shell.h>
35da2e3ebdSchin #include	<ctype.h>
3634f9b3eeSRoland Mainz #endif
37da2e3ebdSchin #include	<fcin.h>
38da2e3ebdSchin #include	<error.h>
39da2e3ebdSchin #include	"shlex.h"
40da2e3ebdSchin #include	"history.h"
41da2e3ebdSchin #include	"builtins.h"
42da2e3ebdSchin #include	"test.h"
43da2e3ebdSchin #include	"history.h"
44da2e3ebdSchin 
45b30d1939SAndy Fiddaman #define HERE_MEM	SF_BUFSIZE	/* size of here-docs kept in memory */
46da2e3ebdSchin 
47b30d1939SAndy Fiddaman #if CDT_VERSION < 20111111L
48da2e3ebdSchin #define hash	nvlink.hl._hash
49b30d1939SAndy Fiddaman #else
50b30d1939SAndy Fiddaman #define hash	nvlink.lh.__hash
51b30d1939SAndy Fiddaman #endif
52da2e3ebdSchin 
53da2e3ebdSchin /* These routines are local to this module */
54da2e3ebdSchin 
557c2fbfb3SApril Chin static Shnode_t	*makeparent(Lex_t*, int, Shnode_t*);
567c2fbfb3SApril Chin static Shnode_t	*makelist(Lex_t*, int, Shnode_t*, Shnode_t*);
57da2e3ebdSchin static struct argnod	*qscan(struct comnod*, int);
587c2fbfb3SApril Chin static struct ionod	*inout(Lex_t*,struct ionod*, int);
597c2fbfb3SApril Chin static Shnode_t	*sh_cmd(Lex_t*,int,int);
607c2fbfb3SApril Chin static Shnode_t	*term(Lex_t*,int);
617c2fbfb3SApril Chin static Shnode_t	*list(Lex_t*,int);
627c2fbfb3SApril Chin static struct regnod	*syncase(Lex_t*,int);
637c2fbfb3SApril Chin static Shnode_t	*item(Lex_t*,int);
647c2fbfb3SApril Chin static Shnode_t	*simple(Lex_t*,int, struct ionod*);
657c2fbfb3SApril Chin static int	skipnl(Lex_t*,int);
667c2fbfb3SApril Chin static Shnode_t	*test_expr(Lex_t*,int);
677c2fbfb3SApril Chin static Shnode_t	*test_and(Lex_t*);
687c2fbfb3SApril Chin static Shnode_t	*test_or(Lex_t*);
697c2fbfb3SApril Chin static Shnode_t	*test_primary(Lex_t*);
70da2e3ebdSchin 
717c2fbfb3SApril Chin #define	sh_getlineno(lp)	(lp->lastline)
72da2e3ebdSchin 
73da2e3ebdSchin #ifndef NIL
74da2e3ebdSchin #   define NIL(type)	((type)0)
75da2e3ebdSchin #endif /* NIL */
76da2e3ebdSchin #define CNTL(x)		((x)&037)
77da2e3ebdSchin 
78da2e3ebdSchin 
79da2e3ebdSchin #if !KSHELL
80da2e3ebdSchin static struct stdata
81da2e3ebdSchin {
82da2e3ebdSchin 	struct slnod    *staklist;
83da2e3ebdSchin 	int	cmdline;
84da2e3ebdSchin } st;
85da2e3ebdSchin #endif
86da2e3ebdSchin 
877c2fbfb3SApril Chin static int		opt_get;
88da2e3ebdSchin static int		loop_level;
89da2e3ebdSchin static struct argnod	*label_list;
90da2e3ebdSchin static struct argnod	*label_last;
91da2e3ebdSchin 
92da2e3ebdSchin #define getnode(type)	((Shnode_t*)stakalloc(sizeof(struct type)))
93da2e3ebdSchin 
94da2e3ebdSchin #if SHOPT_KIA
95da2e3ebdSchin #include	"path.h"
96da2e3ebdSchin /*
97da2e3ebdSchin  * write out entities for each item in the list
98da2e3ebdSchin  * type=='V' for variable assignment lists
99da2e3ebdSchin  * Otherwise type is determined by the command */
writedefs(Lex_t * lexp,struct argnod * arglist,int line,int type,struct argnod * cmd)1007c2fbfb3SApril Chin static unsigned long writedefs(Lex_t *lexp,struct argnod *arglist, int line, int type, struct argnod *cmd)
101da2e3ebdSchin {
102da2e3ebdSchin 	register struct argnod *argp = arglist;
103da2e3ebdSchin 	register char *cp;
104da2e3ebdSchin 	register int n,eline;
105da2e3ebdSchin 	int width=0;
106da2e3ebdSchin 	unsigned long r=0;
107da2e3ebdSchin 	static char atbuff[20];
108da2e3ebdSchin 	int  justify=0;
109da2e3ebdSchin 	char *attribute = atbuff;
1107c2fbfb3SApril Chin 	unsigned long parent=lexp->script;
111da2e3ebdSchin 	if(type==0)
112da2e3ebdSchin 	{
1137c2fbfb3SApril Chin 		parent = lexp->current;
114da2e3ebdSchin 		type = 'v';
115da2e3ebdSchin 		switch(*argp->argval)
116da2e3ebdSchin 		{
117da2e3ebdSchin 		    case 'a':
118da2e3ebdSchin 			type='p';
119da2e3ebdSchin 			justify = 'a';
120da2e3ebdSchin 			break;
121da2e3ebdSchin 		    case 'e':
122da2e3ebdSchin 			*attribute++ =  'x';
123da2e3ebdSchin 			break;
124da2e3ebdSchin 		    case 'r':
125da2e3ebdSchin 			*attribute++ = 'r';
126da2e3ebdSchin 			break;
127da2e3ebdSchin 		    case 'l':
128da2e3ebdSchin 			break;
129da2e3ebdSchin 		}
130da2e3ebdSchin 		while(argp = argp->argnxt.ap)
131da2e3ebdSchin 		{
132da2e3ebdSchin 			if((n= *(cp=argp->argval))!='-' && n!='+')
133da2e3ebdSchin 				break;
134da2e3ebdSchin 			if(cp[1]==n)
135da2e3ebdSchin 				break;
136da2e3ebdSchin 			while((n= *++cp))
137da2e3ebdSchin 			{
138da2e3ebdSchin 				if(isdigit(n))
139da2e3ebdSchin 					width = 10*width + n-'0';
140da2e3ebdSchin 				else if(n=='L' || n=='R' || n =='Z')
141da2e3ebdSchin 					justify=n;
142da2e3ebdSchin 				else
143da2e3ebdSchin 					*attribute++ = n;
144da2e3ebdSchin 			}
145da2e3ebdSchin 		}
146da2e3ebdSchin 	}
147da2e3ebdSchin 	else if(cmd)
1487c2fbfb3SApril Chin 		parent=kiaentity(lexp,sh_argstr(cmd),-1,'p',-1,-1,lexp->unknown,'b',0,"");
149da2e3ebdSchin 	*attribute = 0;
150da2e3ebdSchin 	while(argp)
151da2e3ebdSchin 	{
152da2e3ebdSchin 		if((cp=strchr(argp->argval,'='))||(cp=strchr(argp->argval,'?')))
153da2e3ebdSchin 			n = cp-argp->argval;
154da2e3ebdSchin 		else
155da2e3ebdSchin 			n = strlen(argp->argval);
1567c2fbfb3SApril Chin 		eline = lexp->sh->inlineno-(lexp->token==NL);
1577c2fbfb3SApril Chin 		r=kiaentity(lexp,argp->argval,n,type,line,eline,parent,justify,width,atbuff);
1587c2fbfb3SApril Chin 		sfprintf(lexp->kiatmp,"p;%..64d;v;%..64d;%d;%d;s;\n",lexp->current,r,line,eline);
159da2e3ebdSchin 		argp = argp->argnxt.ap;
160da2e3ebdSchin 	}
161da2e3ebdSchin 	return(r);
162da2e3ebdSchin }
163da2e3ebdSchin #endif /* SHOPT_KIA */
1647c2fbfb3SApril Chin 
typeset_order(const char * str,int line)1657c2fbfb3SApril Chin static void typeset_order(const char *str,int line)
1667c2fbfb3SApril Chin {
1677c2fbfb3SApril Chin 	register int		c,n=0;
1687c2fbfb3SApril Chin 	unsigned const char	*cp=(unsigned char*)str;
1697c2fbfb3SApril Chin 	static unsigned char	*table;
1707c2fbfb3SApril Chin 	if(*cp!='+' && *cp!='-')
1717c2fbfb3SApril Chin 		return;
1727c2fbfb3SApril Chin 	if(!table)
1737c2fbfb3SApril Chin 	{
1747c2fbfb3SApril Chin 		table = calloc(1,256);
1757c2fbfb3SApril Chin 		for(cp=(unsigned char*)"bflmnprstuxACHS";c = *cp; cp++)
1767c2fbfb3SApril Chin 			table[c] = 1;
1777c2fbfb3SApril Chin 		for(cp=(unsigned char*)"aiEFLRXhTZ";c = *cp; cp++)
1787c2fbfb3SApril Chin 			table[c] = 2;
1797c2fbfb3SApril Chin 		for(c='0'; c <='9'; c++)
1807c2fbfb3SApril Chin 			table[c] = 3;
1817c2fbfb3SApril Chin 	}
1827c2fbfb3SApril Chin 	for(cp=(unsigned char*)str; c= *cp++; n=table[c])
1837c2fbfb3SApril Chin 	{
1847c2fbfb3SApril Chin 		if(table[c] < n)
1857c2fbfb3SApril Chin 			errormsg(SH_DICT,ERROR_warn(0),e_lextypeset,line,str);
1867c2fbfb3SApril Chin 	}
1877c2fbfb3SApril Chin }
1887c2fbfb3SApril Chin 
1897c2fbfb3SApril Chin /*
1907c2fbfb3SApril Chin  * add type definitions when compiling with -n
1917c2fbfb3SApril Chin  */
check_typedef(struct comnod * tp)1927c2fbfb3SApril Chin static void check_typedef(struct comnod *tp)
1937c2fbfb3SApril Chin {
1947c2fbfb3SApril Chin 	char	*cp=0;
1957c2fbfb3SApril Chin 	if(tp->comtyp&COMSCAN)
1967c2fbfb3SApril Chin 	{
1977c2fbfb3SApril Chin 		struct argnod *ap = tp->comarg;
1987c2fbfb3SApril Chin 		while(ap = ap->argnxt.ap)
1997c2fbfb3SApril Chin 		{
2007c2fbfb3SApril Chin 			if(!(ap->argflag&ARG_RAW) || memcmp(ap->argval,"--",2))
2017c2fbfb3SApril Chin 				break;
2027c2fbfb3SApril Chin 			if(sh_isoption(SH_NOEXEC))
2037c2fbfb3SApril Chin 				typeset_order(ap->argval,tp->comline);
2047c2fbfb3SApril Chin 			if(memcmp(ap->argval,"-T",2)==0)
2057c2fbfb3SApril Chin 			{
2067c2fbfb3SApril Chin 				if(ap->argval[2])
2077c2fbfb3SApril Chin 					cp = ap->argval+2;
2087c2fbfb3SApril Chin 				else if((ap->argnxt.ap)->argflag&ARG_RAW)
2097c2fbfb3SApril Chin 					cp = (ap->argnxt.ap)->argval;
2107c2fbfb3SApril Chin 				if(cp)
2117c2fbfb3SApril Chin 					break;
2127c2fbfb3SApril Chin 			}
2137c2fbfb3SApril Chin 		}
2147c2fbfb3SApril Chin 	}
2157c2fbfb3SApril Chin 	else
2167c2fbfb3SApril Chin 	{
2177c2fbfb3SApril Chin 		struct dolnod *dp = (struct dolnod*)tp->comarg;
2187c2fbfb3SApril Chin 		char **argv = dp->dolval + dp->dolbot+1;
2197c2fbfb3SApril Chin 		while((cp= *argv++) && memcmp(cp,"--",2))
2207c2fbfb3SApril Chin 		{
2217c2fbfb3SApril Chin 			if(sh_isoption(SH_NOEXEC))
2227c2fbfb3SApril Chin 				typeset_order(cp,tp->comline);
2237c2fbfb3SApril Chin 			if(memcmp(cp,"-T",2)==0)
2247c2fbfb3SApril Chin 			{
2257c2fbfb3SApril Chin 				if(cp[2])
2267c2fbfb3SApril Chin 					cp = cp+2;
2277c2fbfb3SApril Chin 				else
2287c2fbfb3SApril Chin 					cp = *argv;
2297c2fbfb3SApril Chin 				break;
2307c2fbfb3SApril Chin 			}
2317c2fbfb3SApril Chin 		}
2327c2fbfb3SApril Chin 	}
2337c2fbfb3SApril Chin 	if(cp)
2347c2fbfb3SApril Chin 	{
2357c2fbfb3SApril Chin 		Namval_t	*mp=(Namval_t*)tp->comnamp ,*bp;
236b30d1939SAndy Fiddaman 		bp = sh_addbuiltin(cp, (Shbltin_f)mp->nvalue.bfp, (void*)0);
2377c2fbfb3SApril Chin 		nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
2387c2fbfb3SApril Chin 	}
2397c2fbfb3SApril Chin }
2407c2fbfb3SApril Chin 
241da2e3ebdSchin /*
242da2e3ebdSchin  * Make a parent node for fork() or io-redirection
243da2e3ebdSchin  */
makeparent(Lex_t * lp,int flag,Shnode_t * child)2447c2fbfb3SApril Chin static Shnode_t	*makeparent(Lex_t *lp, int flag, Shnode_t *child)
245da2e3ebdSchin {
246da2e3ebdSchin 	register Shnode_t	*par = getnode(forknod);
247da2e3ebdSchin 	par->fork.forktyp = flag;
248da2e3ebdSchin 	par->fork.forktre = child;
249da2e3ebdSchin 	par->fork.forkio = 0;
2507c2fbfb3SApril Chin 	par->fork.forkline = sh_getlineno(lp)-1;
251da2e3ebdSchin 	return(par);
252da2e3ebdSchin }
253da2e3ebdSchin 
paramsub(const char * str)254*be548e87SAndy Fiddaman static const char *paramsub(const char *str)
2553e14f97fSRoger A. Faulkner {
2563e14f97fSRoger A. Faulkner 	register int c,sub=0,lit=0;
2573e14f97fSRoger A. Faulkner 	while(c= *str++)
2583e14f97fSRoger A. Faulkner 	{
2593e14f97fSRoger A. Faulkner 		if(c=='$' && !lit)
2603e14f97fSRoger A. Faulkner 		{
2613e14f97fSRoger A. Faulkner 			if(*str=='(')
262*be548e87SAndy Fiddaman 				return(NULL);
2633e14f97fSRoger A. Faulkner 			if(sub)
2643e14f97fSRoger A. Faulkner 				continue;
2653e14f97fSRoger A. Faulkner 			if(*str=='{')
2663e14f97fSRoger A. Faulkner 				str++;
2673e14f97fSRoger A. Faulkner 			if(!isdigit(*str) && strchr("?#@*!$ ",*str)==0)
268*be548e87SAndy Fiddaman 				return(str);
2693e14f97fSRoger A. Faulkner 		}
2703e14f97fSRoger A. Faulkner 		else if(c=='`')
271*be548e87SAndy Fiddaman 			return(NULL);
2723e14f97fSRoger A. Faulkner 		else if(c=='[' && !lit)
2733e14f97fSRoger A. Faulkner 			sub++;
2743e14f97fSRoger A. Faulkner 		else if(c==']' && !lit)
2753e14f97fSRoger A. Faulkner 			sub--;
2763e14f97fSRoger A. Faulkner 		else if(c=='\'')
2773e14f97fSRoger A. Faulkner 			lit = !lit;
2783e14f97fSRoger A. Faulkner 	}
279*be548e87SAndy Fiddaman 	return(NULL);
2803e14f97fSRoger A. Faulkner }
2813e14f97fSRoger A. Faulkner 
getanode(Lex_t * lp,struct argnod * ap)2827c2fbfb3SApril Chin static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
283da2e3ebdSchin {
284da2e3ebdSchin 	register Shnode_t *t = getnode(arithnod);
285da2e3ebdSchin 	t->ar.artyp = TARITH;
2867c2fbfb3SApril Chin 	t->ar.arline = sh_getlineno(lp);
287da2e3ebdSchin 	t->ar.arexpr = ap;
288da2e3ebdSchin 	if(ap->argflag&ARG_RAW)
289b30d1939SAndy Fiddaman 		t->ar.arcomp = sh_arithcomp(lp->sh,ap->argval);
290da2e3ebdSchin 	else
2913e14f97fSRoger A. Faulkner 	{
292*be548e87SAndy Fiddaman 		const char *p, *q;
293*be548e87SAndy Fiddaman 
294*be548e87SAndy Fiddaman 		if (sh_isoption(SH_NOEXEC) && (ap->argflag&ARG_MAC) &&
295*be548e87SAndy Fiddaman 		    (p = paramsub(ap->argval)) != NULL) {
296*be548e87SAndy Fiddaman 			for (q = p; !isspace(*q) && *q != '\0'; q++)
297*be548e87SAndy Fiddaman 				;
298*be548e87SAndy Fiddaman 			errormsg(SH_DICT, ERROR_warn(0), e_lexwarnvar,
299*be548e87SAndy Fiddaman 			    lp->sh->inlineno, ap->argval, q - p, p);
300*be548e87SAndy Fiddaman 		}
301da2e3ebdSchin 		t->ar.arcomp = 0;
3023e14f97fSRoger A. Faulkner 	}
303da2e3ebdSchin 	return(t);
304da2e3ebdSchin }
305da2e3ebdSchin 
306da2e3ebdSchin /*
307da2e3ebdSchin  *  Make a node corresponding to a command list
308da2e3ebdSchin  */
makelist(Lex_t * lexp,int type,Shnode_t * l,Shnode_t * r)3097c2fbfb3SApril Chin static Shnode_t	*makelist(Lex_t *lexp, int type, Shnode_t *l, Shnode_t *r)
310da2e3ebdSchin {
311da2e3ebdSchin 	register Shnode_t	*t;
312da2e3ebdSchin 	if(!l || !r)
3137c2fbfb3SApril Chin 		sh_syntax(lexp);
314da2e3ebdSchin 	else
315da2e3ebdSchin 	{
316da2e3ebdSchin 		if((type&COMMSK) == TTST)
317da2e3ebdSchin 			t = getnode(tstnod);
318da2e3ebdSchin 		else
319da2e3ebdSchin 			t = getnode(lstnod);
320da2e3ebdSchin 		t->lst.lsttyp = type;
321da2e3ebdSchin 		t->lst.lstlef = l;
322da2e3ebdSchin 		t->lst.lstrit = r;
323da2e3ebdSchin 	}
324da2e3ebdSchin 	return(t);
325da2e3ebdSchin }
326da2e3ebdSchin 
327da2e3ebdSchin /*
328da2e3ebdSchin  * entry to shell parser
329da2e3ebdSchin  * Flag can be the union of SH_EOF|SH_NL
330da2e3ebdSchin  */
331da2e3ebdSchin 
sh_parse(Shell_t * shp,Sfio_t * iop,int flag)332da2e3ebdSchin void	*sh_parse(Shell_t *shp, Sfio_t *iop, int flag)
333da2e3ebdSchin {
334da2e3ebdSchin 	register Shnode_t	*t;
3357c2fbfb3SApril Chin 	Lex_t			*lexp = (Lex_t*)shp->lex_context;
336da2e3ebdSchin 	Fcin_t	sav_input;
3377c2fbfb3SApril Chin 	struct argnod *sav_arg = lexp->arg;
338da2e3ebdSchin 	int	sav_prompt = shp->nextprompt;
33934f9b3eeSRoland Mainz 	if(shp->binscript && (sffileno(iop)==shp->infd || (flag&SH_FUNEVAL)))
3407c2fbfb3SApril Chin 		return((void*)sh_trestore(shp,iop));
341da2e3ebdSchin 	fcsave(&sav_input);
342da2e3ebdSchin 	shp->st.staklist = 0;
343b30d1939SAndy Fiddaman 	lexp->noreserv = 0;
3447c2fbfb3SApril Chin 	lexp->heredoc = 0;
3457c2fbfb3SApril Chin 	lexp->inlineno = shp->inlineno;
3467c2fbfb3SApril Chin 	lexp->firstline = shp->st.firstline;
347da2e3ebdSchin 	shp->nextprompt = 1;
348da2e3ebdSchin 	loop_level = 0;
349da2e3ebdSchin 	label_list = label_last = 0;
350da2e3ebdSchin 	if(sh_isoption(SH_INTERACTIVE))
351da2e3ebdSchin 		sh_onstate(SH_INTERACTIVE);
352da2e3ebdSchin 	if(sh_isoption(SH_VERBOSE))
353da2e3ebdSchin 		sh_onstate(SH_VERBOSE);
3547c2fbfb3SApril Chin 	sh_lexopen(lexp,shp,0);
355da2e3ebdSchin 	if(fcfopen(iop) < 0)
356da2e3ebdSchin 		return(NIL(void*));
357da2e3ebdSchin 	if(fcfile())
358da2e3ebdSchin 	{
359da2e3ebdSchin 		char *cp = fcfirst();
360da2e3ebdSchin 		if( cp[0]==CNTL('k') &&  cp[1]==CNTL('s') && cp[2]==CNTL('h') && cp[3]==0)
361da2e3ebdSchin 		{
362da2e3ebdSchin 			int version;
363da2e3ebdSchin 			fcseek(4);
364da2e3ebdSchin 			fcgetc(version);
365da2e3ebdSchin 			fcclose();
366da2e3ebdSchin 			fcrestore(&sav_input);
3677c2fbfb3SApril Chin 			lexp->arg = sav_arg;
368da2e3ebdSchin 			if(version > 3)
369da2e3ebdSchin 				errormsg(SH_DICT,ERROR_exit(1),e_lexversion);
37034f9b3eeSRoland Mainz 			if(sffileno(iop)==shp->infd || (flag&SH_FUNEVAL))
371da2e3ebdSchin 				shp->binscript = 1;
372da2e3ebdSchin 			sfgetc(iop);
373b30d1939SAndy Fiddaman 			t = sh_trestore(shp,iop);
374b30d1939SAndy Fiddaman 			if(flag&SH_NL)
375b30d1939SAndy Fiddaman 			{
376b30d1939SAndy Fiddaman 				Shnode_t *tt;
377b30d1939SAndy Fiddaman 				while(1)
378b30d1939SAndy Fiddaman 				{
379b30d1939SAndy Fiddaman 					if(!(tt = sh_trestore(shp,iop)))
380b30d1939SAndy Fiddaman 						break;
381b30d1939SAndy Fiddaman 					t =makelist(lexp,TLST, t, tt);
382b30d1939SAndy Fiddaman 				}
383b30d1939SAndy Fiddaman 			}
384b30d1939SAndy Fiddaman 			return((void*)t);
385da2e3ebdSchin 		}
386da2e3ebdSchin 	}
38734f9b3eeSRoland Mainz 	flag &= ~SH_FUNEVAL;
388da2e3ebdSchin 	if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0)
389da2e3ebdSchin 		shp->inlineno=1;
390da2e3ebdSchin #if KSHELL
391da2e3ebdSchin 	shp->nextprompt = 2;
392da2e3ebdSchin #endif
3937c2fbfb3SApril Chin 	t = sh_cmd(lexp,(flag&SH_EOF)?EOFSYM:'\n',SH_SEMI|SH_EMPTY|(flag&SH_NL));
394da2e3ebdSchin 	fcclose();
395da2e3ebdSchin 	fcrestore(&sav_input);
3967c2fbfb3SApril Chin 	lexp->arg = sav_arg;
397da2e3ebdSchin 	/* unstack any completed alias expansions */
398da2e3ebdSchin 	if((sfset(iop,0,0)&SF_STRING) && !sfreserve(iop,0,-1))
399da2e3ebdSchin 	{
400da2e3ebdSchin 		Sfio_t *sp = sfstack(iop,NULL);
401da2e3ebdSchin 		if(sp)
402da2e3ebdSchin 			sfclose(sp);
403da2e3ebdSchin 	}
404da2e3ebdSchin 	shp->nextprompt = sav_prompt;
405da2e3ebdSchin 	if(flag&SH_NL)
406da2e3ebdSchin 	{
4077c2fbfb3SApril Chin 		shp->st.firstline = lexp->firstline;
4087c2fbfb3SApril Chin 		shp->inlineno = lexp->inlineno;
409da2e3ebdSchin 	}
4107c2fbfb3SApril Chin 	stkseek(shp->stk,0);
411da2e3ebdSchin 	return((void*)t);
412da2e3ebdSchin }
413da2e3ebdSchin 
414da2e3ebdSchin /*
415da2e3ebdSchin  * This routine parses up the matching right parenthesis and returns
416da2e3ebdSchin  * the parse tree
417da2e3ebdSchin  */
sh_dolparen(Lex_t * lp)4187c2fbfb3SApril Chin Shnode_t *sh_dolparen(Lex_t* lp)
419da2e3ebdSchin {
420da2e3ebdSchin 	register Shnode_t *t=0;
421da2e3ebdSchin 	Sfio_t *sp = fcfile();
4227c2fbfb3SApril Chin 	int line = lp->sh->inlineno;
4237c2fbfb3SApril Chin 	lp->sh->inlineno = error_info.line+lp->sh->st.firstline;
4247c2fbfb3SApril Chin 	sh_lexopen(lp,lp->sh,1);
4257c2fbfb3SApril Chin 	lp->comsub = 1;
4267c2fbfb3SApril Chin 	switch(sh_lex(lp))
427da2e3ebdSchin 	{
428da2e3ebdSchin 	    /* ((...)) arithmetic expression */
429da2e3ebdSchin 	    case EXPRSYM:
4307c2fbfb3SApril Chin 		t = getanode(lp,lp->arg);
431da2e3ebdSchin 		break;
432da2e3ebdSchin 	    case LPAREN:
4337c2fbfb3SApril Chin 		t = sh_cmd(lp,RPAREN,SH_NL|SH_EMPTY);
4347c2fbfb3SApril Chin 		break;
4357c2fbfb3SApril Chin 	    case LBRACE:
4367c2fbfb3SApril Chin 		t = sh_cmd(lp,RBRACE,SH_NL|SH_EMPTY);
437da2e3ebdSchin 		break;
438da2e3ebdSchin 	}
4397c2fbfb3SApril Chin 	lp->comsub = 0;
440da2e3ebdSchin 	if(!sp && (sp=fcfile()))
441da2e3ebdSchin 	{
442da2e3ebdSchin 		/*
443da2e3ebdSchin 		 * This code handles the case where string has been converted
444da2e3ebdSchin 		 * to a file by an alias setup
445da2e3ebdSchin 		 */
446da2e3ebdSchin 		register int c;
447da2e3ebdSchin 		char *cp;
448da2e3ebdSchin 		if(fcgetc(c) > 0)
449da2e3ebdSchin 			fcseek(-1);
450da2e3ebdSchin 		cp = fcseek(0);
451da2e3ebdSchin 		fcclose();
452da2e3ebdSchin 		fcsopen(cp);
453da2e3ebdSchin 		sfclose(sp);
454da2e3ebdSchin 	}
4557c2fbfb3SApril Chin 	lp->sh->inlineno = line;
456da2e3ebdSchin 	return(t);
457da2e3ebdSchin }
458da2e3ebdSchin 
459da2e3ebdSchin /*
460da2e3ebdSchin  * remove temporary files and stacks
461da2e3ebdSchin  */
462da2e3ebdSchin 
sh_freeup(Shell_t * shp)4637c2fbfb3SApril Chin void	sh_freeup(Shell_t *shp)
464da2e3ebdSchin {
4657c2fbfb3SApril Chin 	if(shp->st.staklist)
4667c2fbfb3SApril Chin 		sh_funstaks(shp->st.staklist,-1);
4677c2fbfb3SApril Chin 	shp->st.staklist = 0;
468da2e3ebdSchin }
469da2e3ebdSchin 
470da2e3ebdSchin /*
471da2e3ebdSchin  * increase reference count for each stack in function list when flag>0
472da2e3ebdSchin  * decrease reference count for each stack in function list when flag<=0
473da2e3ebdSchin  * stack is freed when reference count is zero
474da2e3ebdSchin  */
475da2e3ebdSchin 
sh_funstaks(register struct slnod * slp,int flag)476da2e3ebdSchin void sh_funstaks(register struct slnod *slp,int flag)
477da2e3ebdSchin {
478da2e3ebdSchin 	register struct slnod *slpold;
479da2e3ebdSchin 	while(slpold=slp)
480da2e3ebdSchin 	{
481da2e3ebdSchin 		if(slp->slchild)
482da2e3ebdSchin 			sh_funstaks(slp->slchild,flag);
483da2e3ebdSchin 		slp = slp->slnext;
484da2e3ebdSchin 		if(flag<=0)
485da2e3ebdSchin 			stakdelete(slpold->slptr);
486da2e3ebdSchin 		else
487da2e3ebdSchin 			staklink(slpold->slptr);
488da2e3ebdSchin 	}
489da2e3ebdSchin }
490da2e3ebdSchin /*
491da2e3ebdSchin  * cmd
492da2e3ebdSchin  *	empty
493da2e3ebdSchin  *	list
494da2e3ebdSchin  *	list & [ cmd ]
495da2e3ebdSchin  *	list [ ; cmd ]
496da2e3ebdSchin  */
497da2e3ebdSchin 
sh_cmd(Lex_t * lexp,register int sym,int flag)4987c2fbfb3SApril Chin static Shnode_t	*sh_cmd(Lex_t *lexp, register int sym, int flag)
499da2e3ebdSchin {
500da2e3ebdSchin 	register Shnode_t	*left, *right;
501da2e3ebdSchin 	register int type = FINT|FAMP;
502da2e3ebdSchin 	if(sym==NL)
5037c2fbfb3SApril Chin 		lexp->lasttok = 0;
5047c2fbfb3SApril Chin 	left = list(lexp,flag);
5057c2fbfb3SApril Chin 	if(lexp->token==NL)
506da2e3ebdSchin 	{
507da2e3ebdSchin 		if(flag&SH_NL)
5087c2fbfb3SApril Chin 			lexp->token=';';
509da2e3ebdSchin 	}
510da2e3ebdSchin 	else if(!left && !(flag&SH_EMPTY))
5117c2fbfb3SApril Chin 		sh_syntax(lexp);
5127c2fbfb3SApril Chin 	switch(lexp->token)
513da2e3ebdSchin 	{
514da2e3ebdSchin 	    case COOPSYM:		/* set up a cooperating process */
515da2e3ebdSchin 		type |= (FPIN|FPOU|FPCL|FCOOP);
5165ae8bd53SToomas Soome 		/* FALLTHROUGH */
517da2e3ebdSchin 	    case '&':
518da2e3ebdSchin 		if(left)
519da2e3ebdSchin 		{
520da2e3ebdSchin 			/* (...)& -> {...;} & */
521da2e3ebdSchin 			if(left->tre.tretyp==TPAR)
522da2e3ebdSchin 				left = left->par.partre;
5237c2fbfb3SApril Chin 			left = makeparent(lexp,TFORK|type, left);
524da2e3ebdSchin 		}
5255ae8bd53SToomas Soome 		/* FALLTHROUGH */
526da2e3ebdSchin 	    case ';':
527da2e3ebdSchin 		if(!left)
5287c2fbfb3SApril Chin 			sh_syntax(lexp);
5297c2fbfb3SApril Chin 		if(right=sh_cmd(lexp,sym,flag|SH_EMPTY))
5307c2fbfb3SApril Chin 			left=makelist(lexp,TLST, left, right);
531da2e3ebdSchin 		break;
532da2e3ebdSchin 	    case EOFSYM:
533da2e3ebdSchin 		if(sym==NL)
534da2e3ebdSchin 			break;
5355ae8bd53SToomas Soome 		/* FALLTHROUGH */
536da2e3ebdSchin 	    default:
5377c2fbfb3SApril Chin 		if(sym && sym!=lexp->token)
538da2e3ebdSchin 		{
5397c2fbfb3SApril Chin 			if(sym!=ELSESYM || (lexp->token!=ELIFSYM && lexp->token!=FISYM))
5407c2fbfb3SApril Chin 				sh_syntax(lexp);
541da2e3ebdSchin 		}
542da2e3ebdSchin 	}
543da2e3ebdSchin 	return(left);
544da2e3ebdSchin }
545da2e3ebdSchin 
546da2e3ebdSchin /*
547da2e3ebdSchin  * list
548da2e3ebdSchin  *	term
549da2e3ebdSchin  *	list && term
550da2e3ebdSchin  *	list || term
551da2e3ebdSchin  *      unfortunately, these are equal precedence
552da2e3ebdSchin  */
list(Lex_t * lexp,register int flag)5537c2fbfb3SApril Chin static Shnode_t	*list(Lex_t *lexp, register int flag)
554da2e3ebdSchin {
5557c2fbfb3SApril Chin 	register Shnode_t	*t = term(lexp,flag);
556da2e3ebdSchin 	register int 	token;
5577c2fbfb3SApril Chin 	while(t && ((token=lexp->token)==ANDFSYM || token==ORFSYM))
5587c2fbfb3SApril Chin 		t = makelist(lexp,(token==ANDFSYM?TAND:TORF), t, term(lexp,SH_NL|SH_SEMI));
559da2e3ebdSchin 	return(t);
560da2e3ebdSchin }
561da2e3ebdSchin 
562da2e3ebdSchin /*
563da2e3ebdSchin  * term
564da2e3ebdSchin  *	item
565da2e3ebdSchin  *	item | term
566da2e3ebdSchin  */
term(Lex_t * lexp,register int flag)5677c2fbfb3SApril Chin static Shnode_t	*term(Lex_t *lexp,register int flag)
568da2e3ebdSchin {
569da2e3ebdSchin 	register Shnode_t	*t;
570da2e3ebdSchin 	register int token;
571da2e3ebdSchin 	if(flag&SH_NL)
5727c2fbfb3SApril Chin 		token = skipnl(lexp,flag);
573da2e3ebdSchin 	else
5747c2fbfb3SApril Chin 		token = sh_lex(lexp);
575da2e3ebdSchin 	/* check to see if pipeline is to be timed */
576da2e3ebdSchin 	if(token==TIMESYM || token==NOTSYM)
577da2e3ebdSchin 	{
578da2e3ebdSchin 		t = getnode(parnod);
579da2e3ebdSchin 		t->par.partyp=TTIME;
5807c2fbfb3SApril Chin 		if(lexp->token==NOTSYM)
581da2e3ebdSchin 			t->par.partyp |= COMSCAN;
5827c2fbfb3SApril Chin 		t->par.partre = term(lexp,0);
583da2e3ebdSchin 	}
584b30d1939SAndy Fiddaman #if SHOPT_COSHELL
585b30d1939SAndy Fiddaman 	else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && (lexp->token=='|' || lexp->token==PIPESYM2))
586b30d1939SAndy Fiddaman #else
5877c2fbfb3SApril Chin 	else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && lexp->token=='|')
588b30d1939SAndy Fiddaman #endif /* SHOPT_COSHELL */
589da2e3ebdSchin 	{
590da2e3ebdSchin 		register Shnode_t	*tt;
591da2e3ebdSchin 		int showme = t->tre.tretyp&FSHOWME;
5927c2fbfb3SApril Chin 		t = makeparent(lexp,TFORK|FPOU,t);
593b30d1939SAndy Fiddaman #if SHOPT_COSHELL
594b30d1939SAndy Fiddaman 		if(lexp->token==PIPESYM2)
595b30d1939SAndy Fiddaman 			t->tre.tretyp |= FALTPIPE;
596b30d1939SAndy Fiddaman #endif /* SHOPT_COSHELL */
5977c2fbfb3SApril Chin 		if(tt=term(lexp,SH_NL))
598da2e3ebdSchin 		{
599da2e3ebdSchin 			switch(tt->tre.tretyp&COMMSK)
600da2e3ebdSchin 			{
601da2e3ebdSchin 			    case TFORK:
602da2e3ebdSchin 				tt->tre.tretyp |= FPIN|FPCL;
603da2e3ebdSchin 				break;
604da2e3ebdSchin 			    case TFIL:
605da2e3ebdSchin 				tt->lst.lstlef->tre.tretyp |= FPIN|FPCL;
606da2e3ebdSchin 				break;
607da2e3ebdSchin 			    default:
6087c2fbfb3SApril Chin 				tt= makeparent(lexp,TSETIO|FPIN|FPCL,tt);
609da2e3ebdSchin 			}
6107c2fbfb3SApril Chin 			t=makelist(lexp,TFIL,t,tt);
611da2e3ebdSchin 			t->tre.tretyp |= showme;
612da2e3ebdSchin 		}
6137c2fbfb3SApril Chin 		else if(lexp->token)
6147c2fbfb3SApril Chin 			sh_syntax(lexp);
615da2e3ebdSchin 	}
616da2e3ebdSchin 	return(t);
617da2e3ebdSchin }
618da2e3ebdSchin 
619da2e3ebdSchin /*
620da2e3ebdSchin  * case statement
621da2e3ebdSchin  */
syncase(Lex_t * lexp,register int esym)6227c2fbfb3SApril Chin static struct regnod*	syncase(Lex_t *lexp,register int esym)
623da2e3ebdSchin {
6247c2fbfb3SApril Chin 	register int tok = skipnl(lexp,0);
625da2e3ebdSchin 	register struct regnod	*r;
626da2e3ebdSchin 	if(tok==esym)
627da2e3ebdSchin 		return(NIL(struct regnod*));
628da2e3ebdSchin 	r = (struct regnod*)stakalloc(sizeof(struct regnod));
629da2e3ebdSchin 	r->regptr=0;
630da2e3ebdSchin 	r->regflag=0;
631da2e3ebdSchin 	if(tok==LPAREN)
6327c2fbfb3SApril Chin 		skipnl(lexp,0);
633da2e3ebdSchin 	while(1)
634da2e3ebdSchin 	{
6357c2fbfb3SApril Chin 		if(!lexp->arg)
6367c2fbfb3SApril Chin 			sh_syntax(lexp);
6377c2fbfb3SApril Chin 		lexp->arg->argnxt.ap=r->regptr;
6387c2fbfb3SApril Chin 		r->regptr = lexp->arg;
6397c2fbfb3SApril Chin 		if((tok=sh_lex(lexp))==RPAREN)
640da2e3ebdSchin 			break;
641da2e3ebdSchin 		else if(tok=='|')
6427c2fbfb3SApril Chin 			sh_lex(lexp);
643da2e3ebdSchin 		else
6447c2fbfb3SApril Chin 			sh_syntax(lexp);
645da2e3ebdSchin 	}
6467c2fbfb3SApril Chin 	r->regcom=sh_cmd(lexp,0,SH_NL|SH_EMPTY|SH_SEMI);
6477c2fbfb3SApril Chin 	if((tok=lexp->token)==BREAKCASESYM)
6487c2fbfb3SApril Chin 		r->regnxt=syncase(lexp,esym);
649da2e3ebdSchin 	else if(tok==FALLTHRUSYM)
650da2e3ebdSchin 	{
651da2e3ebdSchin 		r->regflag++;
6527c2fbfb3SApril Chin 		r->regnxt=syncase(lexp,esym);
653da2e3ebdSchin 	}
654da2e3ebdSchin 	else
655da2e3ebdSchin 	{
656da2e3ebdSchin 		if(tok!=esym && tok!=EOFSYM)
6577c2fbfb3SApril Chin 			sh_syntax(lexp);
658da2e3ebdSchin 		r->regnxt=0;
659da2e3ebdSchin 	}
6607c2fbfb3SApril Chin 	if(lexp->token==EOFSYM)
661da2e3ebdSchin 		return(NIL(struct regnod*));
662da2e3ebdSchin 	return(r);
663da2e3ebdSchin }
664da2e3ebdSchin 
665da2e3ebdSchin /*
666da2e3ebdSchin  * This routine creates the parse tree for the arithmetic for
667da2e3ebdSchin  * When called, shlex.arg contains the string inside ((...))
668da2e3ebdSchin  * When the first argument is missing, a while node is returned
669da2e3ebdSchin  * Otherise a list containing an arithmetic command and a while
670da2e3ebdSchin  * is returned.
671da2e3ebdSchin  */
arithfor(Lex_t * lexp,register Shnode_t * tf)6727c2fbfb3SApril Chin static Shnode_t	*arithfor(Lex_t *lexp,register Shnode_t *tf)
673da2e3ebdSchin {
674da2e3ebdSchin 	register Shnode_t	*t, *tw = tf;
675da2e3ebdSchin 	register int	offset;
676da2e3ebdSchin 	register struct argnod *argp;
677da2e3ebdSchin 	register int n;
6787c2fbfb3SApril Chin 	Stk_t		*stkp = lexp->sh->stk;
6797c2fbfb3SApril Chin 	int argflag = lexp->arg->argflag;
680da2e3ebdSchin 	/* save current input */
681da2e3ebdSchin 	Fcin_t	sav_input;
682da2e3ebdSchin 	fcsave(&sav_input);
6837c2fbfb3SApril Chin 	fcsopen(lexp->arg->argval);
684da2e3ebdSchin 	/* split ((...)) into three expressions */
685da2e3ebdSchin 	for(n=0; ; n++)
686da2e3ebdSchin 	{
687da2e3ebdSchin 		register int c;
6887c2fbfb3SApril Chin 		argp = (struct argnod*)stkseek(stkp,ARGVAL);
689da2e3ebdSchin 		argp->argnxt.ap = 0;
690da2e3ebdSchin 		argp->argchn.cp = 0;
691da2e3ebdSchin 		argp->argflag = argflag;
692da2e3ebdSchin 		if(n==2)
693da2e3ebdSchin 			break;
694da2e3ebdSchin 		/* copy up to ; onto the stack */
6957c2fbfb3SApril Chin 		sh_lexskip(lexp,';',1,ST_NESTED);
6967c2fbfb3SApril Chin 		offset = stktell(stkp)-1;
697da2e3ebdSchin 		if((c=fcpeek(-1))!=';')
698da2e3ebdSchin 			break;
699da2e3ebdSchin 		/* remove trailing white space */
7007c2fbfb3SApril Chin 		while(offset>ARGVAL && ((c= *stkptr(stkp,offset-1)),isspace(c)))
701da2e3ebdSchin 			offset--;
702da2e3ebdSchin 		/* check for empty initialization expression  */
703da2e3ebdSchin 		if(offset==ARGVAL && n==0)
704da2e3ebdSchin 			continue;
7057c2fbfb3SApril Chin 		stkseek(stkp,offset);
706da2e3ebdSchin 		/* check for empty condition and treat as while((1)) */
707da2e3ebdSchin 		if(offset==ARGVAL)
7087c2fbfb3SApril Chin 			sfputc(stkp,'1');
7097c2fbfb3SApril Chin 		argp = (struct argnod*)stkfreeze(stkp,1);
7107c2fbfb3SApril Chin 		t = getanode(lexp,argp);
711da2e3ebdSchin 		if(n==0)
7127c2fbfb3SApril Chin 			tf = makelist(lexp,TLST,t,tw);
713da2e3ebdSchin 		else
714da2e3ebdSchin 			tw->wh.whtre = t;
715da2e3ebdSchin 	}
716da2e3ebdSchin 	while((offset=fcpeek(0)) && isspace(offset))
717da2e3ebdSchin 		fcseek(1);
718da2e3ebdSchin 	stakputs(fcseek(0));
719da2e3ebdSchin 	argp = (struct argnod*)stakfreeze(1);
720da2e3ebdSchin 	fcrestore(&sav_input);
721da2e3ebdSchin 	if(n<2)
722da2e3ebdSchin 	{
7237c2fbfb3SApril Chin 		lexp->token = RPAREN|SYMREP;
7247c2fbfb3SApril Chin 		sh_syntax(lexp);
725da2e3ebdSchin 	}
726da2e3ebdSchin 	/* check whether the increment is present */
727da2e3ebdSchin 	if(*argp->argval)
728da2e3ebdSchin 	{
7297c2fbfb3SApril Chin 		t = getanode(lexp,argp);
730da2e3ebdSchin 		tw->wh.whinc = (struct arithnod*)t;
731da2e3ebdSchin 	}
732da2e3ebdSchin 	else
733da2e3ebdSchin 		tw->wh.whinc = 0;
7347c2fbfb3SApril Chin 	sh_lexopen(lexp, lexp->sh,1);
7357c2fbfb3SApril Chin 	if((n=sh_lex(lexp))==NL)
7367c2fbfb3SApril Chin 		n = skipnl(lexp,0);
737da2e3ebdSchin 	else if(n==';')
7387c2fbfb3SApril Chin 		n = sh_lex(lexp);
739da2e3ebdSchin 	if(n!=DOSYM && n!=LBRACE)
7407c2fbfb3SApril Chin 		sh_syntax(lexp);
741b30d1939SAndy Fiddaman 	tw->wh.dotre = sh_cmd(lexp,n==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
742da2e3ebdSchin 	tw->wh.whtyp = TWH;
743da2e3ebdSchin 	return(tf);
744da2e3ebdSchin 
745da2e3ebdSchin }
746da2e3ebdSchin 
funct(Lex_t * lexp)7477c2fbfb3SApril Chin static Shnode_t *funct(Lex_t *lexp)
748da2e3ebdSchin {
7497c2fbfb3SApril Chin 	Shell_t	*shp = lexp->sh;
750da2e3ebdSchin 	register Shnode_t *t;
751da2e3ebdSchin 	register int flag;
752da2e3ebdSchin 	struct slnod *volatile slp=0;
75363be7eb5SAndy Fiddaman 	Stak_t *savstak = NULL;
754da2e3ebdSchin 	Sfoff_t	first, last;
7557c2fbfb3SApril Chin 	struct functnod *volatile fp;
756da2e3ebdSchin 	Sfio_t *iop;
757da2e3ebdSchin #if SHOPT_KIA
7587c2fbfb3SApril Chin 	unsigned long current = lexp->current;
759da2e3ebdSchin #endif /* SHOPT_KIA */
760b30d1939SAndy Fiddaman 	int nargs=0,size=0,jmpval, saveloop=loop_level;
761da2e3ebdSchin 	struct argnod *savelabel = label_last;
762da2e3ebdSchin 	struct  checkpt buff;
7637c2fbfb3SApril Chin 	int save_optget = opt_get;
7647c2fbfb3SApril Chin 	void	*in_mktype = shp->mktype;
7657c2fbfb3SApril Chin 	shp->mktype = 0;
7667c2fbfb3SApril Chin 	opt_get = 0;
767da2e3ebdSchin 	t = getnode(functnod);
7687c2fbfb3SApril Chin 	t->funct.functline = shp->inlineno;
769da2e3ebdSchin 	t->funct.functtyp=TFUN;
770da2e3ebdSchin 	t->funct.functargs = 0;
7717c2fbfb3SApril Chin 	if(!(flag = (lexp->token==FUNCTSYM)))
772da2e3ebdSchin 		t->funct.functtyp |= FPOSIX;
7737c2fbfb3SApril Chin 	else if(sh_lex(lexp))
7747c2fbfb3SApril Chin 		sh_syntax(lexp);
775da2e3ebdSchin 	if(!(iop=fcfile()))
776da2e3ebdSchin 	{
777da2e3ebdSchin 		iop = sfopen(NIL(Sfio_t*),fcseek(0),"s");
778da2e3ebdSchin 		fcclose();
779da2e3ebdSchin 		fcfopen(iop);
780da2e3ebdSchin 	}
781da2e3ebdSchin 	t->funct.functloc = first = fctell();
7827c2fbfb3SApril Chin 	if(!shp->st.filename || sffileno(iop)<0)
783da2e3ebdSchin 	{
784da2e3ebdSchin 		if(fcfill() >= 0)
785da2e3ebdSchin 			fcseek(-1);
786b30d1939SAndy Fiddaman 		if(sh_isstate(SH_HISTORY) && shp->gd->hist_ptr)
787b30d1939SAndy Fiddaman 			t->funct.functloc = sfseek(shp->gd->hist_ptr->histfp,(off_t)0,SEEK_CUR);
788da2e3ebdSchin 		else
789da2e3ebdSchin 		{
790da2e3ebdSchin 			/* copy source to temporary file */
791da2e3ebdSchin 			t->funct.functloc = 0;
7927c2fbfb3SApril Chin 			if(lexp->sh->heredocs)
7937c2fbfb3SApril Chin 				t->funct.functloc = sfseek(lexp->sh->heredocs,(Sfoff_t)0, SEEK_END);
794da2e3ebdSchin 			else
7957c2fbfb3SApril Chin 				lexp->sh->heredocs = sftmp(HERE_MEM);
7967c2fbfb3SApril Chin 			lexp->sh->funlog = lexp->sh->heredocs;
797da2e3ebdSchin 			t->funct.functtyp |= FPIN;
798da2e3ebdSchin 		}
799da2e3ebdSchin 	}
8007c2fbfb3SApril Chin 	t->funct.functnam= (char*)lexp->arg->argval;
801da2e3ebdSchin #if SHOPT_KIA
8027c2fbfb3SApril Chin 	if(lexp->kiafile)
8037c2fbfb3SApril Chin 		lexp->current = kiaentity(lexp,t->funct.functnam,-1,'p',-1,-1,lexp->script,'p',0,"");
804da2e3ebdSchin #endif /* SHOPT_KIA */
805da2e3ebdSchin 	if(flag)
806da2e3ebdSchin 	{
8077c2fbfb3SApril Chin 		lexp->token = sh_lex(lexp);
808da2e3ebdSchin #if SHOPT_BASH
8097c2fbfb3SApril Chin 		if(lexp->token == LPAREN)
810da2e3ebdSchin 		{
8117c2fbfb3SApril Chin 			if((lexp->token = sh_lex(lexp)) == RPAREN)
812da2e3ebdSchin 				t->funct.functtyp |= FPOSIX;
813da2e3ebdSchin 			else
8147c2fbfb3SApril Chin 				sh_syntax(lexp);
815da2e3ebdSchin 		}
816da2e3ebdSchin #endif
817da2e3ebdSchin 	}
818da2e3ebdSchin 	if(t->funct.functtyp&FPOSIX)
8197c2fbfb3SApril Chin 		skipnl(lexp,0);
820da2e3ebdSchin 	else
821da2e3ebdSchin 	{
8227c2fbfb3SApril Chin 		if(lexp->token==0)
823b30d1939SAndy Fiddaman 		{
824b30d1939SAndy Fiddaman 			struct comnod	*ac;
825b30d1939SAndy Fiddaman 			char		*cp, **argv, **argv0;
826b30d1939SAndy Fiddaman 			int		c;
827b30d1939SAndy Fiddaman 			t->funct.functargs = ac = (struct comnod*)simple(lexp,SH_NOIO|SH_FUNDEF,NIL(struct ionod*));
828b30d1939SAndy Fiddaman 			if(ac->comset || (ac->comtyp&COMSCAN))
829b30d1939SAndy Fiddaman 				errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax4,lexp->sh->inlineno);
830b30d1939SAndy Fiddaman 			argv0 = argv = ((struct dolnod*)ac->comarg)->dolval+ARG_SPARE;
831b30d1939SAndy Fiddaman 			while(cp= *argv++)
832b30d1939SAndy Fiddaman 			{
833b30d1939SAndy Fiddaman 				size += strlen(cp)+1;
834b30d1939SAndy Fiddaman 				if((c = mbchar(cp)) && isaletter(c))
835b30d1939SAndy Fiddaman 		                        while(c=mbchar(cp), isaname(c));
836b30d1939SAndy Fiddaman 			}
837b30d1939SAndy Fiddaman 			if(c)
838b30d1939SAndy Fiddaman 				errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax4,lexp->sh->inlineno);
839b30d1939SAndy Fiddaman 			nargs = argv-argv0;
840b30d1939SAndy Fiddaman 			size += sizeof(struct dolnod)+(nargs+ARG_SPARE)*sizeof(char*);
841b30d1939SAndy Fiddaman 			if(shp->shcomp && memcmp(".sh.math.",t->funct.functnam,9)==0)
842b30d1939SAndy Fiddaman 			{
843b30d1939SAndy Fiddaman 				Namval_t *np= nv_open(t->funct.functnam,shp->fun_tree,NV_ADD|NV_VARNAME);
844b30d1939SAndy Fiddaman 				np->nvalue.rp = new_of(struct Ufunction,shp->funload?sizeof(Dtlink_t):0);
845b30d1939SAndy Fiddaman 				memset((void*)np->nvalue.rp,0,sizeof(struct Ufunction));
846b30d1939SAndy Fiddaman 				np->nvalue.rp->argc = ((struct dolnod*)ac->comarg)->dolnum;
847b30d1939SAndy Fiddaman 			}
848b30d1939SAndy Fiddaman 		}
8497c2fbfb3SApril Chin 		while(lexp->token==NL)
8507c2fbfb3SApril Chin 			lexp->token = sh_lex(lexp);
851da2e3ebdSchin 	}
8527c2fbfb3SApril Chin 	if((flag && lexp->token!=LBRACE) || lexp->token==EOFSYM)
8537c2fbfb3SApril Chin 		sh_syntax(lexp);
854b30d1939SAndy Fiddaman 	sh_pushcontext(shp,&buff,1);
855da2e3ebdSchin 	jmpval = sigsetjmp(buff.buff,0);
856da2e3ebdSchin 	if(jmpval == 0)
857da2e3ebdSchin 	{
858da2e3ebdSchin 		/* create a new stak frame to compile the command */
859da2e3ebdSchin 		savstak = stakcreate(STAK_SMALL);
860da2e3ebdSchin 		savstak = stakinstall(savstak, 0);
861da2e3ebdSchin 		slp = (struct slnod*)stakalloc(sizeof(struct slnod)+sizeof(struct functnod));
862da2e3ebdSchin 		slp->slchild = 0;
8637c2fbfb3SApril Chin 		slp->slnext = shp->st.staklist;
8647c2fbfb3SApril Chin 		shp->st.staklist = 0;
865da2e3ebdSchin 		t->funct.functstak = (struct slnod*)slp;
866da2e3ebdSchin 		/*
867da2e3ebdSchin 		 * store the pathname of function definition file on stack
868da2e3ebdSchin 		 * in name field of fake for node
869da2e3ebdSchin 		 */
870da2e3ebdSchin 		fp = (struct functnod*)(slp+1);
871da2e3ebdSchin 		fp->functtyp = TFUN|FAMP;
872da2e3ebdSchin 		fp->functnam = 0;
873b30d1939SAndy Fiddaman 		fp->functargs = 0;
874da2e3ebdSchin 		fp->functline = t->funct.functline;
8757c2fbfb3SApril Chin 		if(shp->st.filename)
8767c2fbfb3SApril Chin 			fp->functnam = stakcopy(shp->st.filename);
877da2e3ebdSchin 		loop_level = 0;
878da2e3ebdSchin 		label_last = label_list;
879b30d1939SAndy Fiddaman 		if(size)
880b30d1939SAndy Fiddaman 		{
881b30d1939SAndy Fiddaman 			struct dolnod *dp = (struct dolnod*)stakalloc(size);
882b30d1939SAndy Fiddaman 			char *cp, *sp, **argv, **old = ((struct dolnod*)t->funct.functargs->comarg)->dolval+1;
883b30d1939SAndy Fiddaman 			argv = ((char**)(dp->dolval))+1;
884b30d1939SAndy Fiddaman 			dp->dolnum = ((struct dolnod*)t->funct.functargs->comarg)->dolnum;
885b30d1939SAndy Fiddaman 			t->funct.functargs->comarg = (struct argnod*)dp;
886b30d1939SAndy Fiddaman 			for(cp=(char*)&argv[nargs]; sp= *old++; cp++)
887b30d1939SAndy Fiddaman 			{
888b30d1939SAndy Fiddaman 				*argv++ = cp;
889b30d1939SAndy Fiddaman 				cp = strcopy(cp,sp);
890b30d1939SAndy Fiddaman 			}
891b30d1939SAndy Fiddaman 			*argv = 0;
892b30d1939SAndy Fiddaman 		}
8937c2fbfb3SApril Chin 		if(!flag && lexp->token==0)
894da2e3ebdSchin 		{
895da2e3ebdSchin 			/* copy current word token to current stak frame */
896da2e3ebdSchin 			struct argnod *ap;
8977c2fbfb3SApril Chin 			flag = ARGVAL + strlen(lexp->arg->argval);
898da2e3ebdSchin 			ap = (struct argnod*)stakalloc(flag);
8997c2fbfb3SApril Chin 			memcpy(ap,lexp->arg,flag);
9007c2fbfb3SApril Chin 			lexp->arg = ap;
901da2e3ebdSchin 		}
9027c2fbfb3SApril Chin 		t->funct.functtre = item(lexp,SH_NOIO);
903da2e3ebdSchin 	}
9043e14f97fSRoger A. Faulkner 	else if(shp->shcomp)
9053e14f97fSRoger A. Faulkner 		exit(1);
906b30d1939SAndy Fiddaman 	sh_popcontext(shp,&buff);
907da2e3ebdSchin 	loop_level = saveloop;
908da2e3ebdSchin 	label_last = savelabel;
909da2e3ebdSchin 	/* restore the old stack */
910da2e3ebdSchin 	if(slp)
911da2e3ebdSchin 	{
912da2e3ebdSchin 		slp->slptr =  stakinstall(savstak,0);
9137c2fbfb3SApril Chin 		slp->slchild = shp->st.staklist;
914da2e3ebdSchin 	}
915da2e3ebdSchin #if SHOPT_KIA
9167c2fbfb3SApril Chin 	lexp->current = current;
917da2e3ebdSchin #endif /* SHOPT_KIA */
918da2e3ebdSchin 	if(jmpval)
919da2e3ebdSchin 	{
920da2e3ebdSchin 		if(slp && slp->slptr)
921da2e3ebdSchin 		{
9227c2fbfb3SApril Chin 			shp->st.staklist = slp->slnext;
923da2e3ebdSchin 			stakdelete(slp->slptr);
924da2e3ebdSchin 		}
9257c2fbfb3SApril Chin 		siglongjmp(*shp->jmplist,jmpval);
926da2e3ebdSchin 	}
9277c2fbfb3SApril Chin 	shp->st.staklist = (struct slnod*)slp;
928da2e3ebdSchin 	last = fctell();
929da2e3ebdSchin 	fp->functline = (last-first);
930da2e3ebdSchin 	fp->functtre = t;
9317c2fbfb3SApril Chin 	shp->mktype = in_mktype;
9327c2fbfb3SApril Chin 	if(lexp->sh->funlog)
933da2e3ebdSchin 	{
934da2e3ebdSchin 		if(fcfill()>0)
935da2e3ebdSchin 			fcseek(-1);
9367c2fbfb3SApril Chin 		lexp->sh->funlog = 0;
937da2e3ebdSchin 	}
938da2e3ebdSchin #if 	SHOPT_KIA
9397c2fbfb3SApril Chin 	if(lexp->kiafile)
9407c2fbfb3SApril Chin 		kiaentity(lexp,t->funct.functnam,-1,'p',t->funct.functline,shp->inlineno-1,lexp->current,'p',0,"");
941da2e3ebdSchin #endif /* SHOPT_KIA */
9427c2fbfb3SApril Chin 	t->funct.functtyp |= opt_get;
9437c2fbfb3SApril Chin 	opt_get = save_optget;
944da2e3ebdSchin 	return(t);
945da2e3ebdSchin }
946da2e3ebdSchin 
947da2e3ebdSchin /*
948da2e3ebdSchin  * Compound assignment
949da2e3ebdSchin  */
assign(Lex_t * lexp,register struct argnod * ap,int type)950b30d1939SAndy Fiddaman static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int type)
951da2e3ebdSchin {
952da2e3ebdSchin 	register int n;
953da2e3ebdSchin 	register Shnode_t *t, **tp;
954da2e3ebdSchin 	register struct comnod *ac;
9557c2fbfb3SApril Chin 	Stk_t	*stkp = lexp->sh->stk;
956b30d1939SAndy Fiddaman 	int array=0, index=0;
957da2e3ebdSchin 	Namval_t *np;
958da2e3ebdSchin 	n = strlen(ap->argval)-1;
959da2e3ebdSchin 	if(ap->argval[n]!='=')
9607c2fbfb3SApril Chin 		sh_syntax(lexp);
961da2e3ebdSchin 	if(ap->argval[n-1]=='+')
962da2e3ebdSchin 	{
963da2e3ebdSchin 		ap->argval[n--]=0;
964da2e3ebdSchin 		array = ARG_APPEND;
965b30d1939SAndy Fiddaman 		type |= NV_APPEND;
966da2e3ebdSchin 	}
967da2e3ebdSchin 	/* shift right */
968da2e3ebdSchin 	while(n > 0)
969da2e3ebdSchin 	{
970da2e3ebdSchin 		ap->argval[n] = ap->argval[n-1];
971da2e3ebdSchin 		n--;
972da2e3ebdSchin 	}
973da2e3ebdSchin 	*ap->argval=0;
974da2e3ebdSchin 	t = getnode(fornod);
975da2e3ebdSchin 	t->for_.fornam = (char*)(ap->argval+1);
9767c2fbfb3SApril Chin 	t->for_.fortyp = sh_getlineno(lexp);
977da2e3ebdSchin 	tp = &t->for_.fortre;
978da2e3ebdSchin 	ap->argchn.ap = (struct argnod*)t;
979da2e3ebdSchin 	ap->argflag &= ARG_QUOTED;
980da2e3ebdSchin 	ap->argflag |= array;
9817c2fbfb3SApril Chin 	lexp->assignok = SH_ASSIGN;
982b30d1939SAndy Fiddaman 	if(type==NV_ARRAY)
983b30d1939SAndy Fiddaman 	{
984b30d1939SAndy Fiddaman 		lexp->noreserv = 1;
985b30d1939SAndy Fiddaman 		lexp->assignok = 0;
986b30d1939SAndy Fiddaman 	}
987b30d1939SAndy Fiddaman 	else
988b30d1939SAndy Fiddaman 		lexp->aliasok = 2;
989b30d1939SAndy Fiddaman 	array= (type==NV_ARRAY)?SH_ARRAY:0;
9907c2fbfb3SApril Chin 	if((n=skipnl(lexp,0))==RPAREN || n==LPAREN)
991da2e3ebdSchin 	{
992b30d1939SAndy Fiddaman 		struct argnod *ar,*aq,**settail;
993da2e3ebdSchin 		ac = (struct comnod*)getnode(comnod);
994da2e3ebdSchin 		memset((void*)ac,0,sizeof(*ac));
995b30d1939SAndy Fiddaman 	comarray:
996b30d1939SAndy Fiddaman 		settail= &ac->comset;
9977c2fbfb3SApril Chin 		ac->comline = sh_getlineno(lexp);
998da2e3ebdSchin 		while(n==LPAREN)
999da2e3ebdSchin 		{
1000b30d1939SAndy Fiddaman 			ar = (struct argnod*)stkseek(stkp,ARGVAL);
1001b30d1939SAndy Fiddaman 			ar->argflag= ARG_ASSIGN;
10027c2fbfb3SApril Chin 			sfprintf(stkp,"[%d]=",index++);
1003b30d1939SAndy Fiddaman 			if(aq=ac->comarg)
1004b30d1939SAndy Fiddaman 			{
1005b30d1939SAndy Fiddaman 				ac->comarg = aq->argnxt.ap;
1006b30d1939SAndy Fiddaman 				sfprintf(stkp,"%s",aq->argval);
1007b30d1939SAndy Fiddaman 				ar->argflag |= aq->argflag;
1008b30d1939SAndy Fiddaman 			}
1009b30d1939SAndy Fiddaman 			ar = (struct argnod*)stkfreeze(stkp,1);
1010b30d1939SAndy Fiddaman 			ar->argnxt.ap = 0;
1011b30d1939SAndy Fiddaman 			if(!aq)
1012b30d1939SAndy Fiddaman 				ar = assign(lexp,ar,0);
1013b30d1939SAndy Fiddaman 			ar->argflag |= ARG_MESSAGE;
1014b30d1939SAndy Fiddaman 			*settail = ar;
1015b30d1939SAndy Fiddaman 			settail = &(ar->argnxt.ap);
1016b30d1939SAndy Fiddaman 			if(aq)
1017b30d1939SAndy Fiddaman 				continue;
10187c2fbfb3SApril Chin 			while((n = skipnl(lexp,0))==0)
10197c2fbfb3SApril Chin 			{
1020b30d1939SAndy Fiddaman 				ar = (struct argnod*)stkseek(stkp,ARGVAL);
1021b30d1939SAndy Fiddaman 				ar->argflag= ARG_ASSIGN;
10227c2fbfb3SApril Chin 				sfprintf(stkp,"[%d]=",index++);
10237c2fbfb3SApril Chin 				stakputs(lexp->arg->argval);
1024b30d1939SAndy Fiddaman 				ar = (struct argnod*)stkfreeze(stkp,1);
1025b30d1939SAndy Fiddaman 				ar->argnxt.ap = 0;
1026b30d1939SAndy Fiddaman 				ar->argflag = lexp->arg->argflag;
1027b30d1939SAndy Fiddaman 				*settail = ar;
1028b30d1939SAndy Fiddaman 				settail = &(ar->argnxt.ap);
10297c2fbfb3SApril Chin 			}
1030da2e3ebdSchin 		}
1031da2e3ebdSchin 	}
10327c2fbfb3SApril Chin 	else if(n && n!=FUNCTSYM)
10337c2fbfb3SApril Chin 		sh_syntax(lexp);
1034b30d1939SAndy Fiddaman 	else if(type!=NV_ARRAY && 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)))
10357c2fbfb3SApril Chin 	{
1036da2e3ebdSchin 		array=SH_ARRAY;
10377c2fbfb3SApril Chin 		if(fcgetc(n)==LPAREN)
10387c2fbfb3SApril Chin 		{
10397c2fbfb3SApril Chin 			int c;
10407c2fbfb3SApril Chin 			if(fcgetc(c)==RPAREN)
10417c2fbfb3SApril Chin 			{
10427c2fbfb3SApril Chin 				lexp->token =  SYMRES;
10437c2fbfb3SApril Chin 				array = 0;
10447c2fbfb3SApril Chin 			}
10457c2fbfb3SApril Chin 			else
10467c2fbfb3SApril Chin 				fcseek(-2);
10477c2fbfb3SApril Chin 		}
10487c2fbfb3SApril Chin 		else if(n>0)
10497c2fbfb3SApril Chin 			fcseek(-1);
1050b30d1939SAndy Fiddaman 		if(array && type==NV_TYPE)
1051b30d1939SAndy Fiddaman 		{
1052b30d1939SAndy Fiddaman 			struct argnod *arg = lexp->arg;
1053b30d1939SAndy Fiddaman 			n = lexp->token;
1054b30d1939SAndy Fiddaman 			if(path_search(lexp->sh,lexp->arg->argval,NIL(Pathcomp_t**),1) && (np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && nv_isattr(np,BLT_DCL))
1055b30d1939SAndy Fiddaman 			{
1056b30d1939SAndy Fiddaman 				lexp->token = n;
1057b30d1939SAndy Fiddaman 				lexp->arg = arg;
1058b30d1939SAndy Fiddaman 				array = 0;
1059b30d1939SAndy Fiddaman 			}
1060b30d1939SAndy Fiddaman 			else
1061b30d1939SAndy Fiddaman 				sh_syntax(lexp);
1062b30d1939SAndy Fiddaman 		}
10637c2fbfb3SApril Chin 	}
1064b30d1939SAndy Fiddaman 	lexp->noreserv = 0;
1065da2e3ebdSchin 	while(1)
1066da2e3ebdSchin 	{
10677c2fbfb3SApril Chin 		if((n=lexp->token)==RPAREN)
1068da2e3ebdSchin 			break;
1069da2e3ebdSchin 		if(n==FUNCTSYM || n==SYMRES)
10707c2fbfb3SApril Chin 			ac = (struct comnod*)funct(lexp);
1071da2e3ebdSchin 		else
1072b30d1939SAndy Fiddaman 			ac = (struct comnod*)simple(lexp,SH_NOIO|SH_ASSIGN|type|array,NIL(struct ionod*));
10737c2fbfb3SApril Chin 		if((n=lexp->token)==RPAREN)
1074da2e3ebdSchin 			break;
1075da2e3ebdSchin 		if(n!=NL && n!=';')
1076b30d1939SAndy Fiddaman 		{
1077b30d1939SAndy Fiddaman 			if(array && n==LPAREN)
1078b30d1939SAndy Fiddaman 				goto comarray;
10797c2fbfb3SApril Chin 			sh_syntax(lexp);
1080b30d1939SAndy Fiddaman 		}
10817c2fbfb3SApril Chin 		lexp->assignok = SH_ASSIGN;
10827c2fbfb3SApril Chin 		if((n=skipnl(lexp,0)) || array)
1083da2e3ebdSchin 		{
1084da2e3ebdSchin 			if(n==RPAREN)
1085da2e3ebdSchin 				break;
1086da2e3ebdSchin 			if(array ||  n!=FUNCTSYM)
10877c2fbfb3SApril Chin 				sh_syntax(lexp);
1088da2e3ebdSchin 		}
10897c2fbfb3SApril Chin 		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)))
1090da2e3ebdSchin 		{
10917c2fbfb3SApril Chin 			struct argnod *arg = lexp->arg;
1092da2e3ebdSchin 			if(n!=0)
10937c2fbfb3SApril Chin 				sh_syntax(lexp);
1094da2e3ebdSchin 			/* check for sys5 style function */
10957c2fbfb3SApril Chin 			if(sh_lex(lexp)!=LPAREN || sh_lex(lexp)!=RPAREN)
1096da2e3ebdSchin 			{
10977c2fbfb3SApril Chin 				lexp->arg = arg;
10987c2fbfb3SApril Chin 				lexp->token = 0;
10997c2fbfb3SApril Chin 				sh_syntax(lexp);
1100da2e3ebdSchin 			}
11017c2fbfb3SApril Chin 			lexp->arg = arg;
11027c2fbfb3SApril Chin 			lexp->token = SYMRES;
1103da2e3ebdSchin 		}
11047c2fbfb3SApril Chin 		t = makelist(lexp,TLST,(Shnode_t*)ac,t);
1105da2e3ebdSchin 		*tp = t;
1106da2e3ebdSchin 		tp = &t->lst.lstrit;
1107da2e3ebdSchin 	}
1108da2e3ebdSchin 	*tp = (Shnode_t*)ac;
11097c2fbfb3SApril Chin 	lexp->assignok = 0;
1110da2e3ebdSchin 	return(ap);
1111da2e3ebdSchin }
1112da2e3ebdSchin 
1113da2e3ebdSchin /*
1114da2e3ebdSchin  * item
1115da2e3ebdSchin  *
1116da2e3ebdSchin  *	( cmd ) [ < in ] [ > out ]
1117da2e3ebdSchin  *	word word* [ < in ] [ > out ]
1118da2e3ebdSchin  *	if ... then ... else ... fi
1119da2e3ebdSchin  *	for ... while ... do ... done
1120da2e3ebdSchin  *	case ... in ... esac
1121da2e3ebdSchin  *	begin ... end
1122da2e3ebdSchin  */
1123da2e3ebdSchin 
item(Lex_t * lexp,int flag)11247c2fbfb3SApril Chin static Shnode_t	*item(Lex_t *lexp,int flag)
1125da2e3ebdSchin {
1126da2e3ebdSchin 	register Shnode_t	*t;
1127da2e3ebdSchin 	register struct ionod	*io;
11287c2fbfb3SApril Chin 	register int tok = (lexp->token&0xff);
11297c2fbfb3SApril Chin 	int savwdval = lexp->lasttok;
11307c2fbfb3SApril Chin 	int savline = lexp->lastline;
11317c2fbfb3SApril Chin 	int showme=0, comsub;
11327c2fbfb3SApril Chin 	if(!(flag&SH_NOIO) && (tok=='<' || tok=='>' || lexp->token==IOVNAME))
11337c2fbfb3SApril Chin 		io=inout(lexp,NIL(struct ionod*),1);
1134da2e3ebdSchin 	else
1135da2e3ebdSchin 		io=0;
11367c2fbfb3SApril Chin 	if((tok=lexp->token) && tok!=EOFSYM && tok!=FUNCTSYM)
1137da2e3ebdSchin 	{
11387c2fbfb3SApril Chin 		lexp->lastline =  sh_getlineno(lexp);
11397c2fbfb3SApril Chin 		lexp->lasttok = lexp->token;
1140da2e3ebdSchin 	}
1141da2e3ebdSchin 	switch(tok)
1142da2e3ebdSchin 	{
1143da2e3ebdSchin 	    /* [[ ... ]] test expression */
1144da2e3ebdSchin 	    case BTESTSYM:
11457c2fbfb3SApril Chin 		t = test_expr(lexp,ETESTSYM);
1146da2e3ebdSchin 		t->tre.tretyp &= ~TTEST;
1147da2e3ebdSchin 		break;
1148da2e3ebdSchin 	    /* ((...)) arithmetic expression */
1149da2e3ebdSchin 	    case EXPRSYM:
11507c2fbfb3SApril Chin 		t = getanode(lexp,lexp->arg);
11517c2fbfb3SApril Chin 		sh_lex(lexp);
1152da2e3ebdSchin 		goto done;
1153da2e3ebdSchin 
1154da2e3ebdSchin 	    /* case statement */
1155da2e3ebdSchin 	    case CASESYM:
1156da2e3ebdSchin 	    {
11577c2fbfb3SApril Chin 		int savetok = lexp->lasttok;
11587c2fbfb3SApril Chin 		int saveline = lexp->lastline;
1159da2e3ebdSchin 		t = getnode(swnod);
11607c2fbfb3SApril Chin 		if(sh_lex(lexp))
11617c2fbfb3SApril Chin 			sh_syntax(lexp);
11627c2fbfb3SApril Chin 		t->sw.swarg=lexp->arg;
1163da2e3ebdSchin 		t->sw.swtyp=TSW;
1164da2e3ebdSchin 		t->sw.swio = 0;
1165da2e3ebdSchin 		t->sw.swtyp |= FLINENO;
11667c2fbfb3SApril Chin 		t->sw.swline =  lexp->sh->inlineno;
11677c2fbfb3SApril Chin 		if((tok=skipnl(lexp,0))!=INSYM && tok!=LBRACE)
11687c2fbfb3SApril Chin 			sh_syntax(lexp);
11697c2fbfb3SApril Chin 		if(!(t->sw.swlst=syncase(lexp,tok==INSYM?ESACSYM:RBRACE)) && lexp->token==EOFSYM)
1170da2e3ebdSchin 		{
11717c2fbfb3SApril Chin 			lexp->lasttok = savetok;
11727c2fbfb3SApril Chin 			lexp->lastline = saveline;
11737c2fbfb3SApril Chin 			sh_syntax(lexp);
1174da2e3ebdSchin 		}
1175da2e3ebdSchin 		break;
1176da2e3ebdSchin 	    }
1177da2e3ebdSchin 
1178da2e3ebdSchin 	    /* if statement */
1179da2e3ebdSchin 	    case IFSYM:
1180da2e3ebdSchin 	    {
1181da2e3ebdSchin 		register Shnode_t	*tt;
1182da2e3ebdSchin 		t = getnode(ifnod);
1183da2e3ebdSchin 		t->if_.iftyp=TIF;
11847c2fbfb3SApril Chin 		t->if_.iftre=sh_cmd(lexp,THENSYM,SH_NL);
11857c2fbfb3SApril Chin 		t->if_.thtre=sh_cmd(lexp,ELSESYM,SH_NL|SH_SEMI);
11867c2fbfb3SApril Chin 		tok = lexp->token;
11877c2fbfb3SApril Chin 		t->if_.eltre=(tok==ELSESYM?sh_cmd(lexp,FISYM,SH_NL|SH_SEMI):
11887c2fbfb3SApril Chin 			(tok==ELIFSYM?(lexp->token=IFSYM, tt=item(lexp,SH_NOIO)):0));
1189da2e3ebdSchin 		if(tok==ELIFSYM)
1190da2e3ebdSchin 		{
1191da2e3ebdSchin 			if(!tt || tt->tre.tretyp!=TSETIO)
1192da2e3ebdSchin 				goto done;
1193da2e3ebdSchin 			t->if_.eltre = tt->fork.forktre;
1194da2e3ebdSchin 			tt->fork.forktre = t;
1195da2e3ebdSchin 			t = tt;
1196da2e3ebdSchin 			goto done;
1197da2e3ebdSchin 		}
1198da2e3ebdSchin 		break;
1199da2e3ebdSchin 	    }
1200da2e3ebdSchin 
1201da2e3ebdSchin 	    /* for and select statement */
1202da2e3ebdSchin 	    case FORSYM:
1203da2e3ebdSchin 	    case SELECTSYM:
1204da2e3ebdSchin 	    {
1205da2e3ebdSchin 		t = getnode(fornod);
12067c2fbfb3SApril Chin 		t->for_.fortyp=(lexp->token==FORSYM?TFOR:TSELECT);
1207da2e3ebdSchin 		t->for_.forlst=0;
12087c2fbfb3SApril Chin 		t->for_.forline =  lexp->sh->inlineno;
12097c2fbfb3SApril Chin 		if(sh_lex(lexp))
1210da2e3ebdSchin 		{
12117c2fbfb3SApril Chin 			if(lexp->token!=EXPRSYM || t->for_.fortyp!=TFOR)
12127c2fbfb3SApril Chin 				sh_syntax(lexp);
1213da2e3ebdSchin 			/* arithmetic for */
12147c2fbfb3SApril Chin 			t = arithfor(lexp,t);
1215da2e3ebdSchin 			break;
1216da2e3ebdSchin 		}
12177c2fbfb3SApril Chin 		t->for_.fornam=(char*) lexp->arg->argval;
1218da2e3ebdSchin 		t->for_.fortyp |= FLINENO;
1219da2e3ebdSchin #if SHOPT_KIA
12207c2fbfb3SApril Chin 		if(lexp->kiafile)
12217c2fbfb3SApril Chin 			writedefs(lexp,lexp->arg,lexp->sh->inlineno,'v',NIL(struct argnod*));
1222da2e3ebdSchin #endif /* SHOPT_KIA */
12237c2fbfb3SApril Chin 		while((tok=sh_lex(lexp))==NL);
1224da2e3ebdSchin 		if(tok==INSYM)
1225da2e3ebdSchin 		{
12267c2fbfb3SApril Chin 			if(sh_lex(lexp))
1227da2e3ebdSchin 			{
12287c2fbfb3SApril Chin 				if(lexp->token != NL && lexp->token !=';')
12297c2fbfb3SApril Chin 					sh_syntax(lexp);
1230da2e3ebdSchin 				/* some Linux scripts assume this */
1231da2e3ebdSchin 				if(sh_isoption(SH_NOEXEC))
12327c2fbfb3SApril Chin 					errormsg(SH_DICT,ERROR_warn(0),e_lexemptyfor,lexp->sh->inlineno-(lexp->token=='\n'));
1233da2e3ebdSchin 				t->for_.forlst = (struct comnod*)getnode(comnod);
1234da2e3ebdSchin 				(t->for_.forlst)->comarg = 0;
1235da2e3ebdSchin 				(t->for_.forlst)->comset = 0;
1236da2e3ebdSchin 				(t->for_.forlst)->comnamp = 0;
1237da2e3ebdSchin 				(t->for_.forlst)->comnamq = 0;
1238da2e3ebdSchin 				(t->for_.forlst)->comstate = 0;
1239da2e3ebdSchin 				(t->for_.forlst)->comio = 0;
1240da2e3ebdSchin 				(t->for_.forlst)->comtyp = 0;
1241da2e3ebdSchin 			}
1242da2e3ebdSchin 			else
12437c2fbfb3SApril Chin 				t->for_.forlst=(struct comnod*)simple(lexp,SH_NOIO,NIL(struct ionod*));
12447c2fbfb3SApril Chin 			if(lexp->token != NL && lexp->token !=';')
12457c2fbfb3SApril Chin 				sh_syntax(lexp);
12467c2fbfb3SApril Chin 			tok = skipnl(lexp,0);
1247da2e3ebdSchin 		}
1248da2e3ebdSchin 		/* 'for i;do cmd' is valid syntax */
1249da2e3ebdSchin 		else if(tok==';')
1250b30d1939SAndy Fiddaman 			while((tok=sh_lex(lexp))==NL);
1251da2e3ebdSchin 		if(tok!=DOSYM && tok!=LBRACE)
12527c2fbfb3SApril Chin 			sh_syntax(lexp);
1253da2e3ebdSchin 		loop_level++;
12547c2fbfb3SApril Chin 		t->for_.fortre=sh_cmd(lexp,tok==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
1255da2e3ebdSchin 		if(--loop_level==0)
1256da2e3ebdSchin 			label_last = label_list;
1257da2e3ebdSchin 		break;
1258da2e3ebdSchin 	    }
1259da2e3ebdSchin 
1260da2e3ebdSchin 	    /* This is the code for parsing function definitions */
1261da2e3ebdSchin 	    case FUNCTSYM:
12627c2fbfb3SApril Chin 		return(funct(lexp));
1263da2e3ebdSchin 
1264da2e3ebdSchin #if SHOPT_NAMESPACE
1265da2e3ebdSchin 	    case NSPACESYM:
1266b30d1939SAndy Fiddaman 		t = getnode(functnod);
1267b30d1939SAndy Fiddaman 		t->funct.functtyp=TNSPACE;
1268b30d1939SAndy Fiddaman 		t->funct.functargs = 0;
1269b30d1939SAndy Fiddaman 		t->funct.functloc = 0;
12707c2fbfb3SApril Chin 		if(sh_lex(lexp))
12717c2fbfb3SApril Chin 			sh_syntax(lexp);
1272b30d1939SAndy Fiddaman 		t->funct.functnam=(char*) lexp->arg->argval;
12737c2fbfb3SApril Chin 		while((tok=sh_lex(lexp))==NL);
1274da2e3ebdSchin 		if(tok!=LBRACE)
12757c2fbfb3SApril Chin 			sh_syntax(lexp);
1276b30d1939SAndy Fiddaman 		t->funct.functtre = sh_cmd(lexp,RBRACE,SH_NL);
1277da2e3ebdSchin 		break;
1278da2e3ebdSchin #endif /* SHOPT_NAMESPACE */
1279da2e3ebdSchin 
1280da2e3ebdSchin 	    /* while and until */
1281da2e3ebdSchin 	    case WHILESYM:
1282da2e3ebdSchin 	    case UNTILSYM:
1283da2e3ebdSchin 		t = getnode(whnod);
12847c2fbfb3SApril Chin 		t->wh.whtyp=(lexp->token==WHILESYM ? TWH : TUN);
1285da2e3ebdSchin 		loop_level++;
12867c2fbfb3SApril Chin 		t->wh.whtre = sh_cmd(lexp,DOSYM,SH_NL);
12877c2fbfb3SApril Chin 		t->wh.dotre = sh_cmd(lexp,DONESYM,SH_NL|SH_SEMI);
1288da2e3ebdSchin 		if(--loop_level==0)
1289da2e3ebdSchin 			label_last = label_list;
1290da2e3ebdSchin 		t->wh.whinc = 0;
1291da2e3ebdSchin 		break;
1292da2e3ebdSchin 
1293da2e3ebdSchin 	    case LABLSYM:
1294da2e3ebdSchin 	    {
1295da2e3ebdSchin 		register struct argnod *argp = label_list;
1296da2e3ebdSchin 		while(argp)
1297da2e3ebdSchin 		{
12987c2fbfb3SApril Chin 			if(strcmp(argp->argval,lexp->arg->argval)==0)
12997c2fbfb3SApril Chin 				errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax3,lexp->sh->inlineno,argp->argval);
1300da2e3ebdSchin 			argp = argp->argnxt.ap;
1301da2e3ebdSchin 		}
13027c2fbfb3SApril Chin 		lexp->arg->argnxt.ap = label_list;
13037c2fbfb3SApril Chin 		label_list = lexp->arg;
13047c2fbfb3SApril Chin 		label_list->argchn.len = sh_getlineno(lexp);
1305da2e3ebdSchin 		label_list->argflag = loop_level;
13067c2fbfb3SApril Chin 		skipnl(lexp,flag);
13077c2fbfb3SApril Chin 		if(!(t = item(lexp,SH_NL)))
13087c2fbfb3SApril Chin 			sh_syntax(lexp);
1309da2e3ebdSchin 		tok = (t->tre.tretyp&(COMSCAN|COMSCAN-1));
1310da2e3ebdSchin 		if(sh_isoption(SH_NOEXEC) && tok!=TWH && tok!=TUN && tok!=TFOR && tok!=TSELECT)
1311da2e3ebdSchin 			errormsg(SH_DICT,ERROR_warn(0),e_lexlabignore,label_list->argchn.len,label_list->argval);
1312da2e3ebdSchin 		return(t);
1313da2e3ebdSchin 	    }
1314da2e3ebdSchin 
1315da2e3ebdSchin 	    /* command group with {...} */
1316da2e3ebdSchin 	    case LBRACE:
13177c2fbfb3SApril Chin 		comsub = lexp->comsub;
13187c2fbfb3SApril Chin 		lexp->comsub = 0;
131934f9b3eeSRoland Mainz 		t = sh_cmd(lexp,RBRACE,SH_NL|SH_SEMI);
13207c2fbfb3SApril Chin 		lexp->comsub = comsub;
1321da2e3ebdSchin 		break;
1322da2e3ebdSchin 
1323da2e3ebdSchin 	    case LPAREN:
1324da2e3ebdSchin 		t = getnode(parnod);
132534f9b3eeSRoland Mainz 		t->par.partre=sh_cmd(lexp,RPAREN,SH_NL|SH_SEMI);
1326da2e3ebdSchin 		t->par.partyp=TPAR;
1327da2e3ebdSchin 		break;
1328da2e3ebdSchin 
1329b30d1939SAndy Fiddaman #if SHOPT_COSHELL
1330b30d1939SAndy Fiddaman 	    case '&':
1331b30d1939SAndy Fiddaman 		if(tok=sh_lex(lexp))
1332b30d1939SAndy Fiddaman 		{
1333b30d1939SAndy Fiddaman 			if(tok!=NL)
1334b30d1939SAndy Fiddaman 				sh_syntax(lexp);
1335b30d1939SAndy Fiddaman 			t = getnode(comnod);
1336b30d1939SAndy Fiddaman 			memset(t,0,sizeof(struct comnod));
1337b30d1939SAndy Fiddaman 			t->com.comline = sh_getlineno(lexp);
1338b30d1939SAndy Fiddaman 		}
1339b30d1939SAndy Fiddaman 		else
1340b30d1939SAndy Fiddaman 			t = (Shnode_t*)simple(lexp,SH_NOIO,NIL(struct ionod*));
1341b30d1939SAndy Fiddaman 		t->com.comtyp |= FAMP;
1342b30d1939SAndy Fiddaman 		if(lexp->token=='&' || lexp->token=='|')
1343b30d1939SAndy Fiddaman 			sh_syntax(lexp);
1344b30d1939SAndy Fiddaman 		return(t);
1345b30d1939SAndy Fiddaman 		break;
1346b30d1939SAndy Fiddaman #endif /* SHOPT_COSHELL */
1347da2e3ebdSchin 	    default:
1348da2e3ebdSchin 		if(io==0)
1349da2e3ebdSchin 			return(0);
13505ae8bd53SToomas Soome 		/* FALLTHROUGH */
1351da2e3ebdSchin 
1352da2e3ebdSchin 	    case ';':
1353da2e3ebdSchin 		if(io==0)
1354da2e3ebdSchin 		{
1355da2e3ebdSchin 			if(!(flag&SH_SEMI))
1356da2e3ebdSchin 				return(0);
13577c2fbfb3SApril Chin 			if(sh_lex(lexp)==';')
13587c2fbfb3SApril Chin 				sh_syntax(lexp);
1359da2e3ebdSchin 			showme =  FSHOWME;
1360da2e3ebdSchin 		}
13615ae8bd53SToomas Soome 		/* FALLTHROUGH */
1362da2e3ebdSchin 	    case 0:
13637c2fbfb3SApril Chin 		t = (Shnode_t*)simple(lexp,flag,io);
1364b30d1939SAndy Fiddaman 		if(t->com.comarg && lexp->intypeset)
13657c2fbfb3SApril Chin 			check_typedef(&t->com);
13667c2fbfb3SApril Chin 		lexp->intypeset = 0;
13677c2fbfb3SApril Chin 		lexp->inexec = 0;
1368da2e3ebdSchin 		t->tre.tretyp |= showme;
1369da2e3ebdSchin 		return(t);
1370da2e3ebdSchin 	}
13717c2fbfb3SApril Chin 	sh_lex(lexp);
13727c2fbfb3SApril Chin 	if(io=inout(lexp,io,0))
1373da2e3ebdSchin 	{
1374da2e3ebdSchin 		if((tok=t->tre.tretyp&COMMSK) != TFORK)
1375da2e3ebdSchin 			tok = TSETIO;
13767c2fbfb3SApril Chin 		t=makeparent(lexp,tok,t);
1377da2e3ebdSchin 		t->tre.treio=io;
1378da2e3ebdSchin 	}
1379da2e3ebdSchin done:
13807c2fbfb3SApril Chin 	lexp->lasttok = savwdval;
13817c2fbfb3SApril Chin 	lexp->lastline = savline;
1382da2e3ebdSchin 	return(t);
1383da2e3ebdSchin }
1384da2e3ebdSchin 
process_sub(Lex_t * lexp,int tok)138534f9b3eeSRoland Mainz static struct argnod *process_sub(Lex_t *lexp,int tok)
138634f9b3eeSRoland Mainz {
138734f9b3eeSRoland Mainz 	struct argnod *argp;
138834f9b3eeSRoland Mainz 	Shnode_t *t;
138934f9b3eeSRoland Mainz 	int mode = (tok==OPROCSYM);
139034f9b3eeSRoland Mainz 	t = sh_cmd(lexp,RPAREN,SH_NL);
139134f9b3eeSRoland Mainz 	argp = (struct argnod*)stkalloc(lexp->sh->stk,sizeof(struct argnod));
139234f9b3eeSRoland Mainz 	*argp->argval = 0;
139334f9b3eeSRoland Mainz 	argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t);
139434f9b3eeSRoland Mainz 	argp->argflag =  (ARG_EXP|mode);
139534f9b3eeSRoland Mainz 	return(argp);
139634f9b3eeSRoland Mainz }
139734f9b3eeSRoland Mainz 
139834f9b3eeSRoland Mainz 
1399da2e3ebdSchin /*
1400da2e3ebdSchin  * This is for a simple command, for list, or compound assignment
1401da2e3ebdSchin  */
simple(Lex_t * lexp,int flag,struct ionod * io)14027c2fbfb3SApril Chin static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
1403da2e3ebdSchin {
1404da2e3ebdSchin 	register struct comnod *t;
1405da2e3ebdSchin 	register struct argnod	*argp;
1406da2e3ebdSchin 	register int tok;
14077c2fbfb3SApril Chin 	Stk_t		*stkp = lexp->sh->stk;
1408da2e3ebdSchin 	struct argnod	**argtail;
1409da2e3ebdSchin 	struct argnod	**settail;
14107c2fbfb3SApril Chin 	int	cmdarg=0;
141119700af4SToomas Soome 	int	argno = 0;
1412da2e3ebdSchin 	int	assignment = 0;
1413da2e3ebdSchin 	int	key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
1414da2e3ebdSchin 	int	associative=0;
14157c2fbfb3SApril Chin 	if((argp=lexp->arg) && (argp->argflag&ARG_ASSIGN) && argp->argval[0]=='[')
1416da2e3ebdSchin 	{
1417da2e3ebdSchin 		flag |= SH_ARRAY;
1418da2e3ebdSchin 		associative = 1;
1419da2e3ebdSchin 	}
1420da2e3ebdSchin 	t = (struct comnod*)getnode(comnod);
1421da2e3ebdSchin 	t->comio=io; /*initial io chain*/
1422da2e3ebdSchin 	/* set command line number for error messages */
14237c2fbfb3SApril Chin 	t->comline = sh_getlineno(lexp);
1424da2e3ebdSchin 	argtail = &(t->comarg);
1425da2e3ebdSchin 	t->comset = 0;
1426da2e3ebdSchin 	t->comnamp = 0;
1427da2e3ebdSchin 	t->comnamq = 0;
1428da2e3ebdSchin 	t->comstate = 0;
1429da2e3ebdSchin 	settail = &(t->comset);
14307c2fbfb3SApril Chin 	while(lexp->token==0)
1431da2e3ebdSchin 	{
14327c2fbfb3SApril Chin 		argp = lexp->arg;
1433da2e3ebdSchin 		if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
1434da2e3ebdSchin 		{
14357c2fbfb3SApril Chin 			lexp->token = LBRACE;
1436da2e3ebdSchin 			break;
1437da2e3ebdSchin 		}
1438da2e3ebdSchin 		if(associative && argp->argval[0]!='[')
14397c2fbfb3SApril Chin 			sh_syntax(lexp);
1440da2e3ebdSchin 		/* check for assignment argument */
1441da2e3ebdSchin 		if((argp->argflag&ARG_ASSIGN) && assignment!=2)
1442da2e3ebdSchin 		{
1443da2e3ebdSchin 			*settail = argp;
1444da2e3ebdSchin 			settail = &(argp->argnxt.ap);
14457c2fbfb3SApril Chin 			lexp->assignok = (flag&SH_ASSIGN)?SH_ASSIGN:1;
1446da2e3ebdSchin 			if(assignment)
1447da2e3ebdSchin 			{
1448da2e3ebdSchin 				struct argnod *ap=argp;
1449da2e3ebdSchin 				char *last, *cp;
1450da2e3ebdSchin 				if(assignment==1)
1451da2e3ebdSchin 				{
1452da2e3ebdSchin 					last = strchr(argp->argval,'=');
1453b30d1939SAndy Fiddaman 					if(last && (last[-1]==']'|| (last[-1]=='+' && last[-2]==']')) && (cp=strchr(argp->argval,'[')) && (cp < last) && cp[-1]!='.')
1454da2e3ebdSchin 						last = cp;
14557c2fbfb3SApril Chin 					stkseek(stkp,ARGVAL);
14567c2fbfb3SApril Chin 					sfwrite(stkp,argp->argval,last-argp->argval);
14577c2fbfb3SApril Chin 					ap=(struct argnod*)stkfreeze(stkp,1);
1458da2e3ebdSchin 					ap->argflag = ARG_RAW;
1459da2e3ebdSchin 					ap->argchn.ap = 0;
1460da2e3ebdSchin 				}
1461da2e3ebdSchin 				*argtail = ap;
1462da2e3ebdSchin 				argtail = &(ap->argnxt.ap);
1463da2e3ebdSchin 				if(argno>=0)
1464da2e3ebdSchin 					argno++;
1465da2e3ebdSchin 			}
1466da2e3ebdSchin 			else /* alias substitutions allowed */
14677c2fbfb3SApril Chin 				lexp->aliasok = 1;
1468da2e3ebdSchin 		}
1469da2e3ebdSchin 		else
1470da2e3ebdSchin 		{
1471da2e3ebdSchin 			if(!(argp->argflag&ARG_RAW))
1472da2e3ebdSchin 				argno = -1;
14737c2fbfb3SApril Chin 			if(argno>=0 && argno++==cmdarg && !(flag&SH_ARRAY) && *argp->argval!='/')
1474da2e3ebdSchin 			{
1475da2e3ebdSchin 				/* check for builtin command */
14767c2fbfb3SApril Chin 				Namval_t *np=nv_bfsearch(argp->argval,lexp->sh->fun_tree, (Namval_t**)&t->comnamq,(char**)0);
14777c2fbfb3SApril Chin 				if(cmdarg==0)
14787c2fbfb3SApril Chin 					t->comnamp = (void*)np;
14797c2fbfb3SApril Chin 				if(np && is_abuiltin(np))
1480da2e3ebdSchin 				{
14817c2fbfb3SApril Chin 					if(nv_isattr(np,BLT_DCL))
14827c2fbfb3SApril Chin 					{
14837c2fbfb3SApril Chin 						assignment = 1+(*argp->argval=='a');
14847c2fbfb3SApril Chin 						if(np==SYSTYPESET)
14857c2fbfb3SApril Chin 							lexp->intypeset = 1;
14867c2fbfb3SApril Chin 						key_on = 1;
14877c2fbfb3SApril Chin 					}
14887c2fbfb3SApril Chin 					else if(np==SYSCOMMAND)
14897c2fbfb3SApril Chin 						cmdarg++;
14907c2fbfb3SApril Chin 					else if(np==SYSEXEC)
14917c2fbfb3SApril Chin 						lexp->inexec = 1;
1492b30d1939SAndy Fiddaman 					else if(np->nvalue.bfp==(Nambfp_f)b_getopts)
14937c2fbfb3SApril Chin 						opt_get |= FOPTGET;
1494da2e3ebdSchin 				}
1495da2e3ebdSchin 			}
1496b30d1939SAndy Fiddaman 			if((flag&NV_COMVAR) && !assignment)
1497b30d1939SAndy Fiddaman 				sh_syntax(lexp);
1498da2e3ebdSchin 			*argtail = argp;
1499da2e3ebdSchin 			argtail = &(argp->argnxt.ap);
15007c2fbfb3SApril Chin 			if(!(lexp->assignok=key_on)  && !(flag&SH_NOIO) && sh_isoption(SH_NOEXEC))
15017c2fbfb3SApril Chin 				lexp->assignok = SH_COMPASSIGN;
15027c2fbfb3SApril Chin 			lexp->aliasok = 0;
1503da2e3ebdSchin 		}
1504da2e3ebdSchin 	retry:
15057c2fbfb3SApril Chin 		tok = sh_lex(lexp);
15067c2fbfb3SApril Chin 		if(tok==LABLSYM && (flag&SH_ASSIGN))
15077c2fbfb3SApril Chin 			lexp->token = tok = 0;
1508da2e3ebdSchin 		if((tok==IPROCSYM || tok==OPROCSYM))
1509da2e3ebdSchin 		{
151034f9b3eeSRoland Mainz 			argp = process_sub(lexp,tok);
1511da2e3ebdSchin 			argno = -1;
1512da2e3ebdSchin 			*argtail = argp;
1513da2e3ebdSchin 			argtail = &(argp->argnxt.ap);
1514da2e3ebdSchin 			goto retry;
1515da2e3ebdSchin 		}
1516da2e3ebdSchin 		if(tok==LPAREN)
1517da2e3ebdSchin 		{
1518da2e3ebdSchin 			if(argp->argflag&ARG_ASSIGN)
1519da2e3ebdSchin 			{
15207c2fbfb3SApril Chin 				int intypeset = lexp->intypeset;
1521b30d1939SAndy Fiddaman 				int type = 0;
15227c2fbfb3SApril Chin 				lexp->intypeset = 0;
1523b30d1939SAndy Fiddaman 				if(t->comnamp==SYSTYPESET)
1524b30d1939SAndy Fiddaman 				{
1525b30d1939SAndy Fiddaman 					struct argnod  *ap;
1526b30d1939SAndy Fiddaman 					for(ap=t->comarg->argnxt.ap;ap;ap=ap->argnxt.ap)
1527b30d1939SAndy Fiddaman 					{
1528b30d1939SAndy Fiddaman 						if(*ap->argval!='-')
1529b30d1939SAndy Fiddaman 							break;
1530b30d1939SAndy Fiddaman 						if(strchr(ap->argval,'T'))
1531b30d1939SAndy Fiddaman 							type = NV_TYPE;
1532b30d1939SAndy Fiddaman 						else if(strchr(ap->argval,'a'))
1533b30d1939SAndy Fiddaman 							type = NV_ARRAY;
1534b30d1939SAndy Fiddaman 						else if(strchr(ap->argval,'C'))
1535b30d1939SAndy Fiddaman 							type = NV_COMVAR;
1536b30d1939SAndy Fiddaman 						else
1537b30d1939SAndy Fiddaman 							continue;
1538b30d1939SAndy Fiddaman 						break;
1539b30d1939SAndy Fiddaman 					}
1540b30d1939SAndy Fiddaman 				}
1541b30d1939SAndy Fiddaman 				argp = assign(lexp,argp,type);
15427c2fbfb3SApril Chin 				lexp->intypeset = intypeset;
1543da2e3ebdSchin 				if(associative)
15447c2fbfb3SApril Chin 					lexp->assignok |= SH_ASSIGN;
1545da2e3ebdSchin 				goto retry;
1546da2e3ebdSchin 			}
1547da2e3ebdSchin 			else if(argno==1 && !t->comset)
1548da2e3ebdSchin 			{
1549da2e3ebdSchin 				/* SVR2 style function */
1550b30d1939SAndy Fiddaman 				if(!(flag&SH_ARRAY) && sh_lex(lexp) == RPAREN)
1551da2e3ebdSchin 				{
15527c2fbfb3SApril Chin 					lexp->arg = argp;
15537c2fbfb3SApril Chin 					return(funct(lexp));
1554da2e3ebdSchin 				}
15557c2fbfb3SApril Chin 				lexp->token = LPAREN;
1556da2e3ebdSchin 			}
1557da2e3ebdSchin 		}
1558da2e3ebdSchin 		else if(flag&SH_ASSIGN)
1559da2e3ebdSchin 		{
1560da2e3ebdSchin 			if(tok==RPAREN)
1561da2e3ebdSchin 				break;
1562da2e3ebdSchin 			else if(tok==NL && (flag&SH_ARRAY))
15637c2fbfb3SApril Chin 			{
15647c2fbfb3SApril Chin 				lexp->comp_assign = 2;
1565da2e3ebdSchin 				goto retry;
15667c2fbfb3SApril Chin 			}
15677c2fbfb3SApril Chin 
1568da2e3ebdSchin 		}
1569da2e3ebdSchin 		if(!(flag&SH_NOIO))
1570da2e3ebdSchin 		{
1571da2e3ebdSchin 			if(io)
1572da2e3ebdSchin 			{
1573da2e3ebdSchin 				while(io->ionxt)
1574da2e3ebdSchin 					io = io->ionxt;
15757c2fbfb3SApril Chin 				io->ionxt = inout(lexp,(struct ionod*)0,0);
1576da2e3ebdSchin 			}
1577da2e3ebdSchin 			else
15787c2fbfb3SApril Chin 				t->comio = io = inout(lexp,(struct ionod*)0,0);
1579da2e3ebdSchin 		}
1580da2e3ebdSchin 	}
1581da2e3ebdSchin 	*argtail = 0;
15823e14f97fSRoger A. Faulkner 	t->comtyp = TCOM;
1583da2e3ebdSchin #if SHOPT_KIA
15847c2fbfb3SApril Chin 	if(lexp->kiafile && !(flag&SH_NOIO))
1585da2e3ebdSchin 	{
1586da2e3ebdSchin 		register Namval_t *np=(Namval_t*)t->comnamp;
1587da2e3ebdSchin 		unsigned long r=0;
1588da2e3ebdSchin 		int line = t->comline;
1589da2e3ebdSchin 		argp = t->comarg;
1590da2e3ebdSchin 		if(np)
15917c2fbfb3SApril Chin 			r = kiaentity(lexp,nv_name(np),-1,'p',-1,0,lexp->unknown,'b',0,"");
1592da2e3ebdSchin 		else if(argp)
15937c2fbfb3SApril Chin 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',-1,0,lexp->unknown,'c',0,"");
1594da2e3ebdSchin 		if(r>0)
15957c2fbfb3SApril Chin 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;c;\n",lexp->current,r,line,line);
1596da2e3ebdSchin 		if(t->comset && argno==0)
15977c2fbfb3SApril Chin 			writedefs(lexp,t->comset,line,'v',t->comarg);
1598da2e3ebdSchin 		else if(np && nv_isattr(np,BLT_DCL))
15997c2fbfb3SApril Chin 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
1600da2e3ebdSchin 		else if(argp && strcmp(argp->argval,"read")==0)
16017c2fbfb3SApril Chin 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
1602da2e3ebdSchin #if 0
1603da2e3ebdSchin 		else if(argp && strcmp(argp->argval,"unset")==0)
16047c2fbfb3SApril Chin 			writedefs(lexp,argp,line,'u',NIL(struct argnod*));
1605da2e3ebdSchin #endif
1606da2e3ebdSchin 		else if(argp && *argp->argval=='.' && argp->argval[1]==0 && (argp=argp->argnxt.ap))
1607da2e3ebdSchin 		{
16087c2fbfb3SApril Chin 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',0,0,lexp->script,'d',0,"");
16097c2fbfb3SApril Chin 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;d;\n",lexp->current,r,line,line);
1610da2e3ebdSchin 		}
1611da2e3ebdSchin 	}
1612da2e3ebdSchin #endif /* SHOPT_KIA */
1613da2e3ebdSchin 	if(t->comnamp && (argp=t->comarg->argnxt.ap))
1614da2e3ebdSchin 	{
1615da2e3ebdSchin 		Namval_t *np=(Namval_t*)t->comnamp;
1616da2e3ebdSchin 		if((np==SYSBREAK || np==SYSCONT) && (argp->argflag&ARG_RAW) && !isdigit(*argp->argval))
1617da2e3ebdSchin 		{
1618da2e3ebdSchin 			register char *cp = argp->argval;
1619da2e3ebdSchin 			/* convert break/continue labels to numbers */
1620da2e3ebdSchin 			tok = 0;
1621da2e3ebdSchin 			for(argp=label_list;argp!=label_last;argp=argp->argnxt.ap)
1622da2e3ebdSchin 			{
1623da2e3ebdSchin 				if(strcmp(cp,argp->argval))
1624da2e3ebdSchin 					continue;
1625da2e3ebdSchin 				tok = loop_level-argp->argflag;
1626da2e3ebdSchin 				if(tok>=1)
1627da2e3ebdSchin 				{
1628da2e3ebdSchin 					argp = t->comarg->argnxt.ap;
1629da2e3ebdSchin 					if(tok>9)
1630da2e3ebdSchin 					{
1631da2e3ebdSchin 						argp->argval[1] = '0'+tok%10;
1632da2e3ebdSchin 						argp->argval[2] = 0;
1633da2e3ebdSchin 						tok /= 10;
1634da2e3ebdSchin 					}
1635da2e3ebdSchin 					else
1636da2e3ebdSchin 						argp->argval[1] = 0;
1637da2e3ebdSchin 					*argp->argval = '0'+tok;
1638da2e3ebdSchin 				}
1639da2e3ebdSchin 				break;
1640da2e3ebdSchin 			}
1641da2e3ebdSchin 			if(sh_isoption(SH_NOEXEC) && tok==0)
16427c2fbfb3SApril Chin 				errormsg(SH_DICT,ERROR_warn(0),e_lexlabunknown,lexp->sh->inlineno-(lexp->token=='\n'),cp);
1643da2e3ebdSchin 		}
1644da2e3ebdSchin 		else if(sh_isoption(SH_NOEXEC) && np==SYSSET && ((tok= *argp->argval)=='-'||tok=='+') &&
1645da2e3ebdSchin 			(argp->argval[1]==0||strchr(argp->argval,'k')))
16467c2fbfb3SApril Chin 			errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete5,lexp->sh->inlineno-(lexp->token=='\n'),argp->argval);
1647da2e3ebdSchin 	}
1648da2e3ebdSchin 	/* expand argument list if possible */
1649b30d1939SAndy Fiddaman 	if(argno>0 && !(flag&(SH_ARRAY|NV_APPEND)))
1650da2e3ebdSchin 		t->comarg = qscan(t,argno);
1651da2e3ebdSchin 	else if(t->comarg)
1652da2e3ebdSchin 		t->comtyp |= COMSCAN;
16537c2fbfb3SApril Chin 	lexp->aliasok = 0;
1654da2e3ebdSchin 	return((Shnode_t*)t);
1655da2e3ebdSchin }
1656da2e3ebdSchin 
1657da2e3ebdSchin /*
1658da2e3ebdSchin  * skip past newlines but issue prompt if interactive
1659da2e3ebdSchin  */
skipnl(Lex_t * lexp,int flag)16607c2fbfb3SApril Chin static int	skipnl(Lex_t *lexp,int flag)
1661da2e3ebdSchin {
1662da2e3ebdSchin 	register int token;
16637c2fbfb3SApril Chin 	while((token=sh_lex(lexp))==NL);
1664da2e3ebdSchin 	if(token==';' && !(flag&SH_SEMI))
16657c2fbfb3SApril Chin 		sh_syntax(lexp);
1666da2e3ebdSchin 	return(token);
1667da2e3ebdSchin }
1668da2e3ebdSchin 
1669da2e3ebdSchin /*
1670da2e3ebdSchin  * check for and process and i/o redirections
1671da2e3ebdSchin  * if flag>0 then an alias can be in the next word
1672da2e3ebdSchin  * if flag<0 only one redirection will be processed
1673da2e3ebdSchin  */
inout(Lex_t * lexp,struct ionod * lastio,int flag)16747c2fbfb3SApril Chin static struct ionod	*inout(Lex_t *lexp,struct ionod *lastio,int flag)
1675da2e3ebdSchin {
16767c2fbfb3SApril Chin 	register int 		iof = lexp->digits, token=lexp->token;
1677da2e3ebdSchin 	register struct ionod	*iop;
16787c2fbfb3SApril Chin 	Stk_t			*stkp = lexp->sh->stk;
1679da2e3ebdSchin 	char *iovname=0;
1680da2e3ebdSchin 	register int		errout=0;
1681da2e3ebdSchin 	if(token==IOVNAME)
1682da2e3ebdSchin 	{
16837c2fbfb3SApril Chin 		iovname=lexp->arg->argval+1;
16847c2fbfb3SApril Chin 		token= sh_lex(lexp);
1685da2e3ebdSchin 		iof = 0;
1686da2e3ebdSchin 	}
1687da2e3ebdSchin 	switch(token&0xff)
1688da2e3ebdSchin 	{
1689da2e3ebdSchin 	    case '<':
1690da2e3ebdSchin 		if(token==IODOCSYM)
1691da2e3ebdSchin 			iof |= (IODOC|IORAW);
1692da2e3ebdSchin 		else if(token==IOMOV0SYM)
1693da2e3ebdSchin 			iof |= IOMOV;
169434f9b3eeSRoland Mainz 		else if(token==IORDWRSYMT)
169534f9b3eeSRoland Mainz 			iof |= IORDW|IOREWRITE;
1696da2e3ebdSchin 		else if(token==IORDWRSYM)
1697da2e3ebdSchin 			iof |= IORDW;
1698da2e3ebdSchin 		else if((token&SYMSHARP) == SYMSHARP)
1699da2e3ebdSchin 		{
1700da2e3ebdSchin 			int n;
1701da2e3ebdSchin 			iof |= IOLSEEK;
1702da2e3ebdSchin 			if(fcgetc(n)=='#')
1703da2e3ebdSchin 				iof |= IOCOPY;
1704da2e3ebdSchin 			else if(n>0)
1705da2e3ebdSchin 				fcseek(-1);
1706da2e3ebdSchin 		}
1707da2e3ebdSchin 		break;
1708da2e3ebdSchin 
1709da2e3ebdSchin 	    case '>':
1710da2e3ebdSchin 		if(iof<0)
1711da2e3ebdSchin 		{
1712da2e3ebdSchin 			errout = 1;
1713da2e3ebdSchin 			iof = 1;
1714da2e3ebdSchin 		}
1715da2e3ebdSchin 		iof |= IOPUT;
1716da2e3ebdSchin 		if(token==IOAPPSYM)
1717da2e3ebdSchin 			iof |= IOAPP;
1718da2e3ebdSchin 		else if(token==IOMOV1SYM)
1719da2e3ebdSchin 			iof |= IOMOV;
1720da2e3ebdSchin 		else if(token==IOCLOBSYM)
1721da2e3ebdSchin 			iof |= IOCLOB;
1722da2e3ebdSchin 		else if((token&SYMSHARP) == SYMSHARP)
1723da2e3ebdSchin 			iof |= IOLSEEK;
17247c2fbfb3SApril Chin 		else if((token&SYMSEMI) == SYMSEMI)
17257c2fbfb3SApril Chin 			iof |= IOREWRITE;
1726da2e3ebdSchin 		break;
1727da2e3ebdSchin 
1728da2e3ebdSchin 	    default:
1729da2e3ebdSchin 		return(lastio);
1730da2e3ebdSchin 	}
17317c2fbfb3SApril Chin 	lexp->digits=0;
17327c2fbfb3SApril Chin 	iop=(struct ionod*) stkalloc(stkp,sizeof(struct ionod));
1733da2e3ebdSchin 	iop->iodelim = 0;
17347c2fbfb3SApril Chin 	if(token=sh_lex(lexp))
1735da2e3ebdSchin 	{
17367c2fbfb3SApril Chin 		if(token==RPAREN && (iof&IOLSEEK) && lexp->comsub)
1737da2e3ebdSchin 		{
17387c2fbfb3SApril Chin 			lexp->arg = (struct argnod*)stkalloc(stkp,sizeof(struct argnod)+3);
17397c2fbfb3SApril Chin 			strcpy(lexp->arg->argval,"CUR");
17407c2fbfb3SApril Chin 			lexp->arg->argflag = ARG_RAW;
1741da2e3ebdSchin 			iof |= IOARITH;
1742da2e3ebdSchin 			fcseek(-1);
1743da2e3ebdSchin 		}
1744da2e3ebdSchin 		else if(token==EXPRSYM && (iof&IOLSEEK))
1745da2e3ebdSchin 			iof |= IOARITH;
174634f9b3eeSRoland Mainz 		else if(((token==IPROCSYM && !(iof&IOPUT)) || (token==OPROCSYM && (iof&IOPUT))) && !(iof&(IOLSEEK|IOREWRITE|IOMOV|IODOC)))
174734f9b3eeSRoland Mainz 		{
174834f9b3eeSRoland Mainz 			lexp->arg = process_sub(lexp,token);
174934f9b3eeSRoland Mainz 			iof |= IOPROCSUB;
175034f9b3eeSRoland Mainz 		}
1751da2e3ebdSchin 		else
17527c2fbfb3SApril Chin 			sh_syntax(lexp);
1753da2e3ebdSchin 	}
175434f9b3eeSRoland Mainz 	if( (iof&IOPROCSUB) && !(iof&IOLSEEK))
175534f9b3eeSRoland Mainz 		iop->ioname= (char*)lexp->arg->argchn.ap;
175634f9b3eeSRoland Mainz 	else
175734f9b3eeSRoland Mainz 		iop->ioname=lexp->arg->argval;
1758da2e3ebdSchin 	iop->iovname = iovname;
1759da2e3ebdSchin 	if(iof&IODOC)
1760da2e3ebdSchin 	{
17617c2fbfb3SApril Chin 		if(lexp->digits==2)
1762da2e3ebdSchin 		{
1763da2e3ebdSchin 			iof |= IOSTRG;
17647c2fbfb3SApril Chin 			if(!(lexp->arg->argflag&ARG_RAW))
1765da2e3ebdSchin 				iof &= ~IORAW;
1766da2e3ebdSchin 		}
1767da2e3ebdSchin 		else
1768da2e3ebdSchin 		{
17697c2fbfb3SApril Chin 			if(!lexp->sh->heredocs)
17707c2fbfb3SApril Chin 				lexp->sh->heredocs = sftmp(HERE_MEM);
17717c2fbfb3SApril Chin 			iop->iolst=lexp->heredoc;
17727c2fbfb3SApril Chin 			lexp->heredoc=iop;
17737c2fbfb3SApril Chin 			if(lexp->arg->argflag&ARG_QUOTED)
1774da2e3ebdSchin 				iof |= IOQUOTE;
17757c2fbfb3SApril Chin 			if(lexp->digits==3)
1776da2e3ebdSchin 				iof |= IOLSEEK;
17777c2fbfb3SApril Chin 			if(lexp->digits)
1778da2e3ebdSchin 				iof |= IOSTRIP;
1779da2e3ebdSchin 		}
1780da2e3ebdSchin 	}
1781da2e3ebdSchin 	else
1782da2e3ebdSchin 	{
1783da2e3ebdSchin 		iop->iolst = 0;
17847c2fbfb3SApril Chin 		if(lexp->arg->argflag&ARG_RAW)
1785da2e3ebdSchin 			iof |= IORAW;
1786da2e3ebdSchin 	}
1787da2e3ebdSchin 	iop->iofile=iof;
1788da2e3ebdSchin 	if(flag>0)
1789da2e3ebdSchin 		/* allow alias substitutions and parameter assignments */
17907c2fbfb3SApril Chin 		lexp->aliasok = lexp->assignok = 1;
1791da2e3ebdSchin #if SHOPT_KIA
17927c2fbfb3SApril Chin 	if(lexp->kiafile)
1793da2e3ebdSchin 	{
17947c2fbfb3SApril Chin 		int n = lexp->sh->inlineno-(lexp->token=='\n');
1795da2e3ebdSchin 		if(!(iof&IOMOV))
1796da2e3ebdSchin 		{
17977c2fbfb3SApril Chin 			unsigned long r=kiaentity(lexp,(iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,lexp->script,'f',0,"");
17987c2fbfb3SApril Chin 			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);
1799da2e3ebdSchin 		}
1800da2e3ebdSchin 	}
1801da2e3ebdSchin #endif /* SHOPT_KIA */
1802da2e3ebdSchin 	if(flag>=0)
1803da2e3ebdSchin 	{
1804da2e3ebdSchin 		struct ionod *ioq=iop;
18057c2fbfb3SApril Chin 		sh_lex(lexp);
1806da2e3ebdSchin 		if(errout)
1807da2e3ebdSchin 		{
1808da2e3ebdSchin 			/* redirect standard output to standard error */
18097c2fbfb3SApril Chin 			ioq = (struct ionod*)stkalloc(stkp,sizeof(struct ionod));
181034f9b3eeSRoland Mainz 			memset(ioq,0,sizeof(*ioq));
1811da2e3ebdSchin 			ioq->ioname = "1";
1812da2e3ebdSchin 			ioq->iolst = 0;
1813da2e3ebdSchin 			ioq->iodelim = 0;
1814da2e3ebdSchin 			ioq->iofile = IORAW|IOPUT|IOMOV|2;
1815da2e3ebdSchin 			iop->ionxt=ioq;
1816da2e3ebdSchin 		}
18177c2fbfb3SApril Chin 		ioq->ionxt=inout(lexp,lastio,flag);
1818da2e3ebdSchin 	}
1819da2e3ebdSchin 	else
1820da2e3ebdSchin 		iop->ionxt=0;
1821da2e3ebdSchin 	return(iop);
1822da2e3ebdSchin }
1823da2e3ebdSchin 
1824da2e3ebdSchin /*
1825da2e3ebdSchin  * convert argument chain to argument list when no special arguments
1826da2e3ebdSchin  */
1827da2e3ebdSchin 
qscan(struct comnod * ac,int argn)1828da2e3ebdSchin static struct argnod *qscan(struct comnod *ac,int argn)
1829da2e3ebdSchin {
1830da2e3ebdSchin 	register char **cp;
1831da2e3ebdSchin 	register struct argnod *ap;
1832da2e3ebdSchin 	register struct dolnod* dp;
1833da2e3ebdSchin 	register int special=0;
1834da2e3ebdSchin 	/* special hack for test -t compatibility */
1835da2e3ebdSchin 	if((Namval_t*)ac->comnamp==SYSTEST)
1836da2e3ebdSchin 		special = 2;
1837da2e3ebdSchin 	else if(*(ac->comarg->argval)=='[' && ac->comarg->argval[1]==0)
1838da2e3ebdSchin 		special = 3;
1839da2e3ebdSchin 	if(special)
1840da2e3ebdSchin 	{
1841da2e3ebdSchin 		ap = ac->comarg->argnxt.ap;
1842da2e3ebdSchin 		if(argn==(special+1) && ap->argval[1]==0 && *ap->argval=='!')
1843da2e3ebdSchin 			ap = ap->argnxt.ap;
1844da2e3ebdSchin 		else if(argn!=special)
1845da2e3ebdSchin 			special=0;
1846da2e3ebdSchin 	}
1847da2e3ebdSchin 	if(special)
1848da2e3ebdSchin 	{
1849da2e3ebdSchin 		const char *message;
1850da2e3ebdSchin 		if(strcmp(ap->argval,"-t"))
1851da2e3ebdSchin 		{
1852da2e3ebdSchin 			message = "line %d: Invariant test";
1853da2e3ebdSchin 			special=0;
1854da2e3ebdSchin 		}
1855da2e3ebdSchin 		else
1856da2e3ebdSchin 		{
1857da2e3ebdSchin 			message = "line %d: -t requires argument";
1858da2e3ebdSchin 			argn++;
1859da2e3ebdSchin 		}
1860da2e3ebdSchin 		if(sh_isoption(SH_NOEXEC))
1861da2e3ebdSchin 			errormsg(SH_DICT,ERROR_warn(0),message,ac->comline);
1862da2e3ebdSchin 	}
1863da2e3ebdSchin 	/* leave space for an extra argument at the front */
1864da2e3ebdSchin 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
1865da2e3ebdSchin 	cp = dp->dolval+ARG_SPARE;
1866da2e3ebdSchin 	dp->dolnum = argn;
1867da2e3ebdSchin 	dp->dolbot = ARG_SPARE;
1868da2e3ebdSchin 	ap = ac->comarg;
1869da2e3ebdSchin 	while(ap)
1870da2e3ebdSchin 	{
1871da2e3ebdSchin 		*cp++ = ap->argval;
1872da2e3ebdSchin 		ap = ap->argnxt.ap;
1873da2e3ebdSchin 	}
1874da2e3ebdSchin 	if(special==3)
1875da2e3ebdSchin 	{
1876da2e3ebdSchin 		cp[0] = cp[-1];
1877da2e3ebdSchin 		cp[-1] = "1";
1878da2e3ebdSchin 		cp++;
1879da2e3ebdSchin 	}
1880da2e3ebdSchin 	else if(special)
1881da2e3ebdSchin 		*cp++ = "1";
1882da2e3ebdSchin 	*cp = 0;
1883da2e3ebdSchin 	return((struct argnod*)dp);
1884da2e3ebdSchin }
1885da2e3ebdSchin 
test_expr(Lex_t * lp,int sym)18867c2fbfb3SApril Chin static Shnode_t *test_expr(Lex_t *lp,int sym)
1887da2e3ebdSchin {
18887c2fbfb3SApril Chin 	register Shnode_t *t = test_or(lp);
18897c2fbfb3SApril Chin 	if(lp->token!=sym)
18907c2fbfb3SApril Chin 		sh_syntax(lp);
1891da2e3ebdSchin 	return(t);
1892da2e3ebdSchin }
1893da2e3ebdSchin 
test_or(Lex_t * lp)18947c2fbfb3SApril Chin static Shnode_t *test_or(Lex_t *lp)
1895da2e3ebdSchin {
18967c2fbfb3SApril Chin 	register Shnode_t *t = test_and(lp);
18977c2fbfb3SApril Chin 	while(lp->token==ORFSYM)
18987c2fbfb3SApril Chin 		t = makelist(lp,TORF|TTEST,t,test_and(lp));
1899da2e3ebdSchin 	return(t);
1900da2e3ebdSchin }
1901da2e3ebdSchin 
test_and(Lex_t * lp)19027c2fbfb3SApril Chin static Shnode_t *test_and(Lex_t *lp)
1903da2e3ebdSchin {
19047c2fbfb3SApril Chin 	register Shnode_t *t = test_primary(lp);
19057c2fbfb3SApril Chin 	while(lp->token==ANDFSYM)
19067c2fbfb3SApril Chin 		t = makelist(lp,TAND|TTEST,t,test_primary(lp));
1907da2e3ebdSchin 	return(t);
1908da2e3ebdSchin }
1909da2e3ebdSchin 
1910da2e3ebdSchin /*
1911da2e3ebdSchin  * convert =~ into == ~(E)
1912da2e3ebdSchin  */
ere_match(void)1913da2e3ebdSchin static void ere_match(void)
1914da2e3ebdSchin {
1915da2e3ebdSchin 	Sfio_t *base, *iop = sfopen((Sfio_t*)0," ~(E)","s");
1916da2e3ebdSchin 	register int c;
1917da2e3ebdSchin 	while( fcgetc(c),(c==' ' || c=='\t'));
1918da2e3ebdSchin 	if(c)
1919da2e3ebdSchin 		fcseek(-1);
1920da2e3ebdSchin 	if(!(base=fcfile()))
1921da2e3ebdSchin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
1922da2e3ebdSchin 	fcclose();
1923da2e3ebdSchin         sfstack(base,iop);
1924da2e3ebdSchin         fcfopen(base);
1925da2e3ebdSchin }
1926da2e3ebdSchin 
test_primary(Lex_t * lexp)19277c2fbfb3SApril Chin static Shnode_t *test_primary(Lex_t *lexp)
1928da2e3ebdSchin {
1929da2e3ebdSchin 	register struct argnod *arg;
1930da2e3ebdSchin 	register Shnode_t *t;
1931da2e3ebdSchin 	register int num,token;
19327c2fbfb3SApril Chin 	token = skipnl(lexp,0);
19337c2fbfb3SApril Chin 	num = lexp->digits;
1934da2e3ebdSchin 	switch(token)
1935da2e3ebdSchin 	{
1936da2e3ebdSchin 	    case '(':
19377c2fbfb3SApril Chin 		t = test_expr(lexp,')');
19387c2fbfb3SApril Chin 		t = makelist(lexp,TTST|TTEST|TPAREN ,t, (Shnode_t*)pointerof(lexp->sh->inlineno));
1939da2e3ebdSchin 		break;
1940da2e3ebdSchin 	    case '!':
19417c2fbfb3SApril Chin 		if(!(t = test_primary(lexp)))
19427c2fbfb3SApril Chin 			sh_syntax(lexp);
1943da2e3ebdSchin 		t->tre.tretyp |= TNEGATE;
1944da2e3ebdSchin 		return(t);
1945da2e3ebdSchin 	    case TESTUNOP:
19467c2fbfb3SApril Chin 		if(sh_lex(lexp))
19477c2fbfb3SApril Chin 			sh_syntax(lexp);
1948da2e3ebdSchin #if SHOPT_KIA
19497c2fbfb3SApril Chin 		if(lexp->kiafile && !strchr("sntzoOG",num))
1950da2e3ebdSchin 		{
19517c2fbfb3SApril Chin 			int line = lexp->sh->inlineno- (lexp->token==NL);
1952da2e3ebdSchin 			unsigned long r;
19537c2fbfb3SApril Chin 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->script,'t',0,"");
19547c2fbfb3SApril Chin 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
1955da2e3ebdSchin 		}
1956da2e3ebdSchin #endif /* SHOPT_KIA */
19577c2fbfb3SApril Chin 		t = makelist(lexp,TTST|TTEST|TUNARY|(num<<TSHIFT),
19587c2fbfb3SApril Chin 			(Shnode_t*)lexp->arg,(Shnode_t*)lexp->arg);
19597c2fbfb3SApril Chin 		t->tst.tstline =  lexp->sh->inlineno;
1960da2e3ebdSchin 		break;
1961da2e3ebdSchin 	    /* binary test operators */
1962da2e3ebdSchin 	    case 0:
19637c2fbfb3SApril Chin 		arg = lexp->arg;
19647c2fbfb3SApril Chin 		if((token=sh_lex(lexp))==TESTBINOP)
1965da2e3ebdSchin 		{
19667c2fbfb3SApril Chin 			num = lexp->digits;
1967da2e3ebdSchin 			if(num==TEST_REP)
1968da2e3ebdSchin 			{
1969da2e3ebdSchin 				ere_match();
1970da2e3ebdSchin 				num = TEST_PEQ;
1971da2e3ebdSchin 			}
1972da2e3ebdSchin 		}
1973da2e3ebdSchin 		else if(token=='<')
1974da2e3ebdSchin 			num = TEST_SLT;
1975da2e3ebdSchin 		else if(token=='>')
1976da2e3ebdSchin 			num = TEST_SGT;
1977da2e3ebdSchin 		else if(token==ANDFSYM||token==ORFSYM||token==ETESTSYM||token==RPAREN)
1978da2e3ebdSchin 		{
19797c2fbfb3SApril Chin 			t = makelist(lexp,TTST|TTEST|TUNARY|('n'<<TSHIFT),
1980da2e3ebdSchin 				(Shnode_t*)arg,(Shnode_t*)arg);
19817c2fbfb3SApril Chin 			t->tst.tstline =  lexp->sh->inlineno;
1982da2e3ebdSchin 			return(t);
1983da2e3ebdSchin 		}
1984da2e3ebdSchin 		else
19857c2fbfb3SApril Chin 			sh_syntax(lexp);
1986da2e3ebdSchin #if SHOPT_KIA
19877c2fbfb3SApril Chin 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
1988da2e3ebdSchin 		{
19897c2fbfb3SApril Chin 			int line = lexp->sh->inlineno- (lexp->token==NL);
1990da2e3ebdSchin 			unsigned long r;
19917c2fbfb3SApril Chin 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
19927c2fbfb3SApril Chin 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
1993da2e3ebdSchin 		}
1994da2e3ebdSchin #endif /* SHOPT_KIA */
19957c2fbfb3SApril Chin 		if(sh_lex(lexp))
19967c2fbfb3SApril Chin 			sh_syntax(lexp);
1997da2e3ebdSchin 		if(num&TEST_PATTERN)
1998da2e3ebdSchin 		{
19997c2fbfb3SApril Chin 			if(lexp->arg->argflag&(ARG_EXP|ARG_MAC))
2000da2e3ebdSchin 				num &= ~TEST_PATTERN;
2001da2e3ebdSchin 		}
2002da2e3ebdSchin 		t = getnode(tstnod);
2003da2e3ebdSchin 		t->lst.lsttyp = TTST|TTEST|TBINARY|(num<<TSHIFT);
2004da2e3ebdSchin 		t->lst.lstlef = (Shnode_t*)arg;
20057c2fbfb3SApril Chin 		t->lst.lstrit = (Shnode_t*)lexp->arg;
20067c2fbfb3SApril Chin 		t->tst.tstline =  lexp->sh->inlineno;
2007da2e3ebdSchin #if SHOPT_KIA
20087c2fbfb3SApril Chin 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
2009da2e3ebdSchin 		{
20107c2fbfb3SApril Chin 			int line = lexp->sh->inlineno-(lexp->token==NL);
2011da2e3ebdSchin 			unsigned long r;
20127c2fbfb3SApril Chin 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
20137c2fbfb3SApril Chin 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
2014da2e3ebdSchin 		}
2015da2e3ebdSchin #endif /* SHOPT_KIA */
2016da2e3ebdSchin 		break;
2017da2e3ebdSchin 	    default:
2018da2e3ebdSchin 		return(0);
2019da2e3ebdSchin 	}
20207c2fbfb3SApril Chin 	skipnl(lexp,0);
2021da2e3ebdSchin 	return(t);
2022da2e3ebdSchin }
2023da2e3ebdSchin 
2024da2e3ebdSchin #if SHOPT_KIA
2025da2e3ebdSchin /*
2026da2e3ebdSchin  * return an entity checksum
2027da2e3ebdSchin  * The entity is created if it doesn't exist
2028da2e3ebdSchin  */
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)20297c2fbfb3SApril Chin 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)
2030da2e3ebdSchin {
20317c2fbfb3SApril Chin 	Stk_t	*stkp = lexp->sh->stk;
2032da2e3ebdSchin 	Namval_t *np;
20337c2fbfb3SApril Chin 	long offset = stktell(stkp);
20347c2fbfb3SApril Chin 	sfputc(stkp,type);
2035da2e3ebdSchin 	if(len>0)
20367c2fbfb3SApril Chin 		sfwrite(stkp,name,len);
2037da2e3ebdSchin 	else
2038da2e3ebdSchin 	{
2039da2e3ebdSchin 		if(type=='p')
20407c2fbfb3SApril Chin 			sfputr(stkp,path_basename(name),0);
2041da2e3ebdSchin 		else
20427c2fbfb3SApril Chin 			sfputr(stkp,name,0);
2043da2e3ebdSchin 	}
20447c2fbfb3SApril Chin 	np = nv_search(stakptr(offset),lexp->entity_tree,NV_ADD);
20457c2fbfb3SApril Chin 	stkseek(stkp,offset);
2046da2e3ebdSchin 	np->nvalue.i = pkind;
2047da2e3ebdSchin 	nv_setsize(np,width);
2048da2e3ebdSchin 	if(!nv_isattr(np,NV_TAGGED) && first>=0)
2049da2e3ebdSchin 	{
2050da2e3ebdSchin 		nv_onattr(np,NV_TAGGED);
2051da2e3ebdSchin 		if(!pkind)
2052da2e3ebdSchin 			pkind = '0';
2053da2e3ebdSchin 		if(len>0)
20547c2fbfb3SApril Chin 			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);
2055da2e3ebdSchin 		else
20567c2fbfb3SApril Chin 			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);
2057da2e3ebdSchin 	}
2058da2e3ebdSchin 	return(np->hash);
2059da2e3ebdSchin }
2060da2e3ebdSchin 
kia_add(register Namval_t * np,void * data)2061da2e3ebdSchin static void kia_add(register Namval_t *np, void *data)
2062da2e3ebdSchin {
2063da2e3ebdSchin 	char *name = nv_name(np);
20647c2fbfb3SApril Chin 	Lex_t	*lp = (Lex_t*)data;
2065da2e3ebdSchin 	NOT_USED(data);
20667c2fbfb3SApril Chin 	kiaentity(lp,name+1,-1,*name,0,-1,(*name=='p'?lp->unknown:lp->script),np->nvalue.i,nv_size(np),"");
2067da2e3ebdSchin }
2068da2e3ebdSchin 
kiaclose(Lex_t * lexp)20697c2fbfb3SApril Chin int kiaclose(Lex_t *lexp)
2070da2e3ebdSchin {
2071da2e3ebdSchin 	register off_t off1,off2;
2072da2e3ebdSchin 	register int n;
20737c2fbfb3SApril Chin 	if(lexp->kiafile)
2074da2e3ebdSchin 	{
20757c2fbfb3SApril Chin 		unsigned long r = kiaentity(lexp,lexp->scriptname,-1,'p',-1,lexp->sh->inlineno-1,0,'s',0,"");
20767c2fbfb3SApril Chin 		kiaentity(lexp,lexp->scriptname,-1,'p',1,lexp->sh->inlineno-1,r,'s',0,"");
20777c2fbfb3SApril Chin 		kiaentity(lexp,lexp->scriptname,-1,'f',1,lexp->sh->inlineno-1,r,'s',0,"");
20787c2fbfb3SApril Chin 		nv_scan(lexp->entity_tree,kia_add,(void*)lexp,NV_TAGGED,0);
20797c2fbfb3SApril Chin 		off1 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
20807c2fbfb3SApril Chin 		sfseek(lexp->kiatmp,(off_t)0,SEEK_SET);
20817c2fbfb3SApril Chin 		sfmove(lexp->kiatmp,lexp->kiafile,SF_UNBOUND,-1);
20827c2fbfb3SApril Chin 		off2 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
2083da2e3ebdSchin #ifdef SF_BUFCONST
2084da2e3ebdSchin 		if(off2==off1)
20857c2fbfb3SApril Chin 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin));
2086da2e3ebdSchin 		else
20877c2fbfb3SApril Chin 			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));
2088da2e3ebdSchin 		if(off2 >= INT_MAX)
2089da2e3ebdSchin 			off2 = -(n+12);
20907c2fbfb3SApril Chin 		sfprintf(lexp->kiafile,"%010.10lld;%010d\n",(Sflong_t)off2+10, n+12);
2091da2e3ebdSchin #else
2092da2e3ebdSchin 		if(off2==off1)
20937c2fbfb3SApril Chin 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin);
2094da2e3ebdSchin 		else
20957c2fbfb3SApril Chin 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin,off1,off2-off1);
20967c2fbfb3SApril Chin 		sfprintf(lexp->kiafile,"%010d;%010d\n",off2+10, n+12);
2097da2e3ebdSchin #endif
2098da2e3ebdSchin 	}
20997c2fbfb3SApril Chin 	return(sfclose(lexp->kiafile));
2100da2e3ebdSchin }
2101da2e3ebdSchin #endif /* SHOPT_KIA */
2102