1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin 
22*4887Schin /*
23*4887Schin  * code for tree nodes and name walking
24*4887Schin  *
25*4887Schin  *   David Korn
26*4887Schin  *   AT&T Labs
27*4887Schin  *
28*4887Schin  */
29*4887Schin 
30*4887Schin #include	"defs.h"
31*4887Schin #include	"name.h"
32*4887Schin #include	"argnod.h"
33*4887Schin 
34*4887Schin struct nvdir
35*4887Schin {
36*4887Schin 	Dt_t		*root;
37*4887Schin 	Namval_t	*hp;
38*4887Schin 	Namval_t	*table;
39*4887Schin 	Namval_t	*(*nextnode)(Namval_t*,Dt_t*,Namfun_t*);
40*4887Schin 	Namfun_t	*fun;
41*4887Schin 	struct nvdir	*prev;
42*4887Schin 	int		len;
43*4887Schin 	int		offset;
44*4887Schin 	char		data[1];
45*4887Schin };
46*4887Schin 
47*4887Schin char *nv_getvtree(Namval_t*, Namfun_t *);
48*4887Schin static void put_tree(Namval_t*, const char*, int,Namfun_t*);
49*4887Schin 
50*4887Schin static Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp)
51*4887Schin {
52*4887Schin 	register Namfun_t *fp=dp;
53*4887Schin 	while(fp=fp->next)
54*4887Schin 	{
55*4887Schin 		if(fp->disc && fp->disc->createf)
56*4887Schin 		{
57*4887Schin 			if(np=(*fp->disc->createf)(np,name,flag,fp))
58*4887Schin 				dp->last = fp->last;
59*4887Schin 			return(np);
60*4887Schin 		}
61*4887Schin 	}
62*4887Schin 	return((flag&NV_NOADD)?0:np);
63*4887Schin }
64*4887Schin 
65*4887Schin static const Namdisc_t treedisc =
66*4887Schin {
67*4887Schin 	0,
68*4887Schin 	put_tree,
69*4887Schin 	nv_getvtree,
70*4887Schin 	0,
71*4887Schin 	0,
72*4887Schin 	create_tree
73*4887Schin };
74*4887Schin 
75*4887Schin static char *nextdot(const char *str)
76*4887Schin {
77*4887Schin 	register char *cp;
78*4887Schin 	if(*str=='.')
79*4887Schin 		str++;
80*4887Schin 	if(*str =='[')
81*4887Schin 	{
82*4887Schin 		cp = nv_endsubscript((Namval_t*)0,(char*)str,0);
83*4887Schin 		return(*cp=='.'?cp:0);
84*4887Schin 	}
85*4887Schin 	else
86*4887Schin 		return(strchr(str,'.'));
87*4887Schin }
88*4887Schin 
89*4887Schin static  Namfun_t *nextdisc(Namval_t *np)
90*4887Schin {
91*4887Schin 	register Namfun_t *fp;
92*4887Schin 	if(nv_isref(np))
93*4887Schin 		return(0);
94*4887Schin         for(fp=np->nvfun;fp;fp=fp->next)
95*4887Schin 	{
96*4887Schin 		if(fp && fp->disc && fp->disc->nextf)
97*4887Schin 			return(fp);
98*4887Schin 	}
99*4887Schin 	return(0);
100*4887Schin }
101*4887Schin 
102*4887Schin void *nv_diropen(const char *name)
103*4887Schin {
104*4887Schin 	char *next,*last;
105*4887Schin 	int c,len=strlen(name);
106*4887Schin 	struct nvdir *save, *dp = new_of(struct nvdir,len);
107*4887Schin 	Namval_t *np, fake;
108*4887Schin 	Namfun_t *nfp;
109*4887Schin 	if(!dp)
110*4887Schin 		return(0);
111*4887Schin 	memset((void*)dp, 0, sizeof(*dp));
112*4887Schin 	last=dp->data;
113*4887Schin 	if(name[len-1]=='*' || name[len-1]=='@')
114*4887Schin 		len -= 1;
115*4887Schin 	name = memcpy(last,name,len);
116*4887Schin 	last[len] = 0;
117*4887Schin 	dp->len = len;
118*4887Schin 	dp->root = sh.var_tree;
119*4887Schin 	dp->table = sh.last_table;
120*4887Schin 	if(*name)
121*4887Schin 	{
122*4887Schin 		fake.nvname = (char*)name;
123*4887Schin 		dp->hp = (Namval_t*)dtprev(dp->root,&fake);
124*4887Schin 		dp->hp = (Namval_t*)dtnext(dp->root,dp->hp);
125*4887Schin 	}
126*4887Schin 	else
127*4887Schin 		dp->hp = (Namval_t*)dtfirst(dp->root);
128*4887Schin 	while(next= nextdot(last))
129*4887Schin 	{
130*4887Schin 		c = *next;
131*4887Schin 		*next = 0;
132*4887Schin 		np = nv_search(last,dp->root,0);
133*4887Schin 		*next = c;
134*4887Schin 		if(np && ((nfp=nextdisc(np)) || nv_istable(np)))
135*4887Schin 		{
136*4887Schin 			if(!(save = new_of(struct nvdir,0)))
137*4887Schin 				return(0);
138*4887Schin 			*save = *dp;
139*4887Schin 			dp->prev = save;
140*4887Schin 			if(nv_istable(np))
141*4887Schin 				dp->root = nv_dict(np);
142*4887Schin 			else
143*4887Schin 				dp->root = (Dt_t*)dp;
144*4887Schin 			dp->offset = last-(char*)name;
145*4887Schin 			if(dp->offset<len)
146*4887Schin 				dp->len = len-dp->offset;
147*4887Schin 			else
148*4887Schin 				dp->len = 0;
149*4887Schin 			if(nfp)
150*4887Schin 			{
151*4887Schin 				dp->nextnode = nfp->disc->nextf;
152*4887Schin 				dp->table = np;
153*4887Schin 				dp->fun = nfp;
154*4887Schin 				dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
155*4887Schin 			}
156*4887Schin 			else
157*4887Schin 				dp->nextnode = 0;
158*4887Schin 		}
159*4887Schin 		else
160*4887Schin 			break;
161*4887Schin 		last = next+1;
162*4887Schin 	}
163*4887Schin 	return((void*)dp);
164*4887Schin }
165*4887Schin 
166*4887Schin 
167*4887Schin static Namval_t *nextnode(struct nvdir *dp)
168*4887Schin {
169*4887Schin 	if(dp->nextnode)
170*4887Schin 		return((*dp->nextnode)(dp->hp,dp->root,dp->fun));
171*4887Schin 	if(dp->len && memcmp(dp->data, dp->hp->nvname, dp->len))
172*4887Schin 		return(0);
173*4887Schin 	return((Namval_t*)dtnext(dp->root,dp->hp));
174*4887Schin }
175*4887Schin 
176*4887Schin char *nv_dirnext(void *dir)
177*4887Schin {
178*4887Schin 	register struct nvdir *save, *dp = (struct nvdir*)dir;
179*4887Schin 	register Namval_t *np, *last_table;
180*4887Schin 	register char *cp;
181*4887Schin 	Namfun_t *nfp;
182*4887Schin 	while(1)
183*4887Schin 	{
184*4887Schin 		while(np=dp->hp)
185*4887Schin 		{
186*4887Schin 			dp->hp = nextnode(dp);
187*4887Schin 			if(nv_isnull(np))
188*4887Schin 				continue;
189*4887Schin 			last_table = sh.last_table;
190*4887Schin 			sh.last_table = dp->table;
191*4887Schin 			cp = nv_name(np);
192*4887Schin 			sh.last_table = last_table;
193*4887Schin 			if(!dp->len || memcmp(cp+dp->offset,dp->data,dp->len)==0)
194*4887Schin 			{
195*4887Schin 				if((nfp=nextdisc(np)) || nv_istable(np))
196*4887Schin 				{
197*4887Schin 					Dt_t *root;
198*4887Schin 					if(nv_istable(np))
199*4887Schin 						root = nv_dict(np);
200*4887Schin 					else
201*4887Schin 						root = (Dt_t*)dp;
202*4887Schin 					/* check for recursive walk */
203*4887Schin 					for(save=dp; save;  save=save->prev)
204*4887Schin 					{
205*4887Schin 						if(save->root==root)
206*4887Schin 							break;
207*4887Schin 					}
208*4887Schin 					if(save)
209*4887Schin 						continue;
210*4887Schin 					if(!(save = new_of(struct nvdir,0)))
211*4887Schin 						return(0);
212*4887Schin 					*save = *dp;
213*4887Schin 					dp->prev = save;
214*4887Schin 					dp->root = root;
215*4887Schin 					dp->len = 0;
216*4887Schin 					if(nfp && np->nvfun)
217*4887Schin 					{
218*4887Schin 						dp->nextnode = nfp->disc->nextf;
219*4887Schin 						dp->table = np;
220*4887Schin 						dp->fun = nfp;
221*4887Schin 						dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
222*4887Schin 					}
223*4887Schin 					else
224*4887Schin 						dp->nextnode = 0;
225*4887Schin 				}
226*4887Schin 				return(cp);
227*4887Schin 			}
228*4887Schin 		}
229*4887Schin 		if(!(save=dp->prev))
230*4887Schin 			break;
231*4887Schin #if 0
232*4887Schin 		sh.last_table = dp->table;
233*4887Schin #endif
234*4887Schin 		*dp = *save;
235*4887Schin 		free((void*)save);
236*4887Schin 	}
237*4887Schin 	return(0);
238*4887Schin }
239*4887Schin 
240*4887Schin void nv_dirclose(void *dir)
241*4887Schin {
242*4887Schin 	struct nvdir *dp = (struct nvdir*)dir;
243*4887Schin 	if(dp->prev)
244*4887Schin 		nv_dirclose((void*)dp->prev);
245*4887Schin 	free(dir);
246*4887Schin }
247*4887Schin 
248*4887Schin static void outtype(Namval_t *np, Namfun_t *fp, Sfio_t* out, const char *prefix)
249*4887Schin {
250*4887Schin 	char *type=0;
251*4887Schin 	Namval_t *tp = fp->type;
252*4887Schin 	if(!tp && fp->disc && fp->disc->typef)
253*4887Schin 		tp = (*fp->disc->typef)(np,fp);
254*4887Schin 	for(fp=fp->next;fp;fp=fp->next)
255*4887Schin 	{
256*4887Schin 		if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp)))
257*4887Schin 		{
258*4887Schin 			outtype(np,fp,out,prefix);
259*4887Schin 			break;
260*4887Schin 		}
261*4887Schin 	}
262*4887Schin 	if(prefix && *prefix=='t')
263*4887Schin 		type = "-T";
264*4887Schin 	else if(!prefix)
265*4887Schin 		type = "type";
266*4887Schin 	if(type)
267*4887Schin 		sfprintf(out,"%s %s ",type,tp->nvname);
268*4887Schin }
269*4887Schin 
270*4887Schin /*
271*4887Schin  * print the attributes of name value pair give by <np>
272*4887Schin  */
273*4887Schin void nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname)
274*4887Schin {
275*4887Schin 	register const Shtable_t *tp;
276*4887Schin 	register char *cp;
277*4887Schin 	register unsigned val;
278*4887Schin 	register unsigned mask;
279*4887Schin 	register unsigned attr;
280*4887Schin 	Namfun_t *fp=0;
281*4887Schin 	for(fp=np->nvfun;fp;fp=fp->next)
282*4887Schin 	{
283*4887Schin 		if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp)))
284*4887Schin 			break;
285*4887Schin 	}
286*4887Schin #if 0
287*4887Schin 	if(!fp  && !nv_isattr(np,~NV_ARRAY))
288*4887Schin 	{
289*4887Schin 		if(!nv_isattr(np,NV_ARRAY)  || nv_aindex(np)>=0)
290*4887Schin 			return;
291*4887Schin 	}
292*4887Schin #else
293*4887Schin 	if(!fp  && !nv_isattr(np,~NV_MINIMAL))
294*4887Schin 		return;
295*4887Schin #endif
296*4887Schin 
297*4887Schin 	if ((attr=nv_isattr(np,~NV_NOFREE)) || fp)
298*4887Schin 	{
299*4887Schin 		if((attr&NV_NOPRINT)==NV_NOPRINT)
300*4887Schin 			attr &= ~NV_NOPRINT;
301*4887Schin 		if(!attr && !fp)
302*4887Schin 			return;
303*4887Schin 		if(prefix)
304*4887Schin 			sfputr(out,prefix,' ');
305*4887Schin 		for(tp = shtab_attributes; *tp->sh_name;tp++)
306*4887Schin 		{
307*4887Schin 			val = tp->sh_number;
308*4887Schin 			mask = val;
309*4887Schin 			if(fp && (val&NV_INTEGER))
310*4887Schin 				break;
311*4887Schin 			/*
312*4887Schin 			 * the following test is needed to prevent variables
313*4887Schin 			 * with E attribute from being given the F
314*4887Schin 			 * attribute as well
315*4887Schin 			*/
316*4887Schin 			if(val==(NV_INTEGER|NV_DOUBLE) && (attr&NV_EXPNOTE))
317*4887Schin 				continue;
318*4887Schin 			if(val&NV_INTEGER)
319*4887Schin 				mask |= NV_DOUBLE;
320*4887Schin 			else if(val&NV_HOST)
321*4887Schin 				mask = NV_HOST;
322*4887Schin 			if((attr&mask)==val)
323*4887Schin 			{
324*4887Schin 				if(val==NV_ARRAY)
325*4887Schin 				{
326*4887Schin 					Namarr_t *ap = nv_arrayptr(np);
327*4887Schin 					if(array_assoc(ap))
328*4887Schin 					{
329*4887Schin 						if(tp->sh_name[1]!='A')
330*4887Schin 							continue;
331*4887Schin 					}
332*4887Schin 					else if(tp->sh_name[1]=='A')
333*4887Schin 						continue;
334*4887Schin #if 0
335*4887Schin 						cp = "associative";
336*4887Schin 					else
337*4887Schin 						cp = "indexed";
338*4887Schin 					if(!prefix)
339*4887Schin 						sfputr(out,cp,' ');
340*4887Schin 					else if(*cp=='i')
341*4887Schin 						tp++;
342*4887Schin #endif
343*4887Schin 				}
344*4887Schin 				if(prefix)
345*4887Schin 				{
346*4887Schin 					if(*tp->sh_name=='-')
347*4887Schin 						sfprintf(out,"%.2s ",tp->sh_name);
348*4887Schin 				}
349*4887Schin 				else
350*4887Schin 					sfputr(out,tp->sh_name+2,' ');
351*4887Schin 		                if ((val&(NV_LJUST|NV_RJUST|NV_ZFILL)) && !(val&NV_INTEGER) && val!=NV_HOST)
352*4887Schin 					sfprintf(out,"%d ",nv_size(np));
353*4887Schin 			}
354*4887Schin 		        if(val==NV_INTEGER && nv_isattr(np,NV_INTEGER))
355*4887Schin 			{
356*4887Schin 				if(nv_size(np) != 10)
357*4887Schin 				{
358*4887Schin 					if(nv_isattr(np, NV_DOUBLE))
359*4887Schin 						cp = "precision";
360*4887Schin 					else
361*4887Schin 						cp = "base";
362*4887Schin 					if(!prefix)
363*4887Schin 						sfputr(out,cp,' ');
364*4887Schin 					sfprintf(out,"%d ",nv_size(np));
365*4887Schin 				}
366*4887Schin 				break;
367*4887Schin 			}
368*4887Schin 		}
369*4887Schin 		if(fp)
370*4887Schin 			outtype(np,fp,out,prefix);
371*4887Schin 		if(noname)
372*4887Schin 			return;
373*4887Schin 		sfputr(out,nv_name(np),'\n');
374*4887Schin 	}
375*4887Schin }
376*4887Schin 
377*4887Schin struct Walk
378*4887Schin {
379*4887Schin 	Sfio_t	*out;
380*4887Schin 	Dt_t	*root;
381*4887Schin 	int	noscope;
382*4887Schin 	int	indent;
383*4887Schin };
384*4887Schin 
385*4887Schin static void outval(char *name, const char *vname, struct Walk *wp)
386*4887Schin {
387*4887Schin 	register Namval_t *np, *nq;
388*4887Schin         register Namfun_t *fp;
389*4887Schin 	int isarray=0, associative=0, special=0;
390*4887Schin 	if(!(np=nv_open(vname,wp->root,NV_ARRAY|NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope)))
391*4887Schin 		return;
392*4887Schin 	if(nv_isarray(np) && *name=='.')
393*4887Schin 		special = 1;
394*4887Schin 	if(!special && (fp=nv_hasdisc(np,&treedisc)))
395*4887Schin 	{
396*4887Schin 		if(!wp->out)
397*4887Schin 		{
398*4887Schin 			fp = nv_stack(np,fp);
399*4887Schin 			if(fp = nv_stack(np,NIL(Namfun_t*)))
400*4887Schin 				free((void*)fp);
401*4887Schin 			np->nvfun = 0;
402*4887Schin 		}
403*4887Schin 		return;
404*4887Schin 	}
405*4887Schin 	if(nv_isnull(np))
406*4887Schin 		return;
407*4887Schin 	if(special || nv_isarray(np))
408*4887Schin 	{
409*4887Schin 		isarray=1;
410*4887Schin 		associative= nv_aindex(np)<0;
411*4887Schin 		if(array_elem(nv_arrayptr(np))==0)
412*4887Schin 			isarray=2;
413*4887Schin 		else
414*4887Schin 			nq = nv_putsub(np,NIL(char*),ARRAY_SCAN|(wp->out?ARRAY_NOCHILD:0));
415*4887Schin 	}
416*4887Schin 	if(!wp->out)
417*4887Schin 	{
418*4887Schin 		_nv_unset(np,NV_RDONLY);
419*4887Schin 		nv_close(np);
420*4887Schin 		return;
421*4887Schin 	}
422*4887Schin 	if(isarray==1 && !nq)
423*4887Schin 		return;
424*4887Schin 	if(special)
425*4887Schin 	{
426*4887Schin 		associative = 1;
427*4887Schin 		sfnputc(wp->out,'\t',wp->indent);
428*4887Schin 	}
429*4887Schin 	else
430*4887Schin 	{
431*4887Schin 		sfnputc(wp->out,'\t',wp->indent);
432*4887Schin 		nv_attribute(np,wp->out,"typeset",'=');
433*4887Schin 		nv_outname(wp->out,name,-1);
434*4887Schin 		sfputc(wp->out,(isarray==2?'\n':'='));
435*4887Schin 		if(isarray)
436*4887Schin 		{
437*4887Schin 			if(isarray==2)
438*4887Schin 				return;
439*4887Schin 			sfwrite(wp->out,"(\n",2);
440*4887Schin 			sfnputc(wp->out,'\t',++wp->indent);
441*4887Schin 		}
442*4887Schin 	}
443*4887Schin 	while(1)
444*4887Schin 	{
445*4887Schin 		char *fmtq,*ep;
446*4887Schin 		if(isarray && associative)
447*4887Schin 		{
448*4887Schin 			if(!(fmtq = nv_getsub(np)))
449*4887Schin 				break;
450*4887Schin 			sfprintf(wp->out,"[%s]",sh_fmtq(fmtq));
451*4887Schin 			sfputc(wp->out,'=');
452*4887Schin 		}
453*4887Schin 		if(!(fmtq = sh_fmtq(nv_getval(np))))
454*4887Schin 			fmtq = "";
455*4887Schin 		else if(!associative && (ep=strchr(fmtq,'=')))
456*4887Schin 		{
457*4887Schin 			char *qp = strchr(fmtq,'\'');
458*4887Schin 			if(!qp || qp>ep)
459*4887Schin 			{
460*4887Schin 				sfwrite(wp->out,fmtq,ep-fmtq);
461*4887Schin 				sfputc(wp->out,'\\');
462*4887Schin 				fmtq = ep;
463*4887Schin 			}
464*4887Schin 		}
465*4887Schin 		if(*name=='[' && !isarray)
466*4887Schin 			sfprintf(wp->out,"(%s)\n",fmtq);
467*4887Schin 		else
468*4887Schin 			sfputr(wp->out,fmtq,'\n');
469*4887Schin 		if(!nv_nextsub(np))
470*4887Schin 			break;
471*4887Schin 		sfnputc(wp->out,'\t',wp->indent);
472*4887Schin 	}
473*4887Schin 	if(isarray && !special)
474*4887Schin 	{
475*4887Schin 		sfnputc(wp->out,'\t',--wp->indent);
476*4887Schin 		sfwrite(wp->out,")\n",2);
477*4887Schin 	}
478*4887Schin }
479*4887Schin 
480*4887Schin /*
481*4887Schin  * format initialization list given a list of assignments <argp>
482*4887Schin  */
483*4887Schin static char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp)
484*4887Schin {
485*4887Schin 	register char *cp,*nextcp,*arg;
486*4887Schin 	register int m,r;
487*4887Schin 	register Sfio_t *outfile = wp->out;
488*4887Schin 	if(n==0)
489*4887Schin 		m = strlen(prefix);
490*4887Schin 	else if(cp=nextdot(prefix))
491*4887Schin 		m = cp-prefix;
492*4887Schin 	else
493*4887Schin 		m = strlen(prefix)-1;
494*4887Schin 	m++;
495*4887Schin 	if(outfile)
496*4887Schin 	{
497*4887Schin 		sfwrite(outfile,"(\n",2);
498*4887Schin 		wp->indent++;
499*4887Schin 	}
500*4887Schin 	for(; arg= *argv; argv++)
501*4887Schin 	{
502*4887Schin 		cp = arg + n;
503*4887Schin 		if(n==0 && cp[m-1]!='.')
504*4887Schin 			continue;
505*4887Schin 		if(n && cp[m-1]==0)
506*4887Schin 			break;
507*4887Schin 		if(n==0 || strncmp(arg,prefix-n,m+n)==0)
508*4887Schin 		{
509*4887Schin 			cp +=m;
510*4887Schin 			r = 0;
511*4887Schin 			if(*cp=='.')
512*4887Schin 				cp++,r++;
513*4887Schin 			if(nextcp=nextdot(cp))
514*4887Schin 			{
515*4887Schin 				if(outfile)
516*4887Schin 				{
517*4887Schin 					sfnputc(outfile,'\t',wp->indent);
518*4887Schin 					nv_outname(outfile,cp,nextcp-cp);
519*4887Schin 					sfputc(outfile,'=');
520*4887Schin 				}
521*4887Schin 				argv = genvalue(argv,cp,n+m+r,wp);
522*4887Schin 				if(outfile)
523*4887Schin 					sfputc(outfile,'\n');
524*4887Schin 				if(*argv)
525*4887Schin 					continue;
526*4887Schin 				break;
527*4887Schin 			}
528*4887Schin 			else if(outfile && argv[1] && memcmp(arg,argv[1],r=strlen(arg))==0 && argv[1][r]=='[')
529*4887Schin 			{
530*4887Schin 				Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope);
531*4887Schin 				if(!np)
532*4887Schin 					continue;
533*4887Schin 				sfnputc(outfile,'\t',wp->indent);
534*4887Schin 				nv_attribute(np,outfile,"typeset",1);
535*4887Schin 				nv_close(np);
536*4887Schin 				sfputr(outfile,arg+m+(n?n+1:0),'=');
537*4887Schin 				argv = genvalue(++argv,cp,cp-arg ,wp);
538*4887Schin 				sfputc(outfile,'\n');
539*4887Schin 			}
540*4887Schin 			else if(outfile && *cp=='[')
541*4887Schin 			{
542*4887Schin 				sfnputc(outfile,'\t',wp->indent);
543*4887Schin 				sfputr(outfile,cp,'=');
544*4887Schin 				argv = genvalue(++argv,cp,cp-arg ,wp);
545*4887Schin 				sfputc(outfile,'\n');
546*4887Schin 			}
547*4887Schin 			else
548*4887Schin 				outval(cp,arg,wp);
549*4887Schin 		}
550*4887Schin 		else
551*4887Schin 			break;
552*4887Schin 	}
553*4887Schin 	if(outfile)
554*4887Schin 	{
555*4887Schin 		int c = prefix[m-1];
556*4887Schin 		cp = (char*)prefix;
557*4887Schin 		if(c=='.')
558*4887Schin 			cp[m-1] = 0;
559*4887Schin 		outval(".",prefix-n,wp);
560*4887Schin 		if(c=='.')
561*4887Schin 			cp[m-1] = c;
562*4887Schin 		sfnputc(outfile,'\t',wp->indent-1);
563*4887Schin 		sfputc(outfile,')');
564*4887Schin 	}
565*4887Schin 	return(--argv);
566*4887Schin }
567*4887Schin 
568*4887Schin /*
569*4887Schin  * walk the virtual tree and print or delete name-value pairs
570*4887Schin  */
571*4887Schin static char *walk_tree(register Namval_t *np, int dlete)
572*4887Schin {
573*4887Schin 	static Sfio_t *out;
574*4887Schin 	struct Walk walk;
575*4887Schin 	Sfio_t *outfile;
576*4887Schin 	int savtop = staktell();
577*4887Schin 	char *savptr = stakfreeze(0);
578*4887Schin 	register struct argnod *ap=0;
579*4887Schin 	struct argnod *arglist=0;
580*4887Schin 	char *name,*cp, **argv;
581*4887Schin 	char *subscript=0;
582*4887Schin 	void *dir;
583*4887Schin 	int n=0, noscope=(dlete&NV_NOSCOPE);
584*4887Schin 	stakputs(nv_name(np));
585*4887Schin 	if(subscript = nv_getsub(np))
586*4887Schin 	{
587*4887Schin 		stakputc('[');
588*4887Schin 		stakputs(subscript);
589*4887Schin 		stakputc(']');
590*4887Schin 		stakputc('.');
591*4887Schin 	}
592*4887Schin 	name = stakfreeze(1);
593*4887Schin 	dir = nv_diropen(name);
594*4887Schin 	if(subscript)
595*4887Schin 		name[strlen(name)-1] = 0;
596*4887Schin 	while(cp = nv_dirnext(dir))
597*4887Schin 	{
598*4887Schin 		stakseek(ARGVAL);
599*4887Schin 		stakputs(cp);
600*4887Schin 		ap = (struct argnod*)stakfreeze(1);
601*4887Schin 		ap->argflag = ARG_RAW;
602*4887Schin 		ap->argchn.ap = arglist;
603*4887Schin 		n++;
604*4887Schin 		arglist = ap;
605*4887Schin 	}
606*4887Schin 	argv = (char**)stakalloc((n+1)*sizeof(char*));
607*4887Schin 	argv += n;
608*4887Schin 	*argv = 0;
609*4887Schin 	for(; ap; ap=ap->argchn.ap)
610*4887Schin 		*--argv = ap->argval;
611*4887Schin 	nv_dirclose(dir);
612*4887Schin 	if(dlete&1)
613*4887Schin 		outfile = 0;
614*4887Schin 	else if(!(outfile=out))
615*4887Schin 		outfile = out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
616*4887Schin 	else
617*4887Schin 		sfseek(outfile,0L,SEEK_SET);
618*4887Schin 	walk.out = outfile;
619*4887Schin 	walk.root = sh.last_root;
620*4887Schin 	walk.indent = 0;
621*4887Schin 	walk.noscope = noscope;
622*4887Schin 	genvalue(argv,name,0,&walk);
623*4887Schin 	stakset(savptr,savtop);
624*4887Schin 	if(!outfile)
625*4887Schin 		return((char*)0);
626*4887Schin 	sfputc(out,0);
627*4887Schin 	return((char*)out->_data);
628*4887Schin }
629*4887Schin 
630*4887Schin /*
631*4887Schin  * get discipline for compound initializations
632*4887Schin  */
633*4887Schin char *nv_getvtree(register Namval_t *np, Namfun_t *fp)
634*4887Schin {
635*4887Schin 	NOT_USED(fp);
636*4887Schin 	if(nv_isattr(np,NV_BINARY) &&  nv_isattr(np,NV_RAW))
637*4887Schin 		return(nv_getv(np,fp));
638*4887Schin 	if(nv_isattr(np,NV_ARRAY) && nv_arraychild(np,(Namval_t*)0,0)==np)
639*4887Schin 		return(nv_getv(np,fp));
640*4887Schin 	return(walk_tree(np,0));
641*4887Schin }
642*4887Schin 
643*4887Schin /*
644*4887Schin  * put discipline for compound initializations
645*4887Schin  */
646*4887Schin static void put_tree(register Namval_t *np, const char *val, int flags,Namfun_t *fp)
647*4887Schin {
648*4887Schin 	struct Namarray *ap;
649*4887Schin 	int nleft = 0;
650*4887Schin 	if(!nv_isattr(np,NV_INTEGER))
651*4887Schin 		walk_tree(np,(flags&NV_NOSCOPE)|1);
652*4887Schin 	nv_putv(np, val, flags,fp);
653*4887Schin 	if(nv_isattr(np,NV_INTEGER))
654*4887Schin 		return;
655*4887Schin 	if(ap= nv_arrayptr(np))
656*4887Schin 		nleft = array_elem(ap);
657*4887Schin 	if(nleft==0)
658*4887Schin 	{
659*4887Schin 		fp = nv_stack(np,fp);
660*4887Schin 		if(fp = nv_stack(np,NIL(Namfun_t*)))
661*4887Schin 		{
662*4887Schin 			free((void*)fp);
663*4887Schin 		}
664*4887Schin 	}
665*4887Schin }
666*4887Schin 
667*4887Schin /*
668*4887Schin  * Insert discipline to cause $x to print current tree
669*4887Schin  */
670*4887Schin void nv_setvtree(register Namval_t *np)
671*4887Schin {
672*4887Schin 	register Namfun_t *nfp;
673*4887Schin 	if(nv_hasdisc(np, &treedisc))
674*4887Schin 		return;
675*4887Schin 	nfp = newof(NIL(void*),Namfun_t,1,0);
676*4887Schin 	nfp->disc = &treedisc;
677*4887Schin 	nv_stack(np, nfp);
678*4887Schin }
679*4887Schin 
680