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