1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * UNIX shell
23*4887Schin  *
24*4887Schin  * S. R. Bourne
25*4887Schin  * Rewritten by David Korn
26*4887Schin  * AT&T Labs
27*4887Schin  *
28*4887Schin  *  This is the parser for a shell language
29*4887Schin  */
30*4887Schin 
31*4887Schin #if KSHELL
32*4887Schin #include	"defs.h"
33*4887Schin #else
34*4887Schin #include	<shell.h>
35*4887Schin #endif
36*4887Schin #include	<ctype.h>
37*4887Schin #include	<fcin.h>
38*4887Schin #include	<error.h>
39*4887Schin #include	"shlex.h"
40*4887Schin #include	"history.h"
41*4887Schin #include	"builtins.h"
42*4887Schin #include	"test.h"
43*4887Schin #include	"history.h"
44*4887Schin 
45*4887Schin #define HERE_MEM	1024	/* size of here-docs kept in memory */
46*4887Schin 
47*4887Schin #define hash	nvlink.hl._hash
48*4887Schin 
49*4887Schin /* These routines are local to this module */
50*4887Schin 
51*4887Schin static Shnode_t	*makeparent(int, Shnode_t*);
52*4887Schin static Shnode_t	*makelist(int, Shnode_t*, Shnode_t*);
53*4887Schin static struct argnod	*qscan(struct comnod*, int);
54*4887Schin static struct ionod	*inout(struct ionod*, int);
55*4887Schin static Shnode_t	*sh_cmd(int,int);
56*4887Schin static Shnode_t	*term(int);
57*4887Schin static Shnode_t	*list(int);
58*4887Schin static struct regnod	*syncase(int);
59*4887Schin static Shnode_t	*item(int);
60*4887Schin static Shnode_t	*simple(int, struct ionod*);
61*4887Schin static int	skipnl(int);
62*4887Schin static Shnode_t	*test_expr(int);
63*4887Schin static Shnode_t	*test_and(void);
64*4887Schin static Shnode_t	*test_or(void);
65*4887Schin static Shnode_t	*test_primary(void);
66*4887Schin 
67*4887Schin #define	sh_getlineno()	(shlex.lastline)
68*4887Schin 
69*4887Schin #ifndef NIL
70*4887Schin #   define NIL(type)	((type)0)
71*4887Schin #endif /* NIL */
72*4887Schin #define CNTL(x)		((x)&037)
73*4887Schin 
74*4887Schin 
75*4887Schin #if !KSHELL
76*4887Schin static struct stdata
77*4887Schin {
78*4887Schin 	struct slnod    *staklist;
79*4887Schin 	int	cmdline;
80*4887Schin } st;
81*4887Schin #endif
82*4887Schin 
83*4887Schin static int		loop_level;
84*4887Schin static struct argnod	*label_list;
85*4887Schin static struct argnod	*label_last;
86*4887Schin 
87*4887Schin #define getnode(type)	((Shnode_t*)stakalloc(sizeof(struct type)))
88*4887Schin 
89*4887Schin #if SHOPT_KIA
90*4887Schin #include	"path.h"
91*4887Schin /*
92*4887Schin  * write out entities for each item in the list
93*4887Schin  * type=='V' for variable assignment lists
94*4887Schin  * Otherwise type is determined by the command */
95*4887Schin static unsigned long writedefs(struct argnod *arglist, int line, int type, struct argnod *cmd)
96*4887Schin {
97*4887Schin 	register struct argnod *argp = arglist;
98*4887Schin 	register char *cp;
99*4887Schin 	register int n,eline;
100*4887Schin 	int width=0;
101*4887Schin 	unsigned long r=0;
102*4887Schin 	static char atbuff[20];
103*4887Schin 	int  justify=0;
104*4887Schin 	char *attribute = atbuff;
105*4887Schin 	unsigned long parent=shlex.script;
106*4887Schin 	if(type==0)
107*4887Schin 	{
108*4887Schin 		parent = shlex.current;
109*4887Schin 		type = 'v';
110*4887Schin 		switch(*argp->argval)
111*4887Schin 		{
112*4887Schin 		    case 'a':
113*4887Schin 			type='p';
114*4887Schin 			justify = 'a';
115*4887Schin 			break;
116*4887Schin 		    case 'e':
117*4887Schin 			*attribute++ =  'x';
118*4887Schin 			break;
119*4887Schin 		    case 'r':
120*4887Schin 			*attribute++ = 'r';
121*4887Schin 			break;
122*4887Schin 		    case 'l':
123*4887Schin 			break;
124*4887Schin 		}
125*4887Schin 		while(argp = argp->argnxt.ap)
126*4887Schin 		{
127*4887Schin 			if((n= *(cp=argp->argval))!='-' && n!='+')
128*4887Schin 				break;
129*4887Schin 			if(cp[1]==n)
130*4887Schin 				break;
131*4887Schin 			while((n= *++cp))
132*4887Schin 			{
133*4887Schin 				if(isdigit(n))
134*4887Schin 					width = 10*width + n-'0';
135*4887Schin 				else if(n=='L' || n=='R' || n =='Z')
136*4887Schin 					justify=n;
137*4887Schin 				else
138*4887Schin 					*attribute++ = n;
139*4887Schin 			}
140*4887Schin 		}
141*4887Schin 	}
142*4887Schin 	else if(cmd)
143*4887Schin 		parent=kiaentity(sh_argstr(cmd),-1,'p',-1,-1,shlex.unknown,'b',0,"");
144*4887Schin 	*attribute = 0;
145*4887Schin 	while(argp)
146*4887Schin 	{
147*4887Schin 		if((cp=strchr(argp->argval,'='))||(cp=strchr(argp->argval,'?')))
148*4887Schin 			n = cp-argp->argval;
149*4887Schin 		else
150*4887Schin 			n = strlen(argp->argval);
151*4887Schin 		eline = sh.inlineno-(shlex.token==NL);
152*4887Schin 		r=kiaentity(argp->argval,n,type,line,eline,parent,justify,width,atbuff);
153*4887Schin 		sfprintf(shlex.kiatmp,"p;%..64d;v;%..64d;%d;%d;s;\n",shlex.current,r,line,eline);
154*4887Schin 		argp = argp->argnxt.ap;
155*4887Schin 	}
156*4887Schin 	return(r);
157*4887Schin }
158*4887Schin #endif /* SHOPT_KIA */
159*4887Schin /*
160*4887Schin  * Make a parent node for fork() or io-redirection
161*4887Schin  */
162*4887Schin static Shnode_t	*makeparent(int flag, Shnode_t *child)
163*4887Schin {
164*4887Schin 	register Shnode_t	*par = getnode(forknod);
165*4887Schin 	par->fork.forktyp = flag;
166*4887Schin 	par->fork.forktre = child;
167*4887Schin 	par->fork.forkio = 0;
168*4887Schin 	par->fork.forkline = sh_getlineno()-1;
169*4887Schin 	return(par);
170*4887Schin }
171*4887Schin 
172*4887Schin static Shnode_t *getanode(struct argnod *ap)
173*4887Schin {
174*4887Schin 	register Shnode_t *t = getnode(arithnod);
175*4887Schin 	t->ar.artyp = TARITH;
176*4887Schin 	t->ar.arline = sh_getlineno();
177*4887Schin 	t->ar.arexpr = ap;
178*4887Schin 	if(ap->argflag&ARG_RAW)
179*4887Schin 		t->ar.arcomp = sh_arithcomp(ap->argval);
180*4887Schin 	else
181*4887Schin 		t->ar.arcomp = 0;
182*4887Schin 	return(t);
183*4887Schin }
184*4887Schin 
185*4887Schin /*
186*4887Schin  *  Make a node corresponding to a command list
187*4887Schin  */
188*4887Schin static Shnode_t	*makelist(int type, Shnode_t *l, Shnode_t *r)
189*4887Schin {
190*4887Schin 	register Shnode_t	*t;
191*4887Schin 	if(!l || !r)
192*4887Schin 		sh_syntax();
193*4887Schin 	else
194*4887Schin 	{
195*4887Schin 		if((type&COMMSK) == TTST)
196*4887Schin 			t = getnode(tstnod);
197*4887Schin 		else
198*4887Schin 			t = getnode(lstnod);
199*4887Schin 		t->lst.lsttyp = type;
200*4887Schin 		t->lst.lstlef = l;
201*4887Schin 		t->lst.lstrit = r;
202*4887Schin 	}
203*4887Schin 	return(t);
204*4887Schin }
205*4887Schin 
206*4887Schin /*
207*4887Schin  * entry to shell parser
208*4887Schin  * Flag can be the union of SH_EOF|SH_NL
209*4887Schin  */
210*4887Schin 
211*4887Schin void	*sh_parse(Shell_t *shp, Sfio_t *iop, int flag)
212*4887Schin {
213*4887Schin 	register Shnode_t	*t;
214*4887Schin 	Fcin_t	sav_input;
215*4887Schin 	struct argnod *sav_arg = shlex.arg;
216*4887Schin 	int	sav_prompt = shp->nextprompt;
217*4887Schin 	if(shp->binscript && sffileno(iop)==shp->infd)
218*4887Schin 		return((void*)sh_trestore(iop));
219*4887Schin 	fcsave(&sav_input);
220*4887Schin 	shp->st.staklist = 0;
221*4887Schin 	shlex.heredoc = 0;
222*4887Schin 	shlex.inlineno = shp->inlineno;
223*4887Schin 	shlex.firstline = shp->st.firstline;
224*4887Schin 	shp->nextprompt = 1;
225*4887Schin 	loop_level = 0;
226*4887Schin 	label_list = label_last = 0;
227*4887Schin 	if(sh_isoption(SH_INTERACTIVE))
228*4887Schin 		sh_onstate(SH_INTERACTIVE);
229*4887Schin 	if(sh_isoption(SH_VERBOSE))
230*4887Schin 		sh_onstate(SH_VERBOSE);
231*4887Schin 	sh_lexopen((Lex_t*)shp->lex_context,shp,0);
232*4887Schin 	if(fcfopen(iop) < 0)
233*4887Schin 		return(NIL(void*));
234*4887Schin 	if(fcfile())
235*4887Schin 	{
236*4887Schin 		char *cp = fcfirst();
237*4887Schin 		if( cp[0]==CNTL('k') &&  cp[1]==CNTL('s') && cp[2]==CNTL('h') && cp[3]==0)
238*4887Schin 		{
239*4887Schin 			int version;
240*4887Schin 			fcseek(4);
241*4887Schin 			fcgetc(version);
242*4887Schin 			fcclose();
243*4887Schin 			fcrestore(&sav_input);
244*4887Schin 			shlex.arg = sav_arg;
245*4887Schin 			if(version > 3)
246*4887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_lexversion);
247*4887Schin 			if(sffileno(iop)==shp->infd)
248*4887Schin 				shp->binscript = 1;
249*4887Schin 			sfgetc(iop);
250*4887Schin 			return((void*)sh_trestore(iop));
251*4887Schin 		}
252*4887Schin 	}
253*4887Schin 	if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0)
254*4887Schin 		shp->inlineno=1;
255*4887Schin #if KSHELL
256*4887Schin 	shp->nextprompt = 2;
257*4887Schin #endif
258*4887Schin 	t = sh_cmd((flag&SH_EOF)?EOFSYM:'\n',SH_SEMI|SH_EMPTY|(flag&SH_NL));
259*4887Schin 	fcclose();
260*4887Schin 	fcrestore(&sav_input);
261*4887Schin 	shlex.arg = sav_arg;
262*4887Schin 	/* unstack any completed alias expansions */
263*4887Schin 	if((sfset(iop,0,0)&SF_STRING) && !sfreserve(iop,0,-1))
264*4887Schin 	{
265*4887Schin 		Sfio_t *sp = sfstack(iop,NULL);
266*4887Schin 		if(sp)
267*4887Schin 			sfclose(sp);
268*4887Schin 	}
269*4887Schin 	shp->nextprompt = sav_prompt;
270*4887Schin 	if(flag&SH_NL)
271*4887Schin 	{
272*4887Schin 		shp->st.firstline = shlex.firstline;
273*4887Schin 		shp->inlineno = shlex.inlineno;
274*4887Schin 	}
275*4887Schin 	stakseek(0);
276*4887Schin 	return((void*)t);
277*4887Schin }
278*4887Schin 
279*4887Schin /*
280*4887Schin  * This routine parses up the matching right parenthesis and returns
281*4887Schin  * the parse tree
282*4887Schin  */
283*4887Schin Shnode_t *sh_dolparen(void)
284*4887Schin {
285*4887Schin 	register Shnode_t *t=0;
286*4887Schin 	register Lex_t *lp = (Lex_t*)sh.lex_context;
287*4887Schin 	Sfio_t *sp = fcfile();
288*4887Schin 	int line = sh.inlineno;
289*4887Schin 	sh.inlineno = error_info.line+sh.st.firstline;
290*4887Schin 	sh_lexopen(lp,&sh,1);
291*4887Schin 	shlex.comsub = 1;
292*4887Schin 	switch(sh_lex())
293*4887Schin 	{
294*4887Schin 	    /* ((...)) arithmetic expression */
295*4887Schin 	    case EXPRSYM:
296*4887Schin 		t = getanode(shlex.arg);
297*4887Schin 		break;
298*4887Schin 	    case LPAREN:
299*4887Schin 		t = sh_cmd(RPAREN,SH_NL|SH_EMPTY);
300*4887Schin 		break;
301*4887Schin 	}
302*4887Schin 	shlex.comsub = 0;
303*4887Schin 	if(!sp && (sp=fcfile()))
304*4887Schin 	{
305*4887Schin 		/*
306*4887Schin 		 * This code handles the case where string has been converted
307*4887Schin 		 * to a file by an alias setup
308*4887Schin 		 */
309*4887Schin 		register int c;
310*4887Schin 		char *cp;
311*4887Schin 		if(fcgetc(c) > 0)
312*4887Schin 			fcseek(-1);
313*4887Schin 		cp = fcseek(0);
314*4887Schin 		fcclose();
315*4887Schin 		fcsopen(cp);
316*4887Schin 		sfclose(sp);
317*4887Schin 	}
318*4887Schin 	sh.inlineno = line;
319*4887Schin 	return(t);
320*4887Schin }
321*4887Schin 
322*4887Schin /*
323*4887Schin  * remove temporary files and stacks
324*4887Schin  */
325*4887Schin 
326*4887Schin void	sh_freeup(void)
327*4887Schin {
328*4887Schin 	if(sh.st.staklist)
329*4887Schin 		sh_funstaks(sh.st.staklist,-1);
330*4887Schin 	sh.st.staklist = 0;
331*4887Schin }
332*4887Schin 
333*4887Schin /*
334*4887Schin  * increase reference count for each stack in function list when flag>0
335*4887Schin  * decrease reference count for each stack in function list when flag<=0
336*4887Schin  * stack is freed when reference count is zero
337*4887Schin  */
338*4887Schin 
339*4887Schin void sh_funstaks(register struct slnod *slp,int flag)
340*4887Schin {
341*4887Schin 	register struct slnod *slpold;
342*4887Schin 	while(slpold=slp)
343*4887Schin 	{
344*4887Schin 		if(slp->slchild)
345*4887Schin 			sh_funstaks(slp->slchild,flag);
346*4887Schin 		slp = slp->slnext;
347*4887Schin 		if(flag<=0)
348*4887Schin 			stakdelete(slpold->slptr);
349*4887Schin 		else
350*4887Schin 			staklink(slpold->slptr);
351*4887Schin 	}
352*4887Schin }
353*4887Schin /*
354*4887Schin  * cmd
355*4887Schin  *	empty
356*4887Schin  *	list
357*4887Schin  *	list & [ cmd ]
358*4887Schin  *	list [ ; cmd ]
359*4887Schin  */
360*4887Schin 
361*4887Schin static Shnode_t	*sh_cmd(register int sym, int flag)
362*4887Schin {
363*4887Schin 	register Shnode_t	*left, *right;
364*4887Schin 	register int type = FINT|FAMP;
365*4887Schin 	if(sym==NL)
366*4887Schin 		shlex.lasttok = 0;
367*4887Schin 	left = list(flag);
368*4887Schin 	if(shlex.token==NL)
369*4887Schin 	{
370*4887Schin 		if(flag&SH_NL)
371*4887Schin 			shlex.token=';';
372*4887Schin 	}
373*4887Schin 	else if(!left && !(flag&SH_EMPTY))
374*4887Schin 		sh_syntax();
375*4887Schin 	switch(shlex.token)
376*4887Schin 	{
377*4887Schin 	    case COOPSYM:		/* set up a cooperating process */
378*4887Schin 		type |= (FPIN|FPOU|FPCL|FCOOP);
379*4887Schin 		/* FALL THRU */
380*4887Schin 	    case '&':
381*4887Schin 		if(left)
382*4887Schin 		{
383*4887Schin 			/* (...)& -> {...;} & */
384*4887Schin 			if(left->tre.tretyp==TPAR)
385*4887Schin 				left = left->par.partre;
386*4887Schin 			left = makeparent(TFORK|type, left);
387*4887Schin 		}
388*4887Schin 		/* FALL THRU */
389*4887Schin 	    case ';':
390*4887Schin 		if(!left)
391*4887Schin 			sh_syntax();
392*4887Schin 		if(right=sh_cmd(sym,flag|SH_EMPTY))
393*4887Schin 			left=makelist(TLST, left, right);
394*4887Schin 		break;
395*4887Schin 	    case EOFSYM:
396*4887Schin 		if(sym==NL)
397*4887Schin 			break;
398*4887Schin 	    default:
399*4887Schin 		if(sym && sym!=shlex.token)
400*4887Schin 		{
401*4887Schin 			if(sym!=ELSESYM || (shlex.token!=ELIFSYM && shlex.token!=FISYM))
402*4887Schin 				sh_syntax();
403*4887Schin 		}
404*4887Schin 	}
405*4887Schin 	return(left);
406*4887Schin }
407*4887Schin 
408*4887Schin /*
409*4887Schin  * list
410*4887Schin  *	term
411*4887Schin  *	list && term
412*4887Schin  *	list || term
413*4887Schin  *      unfortunately, these are equal precedence
414*4887Schin  */
415*4887Schin static Shnode_t	*list(register int flag)
416*4887Schin {
417*4887Schin 	register Shnode_t	*t = term(flag);
418*4887Schin 	register int 	token;
419*4887Schin 	while(t && ((token=shlex.token)==ANDFSYM || token==ORFSYM))
420*4887Schin 		t = makelist((token==ANDFSYM?TAND:TORF), t, term(SH_NL|SH_SEMI));
421*4887Schin 	return(t);
422*4887Schin }
423*4887Schin 
424*4887Schin /*
425*4887Schin  * term
426*4887Schin  *	item
427*4887Schin  *	item | term
428*4887Schin  */
429*4887Schin static Shnode_t	*term(register int flag)
430*4887Schin {
431*4887Schin 	register Shnode_t	*t;
432*4887Schin 	register int token;
433*4887Schin 	if(flag&SH_NL)
434*4887Schin 		token = skipnl(flag);
435*4887Schin 	else
436*4887Schin 		token = sh_lex();
437*4887Schin 	/* check to see if pipeline is to be timed */
438*4887Schin 	if(token==TIMESYM || token==NOTSYM)
439*4887Schin 	{
440*4887Schin 		t = getnode(parnod);
441*4887Schin 		t->par.partyp=TTIME;
442*4887Schin 		if(shlex.token==NOTSYM)
443*4887Schin 			t->par.partyp |= COMSCAN;
444*4887Schin 		t->par.partre = term(0);
445*4887Schin 	}
446*4887Schin 	else if((t=item(SH_NL|SH_EMPTY|(flag&SH_SEMI))) && shlex.token=='|')
447*4887Schin 	{
448*4887Schin 		register Shnode_t	*tt;
449*4887Schin 		int showme = t->tre.tretyp&FSHOWME;
450*4887Schin 		t = makeparent(TFORK|FPOU,t);
451*4887Schin 		if(tt=term(SH_NL))
452*4887Schin 		{
453*4887Schin 			switch(tt->tre.tretyp&COMMSK)
454*4887Schin 			{
455*4887Schin 			    case TFORK:
456*4887Schin 				tt->tre.tretyp |= FPIN|FPCL;
457*4887Schin 				break;
458*4887Schin 			    case TFIL:
459*4887Schin 				tt->lst.lstlef->tre.tretyp |= FPIN|FPCL;
460*4887Schin 				break;
461*4887Schin 			    default:
462*4887Schin 				tt= makeparent(TSETIO|FPIN|FPCL,tt);
463*4887Schin 			}
464*4887Schin 			t=makelist(TFIL,t,tt);
465*4887Schin 			t->tre.tretyp |= showme;
466*4887Schin 		}
467*4887Schin 		else if(shlex.token)
468*4887Schin 			sh_syntax();
469*4887Schin 	}
470*4887Schin 	return(t);
471*4887Schin }
472*4887Schin 
473*4887Schin /*
474*4887Schin  * case statement
475*4887Schin  */
476*4887Schin static struct regnod*	syncase(register int esym)
477*4887Schin {
478*4887Schin 	register int tok = skipnl(0);
479*4887Schin 	register struct regnod	*r;
480*4887Schin 	if(tok==esym)
481*4887Schin 		return(NIL(struct regnod*));
482*4887Schin 	r = (struct regnod*)stakalloc(sizeof(struct regnod));
483*4887Schin 	r->regptr=0;
484*4887Schin 	r->regflag=0;
485*4887Schin 	if(tok==LPAREN)
486*4887Schin 		skipnl(0);
487*4887Schin 	while(1)
488*4887Schin 	{
489*4887Schin 		if(!shlex.arg)
490*4887Schin 			sh_syntax();
491*4887Schin 		shlex.arg->argnxt.ap=r->regptr;
492*4887Schin 		r->regptr = shlex.arg;
493*4887Schin 		if((tok=sh_lex())==RPAREN)
494*4887Schin 			break;
495*4887Schin 		else if(tok=='|')
496*4887Schin 			sh_lex();
497*4887Schin 		else
498*4887Schin 			sh_syntax();
499*4887Schin 	}
500*4887Schin 	r->regcom=sh_cmd(0,SH_NL|SH_EMPTY|SH_SEMI);
501*4887Schin 	if((tok=shlex.token)==BREAKCASESYM)
502*4887Schin 		r->regnxt=syncase(esym);
503*4887Schin 	else if(tok==FALLTHRUSYM)
504*4887Schin 	{
505*4887Schin 		r->regflag++;
506*4887Schin 		r->regnxt=syncase(esym);
507*4887Schin 	}
508*4887Schin 	else
509*4887Schin 	{
510*4887Schin 		if(tok!=esym && tok!=EOFSYM)
511*4887Schin 			sh_syntax();
512*4887Schin 		r->regnxt=0;
513*4887Schin 	}
514*4887Schin 	if(shlex.token==EOFSYM)
515*4887Schin 		return(NIL(struct regnod*));
516*4887Schin 	return(r);
517*4887Schin }
518*4887Schin 
519*4887Schin /*
520*4887Schin  * This routine creates the parse tree for the arithmetic for
521*4887Schin  * When called, shlex.arg contains the string inside ((...))
522*4887Schin  * When the first argument is missing, a while node is returned
523*4887Schin  * Otherise a list containing an arithmetic command and a while
524*4887Schin  * is returned.
525*4887Schin  */
526*4887Schin static Shnode_t	*arithfor(register Shnode_t *tf)
527*4887Schin {
528*4887Schin 	register Shnode_t	*t, *tw = tf;
529*4887Schin 	register int	offset;
530*4887Schin 	register struct argnod *argp;
531*4887Schin 	register int n;
532*4887Schin 	int argflag = shlex.arg->argflag;
533*4887Schin 	/* save current input */
534*4887Schin 	Fcin_t	sav_input;
535*4887Schin 	fcsave(&sav_input);
536*4887Schin 	fcsopen(shlex.arg->argval);
537*4887Schin 	/* split ((...)) into three expressions */
538*4887Schin 	for(n=0; ; n++)
539*4887Schin 	{
540*4887Schin 		register int c;
541*4887Schin 		argp = (struct argnod*)stakseek(ARGVAL);
542*4887Schin 		argp->argnxt.ap = 0;
543*4887Schin 		argp->argchn.cp = 0;
544*4887Schin 		argp->argflag = argflag;
545*4887Schin 		if(n==2)
546*4887Schin 			break;
547*4887Schin 		/* copy up to ; onto the stack */
548*4887Schin 		sh_lexskip(';',1,ST_NESTED);
549*4887Schin 		offset = staktell()-1;
550*4887Schin 		if((c=fcpeek(-1))!=';')
551*4887Schin 			break;
552*4887Schin 		/* remove trailing white space */
553*4887Schin 		while(offset>ARGVAL && ((c= *stakptr(offset-1)),isspace(c)))
554*4887Schin 			offset--;
555*4887Schin 		/* check for empty initialization expression  */
556*4887Schin 		if(offset==ARGVAL && n==0)
557*4887Schin 			continue;
558*4887Schin 		stakseek(offset);
559*4887Schin 		/* check for empty condition and treat as while((1)) */
560*4887Schin 		if(offset==ARGVAL)
561*4887Schin 			stakputc('1');
562*4887Schin 		argp = (struct argnod*)stakfreeze(1);
563*4887Schin 		t = getanode(argp);
564*4887Schin 		if(n==0)
565*4887Schin 			tf = makelist(TLST,t,tw);
566*4887Schin 		else
567*4887Schin 			tw->wh.whtre = t;
568*4887Schin 	}
569*4887Schin 	while((offset=fcpeek(0)) && isspace(offset))
570*4887Schin 		fcseek(1);
571*4887Schin 	stakputs(fcseek(0));
572*4887Schin 	argp = (struct argnod*)stakfreeze(1);
573*4887Schin 	fcrestore(&sav_input);
574*4887Schin 	if(n<2)
575*4887Schin 	{
576*4887Schin 		shlex.token = RPAREN|SYMREP;
577*4887Schin 		sh_syntax();
578*4887Schin 	}
579*4887Schin 	/* check whether the increment is present */
580*4887Schin 	if(*argp->argval)
581*4887Schin 	{
582*4887Schin 		t = getanode(argp);
583*4887Schin 		tw->wh.whinc = (struct arithnod*)t;
584*4887Schin 	}
585*4887Schin 	else
586*4887Schin 		tw->wh.whinc = 0;
587*4887Schin 	sh_lexopen((Lex_t*)sh.lex_context, &sh,1);
588*4887Schin 	if((n=sh_lex())==NL)
589*4887Schin 		n = skipnl(0);
590*4887Schin 	else if(n==';')
591*4887Schin 		n = sh_lex();
592*4887Schin 	if(n!=DOSYM && n!=LBRACE)
593*4887Schin 		sh_syntax();
594*4887Schin 	tw->wh.dotre = sh_cmd(n==DOSYM?DONESYM:RBRACE,SH_NL);
595*4887Schin 	tw->wh.whtyp = TWH;
596*4887Schin 	return(tf);
597*4887Schin 
598*4887Schin }
599*4887Schin 
600*4887Schin static Shnode_t *funct(void)
601*4887Schin {
602*4887Schin 	register Shnode_t *t;
603*4887Schin 	register int flag;
604*4887Schin 	struct slnod *volatile slp=0;
605*4887Schin 	Stak_t *savstak;
606*4887Schin 	Sfoff_t	first, last;
607*4887Schin 	struct functnod *fp;
608*4887Schin 	Sfio_t *iop;
609*4887Schin #if SHOPT_KIA
610*4887Schin 	unsigned long current = shlex.current;
611*4887Schin #endif /* SHOPT_KIA */
612*4887Schin 	int jmpval, saveloop=loop_level;
613*4887Schin 	struct argnod *savelabel = label_last;
614*4887Schin 	struct  checkpt buff;
615*4887Schin 	t = getnode(functnod);
616*4887Schin 	t->funct.functline = sh.inlineno;
617*4887Schin 	t->funct.functtyp=TFUN;
618*4887Schin 	t->funct.functargs = 0;
619*4887Schin 	if(!(flag = (shlex.token==FUNCTSYM)))
620*4887Schin 		t->funct.functtyp |= FPOSIX;
621*4887Schin 	else if(sh_lex())
622*4887Schin 		sh_syntax();
623*4887Schin 	if(!(iop=fcfile()))
624*4887Schin 	{
625*4887Schin 		iop = sfopen(NIL(Sfio_t*),fcseek(0),"s");
626*4887Schin 		fcclose();
627*4887Schin 		fcfopen(iop);
628*4887Schin 	}
629*4887Schin 	t->funct.functloc = first = fctell();
630*4887Schin 	if(!sh.st.filename || sffileno(iop)<0)
631*4887Schin 	{
632*4887Schin 		if(fcfill() >= 0)
633*4887Schin 			fcseek(-1);
634*4887Schin 		if(sh_isstate(SH_HISTORY))
635*4887Schin 			t->funct.functloc = sfseek(sh.hist_ptr->histfp,(off_t)0,SEEK_CUR);
636*4887Schin 		else
637*4887Schin 		{
638*4887Schin 			/* copy source to temporary file */
639*4887Schin 			t->funct.functloc = 0;
640*4887Schin 			if(shlex.sh->heredocs)
641*4887Schin 				t->funct.functloc = sfseek(shlex.sh->heredocs,(Sfoff_t)0, SEEK_END);
642*4887Schin 			else
643*4887Schin 				shlex.sh->heredocs = sftmp(HERE_MEM);
644*4887Schin 			shlex.sh->funlog = shlex.sh->heredocs;
645*4887Schin 			t->funct.functtyp |= FPIN;
646*4887Schin 		}
647*4887Schin 	}
648*4887Schin 	t->funct.functnam= (char*)shlex.arg->argval;
649*4887Schin #if SHOPT_KIA
650*4887Schin 	if(shlex.kiafile)
651*4887Schin 		shlex.current = kiaentity(t->funct.functnam,-1,'p',-1,-1,shlex.script,'p',0,"");
652*4887Schin #endif /* SHOPT_KIA */
653*4887Schin 	if(flag)
654*4887Schin 	{
655*4887Schin 		shlex.token = sh_lex();
656*4887Schin #if SHOPT_BASH
657*4887Schin 		if(shlex.token == LPAREN)
658*4887Schin 		{
659*4887Schin 			if((shlex.token = sh_lex()) == RPAREN)
660*4887Schin 				t->funct.functtyp |= FPOSIX;
661*4887Schin 			else
662*4887Schin 				sh_syntax();
663*4887Schin 		}
664*4887Schin #endif
665*4887Schin 	}
666*4887Schin 	if(t->funct.functtyp&FPOSIX)
667*4887Schin 		skipnl(0);
668*4887Schin 	else
669*4887Schin 	{
670*4887Schin 		if(shlex.token==0)
671*4887Schin 			t->funct.functargs = (struct comnod*)simple(SH_NOIO|SH_FUNDEF,NIL(struct ionod*));
672*4887Schin 		while(shlex.token==NL)
673*4887Schin 			shlex.token = sh_lex();
674*4887Schin 	}
675*4887Schin 	if((flag && shlex.token!=LBRACE) || shlex.token==EOFSYM)
676*4887Schin 		sh_syntax();
677*4887Schin 	sh_pushcontext(&buff,1);
678*4887Schin 	jmpval = sigsetjmp(buff.buff,0);
679*4887Schin 	if(jmpval == 0)
680*4887Schin 	{
681*4887Schin 		/* create a new stak frame to compile the command */
682*4887Schin 		savstak = stakcreate(STAK_SMALL);
683*4887Schin 		savstak = stakinstall(savstak, 0);
684*4887Schin 		slp = (struct slnod*)stakalloc(sizeof(struct slnod)+sizeof(struct functnod));
685*4887Schin 		slp->slchild = 0;
686*4887Schin 		slp->slnext = sh.st.staklist;
687*4887Schin 		sh.st.staklist = 0;
688*4887Schin 		t->funct.functstak = (struct slnod*)slp;
689*4887Schin 		/*
690*4887Schin 		 * store the pathname of function definition file on stack
691*4887Schin 		 * in name field of fake for node
692*4887Schin 		 */
693*4887Schin 		fp = (struct functnod*)(slp+1);
694*4887Schin 		fp->functtyp = TFUN|FAMP;
695*4887Schin 		fp->functnam = 0;
696*4887Schin 		fp->functline = t->funct.functline;
697*4887Schin 		if(sh.st.filename)
698*4887Schin 			fp->functnam = stakcopy(sh.st.filename);
699*4887Schin 		loop_level = 0;
700*4887Schin 		label_last = label_list;
701*4887Schin 		if(!flag && shlex.token==0)
702*4887Schin 		{
703*4887Schin 			/* copy current word token to current stak frame */
704*4887Schin 			struct argnod *ap;
705*4887Schin 			flag = ARGVAL + strlen(shlex.arg->argval);
706*4887Schin 			ap = (struct argnod*)stakalloc(flag);
707*4887Schin 			memcpy(ap,shlex.arg,flag);
708*4887Schin 			shlex.arg = ap;
709*4887Schin 		}
710*4887Schin 		t->funct.functtre = item(SH_NOIO);
711*4887Schin 	}
712*4887Schin 	sh_popcontext(&buff);
713*4887Schin 	loop_level = saveloop;
714*4887Schin 	label_last = savelabel;
715*4887Schin 	/* restore the old stack */
716*4887Schin 	if(slp)
717*4887Schin 	{
718*4887Schin 		slp->slptr =  stakinstall(savstak,0);
719*4887Schin 		slp->slchild = sh.st.staklist;
720*4887Schin 	}
721*4887Schin #if SHOPT_KIA
722*4887Schin 	shlex.current = current;
723*4887Schin #endif /* SHOPT_KIA */
724*4887Schin 	if(jmpval)
725*4887Schin 	{
726*4887Schin 		if(slp && slp->slptr)
727*4887Schin 		{
728*4887Schin 			sh.st.staklist = slp->slnext;
729*4887Schin 			stakdelete(slp->slptr);
730*4887Schin 		}
731*4887Schin 		siglongjmp(*sh.jmplist,jmpval);
732*4887Schin 	}
733*4887Schin 	sh.st.staklist = (struct slnod*)slp;
734*4887Schin 	last = fctell();
735*4887Schin 	fp->functline = (last-first);
736*4887Schin 	fp->functtre = t;
737*4887Schin 	if(shlex.sh->funlog)
738*4887Schin 	{
739*4887Schin 		if(fcfill()>0)
740*4887Schin 			fcseek(-1);
741*4887Schin 		shlex.sh->funlog = 0;
742*4887Schin 	}
743*4887Schin #if 	SHOPT_KIA
744*4887Schin 	if(shlex.kiafile)
745*4887Schin 		kiaentity(t->funct.functnam,-1,'p',t->funct.functline,sh.inlineno-1,shlex.current,'p',0,"");
746*4887Schin #endif /* SHOPT_KIA */
747*4887Schin 	return(t);
748*4887Schin }
749*4887Schin 
750*4887Schin /*
751*4887Schin  * Compound assignment
752*4887Schin  */
753*4887Schin static struct argnod *assign(register struct argnod *ap)
754*4887Schin {
755*4887Schin 	register int n;
756*4887Schin 	register Shnode_t *t, **tp;
757*4887Schin 	register struct comnod *ac;
758*4887Schin 	int array=0;
759*4887Schin 	Namval_t *np;
760*4887Schin 	n = strlen(ap->argval)-1;
761*4887Schin 	if(ap->argval[n]!='=')
762*4887Schin 		sh_syntax();
763*4887Schin 	if(ap->argval[n-1]=='+')
764*4887Schin 	{
765*4887Schin 		ap->argval[n--]=0;
766*4887Schin 		array = ARG_APPEND;
767*4887Schin 	}
768*4887Schin 	/* shift right */
769*4887Schin 	while(n > 0)
770*4887Schin 	{
771*4887Schin 		ap->argval[n] = ap->argval[n-1];
772*4887Schin 		n--;
773*4887Schin 	}
774*4887Schin 	*ap->argval=0;
775*4887Schin 	t = getnode(fornod);
776*4887Schin 	t->for_.fornam = (char*)(ap->argval+1);
777*4887Schin 	t->for_.fortyp = sh_getlineno();
778*4887Schin 	tp = &t->for_.fortre;
779*4887Schin 	ap->argchn.ap = (struct argnod*)t;
780*4887Schin 	ap->argflag &= ARG_QUOTED;
781*4887Schin 	ap->argflag |= array;
782*4887Schin 	shlex.assignok = SH_ASSIGN;
783*4887Schin 	array=0;
784*4887Schin 	if((n=skipnl(0))==RPAREN || n==LPAREN)
785*4887Schin 	{
786*4887Schin 		int index= 0;
787*4887Schin 		struct argnod **settail;
788*4887Schin 		ac = (struct comnod*)getnode(comnod);
789*4887Schin 		settail= &ac->comset;
790*4887Schin 		memset((void*)ac,0,sizeof(*ac));
791*4887Schin 		ac->comline = sh_getlineno();
792*4887Schin 		while(n==LPAREN)
793*4887Schin 		{
794*4887Schin 			struct argnod *ap;
795*4887Schin 			ap = (struct argnod*)stakseek(ARGVAL);
796*4887Schin 			ap->argflag= ARG_ASSIGN;
797*4887Schin 			sfprintf(stkstd,"[%d]=",index++);
798*4887Schin 			ap = (struct argnod*)stakfreeze(1);
799*4887Schin 			ap->argnxt.ap = 0;
800*4887Schin 			ap = assign(ap);
801*4887Schin 			ap->argflag |= ARG_MESSAGE;
802*4887Schin 			*settail = ap;
803*4887Schin 			settail = &(ap->argnxt.ap);
804*4887Schin 			n = skipnl(0);
805*4887Schin 		}
806*4887Schin 	}
807*4887Schin 	else if(n)
808*4887Schin 		sh_syntax();
809*4887Schin 	else if(!(shlex.arg->argflag&ARG_ASSIGN) && !((np=nv_search(shlex.arg->argval,sh.fun_tree,0)) && nv_isattr(np,BLT_DCL)))
810*4887Schin 		array=SH_ARRAY;
811*4887Schin 	while(1)
812*4887Schin 	{
813*4887Schin 		if((n=shlex.token)==RPAREN)
814*4887Schin 			break;
815*4887Schin 		if(n==FUNCTSYM || n==SYMRES)
816*4887Schin 			ac = (struct comnod*)funct();
817*4887Schin 		else
818*4887Schin 			ac = (struct comnod*)simple(SH_NOIO|SH_ASSIGN|array,NIL(struct ionod*));
819*4887Schin 		if((n=shlex.token)==RPAREN)
820*4887Schin 			break;
821*4887Schin 		if(n!=NL && n!=';')
822*4887Schin 			sh_syntax();
823*4887Schin 		shlex.assignok = SH_ASSIGN;
824*4887Schin 		if((n=skipnl(0)) || array)
825*4887Schin 		{
826*4887Schin 			if(n==RPAREN)
827*4887Schin 				break;
828*4887Schin 			if(array ||  n!=FUNCTSYM)
829*4887Schin 				sh_syntax();
830*4887Schin 		}
831*4887Schin 		if((n!=FUNCTSYM) && !(shlex.arg->argflag&ARG_ASSIGN) && !((np=nv_search(shlex.arg->argval,sh.fun_tree,0)) && nv_isattr(np,BLT_DCL)))
832*4887Schin 		{
833*4887Schin 			struct argnod *arg = shlex.arg;
834*4887Schin 			if(n!=0)
835*4887Schin 				sh_syntax();
836*4887Schin 			/* check for sys5 style function */
837*4887Schin 			if(sh_lex()!=LPAREN || sh_lex()!=RPAREN)
838*4887Schin 			{
839*4887Schin 				shlex.arg = arg;
840*4887Schin 				shlex.token = 0;
841*4887Schin 				sh_syntax();
842*4887Schin 			}
843*4887Schin 			shlex.arg = arg;
844*4887Schin 			shlex.token = SYMRES;
845*4887Schin 		}
846*4887Schin 		t = makelist(TLST,(Shnode_t*)ac,t);
847*4887Schin 		*tp = t;
848*4887Schin 		tp = &t->lst.lstrit;
849*4887Schin 	}
850*4887Schin 	*tp = (Shnode_t*)ac;
851*4887Schin 	shlex.assignok = 0;
852*4887Schin 	return(ap);
853*4887Schin }
854*4887Schin 
855*4887Schin /*
856*4887Schin  * item
857*4887Schin  *
858*4887Schin  *	( cmd ) [ < in ] [ > out ]
859*4887Schin  *	word word* [ < in ] [ > out ]
860*4887Schin  *	if ... then ... else ... fi
861*4887Schin  *	for ... while ... do ... done
862*4887Schin  *	case ... in ... esac
863*4887Schin  *	begin ... end
864*4887Schin  */
865*4887Schin 
866*4887Schin static Shnode_t	*item(int flag)
867*4887Schin {
868*4887Schin 	register Shnode_t	*t;
869*4887Schin 	register struct ionod	*io;
870*4887Schin 	register int tok = (shlex.token&0xff);
871*4887Schin 	int savwdval = shlex.lasttok;
872*4887Schin 	int savline = shlex.lastline;
873*4887Schin 	int showme=0;
874*4887Schin 	if(!(flag&SH_NOIO) && (tok=='<' || tok=='>'))
875*4887Schin 		io=inout(NIL(struct ionod*),1);
876*4887Schin 	else
877*4887Schin 		io=0;
878*4887Schin 	if((tok=shlex.token) && tok!=EOFSYM && tok!=FUNCTSYM)
879*4887Schin 	{
880*4887Schin 		shlex.lastline =  sh_getlineno();
881*4887Schin 		shlex.lasttok = shlex.token;
882*4887Schin 	}
883*4887Schin 	switch(tok)
884*4887Schin 	{
885*4887Schin 	    /* [[ ... ]] test expression */
886*4887Schin 	    case BTESTSYM:
887*4887Schin 		t = test_expr(ETESTSYM);
888*4887Schin 		t->tre.tretyp &= ~TTEST;
889*4887Schin 		break;
890*4887Schin 	    /* ((...)) arithmetic expression */
891*4887Schin 	    case EXPRSYM:
892*4887Schin 		t = getanode(shlex.arg);
893*4887Schin 		sh_lex();
894*4887Schin 		goto done;
895*4887Schin 
896*4887Schin 	    /* case statement */
897*4887Schin 	    case CASESYM:
898*4887Schin 	    {
899*4887Schin 		int savetok = shlex.lasttok;
900*4887Schin 		int saveline = shlex.lastline;
901*4887Schin 		t = getnode(swnod);
902*4887Schin 		if(sh_lex())
903*4887Schin 			sh_syntax();
904*4887Schin 		t->sw.swarg=shlex.arg;
905*4887Schin 		t->sw.swtyp=TSW;
906*4887Schin 		t->sw.swio = 0;
907*4887Schin 		t->sw.swtyp |= FLINENO;
908*4887Schin 		t->sw.swline =  sh.inlineno;
909*4887Schin 		if((tok=skipnl(0))!=INSYM && tok!=LBRACE)
910*4887Schin 			sh_syntax();
911*4887Schin 		if(!(t->sw.swlst=syncase(tok==INSYM?ESACSYM:RBRACE)) && shlex.token==EOFSYM)
912*4887Schin 		{
913*4887Schin 			shlex.lasttok = savetok;
914*4887Schin 			shlex.lastline = saveline;
915*4887Schin 			sh_syntax();
916*4887Schin 		}
917*4887Schin 		break;
918*4887Schin 	    }
919*4887Schin 
920*4887Schin 	    /* if statement */
921*4887Schin 	    case IFSYM:
922*4887Schin 	    {
923*4887Schin 		register Shnode_t	*tt;
924*4887Schin 		t = getnode(ifnod);
925*4887Schin 		t->if_.iftyp=TIF;
926*4887Schin 		t->if_.iftre=sh_cmd(THENSYM,SH_NL);
927*4887Schin 		t->if_.thtre=sh_cmd(ELSESYM,SH_NL|SH_SEMI);
928*4887Schin 		tok = shlex.token;
929*4887Schin 		t->if_.eltre=(tok==ELSESYM?sh_cmd(FISYM,SH_NL|SH_SEMI):
930*4887Schin 			(tok==ELIFSYM?(shlex.token=IFSYM, tt=item(SH_NOIO)):0));
931*4887Schin 		if(tok==ELIFSYM)
932*4887Schin 		{
933*4887Schin 			if(!tt || tt->tre.tretyp!=TSETIO)
934*4887Schin 				goto done;
935*4887Schin 			t->if_.eltre = tt->fork.forktre;
936*4887Schin 			tt->fork.forktre = t;
937*4887Schin 			t = tt;
938*4887Schin 			goto done;
939*4887Schin 		}
940*4887Schin 		break;
941*4887Schin 	    }
942*4887Schin 
943*4887Schin 	    /* for and select statement */
944*4887Schin 	    case FORSYM:
945*4887Schin 	    case SELECTSYM:
946*4887Schin 	    {
947*4887Schin 		t = getnode(fornod);
948*4887Schin 		t->for_.fortyp=(shlex.token==FORSYM?TFOR:TSELECT);
949*4887Schin 		t->for_.forlst=0;
950*4887Schin 		t->for_.forline =  sh.inlineno;
951*4887Schin 		if(sh_lex())
952*4887Schin 		{
953*4887Schin 			if(shlex.token!=EXPRSYM || t->for_.fortyp!=TFOR)
954*4887Schin 				sh_syntax();
955*4887Schin 			/* arithmetic for */
956*4887Schin 			t = arithfor(t);
957*4887Schin 			break;
958*4887Schin 		}
959*4887Schin 		t->for_.fornam=(char*) shlex.arg->argval;
960*4887Schin 		t->for_.fortyp |= FLINENO;
961*4887Schin #if SHOPT_KIA
962*4887Schin 		if(shlex.kiafile)
963*4887Schin 			writedefs(shlex.arg,sh.inlineno,'v',NIL(struct argnod*));
964*4887Schin #endif /* SHOPT_KIA */
965*4887Schin 		while((tok=sh_lex())==NL);
966*4887Schin 		if(tok==INSYM)
967*4887Schin 		{
968*4887Schin 			if(sh_lex())
969*4887Schin 			{
970*4887Schin 				if(shlex.token != NL && shlex.token !=';')
971*4887Schin 					sh_syntax();
972*4887Schin 				/* some Linux scripts assume this */
973*4887Schin 				if(sh_isoption(SH_NOEXEC))
974*4887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexemptyfor,sh.inlineno-(shlex.token=='\n'));
975*4887Schin 				t->for_.forlst = (struct comnod*)getnode(comnod);
976*4887Schin 				(t->for_.forlst)->comarg = 0;
977*4887Schin 				(t->for_.forlst)->comset = 0;
978*4887Schin 				(t->for_.forlst)->comnamp = 0;
979*4887Schin 				(t->for_.forlst)->comnamq = 0;
980*4887Schin 				(t->for_.forlst)->comstate = 0;
981*4887Schin 				(t->for_.forlst)->comio = 0;
982*4887Schin 				(t->for_.forlst)->comtyp = 0;
983*4887Schin 			}
984*4887Schin 			else
985*4887Schin 				t->for_.forlst=(struct comnod*)simple(SH_NOIO,NIL(struct ionod*));
986*4887Schin 			if(shlex.token != NL && shlex.token !=';')
987*4887Schin 				sh_syntax();
988*4887Schin 			tok = skipnl(0);
989*4887Schin 		}
990*4887Schin 		/* 'for i;do cmd' is valid syntax */
991*4887Schin 		else if(tok==';')
992*4887Schin 			tok=sh_lex();
993*4887Schin 		if(tok!=DOSYM && tok!=LBRACE)
994*4887Schin 			sh_syntax();
995*4887Schin 		loop_level++;
996*4887Schin 		t->for_.fortre=sh_cmd(tok==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
997*4887Schin 		if(--loop_level==0)
998*4887Schin 			label_last = label_list;
999*4887Schin 		break;
1000*4887Schin 	    }
1001*4887Schin 
1002*4887Schin 	    /* This is the code for parsing function definitions */
1003*4887Schin 	    case FUNCTSYM:
1004*4887Schin 		return(funct());
1005*4887Schin 
1006*4887Schin #if SHOPT_NAMESPACE
1007*4887Schin 	    case NSPACESYM:
1008*4887Schin 		t = getnode(fornod);
1009*4887Schin 		t->for_.fortyp=TNSPACE;
1010*4887Schin 		t->for_.forlst=0;
1011*4887Schin 		if(sh_lex())
1012*4887Schin 			sh_syntax();
1013*4887Schin 		t->for_.fornam=(char*) shlex.arg->argval;
1014*4887Schin 		while((tok=sh_lex())==NL);
1015*4887Schin 		if(tok!=LBRACE)
1016*4887Schin 			sh_syntax();
1017*4887Schin 		t->for_.fortre = sh_cmd(RBRACE,SH_NL);
1018*4887Schin 		break;
1019*4887Schin #endif /* SHOPT_NAMESPACE */
1020*4887Schin 
1021*4887Schin 	    /* while and until */
1022*4887Schin 	    case WHILESYM:
1023*4887Schin 	    case UNTILSYM:
1024*4887Schin 		t = getnode(whnod);
1025*4887Schin 		t->wh.whtyp=(shlex.token==WHILESYM ? TWH : TUN);
1026*4887Schin 		loop_level++;
1027*4887Schin 		t->wh.whtre = sh_cmd(DOSYM,SH_NL);
1028*4887Schin 		t->wh.dotre = sh_cmd(DONESYM,SH_NL|SH_SEMI);
1029*4887Schin 		if(--loop_level==0)
1030*4887Schin 			label_last = label_list;
1031*4887Schin 		t->wh.whinc = 0;
1032*4887Schin 		break;
1033*4887Schin 
1034*4887Schin 	    case LABLSYM:
1035*4887Schin 	    {
1036*4887Schin 		register struct argnod *argp = label_list;
1037*4887Schin 		while(argp)
1038*4887Schin 		{
1039*4887Schin 			if(strcmp(argp->argval,shlex.arg->argval)==0)
1040*4887Schin 				errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax3,sh.inlineno,argp->argval);
1041*4887Schin 			argp = argp->argnxt.ap;
1042*4887Schin 		}
1043*4887Schin 		shlex.arg->argnxt.ap = label_list;
1044*4887Schin 		label_list = shlex.arg;
1045*4887Schin 		label_list->argchn.len = sh_getlineno();
1046*4887Schin 		label_list->argflag = loop_level;
1047*4887Schin 		skipnl(flag);
1048*4887Schin 		if(!(t = item(SH_NL)))
1049*4887Schin 			sh_syntax();
1050*4887Schin 		tok = (t->tre.tretyp&(COMSCAN|COMSCAN-1));
1051*4887Schin 		if(sh_isoption(SH_NOEXEC) && tok!=TWH && tok!=TUN && tok!=TFOR && tok!=TSELECT)
1052*4887Schin 			errormsg(SH_DICT,ERROR_warn(0),e_lexlabignore,label_list->argchn.len,label_list->argval);
1053*4887Schin 		return(t);
1054*4887Schin 	    }
1055*4887Schin 
1056*4887Schin 	    /* command group with {...} */
1057*4887Schin 	    case LBRACE:
1058*4887Schin 		t = sh_cmd(RBRACE,SH_NL);
1059*4887Schin 		break;
1060*4887Schin 
1061*4887Schin 	    case LPAREN:
1062*4887Schin 		t = getnode(parnod);
1063*4887Schin 		t->par.partre=sh_cmd(RPAREN,SH_NL);
1064*4887Schin 		t->par.partyp=TPAR;
1065*4887Schin 		break;
1066*4887Schin 
1067*4887Schin 	    default:
1068*4887Schin 		if(io==0)
1069*4887Schin 			return(0);
1070*4887Schin 
1071*4887Schin 	    case ';':
1072*4887Schin 		if(io==0)
1073*4887Schin 		{
1074*4887Schin 			if(!(flag&SH_SEMI))
1075*4887Schin 				return(0);
1076*4887Schin 			if(sh_lex()==';')
1077*4887Schin 				sh_syntax();
1078*4887Schin 			showme =  FSHOWME;
1079*4887Schin 		}
1080*4887Schin 	    /* simple command */
1081*4887Schin 	    case 0:
1082*4887Schin 		t = (Shnode_t*)simple(flag,io);
1083*4887Schin 		t->tre.tretyp |= showme;
1084*4887Schin 		return(t);
1085*4887Schin 	}
1086*4887Schin 	sh_lex();
1087*4887Schin 	if(io=inout(io,0))
1088*4887Schin 	{
1089*4887Schin 		if((tok=t->tre.tretyp&COMMSK) != TFORK)
1090*4887Schin 			tok = TSETIO;
1091*4887Schin 		t=makeparent(tok,t);
1092*4887Schin 		t->tre.treio=io;
1093*4887Schin 	}
1094*4887Schin done:
1095*4887Schin 	shlex.lasttok = savwdval;
1096*4887Schin 	shlex.lastline = savline;
1097*4887Schin 	return(t);
1098*4887Schin }
1099*4887Schin 
1100*4887Schin /*
1101*4887Schin  * This is for a simple command, for list, or compound assignment
1102*4887Schin  */
1103*4887Schin static Shnode_t *simple(int flag, struct ionod *io)
1104*4887Schin {
1105*4887Schin 	register struct comnod *t;
1106*4887Schin 	register struct argnod	*argp;
1107*4887Schin 	register int tok;
1108*4887Schin 	struct argnod	**argtail;
1109*4887Schin 	struct argnod	**settail;
1110*4887Schin 	int	argno = 0;
1111*4887Schin 	int	assignment = 0;
1112*4887Schin 	int	key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
1113*4887Schin 	int	associative=0;
1114*4887Schin 	if((argp=shlex.arg) && (argp->argflag&ARG_ASSIGN) && argp->argval[0]=='[')
1115*4887Schin 	{
1116*4887Schin 		flag |= SH_ARRAY;
1117*4887Schin 		associative = 1;
1118*4887Schin 	}
1119*4887Schin 	t = (struct comnod*)getnode(comnod);
1120*4887Schin 	t->comio=io; /*initial io chain*/
1121*4887Schin 	/* set command line number for error messages */
1122*4887Schin 	t->comline = sh_getlineno();
1123*4887Schin 	argtail = &(t->comarg);
1124*4887Schin 	t->comset = 0;
1125*4887Schin 	t->comnamp = 0;
1126*4887Schin 	t->comnamq = 0;
1127*4887Schin 	t->comstate = 0;
1128*4887Schin 	settail = &(t->comset);
1129*4887Schin 	while(shlex.token==0)
1130*4887Schin 	{
1131*4887Schin 		argp = shlex.arg;
1132*4887Schin 		if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
1133*4887Schin 		{
1134*4887Schin 			shlex.token = LBRACE;
1135*4887Schin 			break;
1136*4887Schin 		}
1137*4887Schin 		if(associative && argp->argval[0]!='[')
1138*4887Schin 			sh_syntax();
1139*4887Schin 		/* check for assignment argument */
1140*4887Schin 		if((argp->argflag&ARG_ASSIGN) && assignment!=2)
1141*4887Schin 		{
1142*4887Schin 			*settail = argp;
1143*4887Schin 			settail = &(argp->argnxt.ap);
1144*4887Schin 			shlex.assignok = (flag&SH_ASSIGN)?SH_ASSIGN:1;
1145*4887Schin 			if(assignment)
1146*4887Schin 			{
1147*4887Schin 				struct argnod *ap=argp;
1148*4887Schin 				char *last, *cp;
1149*4887Schin 				if(assignment==1)
1150*4887Schin 				{
1151*4887Schin 					last = strchr(argp->argval,'=');
1152*4887Schin 					if((cp=strchr(argp->argval,'[')) && (cp < last))
1153*4887Schin 						last = cp;
1154*4887Schin 					stakseek(ARGVAL);
1155*4887Schin 					stakwrite(argp->argval,last-argp->argval);
1156*4887Schin 					ap=(struct argnod*)stakfreeze(1);
1157*4887Schin 					ap->argflag = ARG_RAW;
1158*4887Schin 					ap->argchn.ap = 0;
1159*4887Schin 				}
1160*4887Schin 				*argtail = ap;
1161*4887Schin 				argtail = &(ap->argnxt.ap);
1162*4887Schin 				if(argno>=0)
1163*4887Schin 					argno++;
1164*4887Schin 			}
1165*4887Schin 			else /* alias substitutions allowed */
1166*4887Schin 				shlex.aliasok = 1;
1167*4887Schin 		}
1168*4887Schin 		else
1169*4887Schin 		{
1170*4887Schin 			if(!(argp->argflag&ARG_RAW))
1171*4887Schin 				argno = -1;
1172*4887Schin 			if(argno>=0 && argno++==0 && !(flag&SH_ARRAY) && *argp->argval!='/')
1173*4887Schin 			{
1174*4887Schin 				/* check for builtin command */
1175*4887Schin 				Namval_t *np=nv_bfsearch(argp->argval,sh.fun_tree, (Namval_t**)&t->comnamq,(char**)0);
1176*4887Schin 				if((t->comnamp=(void*)np) && is_abuiltin(np) &&
1177*4887Schin 					nv_isattr(np,BLT_DCL))
1178*4887Schin 				{
1179*4887Schin 					assignment = 1+(*argp->argval=='a');
1180*4887Schin 					key_on = 1;
1181*4887Schin 				}
1182*4887Schin 			}
1183*4887Schin 			*argtail = argp;
1184*4887Schin 			argtail = &(argp->argnxt.ap);
1185*4887Schin 			if(!(shlex.assignok=key_on)  && !(flag&SH_NOIO))
1186*4887Schin 				shlex.assignok = SH_COMPASSIGN;
1187*4887Schin 			shlex.aliasok = 0;
1188*4887Schin 		}
1189*4887Schin 	retry:
1190*4887Schin 		tok = sh_lex();
1191*4887Schin #if SHOPT_DEVFD
1192*4887Schin 		if((tok==IPROCSYM || tok==OPROCSYM))
1193*4887Schin 		{
1194*4887Schin 			Shnode_t *t;
1195*4887Schin 			int mode = (tok==OPROCSYM);
1196*4887Schin 			t = sh_cmd(RPAREN,SH_NL);
1197*4887Schin 			argp = (struct argnod*)stakalloc(sizeof(struct argnod));
1198*4887Schin 			*argp->argval = 0;
1199*4887Schin 			argno = -1;
1200*4887Schin 			*argtail = argp;
1201*4887Schin 			argtail = &(argp->argnxt.ap);
1202*4887Schin 			argp->argchn.ap = (struct argnod*)makeparent(mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t);
1203*4887Schin 			argp->argflag =  (ARG_EXP|mode);
1204*4887Schin 			goto retry;
1205*4887Schin 		}
1206*4887Schin #endif	/* SHOPT_DEVFD */
1207*4887Schin 		if(tok==LPAREN)
1208*4887Schin 		{
1209*4887Schin 			if(argp->argflag&ARG_ASSIGN)
1210*4887Schin 			{
1211*4887Schin 				argp = assign(argp);
1212*4887Schin 				if(associative)
1213*4887Schin 					shlex.assignok |= SH_ASSIGN;
1214*4887Schin 				goto retry;
1215*4887Schin 			}
1216*4887Schin 			else if(argno==1 && !t->comset)
1217*4887Schin 			{
1218*4887Schin 				/* SVR2 style function */
1219*4887Schin 				if(sh_lex() == RPAREN)
1220*4887Schin 				{
1221*4887Schin 					shlex.arg = argp;
1222*4887Schin 					return(funct());
1223*4887Schin 				}
1224*4887Schin 				shlex.token = LPAREN;
1225*4887Schin 			}
1226*4887Schin 		}
1227*4887Schin 		else if(flag&SH_ASSIGN)
1228*4887Schin 		{
1229*4887Schin 			if(tok==RPAREN)
1230*4887Schin 				break;
1231*4887Schin 			else if(tok==NL && (flag&SH_ARRAY))
1232*4887Schin 				goto retry;
1233*4887Schin 		}
1234*4887Schin 		if(!(flag&SH_NOIO))
1235*4887Schin 		{
1236*4887Schin 			if(io)
1237*4887Schin 			{
1238*4887Schin 				while(io->ionxt)
1239*4887Schin 					io = io->ionxt;
1240*4887Schin 				io->ionxt = inout((struct ionod*)0,0);
1241*4887Schin 			}
1242*4887Schin 			else
1243*4887Schin 				t->comio = io = inout((struct ionod*)0,0);
1244*4887Schin 		}
1245*4887Schin 	}
1246*4887Schin 	*argtail = 0;
1247*4887Schin 	t->comtyp = TCOM;
1248*4887Schin #if SHOPT_KIA
1249*4887Schin 	if(shlex.kiafile && !(flag&SH_NOIO))
1250*4887Schin 	{
1251*4887Schin 		register Namval_t *np=(Namval_t*)t->comnamp;
1252*4887Schin 		unsigned long r=0;
1253*4887Schin 		int line = t->comline;
1254*4887Schin 		argp = t->comarg;
1255*4887Schin 		if(np)
1256*4887Schin 			r = kiaentity(nv_name(np),-1,'p',-1,0,shlex.unknown,'b',0,"");
1257*4887Schin 		else if(argp)
1258*4887Schin 			r = kiaentity(sh_argstr(argp),-1,'p',-1,0,shlex.unknown,'c',0,"");
1259*4887Schin 		if(r>0)
1260*4887Schin 			sfprintf(shlex.kiatmp,"p;%..64d;p;%..64d;%d;%d;c;\n",shlex.current,r,line,line);
1261*4887Schin 		if(t->comset && argno==0)
1262*4887Schin 			writedefs(t->comset,line,'v',t->comarg);
1263*4887Schin 		else if(np && nv_isattr(np,BLT_DCL))
1264*4887Schin 			writedefs(argp,line,0,NIL(struct argnod*));
1265*4887Schin 		else if(argp && strcmp(argp->argval,"read")==0)
1266*4887Schin 			writedefs(argp,line,0,NIL(struct argnod*));
1267*4887Schin #if 0
1268*4887Schin 		else if(argp && strcmp(argp->argval,"unset")==0)
1269*4887Schin 			writedefs(argp,line,'u',NIL(struct argnod*));
1270*4887Schin #endif
1271*4887Schin 		else if(argp && *argp->argval=='.' && argp->argval[1]==0 && (argp=argp->argnxt.ap))
1272*4887Schin 		{
1273*4887Schin 			r = kiaentity(sh_argstr(argp),-1,'p',0,0,shlex.script,'d',0,"");
1274*4887Schin 			sfprintf(shlex.kiatmp,"p;%..64d;p;%..64d;%d;%d;d;\n",shlex.current,r,line,line);
1275*4887Schin 		}
1276*4887Schin 	}
1277*4887Schin #endif /* SHOPT_KIA */
1278*4887Schin 	if(t->comnamp && (argp=t->comarg->argnxt.ap))
1279*4887Schin 	{
1280*4887Schin 		Namval_t *np=(Namval_t*)t->comnamp;
1281*4887Schin 		if((np==SYSBREAK || np==SYSCONT) && (argp->argflag&ARG_RAW) && !isdigit(*argp->argval))
1282*4887Schin 		{
1283*4887Schin 			register char *cp = argp->argval;
1284*4887Schin 			/* convert break/continue labels to numbers */
1285*4887Schin 			tok = 0;
1286*4887Schin 			for(argp=label_list;argp!=label_last;argp=argp->argnxt.ap)
1287*4887Schin 			{
1288*4887Schin 				if(strcmp(cp,argp->argval))
1289*4887Schin 					continue;
1290*4887Schin 				tok = loop_level-argp->argflag;
1291*4887Schin 				if(tok>=1)
1292*4887Schin 				{
1293*4887Schin 					argp = t->comarg->argnxt.ap;
1294*4887Schin 					if(tok>9)
1295*4887Schin 					{
1296*4887Schin 						argp->argval[1] = '0'+tok%10;
1297*4887Schin 						argp->argval[2] = 0;
1298*4887Schin 						tok /= 10;
1299*4887Schin 					}
1300*4887Schin 					else
1301*4887Schin 						argp->argval[1] = 0;
1302*4887Schin 					*argp->argval = '0'+tok;
1303*4887Schin 				}
1304*4887Schin 				break;
1305*4887Schin 			}
1306*4887Schin 			if(sh_isoption(SH_NOEXEC) && tok==0)
1307*4887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_lexlabunknown,sh.inlineno-(shlex.token=='\n'),cp);
1308*4887Schin 		}
1309*4887Schin 		else if(sh_isoption(SH_NOEXEC) && np==SYSSET && ((tok= *argp->argval)=='-'||tok=='+') &&
1310*4887Schin 			(argp->argval[1]==0||strchr(argp->argval,'k')))
1311*4887Schin 			errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete5,sh.inlineno-(shlex.token=='\n'),argp->argval);
1312*4887Schin 	}
1313*4887Schin 	/* expand argument list if possible */
1314*4887Schin 	if(argno>0)
1315*4887Schin 		t->comarg = qscan(t,argno);
1316*4887Schin 	else if(t->comarg)
1317*4887Schin 		t->comtyp |= COMSCAN;
1318*4887Schin 	shlex.aliasok = 0;
1319*4887Schin 	return((Shnode_t*)t);
1320*4887Schin }
1321*4887Schin 
1322*4887Schin /*
1323*4887Schin  * skip past newlines but issue prompt if interactive
1324*4887Schin  */
1325*4887Schin static int	skipnl(int flag)
1326*4887Schin {
1327*4887Schin 	register int token;
1328*4887Schin 	while((token=sh_lex())==NL);
1329*4887Schin 	if(token==';' && !(flag&SH_SEMI))
1330*4887Schin 		sh_syntax();
1331*4887Schin 	return(token);
1332*4887Schin }
1333*4887Schin 
1334*4887Schin /*
1335*4887Schin  * check for and process and i/o redirections
1336*4887Schin  * if flag>0 then an alias can be in the next word
1337*4887Schin  * if flag<0 only one redirection will be processed
1338*4887Schin  */
1339*4887Schin static struct ionod	*inout(struct ionod *lastio,int flag)
1340*4887Schin {
1341*4887Schin 	register int 		iof = shlex.digits, token=shlex.token;
1342*4887Schin 	register struct ionod	*iop;
1343*4887Schin 	char *iovname=0;
1344*4887Schin #if SHOPT_BASH
1345*4887Schin 	register int		errout=0;
1346*4887Schin #endif
1347*4887Schin 	if(token==IOVNAME)
1348*4887Schin 	{
1349*4887Schin 		iovname=shlex.arg->argval+1;
1350*4887Schin 		token= sh_lex();
1351*4887Schin 		iof = 0;
1352*4887Schin 	}
1353*4887Schin 	switch(token&0xff)
1354*4887Schin 	{
1355*4887Schin 	    case '<':
1356*4887Schin 		if(token==IODOCSYM)
1357*4887Schin 			iof |= (IODOC|IORAW);
1358*4887Schin 		else if(token==IOMOV0SYM)
1359*4887Schin 			iof |= IOMOV;
1360*4887Schin 		else if(token==IORDWRSYM)
1361*4887Schin 			iof |= IORDW;
1362*4887Schin 		else if((token&SYMSHARP) == SYMSHARP)
1363*4887Schin 		{
1364*4887Schin 			int n;
1365*4887Schin 			iof |= IOLSEEK;
1366*4887Schin 			if(fcgetc(n)=='#')
1367*4887Schin 				iof |= IOCOPY;
1368*4887Schin 			else if(n>0)
1369*4887Schin 				fcseek(-1);
1370*4887Schin 		}
1371*4887Schin 		break;
1372*4887Schin 
1373*4887Schin 	    case '>':
1374*4887Schin #if SHOPT_BASH
1375*4887Schin 		if(iof<0)
1376*4887Schin 		{
1377*4887Schin 			errout = 1;
1378*4887Schin 			iof = 1;
1379*4887Schin 		}
1380*4887Schin #endif
1381*4887Schin 		iof |= IOPUT;
1382*4887Schin 		if(token==IOAPPSYM)
1383*4887Schin 			iof |= IOAPP;
1384*4887Schin 		else if(token==IOMOV1SYM)
1385*4887Schin 			iof |= IOMOV;
1386*4887Schin 		else if(token==IOCLOBSYM)
1387*4887Schin 			iof |= IOCLOB;
1388*4887Schin 		else if((token&SYMSHARP) == SYMSHARP)
1389*4887Schin 			iof |= IOLSEEK;
1390*4887Schin 		break;
1391*4887Schin 
1392*4887Schin 	    default:
1393*4887Schin 		return(lastio);
1394*4887Schin 	}
1395*4887Schin 	shlex.digits=0;
1396*4887Schin 	iop=(struct ionod*) stakalloc(sizeof(struct ionod));
1397*4887Schin 	iop->iodelim = 0;
1398*4887Schin 	if(token=sh_lex())
1399*4887Schin 	{
1400*4887Schin 		if(token==RPAREN && (iof&IOLSEEK) && shlex.comsub)
1401*4887Schin 		{
1402*4887Schin 			shlex.arg = (struct argnod*)stakalloc(sizeof(struct argnod)+3);
1403*4887Schin 			strcpy(shlex.arg->argval,"CUR");
1404*4887Schin 			shlex.arg->argflag = ARG_RAW;
1405*4887Schin 			iof |= IOARITH;
1406*4887Schin 			fcseek(-1);
1407*4887Schin 		}
1408*4887Schin 		else if(token==EXPRSYM && (iof&IOLSEEK))
1409*4887Schin 			iof |= IOARITH;
1410*4887Schin 		else
1411*4887Schin 			sh_syntax();
1412*4887Schin 	}
1413*4887Schin 	iop->ioname=shlex.arg->argval;
1414*4887Schin 	iop->iovname = iovname;
1415*4887Schin 	if(iof&IODOC)
1416*4887Schin 	{
1417*4887Schin 		if(shlex.digits==2)
1418*4887Schin 		{
1419*4887Schin 			iof |= IOSTRG;
1420*4887Schin 			if(!(shlex.arg->argflag&ARG_RAW))
1421*4887Schin 				iof &= ~IORAW;
1422*4887Schin 		}
1423*4887Schin 		else
1424*4887Schin 		{
1425*4887Schin 			if(!shlex.sh->heredocs)
1426*4887Schin 				shlex.sh->heredocs = sftmp(HERE_MEM);
1427*4887Schin 			iop->iolst=shlex.heredoc;
1428*4887Schin 			shlex.heredoc=iop;
1429*4887Schin 			if(shlex.arg->argflag&ARG_QUOTED)
1430*4887Schin 				iof |= IOQUOTE;
1431*4887Schin 			if(shlex.digits==3)
1432*4887Schin 				iof |= IOLSEEK;
1433*4887Schin 			if(shlex.digits)
1434*4887Schin 				iof |= IOSTRIP;
1435*4887Schin 		}
1436*4887Schin 	}
1437*4887Schin 	else
1438*4887Schin 	{
1439*4887Schin 		iop->iolst = 0;
1440*4887Schin 		if(shlex.arg->argflag&ARG_RAW)
1441*4887Schin 			iof |= IORAW;
1442*4887Schin 	}
1443*4887Schin 	iop->iofile=iof;
1444*4887Schin 	if(flag>0)
1445*4887Schin 		/* allow alias substitutions and parameter assignments */
1446*4887Schin 		shlex.aliasok = shlex.assignok = 1;
1447*4887Schin #if SHOPT_KIA
1448*4887Schin 	if(shlex.kiafile)
1449*4887Schin 	{
1450*4887Schin 		int n = sh.inlineno-(shlex.token=='\n');
1451*4887Schin 		if(!(iof&IOMOV))
1452*4887Schin 		{
1453*4887Schin 			unsigned long r=kiaentity((iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,shlex.script,'f',0,"");
1454*4887Schin 			sfprintf(shlex.kiatmp,"p;%..64d;f;%..64d;%d;%d;%c;%d\n",shlex.current,r,n,n,(iof&IOPUT)?((iof&IOAPP)?'a':'w'):((iof&IODOC)?'h':'r'),iof&IOUFD);
1455*4887Schin 		}
1456*4887Schin 	}
1457*4887Schin #endif /* SHOPT_KIA */
1458*4887Schin 	if(flag>=0)
1459*4887Schin 	{
1460*4887Schin 		struct ionod *ioq=iop;
1461*4887Schin 		sh_lex();
1462*4887Schin #if SHOPT_BASH
1463*4887Schin 		if(errout)
1464*4887Schin 		{
1465*4887Schin 			/* redirect standard output to standard error */
1466*4887Schin 			ioq = (struct ionod*)stakalloc(sizeof(struct ionod));
1467*4887Schin 			ioq->ioname = "1";
1468*4887Schin 			ioq->iolst = 0;
1469*4887Schin 			ioq->iodelim = 0;
1470*4887Schin 			ioq->iofile = IORAW|IOPUT|IOMOV|2;
1471*4887Schin 			iop->ionxt=ioq;
1472*4887Schin 		}
1473*4887Schin #endif
1474*4887Schin 		ioq->ionxt=inout(lastio,flag);
1475*4887Schin 	}
1476*4887Schin 	else
1477*4887Schin 		iop->ionxt=0;
1478*4887Schin 	return(iop);
1479*4887Schin }
1480*4887Schin 
1481*4887Schin /*
1482*4887Schin  * convert argument chain to argument list when no special arguments
1483*4887Schin  */
1484*4887Schin 
1485*4887Schin static struct argnod *qscan(struct comnod *ac,int argn)
1486*4887Schin {
1487*4887Schin 	register char **cp;
1488*4887Schin 	register struct argnod *ap;
1489*4887Schin 	register struct dolnod* dp;
1490*4887Schin 	register int special=0;
1491*4887Schin 	/* special hack for test -t compatibility */
1492*4887Schin 	if((Namval_t*)ac->comnamp==SYSTEST)
1493*4887Schin 		special = 2;
1494*4887Schin 	else if(*(ac->comarg->argval)=='[' && ac->comarg->argval[1]==0)
1495*4887Schin 		special = 3;
1496*4887Schin 	if(special)
1497*4887Schin 	{
1498*4887Schin 		ap = ac->comarg->argnxt.ap;
1499*4887Schin 		if(argn==(special+1) && ap->argval[1]==0 && *ap->argval=='!')
1500*4887Schin 			ap = ap->argnxt.ap;
1501*4887Schin 		else if(argn!=special)
1502*4887Schin 			special=0;
1503*4887Schin 	}
1504*4887Schin 	if(special)
1505*4887Schin 	{
1506*4887Schin 		const char *message;
1507*4887Schin 		if(strcmp(ap->argval,"-t"))
1508*4887Schin 		{
1509*4887Schin 			message = "line %d: Invariant test";
1510*4887Schin 			special=0;
1511*4887Schin 		}
1512*4887Schin 		else
1513*4887Schin 		{
1514*4887Schin 			message = "line %d: -t requires argument";
1515*4887Schin 			argn++;
1516*4887Schin 		}
1517*4887Schin 		if(sh_isoption(SH_NOEXEC))
1518*4887Schin 			errormsg(SH_DICT,ERROR_warn(0),message,ac->comline);
1519*4887Schin 	}
1520*4887Schin 	/* leave space for an extra argument at the front */
1521*4887Schin 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
1522*4887Schin 	cp = dp->dolval+ARG_SPARE;
1523*4887Schin 	dp->dolnum = argn;
1524*4887Schin 	dp->dolbot = ARG_SPARE;
1525*4887Schin 	ap = ac->comarg;
1526*4887Schin 	while(ap)
1527*4887Schin 	{
1528*4887Schin 		*cp++ = ap->argval;
1529*4887Schin 		ap = ap->argnxt.ap;
1530*4887Schin 	}
1531*4887Schin 	if(special==3)
1532*4887Schin 	{
1533*4887Schin 		cp[0] = cp[-1];
1534*4887Schin 		cp[-1] = "1";
1535*4887Schin 		cp++;
1536*4887Schin 	}
1537*4887Schin 	else if(special)
1538*4887Schin 		*cp++ = "1";
1539*4887Schin 	*cp = 0;
1540*4887Schin 	return((struct argnod*)dp);
1541*4887Schin }
1542*4887Schin 
1543*4887Schin static Shnode_t *test_expr(int sym)
1544*4887Schin {
1545*4887Schin 	register Shnode_t *t = test_or();
1546*4887Schin 	if(shlex.token!=sym)
1547*4887Schin 		sh_syntax();
1548*4887Schin 	return(t);
1549*4887Schin }
1550*4887Schin 
1551*4887Schin static Shnode_t *test_or(void)
1552*4887Schin {
1553*4887Schin 	register Shnode_t *t = test_and();
1554*4887Schin 	while(shlex.token==ORFSYM)
1555*4887Schin 		t = makelist(TORF|TTEST,t,test_and());
1556*4887Schin 	return(t);
1557*4887Schin }
1558*4887Schin 
1559*4887Schin static Shnode_t *test_and(void)
1560*4887Schin {
1561*4887Schin 	register Shnode_t *t = test_primary();
1562*4887Schin 	while(shlex.token==ANDFSYM)
1563*4887Schin 		t = makelist(TAND|TTEST,t,test_primary());
1564*4887Schin 	return(t);
1565*4887Schin }
1566*4887Schin 
1567*4887Schin /*
1568*4887Schin  * convert =~ into == ~(E)
1569*4887Schin  */
1570*4887Schin static void ere_match(void)
1571*4887Schin {
1572*4887Schin 	Sfio_t *base, *iop = sfopen((Sfio_t*)0," ~(E)","s");
1573*4887Schin 	register int c;
1574*4887Schin 	while( fcgetc(c),(c==' ' || c=='\t'));
1575*4887Schin 	if(c)
1576*4887Schin 		fcseek(-1);
1577*4887Schin 	if(!(base=fcfile()))
1578*4887Schin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
1579*4887Schin 	fcclose();
1580*4887Schin         sfstack(base,iop);
1581*4887Schin         fcfopen(base);
1582*4887Schin }
1583*4887Schin 
1584*4887Schin static Shnode_t *test_primary(void)
1585*4887Schin {
1586*4887Schin 	register struct argnod *arg;
1587*4887Schin 	register Shnode_t *t;
1588*4887Schin 	register int num,token;
1589*4887Schin 	token = skipnl(0);
1590*4887Schin 	num = shlex.digits;
1591*4887Schin 	switch(token)
1592*4887Schin 	{
1593*4887Schin 	    case '(':
1594*4887Schin 		t = test_expr(')');
1595*4887Schin 		t = makelist(TTST|TTEST|TPAREN ,t, (Shnode_t*)pointerof(sh.inlineno));
1596*4887Schin 		break;
1597*4887Schin 	    case '!':
1598*4887Schin 		if(!(t = test_primary()))
1599*4887Schin 			sh_syntax();
1600*4887Schin 		t->tre.tretyp |= TNEGATE;
1601*4887Schin 		return(t);
1602*4887Schin 	    case TESTUNOP:
1603*4887Schin 		if(sh_lex())
1604*4887Schin 			sh_syntax();
1605*4887Schin #if SHOPT_KIA
1606*4887Schin 		if(shlex.kiafile && !strchr("sntzoOG",num))
1607*4887Schin 		{
1608*4887Schin 			int line = sh.inlineno- (shlex.token==NL);
1609*4887Schin 			unsigned long r;
1610*4887Schin 			r=kiaentity(sh_argstr(shlex.arg),-1,'f',0,0,shlex.script,'t',0,"");
1611*4887Schin 			sfprintf(shlex.kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",shlex.current,r,line,line);
1612*4887Schin 		}
1613*4887Schin #endif /* SHOPT_KIA */
1614*4887Schin 		t = makelist(TTST|TTEST|TUNARY|(num<<TSHIFT),
1615*4887Schin 			(Shnode_t*)shlex.arg,(Shnode_t*)shlex.arg);
1616*4887Schin 		t->tst.tstline =  sh.inlineno;
1617*4887Schin 		break;
1618*4887Schin 	    /* binary test operators */
1619*4887Schin 	    case 0:
1620*4887Schin 		arg = shlex.arg;
1621*4887Schin 		if((token=sh_lex())==TESTBINOP)
1622*4887Schin 		{
1623*4887Schin 			num = shlex.digits;
1624*4887Schin 			if(num==TEST_REP)
1625*4887Schin 			{
1626*4887Schin 				ere_match();
1627*4887Schin 				num = TEST_PEQ;
1628*4887Schin 			}
1629*4887Schin 		}
1630*4887Schin 		else if(token=='<')
1631*4887Schin 			num = TEST_SLT;
1632*4887Schin 		else if(token=='>')
1633*4887Schin 			num = TEST_SGT;
1634*4887Schin 		else if(token==ANDFSYM||token==ORFSYM||token==ETESTSYM||token==RPAREN)
1635*4887Schin 		{
1636*4887Schin 			t = makelist(TTST|TTEST|TUNARY|('n'<<TSHIFT),
1637*4887Schin 				(Shnode_t*)arg,(Shnode_t*)arg);
1638*4887Schin 			t->tst.tstline =  sh.inlineno;
1639*4887Schin 			return(t);
1640*4887Schin 		}
1641*4887Schin 		else
1642*4887Schin 			sh_syntax();
1643*4887Schin #if SHOPT_KIA
1644*4887Schin 		if(shlex.kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
1645*4887Schin 		{
1646*4887Schin 			int line = sh.inlineno- (shlex.token==NL);
1647*4887Schin 			unsigned long r;
1648*4887Schin 			r=kiaentity(sh_argstr(shlex.arg),-1,'f',0,0,shlex.current,'t',0,"");
1649*4887Schin 			sfprintf(shlex.kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",shlex.current,r,line,line);
1650*4887Schin 		}
1651*4887Schin #endif /* SHOPT_KIA */
1652*4887Schin 		if(sh_lex())
1653*4887Schin 			sh_syntax();
1654*4887Schin 		if(num&TEST_PATTERN)
1655*4887Schin 		{
1656*4887Schin 			if(shlex.arg->argflag&(ARG_EXP|ARG_MAC))
1657*4887Schin 				num &= ~TEST_PATTERN;
1658*4887Schin 		}
1659*4887Schin 		t = getnode(tstnod);
1660*4887Schin 		t->lst.lsttyp = TTST|TTEST|TBINARY|(num<<TSHIFT);
1661*4887Schin 		t->lst.lstlef = (Shnode_t*)arg;
1662*4887Schin 		t->lst.lstrit = (Shnode_t*)shlex.arg;
1663*4887Schin 		t->tst.tstline =  sh.inlineno;
1664*4887Schin #if SHOPT_KIA
1665*4887Schin 		if(shlex.kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
1666*4887Schin 		{
1667*4887Schin 			int line = sh.inlineno-(shlex.token==NL);
1668*4887Schin 			unsigned long r;
1669*4887Schin 			r=kiaentity(sh_argstr(shlex.arg),-1,'f',0,0,shlex.current,'t',0,"");
1670*4887Schin 			sfprintf(shlex.kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",shlex.current,r,line,line);
1671*4887Schin 		}
1672*4887Schin #endif /* SHOPT_KIA */
1673*4887Schin 		break;
1674*4887Schin 	    default:
1675*4887Schin 		return(0);
1676*4887Schin 	}
1677*4887Schin 	skipnl(0);
1678*4887Schin 	return(t);
1679*4887Schin }
1680*4887Schin 
1681*4887Schin #if SHOPT_KIA
1682*4887Schin /*
1683*4887Schin  * return an entity checksum
1684*4887Schin  * The entity is created if it doesn't exist
1685*4887Schin  */
1686*4887Schin unsigned long kiaentity(const char *name,int len,int type,int first,int last,unsigned long parent, int pkind, int width, const char *attr)
1687*4887Schin {
1688*4887Schin 	Namval_t *np;
1689*4887Schin 	long offset = staktell();
1690*4887Schin 	stakputc(type);
1691*4887Schin 	if(len>0)
1692*4887Schin 		stakwrite(name,len);
1693*4887Schin 	else
1694*4887Schin 	{
1695*4887Schin 		if(type=='p')
1696*4887Schin 			stakputs(path_basename(name));
1697*4887Schin 		else
1698*4887Schin 			stakputs(name);
1699*4887Schin 	}
1700*4887Schin 	stakputc(0);
1701*4887Schin 	np = nv_search(stakptr(offset),shlex.entity_tree,NV_ADD);
1702*4887Schin 	stakseek(offset);
1703*4887Schin 	np->nvalue.i = pkind;
1704*4887Schin 	nv_setsize(np,width);
1705*4887Schin 	if(!nv_isattr(np,NV_TAGGED) && first>=0)
1706*4887Schin 	{
1707*4887Schin 		nv_onattr(np,NV_TAGGED);
1708*4887Schin 		if(!pkind)
1709*4887Schin 			pkind = '0';
1710*4887Schin 		if(len>0)
1711*4887Schin 			sfprintf(shlex.kiafile,"%..64d;%c;%.*s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,len,name,first,last,parent,shlex.fscript,pkind,width,attr);
1712*4887Schin 		else
1713*4887Schin 			sfprintf(shlex.kiafile,"%..64d;%c;%s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,name,first,last,parent,shlex.fscript,pkind,width,attr);
1714*4887Schin 	}
1715*4887Schin 	return(np->hash);
1716*4887Schin }
1717*4887Schin 
1718*4887Schin static void kia_add(register Namval_t *np, void *data)
1719*4887Schin {
1720*4887Schin 	char *name = nv_name(np);
1721*4887Schin 	NOT_USED(data);
1722*4887Schin 	kiaentity(name+1,-1,*name,0,-1,(*name=='p'?shlex.unknown:shlex.script),np->nvalue.i,nv_size(np),"");
1723*4887Schin }
1724*4887Schin 
1725*4887Schin int kiaclose(void)
1726*4887Schin {
1727*4887Schin 	register off_t off1,off2;
1728*4887Schin 	register int n;
1729*4887Schin 	if(shlex.kiafile)
1730*4887Schin 	{
1731*4887Schin 		unsigned long r = kiaentity(shlex.scriptname,-1,'p',-1,sh.inlineno-1,0,'s',0,"");
1732*4887Schin 		kiaentity(shlex.scriptname,-1,'p',1,sh.inlineno-1,r,'s',0,"");
1733*4887Schin 		kiaentity(shlex.scriptname,-1,'f',1,sh.inlineno-1,r,'s',0,"");
1734*4887Schin 		nv_scan(shlex.entity_tree,kia_add,(void*)0,NV_TAGGED,0);
1735*4887Schin 		off1 = sfseek(shlex.kiafile,(off_t)0,SEEK_END);
1736*4887Schin 		sfseek(shlex.kiatmp,(off_t)0,SEEK_SET);
1737*4887Schin 		sfmove(shlex.kiatmp,shlex.kiafile,SF_UNBOUND,-1);
1738*4887Schin 		off2 = sfseek(shlex.kiafile,(off_t)0,SEEK_END);
1739*4887Schin #ifdef SF_BUFCONST
1740*4887Schin 		if(off2==off1)
1741*4887Schin 			n= sfprintf(shlex.kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)shlex.kiabegin,(size_t)(off1-shlex.kiabegin));
1742*4887Schin 		else
1743*4887Schin 			n= sfprintf(shlex.kiafile,"DIRECTORY\nENTITY;%lld;%d\nRELATIONSHIP;%lld;%d\nDIRECTORY;",(Sflong_t)shlex.kiabegin,(size_t)(off1-shlex.kiabegin),(Sflong_t)off1,(size_t)(off2-off1));
1744*4887Schin 		if(off2 >= INT_MAX)
1745*4887Schin 			off2 = -(n+12);
1746*4887Schin 		sfprintf(shlex.kiafile,"%010.10lld;%010d\n",(Sflong_t)off2+10, n+12);
1747*4887Schin #else
1748*4887Schin 		if(off2==off1)
1749*4887Schin 			n= sfprintf(shlex.kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",shlex.kiabegin,off1-shlex.kiabegin);
1750*4887Schin 		else
1751*4887Schin 			n= sfprintf(shlex.kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",shlex.kiabegin,off1-shlex.kiabegin,off1,off2-off1);
1752*4887Schin 		sfprintf(shlex.kiafile,"%010d;%010d\n",off2+10, n+12);
1753*4887Schin #endif
1754*4887Schin 	}
1755*4887Schin 	return(sfclose(shlex.kiafile));
1756*4887Schin }
1757*4887Schin #endif /* SHOPT_KIA */
1758