1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2010 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 * David Korn
23 * AT&T Labs
24 *
25 * shell intermediate code reader
26 *
27 */
28
29#include	"defs.h"
30#include	"shnodes.h"
31#include	"path.h"
32#include	"io.h"
33#include	<ccode.h>
34
35static struct dolnod	*r_comlist(Shell_t*);
36static struct argnod	*r_arg(Shell_t*);
37static struct ionod	*r_redirect(Shell_t*);
38static struct regnod	*r_switch(Shell_t*);
39static Shnode_t		*r_tree(Shell_t*);
40static char		*r_string(Stk_t*);
41static void		r_comarg(Shell_t*,struct comnod*);
42
43static Sfio_t *infile;
44
45#define getnode(s,type)   ((Shnode_t*)stkalloc((s),sizeof(struct type)))
46
47Shnode_t *sh_trestore(Shell_t *shp,Sfio_t *in)
48{
49	Shnode_t *t;
50	infile = in;
51	t = r_tree(shp);
52	return(t);
53}
54/*
55 * read in a shell tree
56 */
57static Shnode_t *r_tree(Shell_t *shp)
58{
59	long l = sfgetl(infile);
60	register int type;
61	register Shnode_t *t=0;
62	if(l<0)
63		return(t);
64	type = l;
65	switch(type&COMMSK)
66	{
67		case TTIME:
68		case TPAR:
69			t = getnode(shp->stk,parnod);
70			t->par.partre = r_tree(shp);
71			break;
72		case TCOM:
73			t = getnode(shp->stk,comnod);
74			t->tre.tretyp = type;
75			r_comarg(shp,(struct comnod*)t);
76			break;
77		case TSETIO:
78		case TFORK:
79			t = getnode(shp->stk,forknod);
80			t->fork.forkline = sfgetu(infile);
81			t->fork.forktre = r_tree(shp);
82			t->fork.forkio = r_redirect(shp);
83			break;
84		case TIF:
85			t = getnode(shp->stk,ifnod);
86			t->if_.iftre = r_tree(shp);
87			t->if_.thtre = r_tree(shp);
88			t->if_.eltre = r_tree(shp);
89			break;
90		case TWH:
91			t = getnode(shp->stk,whnod);
92			t->wh.whinc = (struct arithnod*)r_tree(shp);
93			t->wh.whtre = r_tree(shp);
94			t->wh.dotre = r_tree(shp);
95			break;
96		case TLST:
97		case TAND:
98		case TORF:
99		case TFIL:
100			t = getnode(shp->stk,lstnod);
101			t->lst.lstlef = r_tree(shp);
102			t->lst.lstrit = r_tree(shp);
103			break;
104		case TARITH:
105			t = getnode(shp->stk,arithnod);
106			t->ar.arline = sfgetu(infile);
107			t->ar.arexpr = r_arg(shp);
108			t->ar.arcomp = 0;
109			if((t->ar.arexpr)->argflag&ARG_RAW)
110				 t->ar.arcomp = sh_arithcomp((t->ar.arexpr)->argval);
111			break;
112		case TFOR:
113			t = getnode(shp->stk,fornod);
114			t->for_.forline = 0;
115			if(type&FLINENO)
116				t->for_.forline = sfgetu(infile);
117			t->for_.fortre = r_tree(shp);
118			t->for_.fornam = r_string(shp->stk);
119			t->for_.forlst = (struct comnod*)r_tree(shp);
120			break;
121		case TSW:
122			t = getnode(shp->stk,swnod);
123			t->sw.swline = 0;
124			if(type&FLINENO)
125				t->sw.swline = sfgetu(infile);
126			t->sw.swarg = r_arg(shp);
127			if(type&COMSCAN)
128				t->sw.swio = r_redirect(shp);
129			else
130				t->sw.swio = 0;
131			t->sw.swlst = r_switch(shp);
132			break;
133		case TFUN:
134		{
135			Stak_t *savstak;
136			struct slnod *slp;
137			struct functnod *fp;
138			t = getnode(shp->stk,functnod);
139			t->funct.functloc = -1;
140			t->funct.functline = sfgetu(infile);
141			t->funct.functnam = r_string(shp->stk);
142			savstak = stakcreate(STAK_SMALL);
143			savstak = stakinstall(savstak, 0);
144			slp = (struct slnod*)stkalloc(shp->stk,sizeof(struct slnod)+sizeof(struct functnod));
145			slp->slchild = 0;
146			slp->slnext = shp->st.staklist;
147			shp->st.staklist = 0;
148			fp = (struct functnod*)(slp+1);
149			memset(fp, 0, sizeof(*fp));
150			fp->functtyp = TFUN|FAMP;
151			if(shp->st.filename)
152				fp->functnam = stkcopy(shp->stk,shp->st.filename);
153			t->funct.functtre = r_tree(shp);
154			t->funct.functstak = slp;
155			slp->slptr =  stakinstall(savstak,0);
156			slp->slchild = shp->st.staklist;
157			t->funct.functargs = (struct comnod*)r_tree(shp);
158			break;
159		}
160		case TTST:
161			t = getnode(shp->stk,tstnod);
162			t->tst.tstline = sfgetu(infile);
163			if((type&TPAREN)==TPAREN)
164				t->lst.lstlef = r_tree(shp);
165			else
166			{
167				t->lst.lstlef = (Shnode_t*)r_arg(shp);
168				if((type&TBINARY))
169					t->lst.lstrit = (Shnode_t*)r_arg(shp);
170			}
171	}
172	if(t)
173		t->tre.tretyp = type;
174	return(t);
175}
176
177static struct argnod *r_arg(Shell_t *shp)
178{
179	register struct argnod *ap=0, *apold, *aptop=0;
180	register long l;
181	Stk_t		*stkp=shp->stk;
182	while((l=sfgetu(infile))>0)
183	{
184		ap = (struct argnod*)stkseek(stkp,(unsigned)l+ARGVAL);
185		if(!aptop)
186			aptop = ap;
187		else
188			apold->argnxt.ap = ap;
189		if(--l > 0)
190		{
191			sfread(infile,ap->argval,(size_t)l);
192			ccmaps(ap->argval, l, CC_ASCII, CC_NATIVE);
193		}
194		ap->argval[l] = 0;
195		ap->argchn.cp = 0;
196		ap->argflag = sfgetc(infile);
197		if((ap->argflag&ARG_MESSAGE) && *ap->argval)
198		{
199			/* replace international messages */
200			ap = sh_endword(shp,1);
201			ap->argflag &= ~ARG_MESSAGE;
202			if(!(ap->argflag&(ARG_MAC|ARG_EXP)))
203				ap = sh_endword(shp,0);
204			else
205			{
206				ap = (struct argnod*)stkfreeze(stkp,0);
207				if(ap->argflag==0)
208					ap->argflag = ARG_RAW;
209			}
210		}
211		else
212			ap = (struct argnod*)stkfreeze(stkp,0);
213		if(*ap->argval==0 && (ap->argflag&~(ARG_APPEND|ARG_MESSAGE|ARG_QUOTED))==0)
214		{
215			struct fornod *fp = (struct fornod*)getnode(shp->stk,fornod);
216			fp->fortyp = sfgetu(infile);
217			fp->fortre = r_tree(shp);
218			fp->fornam = ap->argval+1;
219			ap->argchn.ap = (struct argnod*)fp;
220		}
221		apold = ap;
222	}
223	if(ap)
224		ap->argnxt.ap = 0;
225	return(aptop);
226}
227
228static struct ionod *r_redirect(Shell_t* shp)
229{
230	register long l;
231	register struct ionod *iop=0, *iopold, *ioptop=0;
232	while((l=sfgetl(infile))>=0)
233	{
234		iop = (struct ionod*)getnode(shp->stk,ionod);
235		if(!ioptop)
236			ioptop = iop;
237		else
238			iopold->ionxt = iop;
239		iop->iofile = l;
240		iop->ioname = r_string(shp->stk);
241		if(iop->iodelim = r_string(shp->stk))
242		{
243			iop->iosize = sfgetl(infile);
244			if(shp->heredocs)
245				iop->iooffset = sfseek(shp->heredocs,(off_t)0,SEEK_END);
246			else
247			{
248				shp->heredocs = sftmp(512);
249				iop->iooffset = 0;
250			}
251			sfmove(infile,shp->heredocs, iop->iosize, -1);
252		}
253		iopold = iop;
254		if(iop->iofile&IOVNM)
255			iop->iovname = r_string(shp->stk);
256		else
257			iop->iovname = 0;
258		iop->iofile &= ~IOVNM;
259	}
260	if(iop)
261		iop->ionxt = 0;
262	return(ioptop);
263}
264
265static void r_comarg(Shell_t *shp,struct comnod *com)
266{
267	char *cmdname=0;
268	com->comio = r_redirect(shp);
269	com->comset = r_arg(shp);
270	com->comstate = 0;
271	if(com->comtyp&COMSCAN)
272	{
273		com->comarg = r_arg(shp);
274		if(com->comarg->argflag==ARG_RAW)
275			cmdname = com->comarg->argval;
276	}
277	else if(com->comarg = (struct argnod*)r_comlist(shp))
278		cmdname = ((struct dolnod*)(com->comarg))->dolval[ARG_SPARE];
279	com->comline = sfgetu(infile);
280	com->comnamq = 0;
281	if(cmdname)
282	{
283		char *cp;
284		com->comnamp = (void*)nv_search(cmdname,shp->fun_tree,0);
285		if(com->comnamp && (cp =strrchr(cmdname+1,'.')))
286		{
287			*cp = 0;
288			com->comnamp =  (void*)nv_open(cmdname,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOARRAY);
289			*cp = '.';
290		}
291	}
292	else
293		com->comnamp  = 0;
294}
295
296static struct dolnod *r_comlist(Shell_t *shp)
297{
298	register struct dolnod *dol=0;
299	register long l;
300	register char **argv;
301	if((l=sfgetl(infile))>0)
302	{
303		dol = (struct dolnod*)stkalloc(shp->stk,sizeof(struct dolnod) + sizeof(char*)*(l+ARG_SPARE));
304		dol->dolnum = l;
305		dol->dolbot = ARG_SPARE;
306		argv = dol->dolval+ARG_SPARE;
307		while(*argv++ = r_string(shp->stk));
308	}
309	return(dol);
310}
311
312static struct regnod *r_switch(Shell_t *shp)
313{
314	register long l;
315	struct regnod *reg=0,*regold,*regtop=0;
316	while((l=sfgetl(infile))>=0)
317	{
318		reg = (struct regnod*)getnode(shp->stk,regnod);
319		if(!regtop)
320			regtop = reg;
321		else
322			regold->regnxt = reg;
323		reg->regflag = l;
324		reg->regptr = r_arg(shp);
325		reg->regcom = r_tree(shp);
326		regold = reg;
327	}
328	if(reg)
329		reg->regnxt = 0;
330	return(regtop);
331}
332
333static char *r_string(Stk_t *stkp)
334{
335	register Sfio_t *in = infile;
336	register unsigned long l = sfgetu(in);
337	register char *ptr;
338	if(l == 0)
339		return(NIL(char*));
340	ptr = stkalloc(stkp,(unsigned)l);
341	if(--l > 0)
342	{
343		if(sfread(in,ptr,(size_t)l)!=(size_t)l)
344			return(NIL(char*));
345		ccmaps(ptr, l, CC_ASCII, CC_NATIVE);
346	}
347	ptr[l] = 0;
348	return(ptr);
349}
350