1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin * UNIX shell
23da2e3ebdSchin *
24da2e3ebdSchin * S. R. Bourne
25da2e3ebdSchin * Rewritten by David Korn
26da2e3ebdSchin * AT&T Labs
27da2e3ebdSchin *
28da2e3ebdSchin * This is the parser for a shell language
29da2e3ebdSchin */
30da2e3ebdSchin
31da2e3ebdSchin #if KSHELL
32da2e3ebdSchin #include "defs.h"
33da2e3ebdSchin #else
34da2e3ebdSchin #include <shell.h>
35da2e3ebdSchin #include <ctype.h>
3634f9b3eeSRoland Mainz #endif
37da2e3ebdSchin #include <fcin.h>
38da2e3ebdSchin #include <error.h>
39da2e3ebdSchin #include "shlex.h"
40da2e3ebdSchin #include "history.h"
41da2e3ebdSchin #include "builtins.h"
42da2e3ebdSchin #include "test.h"
43da2e3ebdSchin #include "history.h"
44da2e3ebdSchin
45da2e3ebdSchin #define HERE_MEM 1024 /* size of here-docs kept in memory */
46da2e3ebdSchin
47da2e3ebdSchin #define hash nvlink.hl._hash
48da2e3ebdSchin
49da2e3ebdSchin /* These routines are local to this module */
50da2e3ebdSchin
517c2fbfb3SApril Chin static Shnode_t *makeparent(Lex_t*, int, Shnode_t*);
527c2fbfb3SApril Chin static Shnode_t *makelist(Lex_t*, int, Shnode_t*, Shnode_t*);
53da2e3ebdSchin static struct argnod *qscan(struct comnod*, int);
547c2fbfb3SApril Chin static struct ionod *inout(Lex_t*,struct ionod*, int);
557c2fbfb3SApril Chin static Shnode_t *sh_cmd(Lex_t*,int,int);
567c2fbfb3SApril Chin static Shnode_t *term(Lex_t*,int);
577c2fbfb3SApril Chin static Shnode_t *list(Lex_t*,int);
587c2fbfb3SApril Chin static struct regnod *syncase(Lex_t*,int);
597c2fbfb3SApril Chin static Shnode_t *item(Lex_t*,int);
607c2fbfb3SApril Chin static Shnode_t *simple(Lex_t*,int, struct ionod*);
617c2fbfb3SApril Chin static int skipnl(Lex_t*,int);
627c2fbfb3SApril Chin static Shnode_t *test_expr(Lex_t*,int);
637c2fbfb3SApril Chin static Shnode_t *test_and(Lex_t*);
647c2fbfb3SApril Chin static Shnode_t *test_or(Lex_t*);
657c2fbfb3SApril Chin static Shnode_t *test_primary(Lex_t*);
66da2e3ebdSchin
677c2fbfb3SApril Chin #define sh_getlineno(lp) (lp->lastline)
68da2e3ebdSchin
69da2e3ebdSchin #ifndef NIL
70da2e3ebdSchin # define NIL(type) ((type)0)
71da2e3ebdSchin #endif /* NIL */
72da2e3ebdSchin #define CNTL(x) ((x)&037)
73da2e3ebdSchin
74da2e3ebdSchin
75da2e3ebdSchin #if !KSHELL
76da2e3ebdSchin static struct stdata
77da2e3ebdSchin {
78da2e3ebdSchin struct slnod *staklist;
79da2e3ebdSchin int cmdline;
80da2e3ebdSchin } st;
81da2e3ebdSchin #endif
82da2e3ebdSchin
837c2fbfb3SApril Chin static int opt_get;
84da2e3ebdSchin static int loop_level;
85da2e3ebdSchin static struct argnod *label_list;
86da2e3ebdSchin static struct argnod *label_last;
87da2e3ebdSchin
88da2e3ebdSchin #define getnode(type) ((Shnode_t*)stakalloc(sizeof(struct type)))
89da2e3ebdSchin
90da2e3ebdSchin #if SHOPT_KIA
91da2e3ebdSchin #include "path.h"
92da2e3ebdSchin /*
93da2e3ebdSchin * write out entities for each item in the list
94da2e3ebdSchin * type=='V' for variable assignment lists
95da2e3ebdSchin * Otherwise type is determined by the command */
writedefs(Lex_t * lexp,struct argnod * arglist,int line,int type,struct argnod * cmd)967c2fbfb3SApril Chin static unsigned long writedefs(Lex_t *lexp,struct argnod *arglist, int line, int type, struct argnod *cmd)
97da2e3ebdSchin {
98da2e3ebdSchin register struct argnod *argp = arglist;
99da2e3ebdSchin register char *cp;
100da2e3ebdSchin register int n,eline;
101da2e3ebdSchin int width=0;
102da2e3ebdSchin unsigned long r=0;
103da2e3ebdSchin static char atbuff[20];
104da2e3ebdSchin int justify=0;
105da2e3ebdSchin char *attribute = atbuff;
1067c2fbfb3SApril Chin unsigned long parent=lexp->script;
107da2e3ebdSchin if(type==0)
108da2e3ebdSchin {
1097c2fbfb3SApril Chin parent = lexp->current;
110da2e3ebdSchin type = 'v';
111da2e3ebdSchin switch(*argp->argval)
112da2e3ebdSchin {
113da2e3ebdSchin case 'a':
114da2e3ebdSchin type='p';
115da2e3ebdSchin justify = 'a';
116da2e3ebdSchin break;
117da2e3ebdSchin case 'e':
118da2e3ebdSchin *attribute++ = 'x';
119da2e3ebdSchin break;
120da2e3ebdSchin case 'r':
121da2e3ebdSchin *attribute++ = 'r';
122da2e3ebdSchin break;
123da2e3ebdSchin case 'l':
124da2e3ebdSchin break;
125da2e3ebdSchin }
126da2e3ebdSchin while(argp = argp->argnxt.ap)
127da2e3ebdSchin {
128da2e3ebdSchin if((n= *(cp=argp->argval))!='-' && n!='+')
129da2e3ebdSchin break;
130da2e3ebdSchin if(cp[1]==n)
131da2e3ebdSchin break;
132da2e3ebdSchin while((n= *++cp))
133da2e3ebdSchin {
134da2e3ebdSchin if(isdigit(n))
135da2e3ebdSchin width = 10*width + n-'0';
136da2e3ebdSchin else if(n=='L' || n=='R' || n =='Z')
137da2e3ebdSchin justify=n;
138da2e3ebdSchin else
139da2e3ebdSchin *attribute++ = n;
140da2e3ebdSchin }
141da2e3ebdSchin }
142da2e3ebdSchin }
143da2e3ebdSchin else if(cmd)
1447c2fbfb3SApril Chin parent=kiaentity(lexp,sh_argstr(cmd),-1,'p',-1,-1,lexp->unknown,'b',0,"");
145da2e3ebdSchin *attribute = 0;
146da2e3ebdSchin while(argp)
147da2e3ebdSchin {
148da2e3ebdSchin if((cp=strchr(argp->argval,'='))||(cp=strchr(argp->argval,'?')))
149da2e3ebdSchin n = cp-argp->argval;
150da2e3ebdSchin else
151da2e3ebdSchin n = strlen(argp->argval);
1527c2fbfb3SApril Chin eline = lexp->sh->inlineno-(lexp->token==NL);
1537c2fbfb3SApril Chin r=kiaentity(lexp,argp->argval,n,type,line,eline,parent,justify,width,atbuff);
1547c2fbfb3SApril Chin sfprintf(lexp->kiatmp,"p;%..64d;v;%..64d;%d;%d;s;\n",lexp->current,r,line,eline);
155da2e3ebdSchin argp = argp->argnxt.ap;
156da2e3ebdSchin }
157da2e3ebdSchin return(r);
158da2e3ebdSchin }
159da2e3ebdSchin #endif /* SHOPT_KIA */
1607c2fbfb3SApril Chin
typeset_order(const char * str,int line)1617c2fbfb3SApril Chin static void typeset_order(const char *str,int line)
1627c2fbfb3SApril Chin {
1637c2fbfb3SApril Chin register int c,n=0;
1647c2fbfb3SApril Chin unsigned const char *cp=(unsigned char*)str;
1657c2fbfb3SApril Chin static unsigned char *table;
1667c2fbfb3SApril Chin if(*cp!='+' && *cp!='-')
1677c2fbfb3SApril Chin return;
1687c2fbfb3SApril Chin if(!table)
1697c2fbfb3SApril Chin {
1707c2fbfb3SApril Chin table = calloc(1,256);
1717c2fbfb3SApril Chin for(cp=(unsigned char*)"bflmnprstuxACHS";c = *cp; cp++)
1727c2fbfb3SApril Chin table[c] = 1;
1737c2fbfb3SApril Chin for(cp=(unsigned char*)"aiEFLRXhTZ";c = *cp; cp++)
1747c2fbfb3SApril Chin table[c] = 2;
1757c2fbfb3SApril Chin for(c='0'; c <='9'; c++)
1767c2fbfb3SApril Chin table[c] = 3;
1777c2fbfb3SApril Chin }
1787c2fbfb3SApril Chin for(cp=(unsigned char*)str; c= *cp++; n=table[c])
1797c2fbfb3SApril Chin {
1807c2fbfb3SApril Chin if(table[c] < n)
1817c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lextypeset,line,str);
1827c2fbfb3SApril Chin }
1837c2fbfb3SApril Chin }
1847c2fbfb3SApril Chin
1857c2fbfb3SApril Chin /*
1867c2fbfb3SApril Chin * add type definitions when compiling with -n
1877c2fbfb3SApril Chin */
check_typedef(struct comnod * tp)1887c2fbfb3SApril Chin static void check_typedef(struct comnod *tp)
1897c2fbfb3SApril Chin {
1907c2fbfb3SApril Chin char *cp=0;
1917c2fbfb3SApril Chin if(tp->comtyp&COMSCAN)
1927c2fbfb3SApril Chin {
1937c2fbfb3SApril Chin struct argnod *ap = tp->comarg;
1947c2fbfb3SApril Chin while(ap = ap->argnxt.ap)
1957c2fbfb3SApril Chin {
1967c2fbfb3SApril Chin if(!(ap->argflag&ARG_RAW) || memcmp(ap->argval,"--",2))
1977c2fbfb3SApril Chin break;
1987c2fbfb3SApril Chin if(sh_isoption(SH_NOEXEC))
1997c2fbfb3SApril Chin typeset_order(ap->argval,tp->comline);
2007c2fbfb3SApril Chin if(memcmp(ap->argval,"-T",2)==0)
2017c2fbfb3SApril Chin {
2027c2fbfb3SApril Chin if(ap->argval[2])
2037c2fbfb3SApril Chin cp = ap->argval+2;
2047c2fbfb3SApril Chin else if((ap->argnxt.ap)->argflag&ARG_RAW)
2057c2fbfb3SApril Chin cp = (ap->argnxt.ap)->argval;
2067c2fbfb3SApril Chin if(cp)
2077c2fbfb3SApril Chin break;
2087c2fbfb3SApril Chin }
2097c2fbfb3SApril Chin }
2107c2fbfb3SApril Chin }
2117c2fbfb3SApril Chin else
2127c2fbfb3SApril Chin {
2137c2fbfb3SApril Chin struct dolnod *dp = (struct dolnod*)tp->comarg;
2147c2fbfb3SApril Chin char **argv = dp->dolval + dp->dolbot+1;
2157c2fbfb3SApril Chin while((cp= *argv++) && memcmp(cp,"--",2))
2167c2fbfb3SApril Chin {
2177c2fbfb3SApril Chin if(sh_isoption(SH_NOEXEC))
2187c2fbfb3SApril Chin typeset_order(cp,tp->comline);
2197c2fbfb3SApril Chin if(memcmp(cp,"-T",2)==0)
2207c2fbfb3SApril Chin {
2217c2fbfb3SApril Chin if(cp[2])
2227c2fbfb3SApril Chin cp = cp+2;
2237c2fbfb3SApril Chin else
2247c2fbfb3SApril Chin cp = *argv;
2257c2fbfb3SApril Chin break;
2267c2fbfb3SApril Chin }
2277c2fbfb3SApril Chin }
2287c2fbfb3SApril Chin }
2297c2fbfb3SApril Chin if(cp)
2307c2fbfb3SApril Chin {
2317c2fbfb3SApril Chin Namval_t *mp=(Namval_t*)tp->comnamp ,*bp;
2327c2fbfb3SApril Chin bp = sh_addbuiltin(cp,mp->nvalue.bfp, (void*)0);
2337c2fbfb3SApril Chin nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
2347c2fbfb3SApril Chin }
2357c2fbfb3SApril Chin }
2367c2fbfb3SApril Chin
237da2e3ebdSchin /*
238da2e3ebdSchin * Make a parent node for fork() or io-redirection
239da2e3ebdSchin */
makeparent(Lex_t * lp,int flag,Shnode_t * child)2407c2fbfb3SApril Chin static Shnode_t *makeparent(Lex_t *lp, int flag, Shnode_t *child)
241da2e3ebdSchin {
242da2e3ebdSchin register Shnode_t *par = getnode(forknod);
243da2e3ebdSchin par->fork.forktyp = flag;
244da2e3ebdSchin par->fork.forktre = child;
245da2e3ebdSchin par->fork.forkio = 0;
2467c2fbfb3SApril Chin par->fork.forkline = sh_getlineno(lp)-1;
247da2e3ebdSchin return(par);
248da2e3ebdSchin }
249da2e3ebdSchin
paramsub(const char * str)250*3e14f97fSRoger A. Faulkner static int paramsub(const char *str)
251*3e14f97fSRoger A. Faulkner {
252*3e14f97fSRoger A. Faulkner register int c,sub=0,lit=0;
253*3e14f97fSRoger A. Faulkner while(c= *str++)
254*3e14f97fSRoger A. Faulkner {
255*3e14f97fSRoger A. Faulkner if(c=='$' && !lit)
256*3e14f97fSRoger A. Faulkner {
257*3e14f97fSRoger A. Faulkner if(*str=='(')
258*3e14f97fSRoger A. Faulkner return(0);
259*3e14f97fSRoger A. Faulkner if(sub)
260*3e14f97fSRoger A. Faulkner continue;
261*3e14f97fSRoger A. Faulkner if(*str=='{')
262*3e14f97fSRoger A. Faulkner str++;
263*3e14f97fSRoger A. Faulkner if(!isdigit(*str) && strchr("?#@*!$ ",*str)==0)
264*3e14f97fSRoger A. Faulkner return(1);
265*3e14f97fSRoger A. Faulkner }
266*3e14f97fSRoger A. Faulkner else if(c=='`')
267*3e14f97fSRoger A. Faulkner return(0);
268*3e14f97fSRoger A. Faulkner else if(c=='[' && !lit)
269*3e14f97fSRoger A. Faulkner sub++;
270*3e14f97fSRoger A. Faulkner else if(c==']' && !lit)
271*3e14f97fSRoger A. Faulkner sub--;
272*3e14f97fSRoger A. Faulkner else if(c=='\'')
273*3e14f97fSRoger A. Faulkner lit = !lit;
274*3e14f97fSRoger A. Faulkner }
275*3e14f97fSRoger A. Faulkner return(0);
276*3e14f97fSRoger A. Faulkner }
277*3e14f97fSRoger A. Faulkner
getanode(Lex_t * lp,struct argnod * ap)2787c2fbfb3SApril Chin static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
279da2e3ebdSchin {
280da2e3ebdSchin register Shnode_t *t = getnode(arithnod);
281da2e3ebdSchin t->ar.artyp = TARITH;
2827c2fbfb3SApril Chin t->ar.arline = sh_getlineno(lp);
283da2e3ebdSchin t->ar.arexpr = ap;
284da2e3ebdSchin if(ap->argflag&ARG_RAW)
285da2e3ebdSchin t->ar.arcomp = sh_arithcomp(ap->argval);
286da2e3ebdSchin else
287*3e14f97fSRoger A. Faulkner {
288*3e14f97fSRoger A. Faulkner if(sh_isoption(SH_NOEXEC) && (ap->argflag&ARG_MAC) && paramsub(ap->argval))
289*3e14f97fSRoger A. Faulkner errormsg(SH_DICT,ERROR_warn(0),"%d: parameter substitution requires unnecessary string to number conversion",lp->sh->inlineno-(lp->token=='\n'));
290da2e3ebdSchin t->ar.arcomp = 0;
291*3e14f97fSRoger A. Faulkner }
292da2e3ebdSchin return(t);
293da2e3ebdSchin }
294da2e3ebdSchin
295da2e3ebdSchin /*
296da2e3ebdSchin * Make a node corresponding to a command list
297da2e3ebdSchin */
makelist(Lex_t * lexp,int type,Shnode_t * l,Shnode_t * r)2987c2fbfb3SApril Chin static Shnode_t *makelist(Lex_t *lexp, int type, Shnode_t *l, Shnode_t *r)
299da2e3ebdSchin {
300da2e3ebdSchin register Shnode_t *t;
301da2e3ebdSchin if(!l || !r)
3027c2fbfb3SApril Chin sh_syntax(lexp);
303da2e3ebdSchin else
304da2e3ebdSchin {
305da2e3ebdSchin if((type&COMMSK) == TTST)
306da2e3ebdSchin t = getnode(tstnod);
307da2e3ebdSchin else
308da2e3ebdSchin t = getnode(lstnod);
309da2e3ebdSchin t->lst.lsttyp = type;
310da2e3ebdSchin t->lst.lstlef = l;
311da2e3ebdSchin t->lst.lstrit = r;
312da2e3ebdSchin }
313da2e3ebdSchin return(t);
314da2e3ebdSchin }
315da2e3ebdSchin
316da2e3ebdSchin /*
317da2e3ebdSchin * entry to shell parser
318da2e3ebdSchin * Flag can be the union of SH_EOF|SH_NL
319da2e3ebdSchin */
320da2e3ebdSchin
sh_parse(Shell_t * shp,Sfio_t * iop,int flag)321da2e3ebdSchin void *sh_parse(Shell_t *shp, Sfio_t *iop, int flag)
322da2e3ebdSchin {
323da2e3ebdSchin register Shnode_t *t;
3247c2fbfb3SApril Chin Lex_t *lexp = (Lex_t*)shp->lex_context;
325da2e3ebdSchin Fcin_t sav_input;
3267c2fbfb3SApril Chin struct argnod *sav_arg = lexp->arg;
327da2e3ebdSchin int sav_prompt = shp->nextprompt;
32834f9b3eeSRoland Mainz if(shp->binscript && (sffileno(iop)==shp->infd || (flag&SH_FUNEVAL)))
3297c2fbfb3SApril Chin return((void*)sh_trestore(shp,iop));
330da2e3ebdSchin fcsave(&sav_input);
331da2e3ebdSchin shp->st.staklist = 0;
3327c2fbfb3SApril Chin lexp->heredoc = 0;
3337c2fbfb3SApril Chin lexp->inlineno = shp->inlineno;
3347c2fbfb3SApril Chin lexp->firstline = shp->st.firstline;
335da2e3ebdSchin shp->nextprompt = 1;
336da2e3ebdSchin loop_level = 0;
337da2e3ebdSchin label_list = label_last = 0;
338da2e3ebdSchin if(sh_isoption(SH_INTERACTIVE))
339da2e3ebdSchin sh_onstate(SH_INTERACTIVE);
340da2e3ebdSchin if(sh_isoption(SH_VERBOSE))
341da2e3ebdSchin sh_onstate(SH_VERBOSE);
3427c2fbfb3SApril Chin sh_lexopen(lexp,shp,0);
343da2e3ebdSchin if(fcfopen(iop) < 0)
344da2e3ebdSchin return(NIL(void*));
345da2e3ebdSchin if(fcfile())
346da2e3ebdSchin {
347da2e3ebdSchin char *cp = fcfirst();
348da2e3ebdSchin if( cp[0]==CNTL('k') && cp[1]==CNTL('s') && cp[2]==CNTL('h') && cp[3]==0)
349da2e3ebdSchin {
350da2e3ebdSchin int version;
351da2e3ebdSchin fcseek(4);
352da2e3ebdSchin fcgetc(version);
353da2e3ebdSchin fcclose();
354da2e3ebdSchin fcrestore(&sav_input);
3557c2fbfb3SApril Chin lexp->arg = sav_arg;
356da2e3ebdSchin if(version > 3)
357da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_lexversion);
35834f9b3eeSRoland Mainz if(sffileno(iop)==shp->infd || (flag&SH_FUNEVAL))
359da2e3ebdSchin shp->binscript = 1;
360da2e3ebdSchin sfgetc(iop);
3617c2fbfb3SApril Chin return((void*)sh_trestore(shp,iop));
362da2e3ebdSchin }
363da2e3ebdSchin }
36434f9b3eeSRoland Mainz flag &= ~SH_FUNEVAL;
365da2e3ebdSchin if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0)
366da2e3ebdSchin shp->inlineno=1;
367da2e3ebdSchin #if KSHELL
368da2e3ebdSchin shp->nextprompt = 2;
369da2e3ebdSchin #endif
3707c2fbfb3SApril Chin t = sh_cmd(lexp,(flag&SH_EOF)?EOFSYM:'\n',SH_SEMI|SH_EMPTY|(flag&SH_NL));
371da2e3ebdSchin fcclose();
372da2e3ebdSchin fcrestore(&sav_input);
3737c2fbfb3SApril Chin lexp->arg = sav_arg;
374da2e3ebdSchin /* unstack any completed alias expansions */
375da2e3ebdSchin if((sfset(iop,0,0)&SF_STRING) && !sfreserve(iop,0,-1))
376da2e3ebdSchin {
377da2e3ebdSchin Sfio_t *sp = sfstack(iop,NULL);
378da2e3ebdSchin if(sp)
379da2e3ebdSchin sfclose(sp);
380da2e3ebdSchin }
381da2e3ebdSchin shp->nextprompt = sav_prompt;
382da2e3ebdSchin if(flag&SH_NL)
383da2e3ebdSchin {
3847c2fbfb3SApril Chin shp->st.firstline = lexp->firstline;
3857c2fbfb3SApril Chin shp->inlineno = lexp->inlineno;
386da2e3ebdSchin }
3877c2fbfb3SApril Chin stkseek(shp->stk,0);
388da2e3ebdSchin return((void*)t);
389da2e3ebdSchin }
390da2e3ebdSchin
391da2e3ebdSchin /*
392da2e3ebdSchin * This routine parses up the matching right parenthesis and returns
393da2e3ebdSchin * the parse tree
394da2e3ebdSchin */
sh_dolparen(Lex_t * lp)3957c2fbfb3SApril Chin Shnode_t *sh_dolparen(Lex_t* lp)
396da2e3ebdSchin {
397da2e3ebdSchin register Shnode_t *t=0;
398da2e3ebdSchin Sfio_t *sp = fcfile();
3997c2fbfb3SApril Chin int line = lp->sh->inlineno;
4007c2fbfb3SApril Chin lp->sh->inlineno = error_info.line+lp->sh->st.firstline;
4017c2fbfb3SApril Chin sh_lexopen(lp,lp->sh,1);
4027c2fbfb3SApril Chin lp->comsub = 1;
4037c2fbfb3SApril Chin switch(sh_lex(lp))
404da2e3ebdSchin {
405da2e3ebdSchin /* ((...)) arithmetic expression */
406da2e3ebdSchin case EXPRSYM:
4077c2fbfb3SApril Chin t = getanode(lp,lp->arg);
408da2e3ebdSchin break;
409da2e3ebdSchin case LPAREN:
4107c2fbfb3SApril Chin t = sh_cmd(lp,RPAREN,SH_NL|SH_EMPTY);
4117c2fbfb3SApril Chin break;
4127c2fbfb3SApril Chin case LBRACE:
4137c2fbfb3SApril Chin t = sh_cmd(lp,RBRACE,SH_NL|SH_EMPTY);
414da2e3ebdSchin break;
415da2e3ebdSchin }
4167c2fbfb3SApril Chin lp->comsub = 0;
417da2e3ebdSchin if(!sp && (sp=fcfile()))
418da2e3ebdSchin {
419da2e3ebdSchin /*
420da2e3ebdSchin * This code handles the case where string has been converted
421da2e3ebdSchin * to a file by an alias setup
422da2e3ebdSchin */
423da2e3ebdSchin register int c;
424da2e3ebdSchin char *cp;
425da2e3ebdSchin if(fcgetc(c) > 0)
426da2e3ebdSchin fcseek(-1);
427da2e3ebdSchin cp = fcseek(0);
428da2e3ebdSchin fcclose();
429da2e3ebdSchin fcsopen(cp);
430da2e3ebdSchin sfclose(sp);
431da2e3ebdSchin }
4327c2fbfb3SApril Chin lp->sh->inlineno = line;
433da2e3ebdSchin return(t);
434da2e3ebdSchin }
435da2e3ebdSchin
436da2e3ebdSchin /*
437da2e3ebdSchin * remove temporary files and stacks
438da2e3ebdSchin */
439da2e3ebdSchin
sh_freeup(Shell_t * shp)4407c2fbfb3SApril Chin void sh_freeup(Shell_t *shp)
441da2e3ebdSchin {
4427c2fbfb3SApril Chin if(shp->st.staklist)
4437c2fbfb3SApril Chin sh_funstaks(shp->st.staklist,-1);
4447c2fbfb3SApril Chin shp->st.staklist = 0;
445da2e3ebdSchin }
446da2e3ebdSchin
447da2e3ebdSchin /*
448da2e3ebdSchin * increase reference count for each stack in function list when flag>0
449da2e3ebdSchin * decrease reference count for each stack in function list when flag<=0
450da2e3ebdSchin * stack is freed when reference count is zero
451da2e3ebdSchin */
452da2e3ebdSchin
sh_funstaks(register struct slnod * slp,int flag)453da2e3ebdSchin void sh_funstaks(register struct slnod *slp,int flag)
454da2e3ebdSchin {
455da2e3ebdSchin register struct slnod *slpold;
456da2e3ebdSchin while(slpold=slp)
457da2e3ebdSchin {
458da2e3ebdSchin if(slp->slchild)
459da2e3ebdSchin sh_funstaks(slp->slchild,flag);
460da2e3ebdSchin slp = slp->slnext;
461da2e3ebdSchin if(flag<=0)
462da2e3ebdSchin stakdelete(slpold->slptr);
463da2e3ebdSchin else
464da2e3ebdSchin staklink(slpold->slptr);
465da2e3ebdSchin }
466da2e3ebdSchin }
467da2e3ebdSchin /*
468da2e3ebdSchin * cmd
469da2e3ebdSchin * empty
470da2e3ebdSchin * list
471da2e3ebdSchin * list & [ cmd ]
472da2e3ebdSchin * list [ ; cmd ]
473da2e3ebdSchin */
474da2e3ebdSchin
sh_cmd(Lex_t * lexp,register int sym,int flag)4757c2fbfb3SApril Chin static Shnode_t *sh_cmd(Lex_t *lexp, register int sym, int flag)
476da2e3ebdSchin {
477da2e3ebdSchin register Shnode_t *left, *right;
478da2e3ebdSchin register int type = FINT|FAMP;
479da2e3ebdSchin if(sym==NL)
4807c2fbfb3SApril Chin lexp->lasttok = 0;
4817c2fbfb3SApril Chin left = list(lexp,flag);
4827c2fbfb3SApril Chin if(lexp->token==NL)
483da2e3ebdSchin {
484da2e3ebdSchin if(flag&SH_NL)
4857c2fbfb3SApril Chin lexp->token=';';
486da2e3ebdSchin }
487da2e3ebdSchin else if(!left && !(flag&SH_EMPTY))
4887c2fbfb3SApril Chin sh_syntax(lexp);
4897c2fbfb3SApril Chin switch(lexp->token)
490da2e3ebdSchin {
491da2e3ebdSchin case COOPSYM: /* set up a cooperating process */
492da2e3ebdSchin type |= (FPIN|FPOU|FPCL|FCOOP);
493da2e3ebdSchin /* FALL THRU */
494da2e3ebdSchin case '&':
495da2e3ebdSchin if(left)
496da2e3ebdSchin {
497da2e3ebdSchin /* (...)& -> {...;} & */
498da2e3ebdSchin if(left->tre.tretyp==TPAR)
499da2e3ebdSchin left = left->par.partre;
5007c2fbfb3SApril Chin left = makeparent(lexp,TFORK|type, left);
501da2e3ebdSchin }
502da2e3ebdSchin /* FALL THRU */
503da2e3ebdSchin case ';':
504da2e3ebdSchin if(!left)
5057c2fbfb3SApril Chin sh_syntax(lexp);
5067c2fbfb3SApril Chin if(right=sh_cmd(lexp,sym,flag|SH_EMPTY))
5077c2fbfb3SApril Chin left=makelist(lexp,TLST, left, right);
508da2e3ebdSchin break;
509da2e3ebdSchin case EOFSYM:
510da2e3ebdSchin if(sym==NL)
511da2e3ebdSchin break;
512da2e3ebdSchin default:
5137c2fbfb3SApril Chin if(sym && sym!=lexp->token)
514da2e3ebdSchin {
5157c2fbfb3SApril Chin if(sym!=ELSESYM || (lexp->token!=ELIFSYM && lexp->token!=FISYM))
5167c2fbfb3SApril Chin sh_syntax(lexp);
517da2e3ebdSchin }
518da2e3ebdSchin }
519da2e3ebdSchin return(left);
520da2e3ebdSchin }
521da2e3ebdSchin
522da2e3ebdSchin /*
523da2e3ebdSchin * list
524da2e3ebdSchin * term
525da2e3ebdSchin * list && term
526da2e3ebdSchin * list || term
527da2e3ebdSchin * unfortunately, these are equal precedence
528da2e3ebdSchin */
list(Lex_t * lexp,register int flag)5297c2fbfb3SApril Chin static Shnode_t *list(Lex_t *lexp, register int flag)
530da2e3ebdSchin {
5317c2fbfb3SApril Chin register Shnode_t *t = term(lexp,flag);
532da2e3ebdSchin register int token;
5337c2fbfb3SApril Chin while(t && ((token=lexp->token)==ANDFSYM || token==ORFSYM))
5347c2fbfb3SApril Chin t = makelist(lexp,(token==ANDFSYM?TAND:TORF), t, term(lexp,SH_NL|SH_SEMI));
535da2e3ebdSchin return(t);
536da2e3ebdSchin }
537da2e3ebdSchin
538da2e3ebdSchin /*
539da2e3ebdSchin * term
540da2e3ebdSchin * item
541da2e3ebdSchin * item | term
542da2e3ebdSchin */
term(Lex_t * lexp,register int flag)5437c2fbfb3SApril Chin static Shnode_t *term(Lex_t *lexp,register int flag)
544da2e3ebdSchin {
545da2e3ebdSchin register Shnode_t *t;
546da2e3ebdSchin register int token;
547da2e3ebdSchin if(flag&SH_NL)
5487c2fbfb3SApril Chin token = skipnl(lexp,flag);
549da2e3ebdSchin else
5507c2fbfb3SApril Chin token = sh_lex(lexp);
551da2e3ebdSchin /* check to see if pipeline is to be timed */
552da2e3ebdSchin if(token==TIMESYM || token==NOTSYM)
553da2e3ebdSchin {
554da2e3ebdSchin t = getnode(parnod);
555da2e3ebdSchin t->par.partyp=TTIME;
5567c2fbfb3SApril Chin if(lexp->token==NOTSYM)
557da2e3ebdSchin t->par.partyp |= COMSCAN;
5587c2fbfb3SApril Chin t->par.partre = term(lexp,0);
559da2e3ebdSchin }
5607c2fbfb3SApril Chin else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && lexp->token=='|')
561da2e3ebdSchin {
562da2e3ebdSchin register Shnode_t *tt;
563da2e3ebdSchin int showme = t->tre.tretyp&FSHOWME;
5647c2fbfb3SApril Chin t = makeparent(lexp,TFORK|FPOU,t);
5657c2fbfb3SApril Chin if(tt=term(lexp,SH_NL))
566da2e3ebdSchin {
567da2e3ebdSchin switch(tt->tre.tretyp&COMMSK)
568da2e3ebdSchin {
569da2e3ebdSchin case TFORK:
570da2e3ebdSchin tt->tre.tretyp |= FPIN|FPCL;
571da2e3ebdSchin break;
572da2e3ebdSchin case TFIL:
573da2e3ebdSchin tt->lst.lstlef->tre.tretyp |= FPIN|FPCL;
574da2e3ebdSchin break;
575da2e3ebdSchin default:
5767c2fbfb3SApril Chin tt= makeparent(lexp,TSETIO|FPIN|FPCL,tt);
577da2e3ebdSchin }
5787c2fbfb3SApril Chin t=makelist(lexp,TFIL,t,tt);
579da2e3ebdSchin t->tre.tretyp |= showme;
580da2e3ebdSchin }
5817c2fbfb3SApril Chin else if(lexp->token)
5827c2fbfb3SApril Chin sh_syntax(lexp);
583da2e3ebdSchin }
584da2e3ebdSchin return(t);
585da2e3ebdSchin }
586da2e3ebdSchin
587da2e3ebdSchin /*
588da2e3ebdSchin * case statement
589da2e3ebdSchin */
syncase(Lex_t * lexp,register int esym)5907c2fbfb3SApril Chin static struct regnod* syncase(Lex_t *lexp,register int esym)
591da2e3ebdSchin {
5927c2fbfb3SApril Chin register int tok = skipnl(lexp,0);
593da2e3ebdSchin register struct regnod *r;
594da2e3ebdSchin if(tok==esym)
595da2e3ebdSchin return(NIL(struct regnod*));
596da2e3ebdSchin r = (struct regnod*)stakalloc(sizeof(struct regnod));
597da2e3ebdSchin r->regptr=0;
598da2e3ebdSchin r->regflag=0;
599da2e3ebdSchin if(tok==LPAREN)
6007c2fbfb3SApril Chin skipnl(lexp,0);
601da2e3ebdSchin while(1)
602da2e3ebdSchin {
6037c2fbfb3SApril Chin if(!lexp->arg)
6047c2fbfb3SApril Chin sh_syntax(lexp);
6057c2fbfb3SApril Chin lexp->arg->argnxt.ap=r->regptr;
6067c2fbfb3SApril Chin r->regptr = lexp->arg;
6077c2fbfb3SApril Chin if((tok=sh_lex(lexp))==RPAREN)
608da2e3ebdSchin break;
609da2e3ebdSchin else if(tok=='|')
6107c2fbfb3SApril Chin sh_lex(lexp);
611da2e3ebdSchin else
6127c2fbfb3SApril Chin sh_syntax(lexp);
613da2e3ebdSchin }
6147c2fbfb3SApril Chin r->regcom=sh_cmd(lexp,0,SH_NL|SH_EMPTY|SH_SEMI);
6157c2fbfb3SApril Chin if((tok=lexp->token)==BREAKCASESYM)
6167c2fbfb3SApril Chin r->regnxt=syncase(lexp,esym);
617da2e3ebdSchin else if(tok==FALLTHRUSYM)
618da2e3ebdSchin {
619da2e3ebdSchin r->regflag++;
6207c2fbfb3SApril Chin r->regnxt=syncase(lexp,esym);
621da2e3ebdSchin }
622da2e3ebdSchin else
623da2e3ebdSchin {
624da2e3ebdSchin if(tok!=esym && tok!=EOFSYM)
6257c2fbfb3SApril Chin sh_syntax(lexp);
626da2e3ebdSchin r->regnxt=0;
627da2e3ebdSchin }
6287c2fbfb3SApril Chin if(lexp->token==EOFSYM)
629da2e3ebdSchin return(NIL(struct regnod*));
630da2e3ebdSchin return(r);
631da2e3ebdSchin }
632da2e3ebdSchin
633da2e3ebdSchin /*
634da2e3ebdSchin * This routine creates the parse tree for the arithmetic for
635da2e3ebdSchin * When called, shlex.arg contains the string inside ((...))
636da2e3ebdSchin * When the first argument is missing, a while node is returned
637da2e3ebdSchin * Otherise a list containing an arithmetic command and a while
638da2e3ebdSchin * is returned.
639da2e3ebdSchin */
arithfor(Lex_t * lexp,register Shnode_t * tf)6407c2fbfb3SApril Chin static Shnode_t *arithfor(Lex_t *lexp,register Shnode_t *tf)
641da2e3ebdSchin {
642da2e3ebdSchin register Shnode_t *t, *tw = tf;
643da2e3ebdSchin register int offset;
644da2e3ebdSchin register struct argnod *argp;
645da2e3ebdSchin register int n;
6467c2fbfb3SApril Chin Stk_t *stkp = lexp->sh->stk;
6477c2fbfb3SApril Chin int argflag = lexp->arg->argflag;
648da2e3ebdSchin /* save current input */
649da2e3ebdSchin Fcin_t sav_input;
650da2e3ebdSchin fcsave(&sav_input);
6517c2fbfb3SApril Chin fcsopen(lexp->arg->argval);
652da2e3ebdSchin /* split ((...)) into three expressions */
653da2e3ebdSchin for(n=0; ; n++)
654da2e3ebdSchin {
655da2e3ebdSchin register int c;
6567c2fbfb3SApril Chin argp = (struct argnod*)stkseek(stkp,ARGVAL);
657da2e3ebdSchin argp->argnxt.ap = 0;
658da2e3ebdSchin argp->argchn.cp = 0;
659da2e3ebdSchin argp->argflag = argflag;
660da2e3ebdSchin if(n==2)
661da2e3ebdSchin break;
662da2e3ebdSchin /* copy up to ; onto the stack */
6637c2fbfb3SApril Chin sh_lexskip(lexp,';',1,ST_NESTED);
6647c2fbfb3SApril Chin offset = stktell(stkp)-1;
665da2e3ebdSchin if((c=fcpeek(-1))!=';')
666da2e3ebdSchin break;
667da2e3ebdSchin /* remove trailing white space */
6687c2fbfb3SApril Chin while(offset>ARGVAL && ((c= *stkptr(stkp,offset-1)),isspace(c)))
669da2e3ebdSchin offset--;
670da2e3ebdSchin /* check for empty initialization expression */
671da2e3ebdSchin if(offset==ARGVAL && n==0)
672da2e3ebdSchin continue;
6737c2fbfb3SApril Chin stkseek(stkp,offset);
674da2e3ebdSchin /* check for empty condition and treat as while((1)) */
675da2e3ebdSchin if(offset==ARGVAL)
6767c2fbfb3SApril Chin sfputc(stkp,'1');
6777c2fbfb3SApril Chin argp = (struct argnod*)stkfreeze(stkp,1);
6787c2fbfb3SApril Chin t = getanode(lexp,argp);
679da2e3ebdSchin if(n==0)
6807c2fbfb3SApril Chin tf = makelist(lexp,TLST,t,tw);
681da2e3ebdSchin else
682da2e3ebdSchin tw->wh.whtre = t;
683da2e3ebdSchin }
684da2e3ebdSchin while((offset=fcpeek(0)) && isspace(offset))
685da2e3ebdSchin fcseek(1);
686da2e3ebdSchin stakputs(fcseek(0));
687da2e3ebdSchin argp = (struct argnod*)stakfreeze(1);
688da2e3ebdSchin fcrestore(&sav_input);
689da2e3ebdSchin if(n<2)
690da2e3ebdSchin {
6917c2fbfb3SApril Chin lexp->token = RPAREN|SYMREP;
6927c2fbfb3SApril Chin sh_syntax(lexp);
693da2e3ebdSchin }
694da2e3ebdSchin /* check whether the increment is present */
695da2e3ebdSchin if(*argp->argval)
696da2e3ebdSchin {
6977c2fbfb3SApril Chin t = getanode(lexp,argp);
698da2e3ebdSchin tw->wh.whinc = (struct arithnod*)t;
699da2e3ebdSchin }
700da2e3ebdSchin else
701da2e3ebdSchin tw->wh.whinc = 0;
7027c2fbfb3SApril Chin sh_lexopen(lexp, lexp->sh,1);
7037c2fbfb3SApril Chin if((n=sh_lex(lexp))==NL)
7047c2fbfb3SApril Chin n = skipnl(lexp,0);
705da2e3ebdSchin else if(n==';')
7067c2fbfb3SApril Chin n = sh_lex(lexp);
707da2e3ebdSchin if(n!=DOSYM && n!=LBRACE)
7087c2fbfb3SApril Chin sh_syntax(lexp);
7097c2fbfb3SApril Chin tw->wh.dotre = sh_cmd(lexp,n==DOSYM?DONESYM:RBRACE,SH_NL);
710da2e3ebdSchin tw->wh.whtyp = TWH;
711da2e3ebdSchin return(tf);
712da2e3ebdSchin
713da2e3ebdSchin }
714da2e3ebdSchin
funct(Lex_t * lexp)7157c2fbfb3SApril Chin static Shnode_t *funct(Lex_t *lexp)
716da2e3ebdSchin {
7177c2fbfb3SApril Chin Shell_t *shp = lexp->sh;
718da2e3ebdSchin register Shnode_t *t;
719da2e3ebdSchin register int flag;
720da2e3ebdSchin struct slnod *volatile slp=0;
721da2e3ebdSchin Stak_t *savstak;
722da2e3ebdSchin Sfoff_t first, last;
7237c2fbfb3SApril Chin struct functnod *volatile fp;
724da2e3ebdSchin Sfio_t *iop;
725da2e3ebdSchin #if SHOPT_KIA
7267c2fbfb3SApril Chin unsigned long current = lexp->current;
727da2e3ebdSchin #endif /* SHOPT_KIA */
728da2e3ebdSchin int jmpval, saveloop=loop_level;
729da2e3ebdSchin struct argnod *savelabel = label_last;
730da2e3ebdSchin struct checkpt buff;
7317c2fbfb3SApril Chin int save_optget = opt_get;
7327c2fbfb3SApril Chin void *in_mktype = shp->mktype;
7337c2fbfb3SApril Chin shp->mktype = 0;
7347c2fbfb3SApril Chin opt_get = 0;
735da2e3ebdSchin t = getnode(functnod);
7367c2fbfb3SApril Chin t->funct.functline = shp->inlineno;
737da2e3ebdSchin t->funct.functtyp=TFUN;
738da2e3ebdSchin t->funct.functargs = 0;
7397c2fbfb3SApril Chin if(!(flag = (lexp->token==FUNCTSYM)))
740da2e3ebdSchin t->funct.functtyp |= FPOSIX;
7417c2fbfb3SApril Chin else if(sh_lex(lexp))
7427c2fbfb3SApril Chin sh_syntax(lexp);
743da2e3ebdSchin if(!(iop=fcfile()))
744da2e3ebdSchin {
745da2e3ebdSchin iop = sfopen(NIL(Sfio_t*),fcseek(0),"s");
746da2e3ebdSchin fcclose();
747da2e3ebdSchin fcfopen(iop);
748da2e3ebdSchin }
749da2e3ebdSchin t->funct.functloc = first = fctell();
7507c2fbfb3SApril Chin if(!shp->st.filename || sffileno(iop)<0)
751da2e3ebdSchin {
752da2e3ebdSchin if(fcfill() >= 0)
753da2e3ebdSchin fcseek(-1);
75434f9b3eeSRoland Mainz if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
7557c2fbfb3SApril Chin t->funct.functloc = sfseek(shp->hist_ptr->histfp,(off_t)0,SEEK_CUR);
756da2e3ebdSchin else
757da2e3ebdSchin {
758da2e3ebdSchin /* copy source to temporary file */
759da2e3ebdSchin t->funct.functloc = 0;
7607c2fbfb3SApril Chin if(lexp->sh->heredocs)
7617c2fbfb3SApril Chin t->funct.functloc = sfseek(lexp->sh->heredocs,(Sfoff_t)0, SEEK_END);
762da2e3ebdSchin else
7637c2fbfb3SApril Chin lexp->sh->heredocs = sftmp(HERE_MEM);
7647c2fbfb3SApril Chin lexp->sh->funlog = lexp->sh->heredocs;
765da2e3ebdSchin t->funct.functtyp |= FPIN;
766da2e3ebdSchin }
767da2e3ebdSchin }
7687c2fbfb3SApril Chin t->funct.functnam= (char*)lexp->arg->argval;
769da2e3ebdSchin #if SHOPT_KIA
7707c2fbfb3SApril Chin if(lexp->kiafile)
7717c2fbfb3SApril Chin lexp->current = kiaentity(lexp,t->funct.functnam,-1,'p',-1,-1,lexp->script,'p',0,"");
772da2e3ebdSchin #endif /* SHOPT_KIA */
773da2e3ebdSchin if(flag)
774da2e3ebdSchin {
7757c2fbfb3SApril Chin lexp->token = sh_lex(lexp);
776da2e3ebdSchin #if SHOPT_BASH
7777c2fbfb3SApril Chin if(lexp->token == LPAREN)
778da2e3ebdSchin {
7797c2fbfb3SApril Chin if((lexp->token = sh_lex(lexp)) == RPAREN)
780da2e3ebdSchin t->funct.functtyp |= FPOSIX;
781da2e3ebdSchin else
7827c2fbfb3SApril Chin sh_syntax(lexp);
783da2e3ebdSchin }
784da2e3ebdSchin #endif
785da2e3ebdSchin }
786da2e3ebdSchin if(t->funct.functtyp&FPOSIX)
7877c2fbfb3SApril Chin skipnl(lexp,0);
788da2e3ebdSchin else
789da2e3ebdSchin {
7907c2fbfb3SApril Chin if(lexp->token==0)
7917c2fbfb3SApril Chin t->funct.functargs = (struct comnod*)simple(lexp,SH_NOIO|SH_FUNDEF,NIL(struct ionod*));
7927c2fbfb3SApril Chin while(lexp->token==NL)
7937c2fbfb3SApril Chin lexp->token = sh_lex(lexp);
794da2e3ebdSchin }
7957c2fbfb3SApril Chin if((flag && lexp->token!=LBRACE) || lexp->token==EOFSYM)
7967c2fbfb3SApril Chin sh_syntax(lexp);
797da2e3ebdSchin sh_pushcontext(&buff,1);
798da2e3ebdSchin jmpval = sigsetjmp(buff.buff,0);
799da2e3ebdSchin if(jmpval == 0)
800da2e3ebdSchin {
801da2e3ebdSchin /* create a new stak frame to compile the command */
802da2e3ebdSchin savstak = stakcreate(STAK_SMALL);
803da2e3ebdSchin savstak = stakinstall(savstak, 0);
804da2e3ebdSchin slp = (struct slnod*)stakalloc(sizeof(struct slnod)+sizeof(struct functnod));
805da2e3ebdSchin slp->slchild = 0;
8067c2fbfb3SApril Chin slp->slnext = shp->st.staklist;
8077c2fbfb3SApril Chin shp->st.staklist = 0;
808da2e3ebdSchin t->funct.functstak = (struct slnod*)slp;
809da2e3ebdSchin /*
810da2e3ebdSchin * store the pathname of function definition file on stack
811da2e3ebdSchin * in name field of fake for node
812da2e3ebdSchin */
813da2e3ebdSchin fp = (struct functnod*)(slp+1);
814da2e3ebdSchin fp->functtyp = TFUN|FAMP;
815da2e3ebdSchin fp->functnam = 0;
816da2e3ebdSchin fp->functline = t->funct.functline;
8177c2fbfb3SApril Chin if(shp->st.filename)
8187c2fbfb3SApril Chin fp->functnam = stakcopy(shp->st.filename);
819da2e3ebdSchin loop_level = 0;
820da2e3ebdSchin label_last = label_list;
8217c2fbfb3SApril Chin if(!flag && lexp->token==0)
822da2e3ebdSchin {
823da2e3ebdSchin /* copy current word token to current stak frame */
824da2e3ebdSchin struct argnod *ap;
8257c2fbfb3SApril Chin flag = ARGVAL + strlen(lexp->arg->argval);
826da2e3ebdSchin ap = (struct argnod*)stakalloc(flag);
8277c2fbfb3SApril Chin memcpy(ap,lexp->arg,flag);
8287c2fbfb3SApril Chin lexp->arg = ap;
829da2e3ebdSchin }
8307c2fbfb3SApril Chin t->funct.functtre = item(lexp,SH_NOIO);
831da2e3ebdSchin }
832*3e14f97fSRoger A. Faulkner else if(shp->shcomp)
833*3e14f97fSRoger A. Faulkner exit(1);
834da2e3ebdSchin sh_popcontext(&buff);
835da2e3ebdSchin loop_level = saveloop;
836da2e3ebdSchin label_last = savelabel;
837da2e3ebdSchin /* restore the old stack */
838da2e3ebdSchin if(slp)
839da2e3ebdSchin {
840da2e3ebdSchin slp->slptr = stakinstall(savstak,0);
8417c2fbfb3SApril Chin slp->slchild = shp->st.staklist;
842da2e3ebdSchin }
843da2e3ebdSchin #if SHOPT_KIA
8447c2fbfb3SApril Chin lexp->current = current;
845da2e3ebdSchin #endif /* SHOPT_KIA */
846da2e3ebdSchin if(jmpval)
847da2e3ebdSchin {
848da2e3ebdSchin if(slp && slp->slptr)
849da2e3ebdSchin {
8507c2fbfb3SApril Chin shp->st.staklist = slp->slnext;
851da2e3ebdSchin stakdelete(slp->slptr);
852da2e3ebdSchin }
8537c2fbfb3SApril Chin siglongjmp(*shp->jmplist,jmpval);
854da2e3ebdSchin }
8557c2fbfb3SApril Chin shp->st.staklist = (struct slnod*)slp;
856da2e3ebdSchin last = fctell();
857da2e3ebdSchin fp->functline = (last-first);
858da2e3ebdSchin fp->functtre = t;
8597c2fbfb3SApril Chin shp->mktype = in_mktype;
8607c2fbfb3SApril Chin if(lexp->sh->funlog)
861da2e3ebdSchin {
862da2e3ebdSchin if(fcfill()>0)
863da2e3ebdSchin fcseek(-1);
8647c2fbfb3SApril Chin lexp->sh->funlog = 0;
865da2e3ebdSchin }
866da2e3ebdSchin #if SHOPT_KIA
8677c2fbfb3SApril Chin if(lexp->kiafile)
8687c2fbfb3SApril Chin kiaentity(lexp,t->funct.functnam,-1,'p',t->funct.functline,shp->inlineno-1,lexp->current,'p',0,"");
869da2e3ebdSchin #endif /* SHOPT_KIA */
8707c2fbfb3SApril Chin t->funct.functtyp |= opt_get;
8717c2fbfb3SApril Chin opt_get = save_optget;
872da2e3ebdSchin return(t);
873da2e3ebdSchin }
874da2e3ebdSchin
875da2e3ebdSchin /*
876da2e3ebdSchin * Compound assignment
877da2e3ebdSchin */
assign(Lex_t * lexp,register struct argnod * ap,int tdef)8787c2fbfb3SApril Chin static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int tdef)
879da2e3ebdSchin {
880da2e3ebdSchin register int n;
881da2e3ebdSchin register Shnode_t *t, **tp;
882da2e3ebdSchin register struct comnod *ac;
8837c2fbfb3SApril Chin Stk_t *stkp = lexp->sh->stk;
884da2e3ebdSchin int array=0;
885da2e3ebdSchin Namval_t *np;
886da2e3ebdSchin n = strlen(ap->argval)-1;
887da2e3ebdSchin if(ap->argval[n]!='=')
8887c2fbfb3SApril Chin sh_syntax(lexp);
889da2e3ebdSchin if(ap->argval[n-1]=='+')
890da2e3ebdSchin {
891da2e3ebdSchin ap->argval[n--]=0;
892da2e3ebdSchin array = ARG_APPEND;
893da2e3ebdSchin }
894da2e3ebdSchin /* shift right */
895da2e3ebdSchin while(n > 0)
896da2e3ebdSchin {
897da2e3ebdSchin ap->argval[n] = ap->argval[n-1];
898da2e3ebdSchin n--;
899da2e3ebdSchin }
900da2e3ebdSchin *ap->argval=0;
901da2e3ebdSchin t = getnode(fornod);
902da2e3ebdSchin t->for_.fornam = (char*)(ap->argval+1);
9037c2fbfb3SApril Chin t->for_.fortyp = sh_getlineno(lexp);
904da2e3ebdSchin tp = &t->for_.fortre;
905da2e3ebdSchin ap->argchn.ap = (struct argnod*)t;
906da2e3ebdSchin ap->argflag &= ARG_QUOTED;
907da2e3ebdSchin ap->argflag |= array;
9087c2fbfb3SApril Chin lexp->assignok = SH_ASSIGN;
9097c2fbfb3SApril Chin lexp->aliasok = 1;
910da2e3ebdSchin array=0;
9117c2fbfb3SApril Chin if((n=skipnl(lexp,0))==RPAREN || n==LPAREN)
912da2e3ebdSchin {
913da2e3ebdSchin int index= 0;
914da2e3ebdSchin struct argnod **settail;
915da2e3ebdSchin ac = (struct comnod*)getnode(comnod);
916da2e3ebdSchin settail= &ac->comset;
917da2e3ebdSchin memset((void*)ac,0,sizeof(*ac));
9187c2fbfb3SApril Chin ac->comline = sh_getlineno(lexp);
919da2e3ebdSchin while(n==LPAREN)
920da2e3ebdSchin {
921da2e3ebdSchin struct argnod *ap;
9227c2fbfb3SApril Chin ap = (struct argnod*)stkseek(stkp,ARGVAL);
923da2e3ebdSchin ap->argflag= ARG_ASSIGN;
9247c2fbfb3SApril Chin sfprintf(stkp,"[%d]=",index++);
9257c2fbfb3SApril Chin ap = (struct argnod*)stkfreeze(stkp,1);
926da2e3ebdSchin ap->argnxt.ap = 0;
9277c2fbfb3SApril Chin ap = assign(lexp,ap,0);
928da2e3ebdSchin ap->argflag |= ARG_MESSAGE;
929da2e3ebdSchin *settail = ap;
930da2e3ebdSchin settail = &(ap->argnxt.ap);
9317c2fbfb3SApril Chin while((n = skipnl(lexp,0))==0)
9327c2fbfb3SApril Chin {
9337c2fbfb3SApril Chin ap = (struct argnod*)stkseek(stkp,ARGVAL);
9347c2fbfb3SApril Chin ap->argflag= ARG_ASSIGN;
9357c2fbfb3SApril Chin sfprintf(stkp,"[%d]=",index++);
9367c2fbfb3SApril Chin stakputs(lexp->arg->argval);
9377c2fbfb3SApril Chin ap = (struct argnod*)stkfreeze(stkp,1);
9387c2fbfb3SApril Chin ap->argnxt.ap = 0;
9397c2fbfb3SApril Chin ap->argflag = lexp->arg->argflag;
9407c2fbfb3SApril Chin *settail = ap;
9417c2fbfb3SApril Chin settail = &(ap->argnxt.ap);
942da2e3ebdSchin }
943da2e3ebdSchin }
9447c2fbfb3SApril Chin }
9457c2fbfb3SApril Chin else if(n && n!=FUNCTSYM)
9467c2fbfb3SApril Chin sh_syntax(lexp);
9477c2fbfb3SApril Chin 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)))
9487c2fbfb3SApril Chin {
949da2e3ebdSchin array=SH_ARRAY;
9507c2fbfb3SApril Chin if(fcgetc(n)==LPAREN)
9517c2fbfb3SApril Chin {
9527c2fbfb3SApril Chin int c;
9537c2fbfb3SApril Chin if(fcgetc(c)==RPAREN)
9547c2fbfb3SApril Chin {
9557c2fbfb3SApril Chin lexp->token = SYMRES;
9567c2fbfb3SApril Chin array = 0;
9577c2fbfb3SApril Chin }
9587c2fbfb3SApril Chin else
9597c2fbfb3SApril Chin fcseek(-2);
9607c2fbfb3SApril Chin }
9617c2fbfb3SApril Chin else if(n>0)
9627c2fbfb3SApril Chin fcseek(-1);
9637c2fbfb3SApril Chin if(array && tdef)
9647c2fbfb3SApril Chin sh_syntax(lexp);
9657c2fbfb3SApril Chin }
966da2e3ebdSchin while(1)
967da2e3ebdSchin {
9687c2fbfb3SApril Chin if((n=lexp->token)==RPAREN)
969da2e3ebdSchin break;
970da2e3ebdSchin if(n==FUNCTSYM || n==SYMRES)
9717c2fbfb3SApril Chin ac = (struct comnod*)funct(lexp);
972da2e3ebdSchin else
9737c2fbfb3SApril Chin ac = (struct comnod*)simple(lexp,SH_NOIO|SH_ASSIGN|array,NIL(struct ionod*));
9747c2fbfb3SApril Chin if((n=lexp->token)==RPAREN)
975da2e3ebdSchin break;
976da2e3ebdSchin if(n!=NL && n!=';')
9777c2fbfb3SApril Chin sh_syntax(lexp);
9787c2fbfb3SApril Chin lexp->assignok = SH_ASSIGN;
9797c2fbfb3SApril Chin if((n=skipnl(lexp,0)) || array)
980da2e3ebdSchin {
981da2e3ebdSchin if(n==RPAREN)
982da2e3ebdSchin break;
983da2e3ebdSchin if(array || n!=FUNCTSYM)
9847c2fbfb3SApril Chin sh_syntax(lexp);
985da2e3ebdSchin }
9867c2fbfb3SApril Chin if((n!=FUNCTSYM) && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)||np==SYSDOT)))
987da2e3ebdSchin {
9887c2fbfb3SApril Chin struct argnod *arg = lexp->arg;
989da2e3ebdSchin if(n!=0)
9907c2fbfb3SApril Chin sh_syntax(lexp);
991da2e3ebdSchin /* check for sys5 style function */
9927c2fbfb3SApril Chin if(sh_lex(lexp)!=LPAREN || sh_lex(lexp)!=RPAREN)
993da2e3ebdSchin {
9947c2fbfb3SApril Chin lexp->arg = arg;
9957c2fbfb3SApril Chin lexp->token = 0;
9967c2fbfb3SApril Chin sh_syntax(lexp);
997da2e3ebdSchin }
9987c2fbfb3SApril Chin lexp->arg = arg;
9997c2fbfb3SApril Chin lexp->token = SYMRES;
1000da2e3ebdSchin }
10017c2fbfb3SApril Chin t = makelist(lexp,TLST,(Shnode_t*)ac,t);
1002da2e3ebdSchin *tp = t;
1003da2e3ebdSchin tp = &t->lst.lstrit;
1004da2e3ebdSchin }
1005da2e3ebdSchin *tp = (Shnode_t*)ac;
10067c2fbfb3SApril Chin lexp->assignok = 0;
1007da2e3ebdSchin return(ap);
1008da2e3ebdSchin }
1009da2e3ebdSchin
1010da2e3ebdSchin /*
1011da2e3ebdSchin * item
1012da2e3ebdSchin *
1013da2e3ebdSchin * ( cmd ) [ < in ] [ > out ]
1014da2e3ebdSchin * word word* [ < in ] [ > out ]
1015da2e3ebdSchin * if ... then ... else ... fi
1016da2e3ebdSchin * for ... while ... do ... done
1017da2e3ebdSchin * case ... in ... esac
1018da2e3ebdSchin * begin ... end
1019da2e3ebdSchin */
1020da2e3ebdSchin
item(Lex_t * lexp,int flag)10217c2fbfb3SApril Chin static Shnode_t *item(Lex_t *lexp,int flag)
1022da2e3ebdSchin {
1023da2e3ebdSchin register Shnode_t *t;
1024da2e3ebdSchin register struct ionod *io;
10257c2fbfb3SApril Chin register int tok = (lexp->token&0xff);
10267c2fbfb3SApril Chin int savwdval = lexp->lasttok;
10277c2fbfb3SApril Chin int savline = lexp->lastline;
10287c2fbfb3SApril Chin int showme=0, comsub;
10297c2fbfb3SApril Chin if(!(flag&SH_NOIO) && (tok=='<' || tok=='>' || lexp->token==IOVNAME))
10307c2fbfb3SApril Chin io=inout(lexp,NIL(struct ionod*),1);
1031da2e3ebdSchin else
1032da2e3ebdSchin io=0;
10337c2fbfb3SApril Chin if((tok=lexp->token) && tok!=EOFSYM && tok!=FUNCTSYM)
1034da2e3ebdSchin {
10357c2fbfb3SApril Chin lexp->lastline = sh_getlineno(lexp);
10367c2fbfb3SApril Chin lexp->lasttok = lexp->token;
1037da2e3ebdSchin }
1038da2e3ebdSchin switch(tok)
1039da2e3ebdSchin {
1040da2e3ebdSchin /* [[ ... ]] test expression */
1041da2e3ebdSchin case BTESTSYM:
10427c2fbfb3SApril Chin t = test_expr(lexp,ETESTSYM);
1043da2e3ebdSchin t->tre.tretyp &= ~TTEST;
1044da2e3ebdSchin break;
1045da2e3ebdSchin /* ((...)) arithmetic expression */
1046da2e3ebdSchin case EXPRSYM:
10477c2fbfb3SApril Chin t = getanode(lexp,lexp->arg);
10487c2fbfb3SApril Chin sh_lex(lexp);
1049da2e3ebdSchin goto done;
1050da2e3ebdSchin
1051da2e3ebdSchin /* case statement */
1052da2e3ebdSchin case CASESYM:
1053da2e3ebdSchin {
10547c2fbfb3SApril Chin int savetok = lexp->lasttok;
10557c2fbfb3SApril Chin int saveline = lexp->lastline;
1056da2e3ebdSchin t = getnode(swnod);
10577c2fbfb3SApril Chin if(sh_lex(lexp))
10587c2fbfb3SApril Chin sh_syntax(lexp);
10597c2fbfb3SApril Chin t->sw.swarg=lexp->arg;
1060da2e3ebdSchin t->sw.swtyp=TSW;
1061da2e3ebdSchin t->sw.swio = 0;
1062da2e3ebdSchin t->sw.swtyp |= FLINENO;
10637c2fbfb3SApril Chin t->sw.swline = lexp->sh->inlineno;
10647c2fbfb3SApril Chin if((tok=skipnl(lexp,0))!=INSYM && tok!=LBRACE)
10657c2fbfb3SApril Chin sh_syntax(lexp);
10667c2fbfb3SApril Chin if(!(t->sw.swlst=syncase(lexp,tok==INSYM?ESACSYM:RBRACE)) && lexp->token==EOFSYM)
1067da2e3ebdSchin {
10687c2fbfb3SApril Chin lexp->lasttok = savetok;
10697c2fbfb3SApril Chin lexp->lastline = saveline;
10707c2fbfb3SApril Chin sh_syntax(lexp);
1071da2e3ebdSchin }
1072da2e3ebdSchin break;
1073da2e3ebdSchin }
1074da2e3ebdSchin
1075da2e3ebdSchin /* if statement */
1076da2e3ebdSchin case IFSYM:
1077da2e3ebdSchin {
1078da2e3ebdSchin register Shnode_t *tt;
1079da2e3ebdSchin t = getnode(ifnod);
1080da2e3ebdSchin t->if_.iftyp=TIF;
10817c2fbfb3SApril Chin t->if_.iftre=sh_cmd(lexp,THENSYM,SH_NL);
10827c2fbfb3SApril Chin t->if_.thtre=sh_cmd(lexp,ELSESYM,SH_NL|SH_SEMI);
10837c2fbfb3SApril Chin tok = lexp->token;
10847c2fbfb3SApril Chin t->if_.eltre=(tok==ELSESYM?sh_cmd(lexp,FISYM,SH_NL|SH_SEMI):
10857c2fbfb3SApril Chin (tok==ELIFSYM?(lexp->token=IFSYM, tt=item(lexp,SH_NOIO)):0));
1086da2e3ebdSchin if(tok==ELIFSYM)
1087da2e3ebdSchin {
1088da2e3ebdSchin if(!tt || tt->tre.tretyp!=TSETIO)
1089da2e3ebdSchin goto done;
1090da2e3ebdSchin t->if_.eltre = tt->fork.forktre;
1091da2e3ebdSchin tt->fork.forktre = t;
1092da2e3ebdSchin t = tt;
1093da2e3ebdSchin goto done;
1094da2e3ebdSchin }
1095da2e3ebdSchin break;
1096da2e3ebdSchin }
1097da2e3ebdSchin
1098da2e3ebdSchin /* for and select statement */
1099da2e3ebdSchin case FORSYM:
1100da2e3ebdSchin case SELECTSYM:
1101da2e3ebdSchin {
1102da2e3ebdSchin t = getnode(fornod);
11037c2fbfb3SApril Chin t->for_.fortyp=(lexp->token==FORSYM?TFOR:TSELECT);
1104da2e3ebdSchin t->for_.forlst=0;
11057c2fbfb3SApril Chin t->for_.forline = lexp->sh->inlineno;
11067c2fbfb3SApril Chin if(sh_lex(lexp))
1107da2e3ebdSchin {
11087c2fbfb3SApril Chin if(lexp->token!=EXPRSYM || t->for_.fortyp!=TFOR)
11097c2fbfb3SApril Chin sh_syntax(lexp);
1110da2e3ebdSchin /* arithmetic for */
11117c2fbfb3SApril Chin t = arithfor(lexp,t);
1112da2e3ebdSchin break;
1113da2e3ebdSchin }
11147c2fbfb3SApril Chin t->for_.fornam=(char*) lexp->arg->argval;
1115da2e3ebdSchin t->for_.fortyp |= FLINENO;
1116da2e3ebdSchin #if SHOPT_KIA
11177c2fbfb3SApril Chin if(lexp->kiafile)
11187c2fbfb3SApril Chin writedefs(lexp,lexp->arg,lexp->sh->inlineno,'v',NIL(struct argnod*));
1119da2e3ebdSchin #endif /* SHOPT_KIA */
11207c2fbfb3SApril Chin while((tok=sh_lex(lexp))==NL);
1121da2e3ebdSchin if(tok==INSYM)
1122da2e3ebdSchin {
11237c2fbfb3SApril Chin if(sh_lex(lexp))
1124da2e3ebdSchin {
11257c2fbfb3SApril Chin if(lexp->token != NL && lexp->token !=';')
11267c2fbfb3SApril Chin sh_syntax(lexp);
1127da2e3ebdSchin /* some Linux scripts assume this */
1128da2e3ebdSchin if(sh_isoption(SH_NOEXEC))
11297c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexemptyfor,lexp->sh->inlineno-(lexp->token=='\n'));
1130da2e3ebdSchin t->for_.forlst = (struct comnod*)getnode(comnod);
1131da2e3ebdSchin (t->for_.forlst)->comarg = 0;
1132da2e3ebdSchin (t->for_.forlst)->comset = 0;
1133da2e3ebdSchin (t->for_.forlst)->comnamp = 0;
1134da2e3ebdSchin (t->for_.forlst)->comnamq = 0;
1135da2e3ebdSchin (t->for_.forlst)->comstate = 0;
1136da2e3ebdSchin (t->for_.forlst)->comio = 0;
1137da2e3ebdSchin (t->for_.forlst)->comtyp = 0;
1138da2e3ebdSchin }
1139da2e3ebdSchin else
11407c2fbfb3SApril Chin t->for_.forlst=(struct comnod*)simple(lexp,SH_NOIO,NIL(struct ionod*));
11417c2fbfb3SApril Chin if(lexp->token != NL && lexp->token !=';')
11427c2fbfb3SApril Chin sh_syntax(lexp);
11437c2fbfb3SApril Chin tok = skipnl(lexp,0);
1144da2e3ebdSchin }
1145da2e3ebdSchin /* 'for i;do cmd' is valid syntax */
1146da2e3ebdSchin else if(tok==';')
11477c2fbfb3SApril Chin tok=sh_lex(lexp);
1148da2e3ebdSchin if(tok!=DOSYM && tok!=LBRACE)
11497c2fbfb3SApril Chin sh_syntax(lexp);
1150da2e3ebdSchin loop_level++;
11517c2fbfb3SApril Chin t->for_.fortre=sh_cmd(lexp,tok==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
1152da2e3ebdSchin if(--loop_level==0)
1153da2e3ebdSchin label_last = label_list;
1154da2e3ebdSchin break;
1155da2e3ebdSchin }
1156da2e3ebdSchin
1157da2e3ebdSchin /* This is the code for parsing function definitions */
1158da2e3ebdSchin case FUNCTSYM:
11597c2fbfb3SApril Chin return(funct(lexp));
1160da2e3ebdSchin
1161da2e3ebdSchin #if SHOPT_NAMESPACE
1162da2e3ebdSchin case NSPACESYM:
1163da2e3ebdSchin t = getnode(fornod);
1164da2e3ebdSchin t->for_.fortyp=TNSPACE;
1165da2e3ebdSchin t->for_.forlst=0;
11667c2fbfb3SApril Chin if(sh_lex(lexp))
11677c2fbfb3SApril Chin sh_syntax(lexp);
11687c2fbfb3SApril Chin t->for_.fornam=(char*) lexp->arg->argval;
11697c2fbfb3SApril Chin while((tok=sh_lex(lexp))==NL);
1170da2e3ebdSchin if(tok!=LBRACE)
11717c2fbfb3SApril Chin sh_syntax(lexp);
11727c2fbfb3SApril Chin t->for_.fortre = sh_cmd(lexp,RBRACE,SH_NL);
1173da2e3ebdSchin break;
1174da2e3ebdSchin #endif /* SHOPT_NAMESPACE */
1175da2e3ebdSchin
1176da2e3ebdSchin /* while and until */
1177da2e3ebdSchin case WHILESYM:
1178da2e3ebdSchin case UNTILSYM:
1179da2e3ebdSchin t = getnode(whnod);
11807c2fbfb3SApril Chin t->wh.whtyp=(lexp->token==WHILESYM ? TWH : TUN);
1181da2e3ebdSchin loop_level++;
11827c2fbfb3SApril Chin t->wh.whtre = sh_cmd(lexp,DOSYM,SH_NL);
11837c2fbfb3SApril Chin t->wh.dotre = sh_cmd(lexp,DONESYM,SH_NL|SH_SEMI);
1184da2e3ebdSchin if(--loop_level==0)
1185da2e3ebdSchin label_last = label_list;
1186da2e3ebdSchin t->wh.whinc = 0;
1187da2e3ebdSchin break;
1188da2e3ebdSchin
1189da2e3ebdSchin case LABLSYM:
1190da2e3ebdSchin {
1191da2e3ebdSchin register struct argnod *argp = label_list;
1192da2e3ebdSchin while(argp)
1193da2e3ebdSchin {
11947c2fbfb3SApril Chin if(strcmp(argp->argval,lexp->arg->argval)==0)
11957c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax3,lexp->sh->inlineno,argp->argval);
1196da2e3ebdSchin argp = argp->argnxt.ap;
1197da2e3ebdSchin }
11987c2fbfb3SApril Chin lexp->arg->argnxt.ap = label_list;
11997c2fbfb3SApril Chin label_list = lexp->arg;
12007c2fbfb3SApril Chin label_list->argchn.len = sh_getlineno(lexp);
1201da2e3ebdSchin label_list->argflag = loop_level;
12027c2fbfb3SApril Chin skipnl(lexp,flag);
12037c2fbfb3SApril Chin if(!(t = item(lexp,SH_NL)))
12047c2fbfb3SApril Chin sh_syntax(lexp);
1205da2e3ebdSchin tok = (t->tre.tretyp&(COMSCAN|COMSCAN-1));
1206da2e3ebdSchin if(sh_isoption(SH_NOEXEC) && tok!=TWH && tok!=TUN && tok!=TFOR && tok!=TSELECT)
1207da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexlabignore,label_list->argchn.len,label_list->argval);
1208da2e3ebdSchin return(t);
1209da2e3ebdSchin }
1210da2e3ebdSchin
1211da2e3ebdSchin /* command group with {...} */
1212da2e3ebdSchin case LBRACE:
12137c2fbfb3SApril Chin comsub = lexp->comsub;
12147c2fbfb3SApril Chin lexp->comsub = 0;
121534f9b3eeSRoland Mainz t = sh_cmd(lexp,RBRACE,SH_NL|SH_SEMI);
12167c2fbfb3SApril Chin lexp->comsub = comsub;
1217da2e3ebdSchin break;
1218da2e3ebdSchin
1219da2e3ebdSchin case LPAREN:
1220da2e3ebdSchin t = getnode(parnod);
122134f9b3eeSRoland Mainz t->par.partre=sh_cmd(lexp,RPAREN,SH_NL|SH_SEMI);
1222da2e3ebdSchin t->par.partyp=TPAR;
1223da2e3ebdSchin break;
1224da2e3ebdSchin
1225da2e3ebdSchin default:
1226da2e3ebdSchin if(io==0)
1227da2e3ebdSchin return(0);
1228da2e3ebdSchin
1229da2e3ebdSchin case ';':
1230da2e3ebdSchin if(io==0)
1231da2e3ebdSchin {
1232da2e3ebdSchin if(!(flag&SH_SEMI))
1233da2e3ebdSchin return(0);
12347c2fbfb3SApril Chin if(sh_lex(lexp)==';')
12357c2fbfb3SApril Chin sh_syntax(lexp);
1236da2e3ebdSchin showme = FSHOWME;
1237da2e3ebdSchin }
1238da2e3ebdSchin /* simple command */
1239da2e3ebdSchin case 0:
12407c2fbfb3SApril Chin t = (Shnode_t*)simple(lexp,flag,io);
12417c2fbfb3SApril Chin if(t->com.comarg && lexp->intypeset && (lexp->sh->shcomp || sh_isoption(SH_NOEXEC) || sh.dot_depth))
12427c2fbfb3SApril Chin check_typedef(&t->com);
12437c2fbfb3SApril Chin lexp->intypeset = 0;
12447c2fbfb3SApril Chin lexp->inexec = 0;
1245da2e3ebdSchin t->tre.tretyp |= showme;
1246da2e3ebdSchin return(t);
1247da2e3ebdSchin }
12487c2fbfb3SApril Chin sh_lex(lexp);
12497c2fbfb3SApril Chin if(io=inout(lexp,io,0))
1250da2e3ebdSchin {
1251da2e3ebdSchin if((tok=t->tre.tretyp&COMMSK) != TFORK)
1252da2e3ebdSchin tok = TSETIO;
12537c2fbfb3SApril Chin t=makeparent(lexp,tok,t);
1254da2e3ebdSchin t->tre.treio=io;
1255da2e3ebdSchin }
1256da2e3ebdSchin done:
12577c2fbfb3SApril Chin lexp->lasttok = savwdval;
12587c2fbfb3SApril Chin lexp->lastline = savline;
1259da2e3ebdSchin return(t);
1260da2e3ebdSchin }
1261da2e3ebdSchin
process_sub(Lex_t * lexp,int tok)126234f9b3eeSRoland Mainz static struct argnod *process_sub(Lex_t *lexp,int tok)
126334f9b3eeSRoland Mainz {
126434f9b3eeSRoland Mainz struct argnod *argp;
126534f9b3eeSRoland Mainz Shnode_t *t;
126634f9b3eeSRoland Mainz int mode = (tok==OPROCSYM);
126734f9b3eeSRoland Mainz t = sh_cmd(lexp,RPAREN,SH_NL);
126834f9b3eeSRoland Mainz argp = (struct argnod*)stkalloc(lexp->sh->stk,sizeof(struct argnod));
126934f9b3eeSRoland Mainz *argp->argval = 0;
127034f9b3eeSRoland Mainz argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t);
127134f9b3eeSRoland Mainz argp->argflag = (ARG_EXP|mode);
127234f9b3eeSRoland Mainz return(argp);
127334f9b3eeSRoland Mainz }
127434f9b3eeSRoland Mainz
127534f9b3eeSRoland Mainz
1276da2e3ebdSchin /*
1277da2e3ebdSchin * This is for a simple command, for list, or compound assignment
1278da2e3ebdSchin */
simple(Lex_t * lexp,int flag,struct ionod * io)12797c2fbfb3SApril Chin static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
1280da2e3ebdSchin {
1281da2e3ebdSchin register struct comnod *t;
1282da2e3ebdSchin register struct argnod *argp;
1283da2e3ebdSchin register int tok;
12847c2fbfb3SApril Chin Stk_t *stkp = lexp->sh->stk;
1285da2e3ebdSchin struct argnod **argtail;
1286da2e3ebdSchin struct argnod **settail;
12877c2fbfb3SApril Chin int cmdarg=0;
12887c2fbfb3SApril Chin int argno = 0, argmax=0;
1289da2e3ebdSchin int assignment = 0;
1290da2e3ebdSchin int key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
1291da2e3ebdSchin int associative=0;
12927c2fbfb3SApril Chin if((argp=lexp->arg) && (argp->argflag&ARG_ASSIGN) && argp->argval[0]=='[')
1293da2e3ebdSchin {
1294da2e3ebdSchin flag |= SH_ARRAY;
1295da2e3ebdSchin associative = 1;
1296da2e3ebdSchin }
1297da2e3ebdSchin t = (struct comnod*)getnode(comnod);
1298da2e3ebdSchin t->comio=io; /*initial io chain*/
1299da2e3ebdSchin /* set command line number for error messages */
13007c2fbfb3SApril Chin t->comline = sh_getlineno(lexp);
1301da2e3ebdSchin argtail = &(t->comarg);
1302da2e3ebdSchin t->comset = 0;
1303da2e3ebdSchin t->comnamp = 0;
1304da2e3ebdSchin t->comnamq = 0;
1305da2e3ebdSchin t->comstate = 0;
1306da2e3ebdSchin settail = &(t->comset);
13077c2fbfb3SApril Chin while(lexp->token==0)
1308da2e3ebdSchin {
13097c2fbfb3SApril Chin argp = lexp->arg;
1310da2e3ebdSchin if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
1311da2e3ebdSchin {
13127c2fbfb3SApril Chin lexp->token = LBRACE;
1313da2e3ebdSchin break;
1314da2e3ebdSchin }
1315da2e3ebdSchin if(associative && argp->argval[0]!='[')
13167c2fbfb3SApril Chin sh_syntax(lexp);
1317da2e3ebdSchin /* check for assignment argument */
1318da2e3ebdSchin if((argp->argflag&ARG_ASSIGN) && assignment!=2)
1319da2e3ebdSchin {
1320da2e3ebdSchin *settail = argp;
1321da2e3ebdSchin settail = &(argp->argnxt.ap);
13227c2fbfb3SApril Chin lexp->assignok = (flag&SH_ASSIGN)?SH_ASSIGN:1;
1323da2e3ebdSchin if(assignment)
1324da2e3ebdSchin {
1325da2e3ebdSchin struct argnod *ap=argp;
1326da2e3ebdSchin char *last, *cp;
1327da2e3ebdSchin if(assignment==1)
1328da2e3ebdSchin {
1329da2e3ebdSchin last = strchr(argp->argval,'=');
133034f9b3eeSRoland Mainz if(last && (last[-1]==']'|| (last[-1]=='+' && last[-2]==']')) && (cp=strchr(argp->argval,'[')) && (cp < last))
1331da2e3ebdSchin last = cp;
13327c2fbfb3SApril Chin stkseek(stkp,ARGVAL);
13337c2fbfb3SApril Chin sfwrite(stkp,argp->argval,last-argp->argval);
13347c2fbfb3SApril Chin ap=(struct argnod*)stkfreeze(stkp,1);
1335da2e3ebdSchin ap->argflag = ARG_RAW;
1336da2e3ebdSchin ap->argchn.ap = 0;
1337da2e3ebdSchin }
1338da2e3ebdSchin *argtail = ap;
1339da2e3ebdSchin argtail = &(ap->argnxt.ap);
1340da2e3ebdSchin if(argno>=0)
1341da2e3ebdSchin argno++;
1342da2e3ebdSchin }
1343da2e3ebdSchin else /* alias substitutions allowed */
13447c2fbfb3SApril Chin lexp->aliasok = 1;
1345da2e3ebdSchin }
1346da2e3ebdSchin else
1347da2e3ebdSchin {
1348da2e3ebdSchin if(!(argp->argflag&ARG_RAW))
13497c2fbfb3SApril Chin {
13507c2fbfb3SApril Chin if(argno>0)
13517c2fbfb3SApril Chin argmax = argno;
1352da2e3ebdSchin argno = -1;
13537c2fbfb3SApril Chin }
13547c2fbfb3SApril Chin if(argno>=0 && argno++==cmdarg && !(flag&SH_ARRAY) && *argp->argval!='/')
1355da2e3ebdSchin {
1356da2e3ebdSchin /* check for builtin command */
13577c2fbfb3SApril Chin Namval_t *np=nv_bfsearch(argp->argval,lexp->sh->fun_tree, (Namval_t**)&t->comnamq,(char**)0);
13587c2fbfb3SApril Chin if(cmdarg==0)
13597c2fbfb3SApril Chin t->comnamp = (void*)np;
13607c2fbfb3SApril Chin if(np && is_abuiltin(np))
13617c2fbfb3SApril Chin {
13627c2fbfb3SApril Chin if(nv_isattr(np,BLT_DCL))
1363da2e3ebdSchin {
1364da2e3ebdSchin assignment = 1+(*argp->argval=='a');
13657c2fbfb3SApril Chin if(np==SYSTYPESET)
13667c2fbfb3SApril Chin lexp->intypeset = 1;
1367da2e3ebdSchin key_on = 1;
1368da2e3ebdSchin }
13697c2fbfb3SApril Chin else if(np==SYSCOMMAND)
13707c2fbfb3SApril Chin cmdarg++;
13717c2fbfb3SApril Chin else if(np==SYSEXEC)
13727c2fbfb3SApril Chin lexp->inexec = 1;
13737c2fbfb3SApril Chin else if(np->nvalue.bfp==b_getopts)
13747c2fbfb3SApril Chin opt_get |= FOPTGET;
13757c2fbfb3SApril Chin }
1376da2e3ebdSchin }
1377da2e3ebdSchin *argtail = argp;
1378da2e3ebdSchin argtail = &(argp->argnxt.ap);
13797c2fbfb3SApril Chin if(!(lexp->assignok=key_on) && !(flag&SH_NOIO) && sh_isoption(SH_NOEXEC))
13807c2fbfb3SApril Chin lexp->assignok = SH_COMPASSIGN;
13817c2fbfb3SApril Chin lexp->aliasok = 0;
1382da2e3ebdSchin }
1383da2e3ebdSchin retry:
13847c2fbfb3SApril Chin tok = sh_lex(lexp);
13857c2fbfb3SApril Chin if(tok==LABLSYM && (flag&SH_ASSIGN))
13867c2fbfb3SApril Chin lexp->token = tok = 0;
1387da2e3ebdSchin #if SHOPT_DEVFD
1388da2e3ebdSchin if((tok==IPROCSYM || tok==OPROCSYM))
1389da2e3ebdSchin {
139034f9b3eeSRoland Mainz argp = process_sub(lexp,tok);
13917c2fbfb3SApril Chin argmax = 0;
1392da2e3ebdSchin argno = -1;
1393da2e3ebdSchin *argtail = argp;
1394da2e3ebdSchin argtail = &(argp->argnxt.ap);
1395da2e3ebdSchin goto retry;
1396da2e3ebdSchin }
1397da2e3ebdSchin #endif /* SHOPT_DEVFD */
1398da2e3ebdSchin if(tok==LPAREN)
1399da2e3ebdSchin {
1400da2e3ebdSchin if(argp->argflag&ARG_ASSIGN)
1401da2e3ebdSchin {
14027c2fbfb3SApril Chin int intypeset = lexp->intypeset;
14037c2fbfb3SApril Chin int tdef = 0;
14047c2fbfb3SApril Chin lexp->intypeset = 0;
14057c2fbfb3SApril Chin if(t->comnamp==SYSTYPESET && t->comarg->argnxt.ap && strcmp(t->comarg->argnxt.ap->argval,"-T")==0)
14067c2fbfb3SApril Chin tdef = 1;
14077c2fbfb3SApril Chin argp = assign(lexp,argp,tdef);
14087c2fbfb3SApril Chin lexp->intypeset = intypeset;
1409da2e3ebdSchin if(associative)
14107c2fbfb3SApril Chin lexp->assignok |= SH_ASSIGN;
1411da2e3ebdSchin goto retry;
1412da2e3ebdSchin }
1413da2e3ebdSchin else if(argno==1 && !t->comset)
1414da2e3ebdSchin {
1415da2e3ebdSchin /* SVR2 style function */
14167c2fbfb3SApril Chin if(sh_lex(lexp) == RPAREN)
1417da2e3ebdSchin {
14187c2fbfb3SApril Chin lexp->arg = argp;
14197c2fbfb3SApril Chin return(funct(lexp));
1420da2e3ebdSchin }
14217c2fbfb3SApril Chin lexp->token = LPAREN;
1422da2e3ebdSchin }
1423da2e3ebdSchin }
1424da2e3ebdSchin else if(flag&SH_ASSIGN)
1425da2e3ebdSchin {
1426da2e3ebdSchin if(tok==RPAREN)
1427da2e3ebdSchin break;
1428da2e3ebdSchin else if(tok==NL && (flag&SH_ARRAY))
14297c2fbfb3SApril Chin {
14307c2fbfb3SApril Chin lexp->comp_assign = 2;
1431da2e3ebdSchin goto retry;
1432da2e3ebdSchin }
14337c2fbfb3SApril Chin
14347c2fbfb3SApril Chin }
1435da2e3ebdSchin if(!(flag&SH_NOIO))
1436da2e3ebdSchin {
1437da2e3ebdSchin if(io)
1438da2e3ebdSchin {
1439da2e3ebdSchin while(io->ionxt)
1440da2e3ebdSchin io = io->ionxt;
14417c2fbfb3SApril Chin io->ionxt = inout(lexp,(struct ionod*)0,0);
1442da2e3ebdSchin }
1443da2e3ebdSchin else
14447c2fbfb3SApril Chin t->comio = io = inout(lexp,(struct ionod*)0,0);
1445da2e3ebdSchin }
1446da2e3ebdSchin }
1447da2e3ebdSchin *argtail = 0;
14487c2fbfb3SApril Chin if(argno>0)
14497c2fbfb3SApril Chin argmax = argno;
1450*3e14f97fSRoger A. Faulkner t->comtyp = TCOM;
1451da2e3ebdSchin #if SHOPT_KIA
14527c2fbfb3SApril Chin if(lexp->kiafile && !(flag&SH_NOIO))
1453da2e3ebdSchin {
1454da2e3ebdSchin register Namval_t *np=(Namval_t*)t->comnamp;
1455da2e3ebdSchin unsigned long r=0;
1456da2e3ebdSchin int line = t->comline;
1457da2e3ebdSchin argp = t->comarg;
1458da2e3ebdSchin if(np)
14597c2fbfb3SApril Chin r = kiaentity(lexp,nv_name(np),-1,'p',-1,0,lexp->unknown,'b',0,"");
1460da2e3ebdSchin else if(argp)
14617c2fbfb3SApril Chin r = kiaentity(lexp,sh_argstr(argp),-1,'p',-1,0,lexp->unknown,'c',0,"");
1462da2e3ebdSchin if(r>0)
14637c2fbfb3SApril Chin sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;c;\n",lexp->current,r,line,line);
1464da2e3ebdSchin if(t->comset && argno==0)
14657c2fbfb3SApril Chin writedefs(lexp,t->comset,line,'v',t->comarg);
1466da2e3ebdSchin else if(np && nv_isattr(np,BLT_DCL))
14677c2fbfb3SApril Chin writedefs(lexp,argp,line,0,NIL(struct argnod*));
1468da2e3ebdSchin else if(argp && strcmp(argp->argval,"read")==0)
14697c2fbfb3SApril Chin writedefs(lexp,argp,line,0,NIL(struct argnod*));
1470da2e3ebdSchin #if 0
1471da2e3ebdSchin else if(argp && strcmp(argp->argval,"unset")==0)
14727c2fbfb3SApril Chin writedefs(lexp,argp,line,'u',NIL(struct argnod*));
1473da2e3ebdSchin #endif
1474da2e3ebdSchin else if(argp && *argp->argval=='.' && argp->argval[1]==0 && (argp=argp->argnxt.ap))
1475da2e3ebdSchin {
14767c2fbfb3SApril Chin r = kiaentity(lexp,sh_argstr(argp),-1,'p',0,0,lexp->script,'d',0,"");
14777c2fbfb3SApril Chin sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;d;\n",lexp->current,r,line,line);
1478da2e3ebdSchin }
1479da2e3ebdSchin }
1480da2e3ebdSchin #endif /* SHOPT_KIA */
1481da2e3ebdSchin if(t->comnamp && (argp=t->comarg->argnxt.ap))
1482da2e3ebdSchin {
1483da2e3ebdSchin Namval_t *np=(Namval_t*)t->comnamp;
1484da2e3ebdSchin if((np==SYSBREAK || np==SYSCONT) && (argp->argflag&ARG_RAW) && !isdigit(*argp->argval))
1485da2e3ebdSchin {
1486da2e3ebdSchin register char *cp = argp->argval;
1487da2e3ebdSchin /* convert break/continue labels to numbers */
1488da2e3ebdSchin tok = 0;
1489da2e3ebdSchin for(argp=label_list;argp!=label_last;argp=argp->argnxt.ap)
1490da2e3ebdSchin {
1491da2e3ebdSchin if(strcmp(cp,argp->argval))
1492da2e3ebdSchin continue;
1493da2e3ebdSchin tok = loop_level-argp->argflag;
1494da2e3ebdSchin if(tok>=1)
1495da2e3ebdSchin {
1496da2e3ebdSchin argp = t->comarg->argnxt.ap;
1497da2e3ebdSchin if(tok>9)
1498da2e3ebdSchin {
1499da2e3ebdSchin argp->argval[1] = '0'+tok%10;
1500da2e3ebdSchin argp->argval[2] = 0;
1501da2e3ebdSchin tok /= 10;
1502da2e3ebdSchin }
1503da2e3ebdSchin else
1504da2e3ebdSchin argp->argval[1] = 0;
1505da2e3ebdSchin *argp->argval = '0'+tok;
1506da2e3ebdSchin }
1507da2e3ebdSchin break;
1508da2e3ebdSchin }
1509da2e3ebdSchin if(sh_isoption(SH_NOEXEC) && tok==0)
15107c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexlabunknown,lexp->sh->inlineno-(lexp->token=='\n'),cp);
1511da2e3ebdSchin }
1512da2e3ebdSchin else if(sh_isoption(SH_NOEXEC) && np==SYSSET && ((tok= *argp->argval)=='-'||tok=='+') &&
1513da2e3ebdSchin (argp->argval[1]==0||strchr(argp->argval,'k')))
15147c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete5,lexp->sh->inlineno-(lexp->token=='\n'),argp->argval);
1515da2e3ebdSchin }
1516da2e3ebdSchin /* expand argument list if possible */
1517da2e3ebdSchin if(argno>0)
1518da2e3ebdSchin t->comarg = qscan(t,argno);
1519da2e3ebdSchin else if(t->comarg)
1520da2e3ebdSchin t->comtyp |= COMSCAN;
15217c2fbfb3SApril Chin lexp->aliasok = 0;
1522da2e3ebdSchin return((Shnode_t*)t);
1523da2e3ebdSchin }
1524da2e3ebdSchin
1525da2e3ebdSchin /*
1526da2e3ebdSchin * skip past newlines but issue prompt if interactive
1527da2e3ebdSchin */
skipnl(Lex_t * lexp,int flag)15287c2fbfb3SApril Chin static int skipnl(Lex_t *lexp,int flag)
1529da2e3ebdSchin {
1530da2e3ebdSchin register int token;
15317c2fbfb3SApril Chin while((token=sh_lex(lexp))==NL);
1532da2e3ebdSchin if(token==';' && !(flag&SH_SEMI))
15337c2fbfb3SApril Chin sh_syntax(lexp);
1534da2e3ebdSchin return(token);
1535da2e3ebdSchin }
1536da2e3ebdSchin
1537da2e3ebdSchin /*
1538da2e3ebdSchin * check for and process and i/o redirections
1539da2e3ebdSchin * if flag>0 then an alias can be in the next word
1540da2e3ebdSchin * if flag<0 only one redirection will be processed
1541da2e3ebdSchin */
inout(Lex_t * lexp,struct ionod * lastio,int flag)15427c2fbfb3SApril Chin static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag)
1543da2e3ebdSchin {
15447c2fbfb3SApril Chin register int iof = lexp->digits, token=lexp->token;
1545da2e3ebdSchin register struct ionod *iop;
15467c2fbfb3SApril Chin Stk_t *stkp = lexp->sh->stk;
1547da2e3ebdSchin char *iovname=0;
1548da2e3ebdSchin register int errout=0;
1549da2e3ebdSchin if(token==IOVNAME)
1550da2e3ebdSchin {
15517c2fbfb3SApril Chin iovname=lexp->arg->argval+1;
15527c2fbfb3SApril Chin token= sh_lex(lexp);
1553da2e3ebdSchin iof = 0;
1554da2e3ebdSchin }
1555da2e3ebdSchin switch(token&0xff)
1556da2e3ebdSchin {
1557da2e3ebdSchin case '<':
1558da2e3ebdSchin if(token==IODOCSYM)
1559da2e3ebdSchin iof |= (IODOC|IORAW);
1560da2e3ebdSchin else if(token==IOMOV0SYM)
1561da2e3ebdSchin iof |= IOMOV;
156234f9b3eeSRoland Mainz else if(token==IORDWRSYMT)
156334f9b3eeSRoland Mainz iof |= IORDW|IOREWRITE;
1564da2e3ebdSchin else if(token==IORDWRSYM)
1565da2e3ebdSchin iof |= IORDW;
1566da2e3ebdSchin else if((token&SYMSHARP) == SYMSHARP)
1567da2e3ebdSchin {
1568da2e3ebdSchin int n;
1569da2e3ebdSchin iof |= IOLSEEK;
1570da2e3ebdSchin if(fcgetc(n)=='#')
1571da2e3ebdSchin iof |= IOCOPY;
1572da2e3ebdSchin else if(n>0)
1573da2e3ebdSchin fcseek(-1);
1574da2e3ebdSchin }
1575da2e3ebdSchin break;
1576da2e3ebdSchin
1577da2e3ebdSchin case '>':
1578da2e3ebdSchin if(iof<0)
1579da2e3ebdSchin {
1580da2e3ebdSchin errout = 1;
1581da2e3ebdSchin iof = 1;
1582da2e3ebdSchin }
1583da2e3ebdSchin iof |= IOPUT;
1584da2e3ebdSchin if(token==IOAPPSYM)
1585da2e3ebdSchin iof |= IOAPP;
1586da2e3ebdSchin else if(token==IOMOV1SYM)
1587da2e3ebdSchin iof |= IOMOV;
1588da2e3ebdSchin else if(token==IOCLOBSYM)
1589da2e3ebdSchin iof |= IOCLOB;
1590da2e3ebdSchin else if((token&SYMSHARP) == SYMSHARP)
1591da2e3ebdSchin iof |= IOLSEEK;
15927c2fbfb3SApril Chin else if((token&SYMSEMI) == SYMSEMI)
15937c2fbfb3SApril Chin iof |= IOREWRITE;
1594da2e3ebdSchin break;
1595da2e3ebdSchin
1596da2e3ebdSchin default:
1597da2e3ebdSchin return(lastio);
1598da2e3ebdSchin }
15997c2fbfb3SApril Chin lexp->digits=0;
16007c2fbfb3SApril Chin iop=(struct ionod*) stkalloc(stkp,sizeof(struct ionod));
1601da2e3ebdSchin iop->iodelim = 0;
16027c2fbfb3SApril Chin if(token=sh_lex(lexp))
1603da2e3ebdSchin {
16047c2fbfb3SApril Chin if(token==RPAREN && (iof&IOLSEEK) && lexp->comsub)
1605da2e3ebdSchin {
16067c2fbfb3SApril Chin lexp->arg = (struct argnod*)stkalloc(stkp,sizeof(struct argnod)+3);
16077c2fbfb3SApril Chin strcpy(lexp->arg->argval,"CUR");
16087c2fbfb3SApril Chin lexp->arg->argflag = ARG_RAW;
1609da2e3ebdSchin iof |= IOARITH;
1610da2e3ebdSchin fcseek(-1);
1611da2e3ebdSchin }
1612da2e3ebdSchin else if(token==EXPRSYM && (iof&IOLSEEK))
1613da2e3ebdSchin iof |= IOARITH;
161434f9b3eeSRoland Mainz else if(((token==IPROCSYM && !(iof&IOPUT)) || (token==OPROCSYM && (iof&IOPUT))) && !(iof&(IOLSEEK|IOREWRITE|IOMOV|IODOC)))
161534f9b3eeSRoland Mainz {
161634f9b3eeSRoland Mainz lexp->arg = process_sub(lexp,token);
161734f9b3eeSRoland Mainz iof |= IOPROCSUB;
161834f9b3eeSRoland Mainz }
1619da2e3ebdSchin else
16207c2fbfb3SApril Chin sh_syntax(lexp);
1621da2e3ebdSchin }
162234f9b3eeSRoland Mainz if( (iof&IOPROCSUB) && !(iof&IOLSEEK))
162334f9b3eeSRoland Mainz iop->ioname= (char*)lexp->arg->argchn.ap;
162434f9b3eeSRoland Mainz else
16257c2fbfb3SApril Chin iop->ioname=lexp->arg->argval;
1626da2e3ebdSchin iop->iovname = iovname;
1627da2e3ebdSchin if(iof&IODOC)
1628da2e3ebdSchin {
16297c2fbfb3SApril Chin if(lexp->digits==2)
1630da2e3ebdSchin {
1631da2e3ebdSchin iof |= IOSTRG;
16327c2fbfb3SApril Chin if(!(lexp->arg->argflag&ARG_RAW))
1633da2e3ebdSchin iof &= ~IORAW;
1634da2e3ebdSchin }
1635da2e3ebdSchin else
1636da2e3ebdSchin {
16377c2fbfb3SApril Chin if(!lexp->sh->heredocs)
16387c2fbfb3SApril Chin lexp->sh->heredocs = sftmp(HERE_MEM);
16397c2fbfb3SApril Chin iop->iolst=lexp->heredoc;
16407c2fbfb3SApril Chin lexp->heredoc=iop;
16417c2fbfb3SApril Chin if(lexp->arg->argflag&ARG_QUOTED)
1642da2e3ebdSchin iof |= IOQUOTE;
16437c2fbfb3SApril Chin if(lexp->digits==3)
1644da2e3ebdSchin iof |= IOLSEEK;
16457c2fbfb3SApril Chin if(lexp->digits)
1646da2e3ebdSchin iof |= IOSTRIP;
1647da2e3ebdSchin }
1648da2e3ebdSchin }
1649da2e3ebdSchin else
1650da2e3ebdSchin {
1651da2e3ebdSchin iop->iolst = 0;
16527c2fbfb3SApril Chin if(lexp->arg->argflag&ARG_RAW)
1653da2e3ebdSchin iof |= IORAW;
1654da2e3ebdSchin }
1655da2e3ebdSchin iop->iofile=iof;
1656da2e3ebdSchin if(flag>0)
1657da2e3ebdSchin /* allow alias substitutions and parameter assignments */
16587c2fbfb3SApril Chin lexp->aliasok = lexp->assignok = 1;
1659da2e3ebdSchin #if SHOPT_KIA
16607c2fbfb3SApril Chin if(lexp->kiafile)
1661da2e3ebdSchin {
16627c2fbfb3SApril Chin int n = lexp->sh->inlineno-(lexp->token=='\n');
1663da2e3ebdSchin if(!(iof&IOMOV))
1664da2e3ebdSchin {
16657c2fbfb3SApril Chin unsigned long r=kiaentity(lexp,(iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,lexp->script,'f',0,"");
16667c2fbfb3SApril Chin sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;%c;%d\n",lexp->current,r,n,n,(iof&IOPUT)?((iof&IOAPP)?'a':'w'):((iof&IODOC)?'h':'r'),iof&IOUFD);
1667da2e3ebdSchin }
1668da2e3ebdSchin }
1669da2e3ebdSchin #endif /* SHOPT_KIA */
1670da2e3ebdSchin if(flag>=0)
1671da2e3ebdSchin {
1672da2e3ebdSchin struct ionod *ioq=iop;
16737c2fbfb3SApril Chin sh_lex(lexp);
1674da2e3ebdSchin if(errout)
1675da2e3ebdSchin {
1676da2e3ebdSchin /* redirect standard output to standard error */
16777c2fbfb3SApril Chin ioq = (struct ionod*)stkalloc(stkp,sizeof(struct ionod));
167834f9b3eeSRoland Mainz memset(ioq,0,sizeof(*ioq));
1679da2e3ebdSchin ioq->ioname = "1";
1680da2e3ebdSchin ioq->iolst = 0;
1681da2e3ebdSchin ioq->iodelim = 0;
1682da2e3ebdSchin ioq->iofile = IORAW|IOPUT|IOMOV|2;
1683da2e3ebdSchin iop->ionxt=ioq;
1684da2e3ebdSchin }
16857c2fbfb3SApril Chin ioq->ionxt=inout(lexp,lastio,flag);
1686da2e3ebdSchin }
1687da2e3ebdSchin else
1688da2e3ebdSchin iop->ionxt=0;
1689da2e3ebdSchin return(iop);
1690da2e3ebdSchin }
1691da2e3ebdSchin
1692da2e3ebdSchin /*
1693da2e3ebdSchin * convert argument chain to argument list when no special arguments
1694da2e3ebdSchin */
1695da2e3ebdSchin
qscan(struct comnod * ac,int argn)1696da2e3ebdSchin static struct argnod *qscan(struct comnod *ac,int argn)
1697da2e3ebdSchin {
1698da2e3ebdSchin register char **cp;
1699da2e3ebdSchin register struct argnod *ap;
1700da2e3ebdSchin register struct dolnod* dp;
1701da2e3ebdSchin register int special=0;
1702da2e3ebdSchin /* special hack for test -t compatibility */
1703da2e3ebdSchin if((Namval_t*)ac->comnamp==SYSTEST)
1704da2e3ebdSchin special = 2;
1705da2e3ebdSchin else if(*(ac->comarg->argval)=='[' && ac->comarg->argval[1]==0)
1706da2e3ebdSchin special = 3;
1707da2e3ebdSchin if(special)
1708da2e3ebdSchin {
1709da2e3ebdSchin ap = ac->comarg->argnxt.ap;
1710da2e3ebdSchin if(argn==(special+1) && ap->argval[1]==0 && *ap->argval=='!')
1711da2e3ebdSchin ap = ap->argnxt.ap;
1712da2e3ebdSchin else if(argn!=special)
1713da2e3ebdSchin special=0;
1714da2e3ebdSchin }
1715da2e3ebdSchin if(special)
1716da2e3ebdSchin {
1717da2e3ebdSchin const char *message;
1718da2e3ebdSchin if(strcmp(ap->argval,"-t"))
1719da2e3ebdSchin {
1720da2e3ebdSchin message = "line %d: Invariant test";
1721da2e3ebdSchin special=0;
1722da2e3ebdSchin }
1723da2e3ebdSchin else
1724da2e3ebdSchin {
1725da2e3ebdSchin message = "line %d: -t requires argument";
1726da2e3ebdSchin argn++;
1727da2e3ebdSchin }
1728da2e3ebdSchin if(sh_isoption(SH_NOEXEC))
1729da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),message,ac->comline);
1730da2e3ebdSchin }
1731da2e3ebdSchin /* leave space for an extra argument at the front */
1732da2e3ebdSchin dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
1733da2e3ebdSchin cp = dp->dolval+ARG_SPARE;
1734da2e3ebdSchin dp->dolnum = argn;
1735da2e3ebdSchin dp->dolbot = ARG_SPARE;
1736da2e3ebdSchin ap = ac->comarg;
1737da2e3ebdSchin while(ap)
1738da2e3ebdSchin {
1739da2e3ebdSchin *cp++ = ap->argval;
1740da2e3ebdSchin ap = ap->argnxt.ap;
1741da2e3ebdSchin }
1742da2e3ebdSchin if(special==3)
1743da2e3ebdSchin {
1744da2e3ebdSchin cp[0] = cp[-1];
1745da2e3ebdSchin cp[-1] = "1";
1746da2e3ebdSchin cp++;
1747da2e3ebdSchin }
1748da2e3ebdSchin else if(special)
1749da2e3ebdSchin *cp++ = "1";
1750da2e3ebdSchin *cp = 0;
1751da2e3ebdSchin return((struct argnod*)dp);
1752da2e3ebdSchin }
1753da2e3ebdSchin
test_expr(Lex_t * lp,int sym)17547c2fbfb3SApril Chin static Shnode_t *test_expr(Lex_t *lp,int sym)
1755da2e3ebdSchin {
17567c2fbfb3SApril Chin register Shnode_t *t = test_or(lp);
17577c2fbfb3SApril Chin if(lp->token!=sym)
17587c2fbfb3SApril Chin sh_syntax(lp);
1759da2e3ebdSchin return(t);
1760da2e3ebdSchin }
1761da2e3ebdSchin
test_or(Lex_t * lp)17627c2fbfb3SApril Chin static Shnode_t *test_or(Lex_t *lp)
1763da2e3ebdSchin {
17647c2fbfb3SApril Chin register Shnode_t *t = test_and(lp);
17657c2fbfb3SApril Chin while(lp->token==ORFSYM)
17667c2fbfb3SApril Chin t = makelist(lp,TORF|TTEST,t,test_and(lp));
1767da2e3ebdSchin return(t);
1768da2e3ebdSchin }
1769da2e3ebdSchin
test_and(Lex_t * lp)17707c2fbfb3SApril Chin static Shnode_t *test_and(Lex_t *lp)
1771da2e3ebdSchin {
17727c2fbfb3SApril Chin register Shnode_t *t = test_primary(lp);
17737c2fbfb3SApril Chin while(lp->token==ANDFSYM)
17747c2fbfb3SApril Chin t = makelist(lp,TAND|TTEST,t,test_primary(lp));
1775da2e3ebdSchin return(t);
1776da2e3ebdSchin }
1777da2e3ebdSchin
1778da2e3ebdSchin /*
1779da2e3ebdSchin * convert =~ into == ~(E)
1780da2e3ebdSchin */
ere_match(void)1781da2e3ebdSchin static void ere_match(void)
1782da2e3ebdSchin {
1783da2e3ebdSchin Sfio_t *base, *iop = sfopen((Sfio_t*)0," ~(E)","s");
1784da2e3ebdSchin register int c;
1785da2e3ebdSchin while( fcgetc(c),(c==' ' || c=='\t'));
1786da2e3ebdSchin if(c)
1787da2e3ebdSchin fcseek(-1);
1788da2e3ebdSchin if(!(base=fcfile()))
1789da2e3ebdSchin base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
1790da2e3ebdSchin fcclose();
1791da2e3ebdSchin sfstack(base,iop);
1792da2e3ebdSchin fcfopen(base);
1793da2e3ebdSchin }
1794da2e3ebdSchin
test_primary(Lex_t * lexp)17957c2fbfb3SApril Chin static Shnode_t *test_primary(Lex_t *lexp)
1796da2e3ebdSchin {
1797da2e3ebdSchin register struct argnod *arg;
1798da2e3ebdSchin register Shnode_t *t;
1799da2e3ebdSchin register int num,token;
18007c2fbfb3SApril Chin token = skipnl(lexp,0);
18017c2fbfb3SApril Chin num = lexp->digits;
1802da2e3ebdSchin switch(token)
1803da2e3ebdSchin {
1804da2e3ebdSchin case '(':
18057c2fbfb3SApril Chin t = test_expr(lexp,')');
18067c2fbfb3SApril Chin t = makelist(lexp,TTST|TTEST|TPAREN ,t, (Shnode_t*)pointerof(lexp->sh->inlineno));
1807da2e3ebdSchin break;
1808da2e3ebdSchin case '!':
18097c2fbfb3SApril Chin if(!(t = test_primary(lexp)))
18107c2fbfb3SApril Chin sh_syntax(lexp);
1811da2e3ebdSchin t->tre.tretyp |= TNEGATE;
1812da2e3ebdSchin return(t);
1813da2e3ebdSchin case TESTUNOP:
18147c2fbfb3SApril Chin if(sh_lex(lexp))
18157c2fbfb3SApril Chin sh_syntax(lexp);
1816da2e3ebdSchin #if SHOPT_KIA
18177c2fbfb3SApril Chin if(lexp->kiafile && !strchr("sntzoOG",num))
1818da2e3ebdSchin {
18197c2fbfb3SApril Chin int line = lexp->sh->inlineno- (lexp->token==NL);
1820da2e3ebdSchin unsigned long r;
18217c2fbfb3SApril Chin r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->script,'t',0,"");
18227c2fbfb3SApril Chin sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
1823da2e3ebdSchin }
1824da2e3ebdSchin #endif /* SHOPT_KIA */
18257c2fbfb3SApril Chin t = makelist(lexp,TTST|TTEST|TUNARY|(num<<TSHIFT),
18267c2fbfb3SApril Chin (Shnode_t*)lexp->arg,(Shnode_t*)lexp->arg);
18277c2fbfb3SApril Chin t->tst.tstline = lexp->sh->inlineno;
1828da2e3ebdSchin break;
1829da2e3ebdSchin /* binary test operators */
1830da2e3ebdSchin case 0:
18317c2fbfb3SApril Chin arg = lexp->arg;
18327c2fbfb3SApril Chin if((token=sh_lex(lexp))==TESTBINOP)
1833da2e3ebdSchin {
18347c2fbfb3SApril Chin num = lexp->digits;
1835da2e3ebdSchin if(num==TEST_REP)
1836da2e3ebdSchin {
1837da2e3ebdSchin ere_match();
1838da2e3ebdSchin num = TEST_PEQ;
1839da2e3ebdSchin }
1840da2e3ebdSchin }
1841da2e3ebdSchin else if(token=='<')
1842da2e3ebdSchin num = TEST_SLT;
1843da2e3ebdSchin else if(token=='>')
1844da2e3ebdSchin num = TEST_SGT;
1845da2e3ebdSchin else if(token==ANDFSYM||token==ORFSYM||token==ETESTSYM||token==RPAREN)
1846da2e3ebdSchin {
18477c2fbfb3SApril Chin t = makelist(lexp,TTST|TTEST|TUNARY|('n'<<TSHIFT),
1848da2e3ebdSchin (Shnode_t*)arg,(Shnode_t*)arg);
18497c2fbfb3SApril Chin t->tst.tstline = lexp->sh->inlineno;
1850da2e3ebdSchin return(t);
1851da2e3ebdSchin }
1852da2e3ebdSchin else
18537c2fbfb3SApril Chin sh_syntax(lexp);
1854da2e3ebdSchin #if SHOPT_KIA
18557c2fbfb3SApril Chin if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
1856da2e3ebdSchin {
18577c2fbfb3SApril Chin int line = lexp->sh->inlineno- (lexp->token==NL);
1858da2e3ebdSchin unsigned long r;
18597c2fbfb3SApril Chin r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
18607c2fbfb3SApril Chin sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
1861da2e3ebdSchin }
1862da2e3ebdSchin #endif /* SHOPT_KIA */
18637c2fbfb3SApril Chin if(sh_lex(lexp))
18647c2fbfb3SApril Chin sh_syntax(lexp);
1865da2e3ebdSchin if(num&TEST_PATTERN)
1866da2e3ebdSchin {
18677c2fbfb3SApril Chin if(lexp->arg->argflag&(ARG_EXP|ARG_MAC))
1868da2e3ebdSchin num &= ~TEST_PATTERN;
1869da2e3ebdSchin }
1870da2e3ebdSchin t = getnode(tstnod);
1871da2e3ebdSchin t->lst.lsttyp = TTST|TTEST|TBINARY|(num<<TSHIFT);
1872da2e3ebdSchin t->lst.lstlef = (Shnode_t*)arg;
18737c2fbfb3SApril Chin t->lst.lstrit = (Shnode_t*)lexp->arg;
18747c2fbfb3SApril Chin t->tst.tstline = lexp->sh->inlineno;
1875da2e3ebdSchin #if SHOPT_KIA
18767c2fbfb3SApril Chin if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
1877da2e3ebdSchin {
18787c2fbfb3SApril Chin int line = lexp->sh->inlineno-(lexp->token==NL);
1879da2e3ebdSchin unsigned long r;
18807c2fbfb3SApril Chin r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
18817c2fbfb3SApril Chin sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
1882da2e3ebdSchin }
1883da2e3ebdSchin #endif /* SHOPT_KIA */
1884da2e3ebdSchin break;
1885da2e3ebdSchin default:
1886da2e3ebdSchin return(0);
1887da2e3ebdSchin }
18887c2fbfb3SApril Chin skipnl(lexp,0);
1889da2e3ebdSchin return(t);
1890da2e3ebdSchin }
1891da2e3ebdSchin
1892da2e3ebdSchin #if SHOPT_KIA
1893da2e3ebdSchin /*
1894da2e3ebdSchin * return an entity checksum
1895da2e3ebdSchin * The entity is created if it doesn't exist
1896da2e3ebdSchin */
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)18977c2fbfb3SApril Chin unsigned long kiaentity(Lex_t *lexp,const char *name,int len,int type,int first,int last,unsigned long parent, int pkind, int width, const char *attr)
1898da2e3ebdSchin {
18997c2fbfb3SApril Chin Stk_t *stkp = lexp->sh->stk;
1900da2e3ebdSchin Namval_t *np;
19017c2fbfb3SApril Chin long offset = stktell(stkp);
19027c2fbfb3SApril Chin sfputc(stkp,type);
1903da2e3ebdSchin if(len>0)
19047c2fbfb3SApril Chin sfwrite(stkp,name,len);
1905da2e3ebdSchin else
1906da2e3ebdSchin {
1907da2e3ebdSchin if(type=='p')
19087c2fbfb3SApril Chin sfputr(stkp,path_basename(name),0);
1909da2e3ebdSchin else
19107c2fbfb3SApril Chin sfputr(stkp,name,0);
1911da2e3ebdSchin }
19127c2fbfb3SApril Chin np = nv_search(stakptr(offset),lexp->entity_tree,NV_ADD);
19137c2fbfb3SApril Chin stkseek(stkp,offset);
1914da2e3ebdSchin np->nvalue.i = pkind;
1915da2e3ebdSchin nv_setsize(np,width);
1916da2e3ebdSchin if(!nv_isattr(np,NV_TAGGED) && first>=0)
1917da2e3ebdSchin {
1918da2e3ebdSchin nv_onattr(np,NV_TAGGED);
1919da2e3ebdSchin if(!pkind)
1920da2e3ebdSchin pkind = '0';
1921da2e3ebdSchin if(len>0)
19227c2fbfb3SApril Chin sfprintf(lexp->kiafile,"%..64d;%c;%.*s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,len,name,first,last,parent,lexp->fscript,pkind,width,attr);
1923da2e3ebdSchin else
19247c2fbfb3SApril Chin sfprintf(lexp->kiafile,"%..64d;%c;%s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,name,first,last,parent,lexp->fscript,pkind,width,attr);
1925da2e3ebdSchin }
1926da2e3ebdSchin return(np->hash);
1927da2e3ebdSchin }
1928da2e3ebdSchin
kia_add(register Namval_t * np,void * data)1929da2e3ebdSchin static void kia_add(register Namval_t *np, void *data)
1930da2e3ebdSchin {
1931da2e3ebdSchin char *name = nv_name(np);
19327c2fbfb3SApril Chin Lex_t *lp = (Lex_t*)data;
1933da2e3ebdSchin NOT_USED(data);
19347c2fbfb3SApril Chin kiaentity(lp,name+1,-1,*name,0,-1,(*name=='p'?lp->unknown:lp->script),np->nvalue.i,nv_size(np),"");
1935da2e3ebdSchin }
1936da2e3ebdSchin
kiaclose(Lex_t * lexp)19377c2fbfb3SApril Chin int kiaclose(Lex_t *lexp)
1938da2e3ebdSchin {
1939da2e3ebdSchin register off_t off1,off2;
1940da2e3ebdSchin register int n;
19417c2fbfb3SApril Chin if(lexp->kiafile)
1942da2e3ebdSchin {
19437c2fbfb3SApril Chin unsigned long r = kiaentity(lexp,lexp->scriptname,-1,'p',-1,lexp->sh->inlineno-1,0,'s',0,"");
19447c2fbfb3SApril Chin kiaentity(lexp,lexp->scriptname,-1,'p',1,lexp->sh->inlineno-1,r,'s',0,"");
19457c2fbfb3SApril Chin kiaentity(lexp,lexp->scriptname,-1,'f',1,lexp->sh->inlineno-1,r,'s',0,"");
19467c2fbfb3SApril Chin nv_scan(lexp->entity_tree,kia_add,(void*)lexp,NV_TAGGED,0);
19477c2fbfb3SApril Chin off1 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
19487c2fbfb3SApril Chin sfseek(lexp->kiatmp,(off_t)0,SEEK_SET);
19497c2fbfb3SApril Chin sfmove(lexp->kiatmp,lexp->kiafile,SF_UNBOUND,-1);
19507c2fbfb3SApril Chin off2 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
1951da2e3ebdSchin #ifdef SF_BUFCONST
1952da2e3ebdSchin if(off2==off1)
19537c2fbfb3SApril Chin n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin));
1954da2e3ebdSchin else
19557c2fbfb3SApril Chin n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nRELATIONSHIP;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin),(Sflong_t)off1,(size_t)(off2-off1));
1956da2e3ebdSchin if(off2 >= INT_MAX)
1957da2e3ebdSchin off2 = -(n+12);
19587c2fbfb3SApril Chin sfprintf(lexp->kiafile,"%010.10lld;%010d\n",(Sflong_t)off2+10, n+12);
1959da2e3ebdSchin #else
1960da2e3ebdSchin if(off2==off1)
19617c2fbfb3SApril Chin n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin);
1962da2e3ebdSchin else
19637c2fbfb3SApril Chin n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin,off1,off2-off1);
19647c2fbfb3SApril Chin sfprintf(lexp->kiafile,"%010d;%010d\n",off2+10, n+12);
1965da2e3ebdSchin #endif
1966da2e3ebdSchin }
19677c2fbfb3SApril Chin return(sfclose(lexp->kiafile));
1968da2e3ebdSchin }
1969da2e3ebdSchin #endif /* SHOPT_KIA */
1970