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