14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin 
224887Schin /*
234887Schin  * code for tree nodes and name walking
244887Schin  *
254887Schin  *   David Korn
264887Schin  *   AT&T Labs
274887Schin  *
284887Schin  */
294887Schin 
304887Schin #include	"defs.h"
314887Schin #include	"name.h"
324887Schin #include	"argnod.h"
33*8462SApril.Chin@Sun.COM #include	"lexstates.h"
344887Schin 
354887Schin struct nvdir
364887Schin {
374887Schin 	Dt_t		*root;
384887Schin 	Namval_t	*hp;
394887Schin 	Namval_t	*table;
40*8462SApril.Chin@Sun.COM 	Namval_t	*otable;
414887Schin 	Namval_t	*(*nextnode)(Namval_t*,Dt_t*,Namfun_t*);
424887Schin 	Namfun_t	*fun;
434887Schin 	struct nvdir	*prev;
444887Schin 	int		len;
454887Schin 	char		data[1];
464887Schin };
474887Schin 
484887Schin char *nv_getvtree(Namval_t*, Namfun_t *);
494887Schin static void put_tree(Namval_t*, const char*, int,Namfun_t*);
50*8462SApril.Chin@Sun.COM static char *walk_tree(Namval_t*, Namval_t*, int);
51*8462SApril.Chin@Sun.COM 
52*8462SApril.Chin@Sun.COM static int read_tree(Namval_t* np, Sfio_t *iop, int n, Namfun_t *dp)
53*8462SApril.Chin@Sun.COM {
54*8462SApril.Chin@Sun.COM 	Sfio_t	*sp;
55*8462SApril.Chin@Sun.COM 	char	*cp;
56*8462SApril.Chin@Sun.COM 	int	c;
57*8462SApril.Chin@Sun.COM 	if(n>=0)
58*8462SApril.Chin@Sun.COM 		return(-1);
59*8462SApril.Chin@Sun.COM 	while((c = sfgetc(iop)) &&  isblank(c));
60*8462SApril.Chin@Sun.COM 	sfungetc(iop,c);
61*8462SApril.Chin@Sun.COM 	sfprintf(sh.strbuf,"%s=%c",nv_name(np),0);
62*8462SApril.Chin@Sun.COM 	cp = sfstruse(sh.strbuf);
63*8462SApril.Chin@Sun.COM 	sp = sfopen((Sfio_t*)0,cp,"s");
64*8462SApril.Chin@Sun.COM 	sfstack(iop,sp);
65*8462SApril.Chin@Sun.COM 	c=sh_eval(iop,SH_READEVAL);
66*8462SApril.Chin@Sun.COM 	return(c);
67*8462SApril.Chin@Sun.COM }
684887Schin 
694887Schin static Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp)
704887Schin {
714887Schin 	register Namfun_t *fp=dp;
724887Schin 	while(fp=fp->next)
734887Schin 	{
744887Schin 		if(fp->disc && fp->disc->createf)
754887Schin 		{
764887Schin 			if(np=(*fp->disc->createf)(np,name,flag,fp))
774887Schin 				dp->last = fp->last;
784887Schin 			return(np);
794887Schin 		}
804887Schin 	}
814887Schin 	return((flag&NV_NOADD)?0:np);
824887Schin }
834887Schin 
84*8462SApril.Chin@Sun.COM static Namfun_t *clone_tree(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp){
85*8462SApril.Chin@Sun.COM 	Namfun_t	*dp;
86*8462SApril.Chin@Sun.COM 	if ((flags&NV_MOVE) && nv_type(np))
87*8462SApril.Chin@Sun.COM 		return(fp);
88*8462SApril.Chin@Sun.COM 	dp = nv_clone_disc(fp,flags);
89*8462SApril.Chin@Sun.COM 	if((flags&NV_COMVAR) && !(flags&NV_RAW))
90*8462SApril.Chin@Sun.COM 	{
91*8462SApril.Chin@Sun.COM 		walk_tree(np,mp,flags);
92*8462SApril.Chin@Sun.COM 		if((flags&NV_MOVE) && !(fp->nofree&1))
93*8462SApril.Chin@Sun.COM 			free((void*)fp);
94*8462SApril.Chin@Sun.COM 	}
95*8462SApril.Chin@Sun.COM 	return(dp);
96*8462SApril.Chin@Sun.COM }
97*8462SApril.Chin@Sun.COM 
984887Schin static const Namdisc_t treedisc =
994887Schin {
1004887Schin 	0,
1014887Schin 	put_tree,
1024887Schin 	nv_getvtree,
1034887Schin 	0,
1044887Schin 	0,
105*8462SApril.Chin@Sun.COM 	create_tree,
106*8462SApril.Chin@Sun.COM 	clone_tree
107*8462SApril.Chin@Sun.COM 	,0,0,0,
108*8462SApril.Chin@Sun.COM 	read_tree
1094887Schin };
1104887Schin 
1114887Schin static char *nextdot(const char *str)
1124887Schin {
1134887Schin 	register char *cp;
114*8462SApril.Chin@Sun.COM 	register int c;
1154887Schin 	if(*str=='.')
1164887Schin 		str++;
117*8462SApril.Chin@Sun.COM 	for(cp=(char*)str;c= *cp; cp++)
1184887Schin 	{
119*8462SApril.Chin@Sun.COM 		if(c=='[')
120*8462SApril.Chin@Sun.COM 		{
121*8462SApril.Chin@Sun.COM 			cp = nv_endsubscript((Namval_t*)0,(char*)cp,0);
122*8462SApril.Chin@Sun.COM 			return(*cp=='.'?cp:0);
123*8462SApril.Chin@Sun.COM 		}
124*8462SApril.Chin@Sun.COM 		if(c=='.')
125*8462SApril.Chin@Sun.COM 			return(cp);
1264887Schin 	}
127*8462SApril.Chin@Sun.COM 	return(0);
1284887Schin }
1294887Schin 
1304887Schin static  Namfun_t *nextdisc(Namval_t *np)
1314887Schin {
1324887Schin 	register Namfun_t *fp;
1334887Schin 	if(nv_isref(np))
1344887Schin 		return(0);
1354887Schin         for(fp=np->nvfun;fp;fp=fp->next)
1364887Schin 	{
1374887Schin 		if(fp && fp->disc && fp->disc->nextf)
1384887Schin 			return(fp);
1394887Schin 	}
1404887Schin 	return(0);
1414887Schin }
1424887Schin 
143*8462SApril.Chin@Sun.COM void *nv_diropen(Namval_t *np,const char *name)
1444887Schin {
1454887Schin 	char *next,*last;
1464887Schin 	int c,len=strlen(name);
1474887Schin 	struct nvdir *save, *dp = new_of(struct nvdir,len);
148*8462SApril.Chin@Sun.COM 	Namval_t *nq=0,fake;
149*8462SApril.Chin@Sun.COM 	Namfun_t *nfp=0;
1504887Schin 	if(!dp)
1514887Schin 		return(0);
1524887Schin 	memset((void*)dp, 0, sizeof(*dp));
1534887Schin 	if(name[len-1]=='*' || name[len-1]=='@')
1544887Schin 		len -= 1;
155*8462SApril.Chin@Sun.COM 	name = memcpy(dp->data,name,len);
156*8462SApril.Chin@Sun.COM 	dp->data[len] = 0;
1574887Schin 	dp->len = len;
158*8462SApril.Chin@Sun.COM 	dp->root = sh.last_root?sh.last_root:sh.var_tree;
159*8462SApril.Chin@Sun.COM #if 1
160*8462SApril.Chin@Sun.COM 	while(1)
161*8462SApril.Chin@Sun.COM 	{
162*8462SApril.Chin@Sun.COM 		dp->table = sh.last_table;
163*8462SApril.Chin@Sun.COM 		sh.last_table = 0;
164*8462SApril.Chin@Sun.COM 		if(*(last=(char*)name)==0)
165*8462SApril.Chin@Sun.COM 			break;
166*8462SApril.Chin@Sun.COM 		if(!(next=nextdot(last)))
167*8462SApril.Chin@Sun.COM 			break;
168*8462SApril.Chin@Sun.COM 		*next = 0;
169*8462SApril.Chin@Sun.COM 		np = nv_open(name, dp->root, NV_NOFAIL);
170*8462SApril.Chin@Sun.COM 		*next = '.';
171*8462SApril.Chin@Sun.COM 		if(!np || !nv_istable(np))
172*8462SApril.Chin@Sun.COM 			break;
173*8462SApril.Chin@Sun.COM 		dp->root = nv_dict(np);
174*8462SApril.Chin@Sun.COM 		name = next+1;
175*8462SApril.Chin@Sun.COM 	}
176*8462SApril.Chin@Sun.COM #else
1774887Schin 	dp->table = sh.last_table;
178*8462SApril.Chin@Sun.COM 	sh.last_table = 0;
179*8462SApril.Chin@Sun.COM 	last = dp->data;
180*8462SApril.Chin@Sun.COM #endif
1814887Schin 	if(*name)
1824887Schin 	{
1834887Schin 		fake.nvname = (char*)name;
184*8462SApril.Chin@Sun.COM 		if(dp->hp = (Namval_t*)dtprev(dp->root,&fake))
185*8462SApril.Chin@Sun.COM 		{
186*8462SApril.Chin@Sun.COM 			char *cp = nv_name(dp->hp);
187*8462SApril.Chin@Sun.COM 			c = strlen(cp);
188*8462SApril.Chin@Sun.COM 			if(memcmp(name,cp,c) || name[c]!='[')
189*8462SApril.Chin@Sun.COM 				dp->hp = (Namval_t*)dtnext(dp->root,dp->hp);
190*8462SApril.Chin@Sun.COM 			else
191*8462SApril.Chin@Sun.COM 			{
192*8462SApril.Chin@Sun.COM 				np = dp->hp;
193*8462SApril.Chin@Sun.COM 				last = 0;
194*8462SApril.Chin@Sun.COM 			}
195*8462SApril.Chin@Sun.COM 		}
1964887Schin 	}
1974887Schin 	else
1984887Schin 		dp->hp = (Namval_t*)dtfirst(dp->root);
199*8462SApril.Chin@Sun.COM 	while(1)
2004887Schin 	{
201*8462SApril.Chin@Sun.COM 		if(!last)
202*8462SApril.Chin@Sun.COM 			next = 0;
203*8462SApril.Chin@Sun.COM 		else if(next= nextdot(last))
204*8462SApril.Chin@Sun.COM 		{
205*8462SApril.Chin@Sun.COM 			c = *next;
206*8462SApril.Chin@Sun.COM 			*next = 0;
207*8462SApril.Chin@Sun.COM 		}
208*8462SApril.Chin@Sun.COM 		if(!np)
209*8462SApril.Chin@Sun.COM 		{
210*8462SApril.Chin@Sun.COM 			if(nfp && nfp->disc && nfp->disc->createf)
211*8462SApril.Chin@Sun.COM 			{
212*8462SApril.Chin@Sun.COM 				np =  (*nfp->disc->createf)(nq,last,0,nfp);
213*8462SApril.Chin@Sun.COM 				if(*nfp->last == '[')
214*8462SApril.Chin@Sun.COM 				{
215*8462SApril.Chin@Sun.COM 					nv_endsubscript(np,nfp->last,NV_NOADD);
216*8462SApril.Chin@Sun.COM 					if(nq = nv_opensub(np))
217*8462SApril.Chin@Sun.COM 						np = nq;
218*8462SApril.Chin@Sun.COM 				}
219*8462SApril.Chin@Sun.COM 			}
220*8462SApril.Chin@Sun.COM 			else
221*8462SApril.Chin@Sun.COM 				np = nv_search(last,dp->root,0);
222*8462SApril.Chin@Sun.COM 		}
223*8462SApril.Chin@Sun.COM 		if(next)
224*8462SApril.Chin@Sun.COM 			*next = c;
225*8462SApril.Chin@Sun.COM 		if(np==dp->hp && !next)
226*8462SApril.Chin@Sun.COM 			dp->hp = (Namval_t*)dtnext(dp->root,dp->hp);
2274887Schin 		if(np && ((nfp=nextdisc(np)) || nv_istable(np)))
2284887Schin 		{
2294887Schin 			if(!(save = new_of(struct nvdir,0)))
2304887Schin 				return(0);
2314887Schin 			*save = *dp;
2324887Schin 			dp->prev = save;
2334887Schin 			if(nv_istable(np))
2344887Schin 				dp->root = nv_dict(np);
2354887Schin 			else
236*8462SApril.Chin@Sun.COM 				dp->root = (Dt_t*)np;
2374887Schin 			if(nfp)
2384887Schin 			{
2394887Schin 				dp->nextnode = nfp->disc->nextf;
2404887Schin 				dp->table = np;
241*8462SApril.Chin@Sun.COM 				dp->otable = sh.last_table;
2424887Schin 				dp->fun = nfp;
2434887Schin 				dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
2444887Schin 			}
2454887Schin 			else
2464887Schin 				dp->nextnode = 0;
2474887Schin 		}
2484887Schin 		else
2494887Schin 			break;
250*8462SApril.Chin@Sun.COM 		if(!next || next[1]==0)
251*8462SApril.Chin@Sun.COM 			break;
2524887Schin 		last = next+1;
253*8462SApril.Chin@Sun.COM 		nq = np;
254*8462SApril.Chin@Sun.COM 		np = 0;
2554887Schin 	}
2564887Schin 	return((void*)dp);
2574887Schin }
2584887Schin 
2594887Schin 
2604887Schin static Namval_t *nextnode(struct nvdir *dp)
2614887Schin {
2624887Schin 	if(dp->nextnode)
2634887Schin 		return((*dp->nextnode)(dp->hp,dp->root,dp->fun));
2644887Schin 	if(dp->len && memcmp(dp->data, dp->hp->nvname, dp->len))
2654887Schin 		return(0);
2664887Schin 	return((Namval_t*)dtnext(dp->root,dp->hp));
2674887Schin }
2684887Schin 
2694887Schin char *nv_dirnext(void *dir)
2704887Schin {
2714887Schin 	register struct nvdir *save, *dp = (struct nvdir*)dir;
2724887Schin 	register Namval_t *np, *last_table;
2734887Schin 	register char *cp;
2744887Schin 	Namfun_t *nfp;
275*8462SApril.Chin@Sun.COM 	Namval_t *nq;
2764887Schin 	while(1)
2774887Schin 	{
2784887Schin 		while(np=dp->hp)
2794887Schin 		{
280*8462SApril.Chin@Sun.COM #if 0
281*8462SApril.Chin@Sun.COM 			char *sptr;
282*8462SApril.Chin@Sun.COM #endif
283*8462SApril.Chin@Sun.COM 			if(nv_isarray(np))
284*8462SApril.Chin@Sun.COM 				nv_putsub(np,(char*)0, ARRAY_UNDEF);
2854887Schin 			dp->hp = nextnode(dp);
286*8462SApril.Chin@Sun.COM 			if(nv_isnull(np) && !nv_isarray(np))
2874887Schin 				continue;
2884887Schin 			last_table = sh.last_table;
289*8462SApril.Chin@Sun.COM #if 0
290*8462SApril.Chin@Sun.COM 			if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL))
291*8462SApril.Chin@Sun.COM 			{
292*8462SApril.Chin@Sun.COM 				sptr = dp->table->nvenv;
293*8462SApril.Chin@Sun.COM 				dp->table->nvenv = (char*)dp->otable;
294*8462SApril.Chin@Sun.COM 			}
295*8462SApril.Chin@Sun.COM #endif
2964887Schin 			sh.last_table = dp->table;
2974887Schin 			cp = nv_name(np);
298*8462SApril.Chin@Sun.COM #if 0
299*8462SApril.Chin@Sun.COM 			if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL))
300*8462SApril.Chin@Sun.COM 				dp->table->nvenv = sptr;
301*8462SApril.Chin@Sun.COM #endif
302*8462SApril.Chin@Sun.COM 			if(dp->nextnode && !dp->hp && (nq = (Namval_t*)dp->table))
303*8462SApril.Chin@Sun.COM 			{
304*8462SApril.Chin@Sun.COM 				Namarr_t  *ap = nv_arrayptr(nq);
305*8462SApril.Chin@Sun.COM 				if(ap && (ap->nelem&ARRAY_SCAN) && nv_nextsub(nq))
306*8462SApril.Chin@Sun.COM 					dp->hp = (*dp->nextnode)(np,(Dt_t*)0,dp->fun);
307*8462SApril.Chin@Sun.COM 			}
3084887Schin 			sh.last_table = last_table;
309*8462SApril.Chin@Sun.COM 			if(!dp->len || memcmp(cp,dp->data,dp->len)==0)
3104887Schin 			{
311*8462SApril.Chin@Sun.COM 				if((nfp=nextdisc(np)) && (nfp->disc->getval||nfp->disc->getnum) && nv_isvtree(np) && strcmp(cp,dp->data))
312*8462SApril.Chin@Sun.COM 					nfp = 0;
313*8462SApril.Chin@Sun.COM 				if(nfp || nv_istable(np))
3144887Schin 				{
3154887Schin 					Dt_t *root;
3164887Schin 					if(nv_istable(np))
3174887Schin 						root = nv_dict(np);
3184887Schin 					else
319*8462SApril.Chin@Sun.COM 						root = (Dt_t*)np;
3204887Schin 					/* check for recursive walk */
3214887Schin 					for(save=dp; save;  save=save->prev)
3224887Schin 					{
3234887Schin 						if(save->root==root)
3244887Schin 							break;
3254887Schin 					}
3264887Schin 					if(save)
327*8462SApril.Chin@Sun.COM 						return(cp);
3284887Schin 					if(!(save = new_of(struct nvdir,0)))
3294887Schin 						return(0);
3304887Schin 					*save = *dp;
3314887Schin 					dp->prev = save;
3324887Schin 					dp->root = root;
3334887Schin 					dp->len = 0;
3344887Schin 					if(nfp && np->nvfun)
3354887Schin 					{
336*8462SApril.Chin@Sun.COM #if 0
337*8462SApril.Chin@Sun.COM 				                Namarr_t *ap = nv_arrayptr(np);
338*8462SApril.Chin@Sun.COM 				                if(ap && (ap->nelem&ARRAY_UNDEF))
339*8462SApril.Chin@Sun.COM 				                        nv_putsub(np,(char*)0,ARRAY_SCAN);
340*8462SApril.Chin@Sun.COM #endif
3414887Schin 						dp->nextnode = nfp->disc->nextf;
342*8462SApril.Chin@Sun.COM 						dp->otable = dp->table;
3434887Schin 						dp->table = np;
3444887Schin 						dp->fun = nfp;
3454887Schin 						dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
3464887Schin 					}
3474887Schin 					else
3484887Schin 						dp->nextnode = 0;
3494887Schin 				}
3504887Schin 				return(cp);
3514887Schin 			}
3524887Schin 		}
3534887Schin 		if(!(save=dp->prev))
3544887Schin 			break;
3554887Schin 		*dp = *save;
3564887Schin 		free((void*)save);
3574887Schin 	}
3584887Schin 	return(0);
3594887Schin }
3604887Schin 
3614887Schin void nv_dirclose(void *dir)
3624887Schin {
3634887Schin 	struct nvdir *dp = (struct nvdir*)dir;
3644887Schin 	if(dp->prev)
3654887Schin 		nv_dirclose((void*)dp->prev);
3664887Schin 	free(dir);
3674887Schin }
3684887Schin 
3694887Schin static void outtype(Namval_t *np, Namfun_t *fp, Sfio_t* out, const char *prefix)
3704887Schin {
3714887Schin 	char *type=0;
3724887Schin 	Namval_t *tp = fp->type;
3734887Schin 	if(!tp && fp->disc && fp->disc->typef)
3744887Schin 		tp = (*fp->disc->typef)(np,fp);
3754887Schin 	for(fp=fp->next;fp;fp=fp->next)
3764887Schin 	{
3774887Schin 		if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp)))
3784887Schin 		{
3794887Schin 			outtype(np,fp,out,prefix);
3804887Schin 			break;
3814887Schin 		}
3824887Schin 	}
3834887Schin 	if(prefix && *prefix=='t')
3844887Schin 		type = "-T";
3854887Schin 	else if(!prefix)
3864887Schin 		type = "type";
3874887Schin 	if(type)
388*8462SApril.Chin@Sun.COM 	{
389*8462SApril.Chin@Sun.COM 		char *cp=tp->nvname;
390*8462SApril.Chin@Sun.COM 		if(cp=strrchr(cp,'.'))
391*8462SApril.Chin@Sun.COM 			cp++;
392*8462SApril.Chin@Sun.COM 		else
393*8462SApril.Chin@Sun.COM 			cp = tp->nvname;
394*8462SApril.Chin@Sun.COM 		sfprintf(out,"%s %s ",type,cp);
395*8462SApril.Chin@Sun.COM 	}
3964887Schin }
3974887Schin 
3984887Schin /*
3994887Schin  * print the attributes of name value pair give by <np>
4004887Schin  */
4014887Schin void nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname)
4024887Schin {
4034887Schin 	register const Shtable_t *tp;
4044887Schin 	register char *cp;
405*8462SApril.Chin@Sun.COM 	register unsigned val,mask,attr;
406*8462SApril.Chin@Sun.COM 	char *ip=0;
4074887Schin 	Namfun_t *fp=0;
408*8462SApril.Chin@Sun.COM 	Namval_t *typep=0;
4094887Schin 	for(fp=np->nvfun;fp;fp=fp->next)
4104887Schin 	{
411*8462SApril.Chin@Sun.COM 		if((typep=fp->type) || (fp->disc && fp->disc->typef && (typep=(*fp->disc->typef)(np,fp))))
4124887Schin 			break;
4134887Schin 	}
414*8462SApril.Chin@Sun.COM 	if(!fp  && !nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)))
4154887Schin 	{
416*8462SApril.Chin@Sun.COM 		if(prefix && *prefix)
417*8462SApril.Chin@Sun.COM 		{
418*8462SApril.Chin@Sun.COM 			if(nv_isvtree(np))
419*8462SApril.Chin@Sun.COM 				sfprintf(out,"%s -C ",prefix);
420*8462SApril.Chin@Sun.COM 			else if(!np->nvalue.cp && nv_isattr(np,~NV_NOFREE)==NV_MINIMAL && strcmp(np->nvname,"_"))
421*8462SApril.Chin@Sun.COM 				sfputr(out,prefix,' ');
422*8462SApril.Chin@Sun.COM 		}
423*8462SApril.Chin@Sun.COM 		return;
4244887Schin 	}
4254887Schin 
4264887Schin 	if ((attr=nv_isattr(np,~NV_NOFREE)) || fp)
4274887Schin 	{
428*8462SApril.Chin@Sun.COM 		if((attr&NV_NOPRINT|NV_INTEGER)==NV_NOPRINT)
4294887Schin 			attr &= ~NV_NOPRINT;
4304887Schin 		if(!attr && !fp)
4314887Schin 			return;
432*8462SApril.Chin@Sun.COM 		if(fp)
433*8462SApril.Chin@Sun.COM 		{
434*8462SApril.Chin@Sun.COM 			prefix = Empty;
435*8462SApril.Chin@Sun.COM 			attr &= NV_RDONLY|NV_ARRAY;
436*8462SApril.Chin@Sun.COM 			if(nv_isattr(np,NV_REF|NV_TAGGED)==(NV_REF|NV_TAGGED))
437*8462SApril.Chin@Sun.COM 				attr |= (NV_REF|NV_TAGGED);
438*8462SApril.Chin@Sun.COM 			if(typep)
439*8462SApril.Chin@Sun.COM 			{
440*8462SApril.Chin@Sun.COM 				char *cp = typep->nvname;
441*8462SApril.Chin@Sun.COM 				if(cp = strrchr(cp,'.'))
442*8462SApril.Chin@Sun.COM 					cp++;
443*8462SApril.Chin@Sun.COM 				else
444*8462SApril.Chin@Sun.COM 					cp = typep->nvname;
445*8462SApril.Chin@Sun.COM 				sfputr(out,cp,' ');
446*8462SApril.Chin@Sun.COM 				fp = 0;
447*8462SApril.Chin@Sun.COM 			}
448*8462SApril.Chin@Sun.COM 		}
449*8462SApril.Chin@Sun.COM 		else if(prefix && *prefix)
4504887Schin 			sfputr(out,prefix,' ');
4514887Schin 		for(tp = shtab_attributes; *tp->sh_name;tp++)
4524887Schin 		{
4534887Schin 			val = tp->sh_number;
4544887Schin 			mask = val;
4554887Schin 			if(fp && (val&NV_INTEGER))
4564887Schin 				break;
4574887Schin 			/*
4584887Schin 			 * the following test is needed to prevent variables
4594887Schin 			 * with E attribute from being given the F
4604887Schin 			 * attribute as well
4614887Schin 			*/
462*8462SApril.Chin@Sun.COM 			if(val==NV_DOUBLE && (attr&(NV_EXPNOTE|NV_HEXFLOAT)))
4634887Schin 				continue;
4644887Schin 			if(val&NV_INTEGER)
4654887Schin 				mask |= NV_DOUBLE;
4664887Schin 			else if(val&NV_HOST)
4674887Schin 				mask = NV_HOST;
4684887Schin 			if((attr&mask)==val)
4694887Schin 			{
4704887Schin 				if(val==NV_ARRAY)
4714887Schin 				{
4724887Schin 					Namarr_t *ap = nv_arrayptr(np);
473*8462SApril.Chin@Sun.COM 					char **xp=0;
474*8462SApril.Chin@Sun.COM 					if(ap && array_assoc(ap))
4754887Schin 					{
4764887Schin 						if(tp->sh_name[1]!='A')
4774887Schin 							continue;
4784887Schin 					}
4794887Schin 					else if(tp->sh_name[1]=='A')
4804887Schin 						continue;
481*8462SApril.Chin@Sun.COM 					if(ap && (ap->nelem&ARRAY_TREE))
482*8462SApril.Chin@Sun.COM 					{
483*8462SApril.Chin@Sun.COM 						if(prefix && *prefix)
484*8462SApril.Chin@Sun.COM 							sfwrite(out,"-C ",3);
485*8462SApril.Chin@Sun.COM 					}
486*8462SApril.Chin@Sun.COM 					if(ap && !array_assoc(ap) && (xp=(char**)(ap+1)) && *xp)
487*8462SApril.Chin@Sun.COM 						ip = nv_namptr(*xp,0)->nvname;
4884887Schin 				}
4894887Schin 				if(prefix)
4904887Schin 				{
4914887Schin 					if(*tp->sh_name=='-')
4924887Schin 						sfprintf(out,"%.2s ",tp->sh_name);
493*8462SApril.Chin@Sun.COM 					if(ip)
494*8462SApril.Chin@Sun.COM 					{
495*8462SApril.Chin@Sun.COM 						sfprintf(out,"[%s] ",ip);
496*8462SApril.Chin@Sun.COM 						ip = 0;
497*8462SApril.Chin@Sun.COM 					}
4984887Schin 				}
4994887Schin 				else
5004887Schin 					sfputr(out,tp->sh_name+2,' ');
5014887Schin 		                if ((val&(NV_LJUST|NV_RJUST|NV_ZFILL)) && !(val&NV_INTEGER) && val!=NV_HOST)
5024887Schin 					sfprintf(out,"%d ",nv_size(np));
503*8462SApril.Chin@Sun.COM 				if(val==(NV_REF|NV_TAGGED))
504*8462SApril.Chin@Sun.COM 					attr &= ~(NV_REF|NV_TAGGED);
5054887Schin 			}
5064887Schin 		        if(val==NV_INTEGER && nv_isattr(np,NV_INTEGER))
5074887Schin 			{
5084887Schin 				if(nv_size(np) != 10)
5094887Schin 				{
510*8462SApril.Chin@Sun.COM 					if(nv_isattr(np, NV_DOUBLE)== NV_DOUBLE)
5114887Schin 						cp = "precision";
5124887Schin 					else
5134887Schin 						cp = "base";
5144887Schin 					if(!prefix)
5154887Schin 						sfputr(out,cp,' ');
5164887Schin 					sfprintf(out,"%d ",nv_size(np));
5174887Schin 				}
5184887Schin 				break;
5194887Schin 			}
5204887Schin 		}
5214887Schin 		if(fp)
5224887Schin 			outtype(np,fp,out,prefix);
5234887Schin 		if(noname)
5244887Schin 			return;
5254887Schin 		sfputr(out,nv_name(np),'\n');
5264887Schin 	}
5274887Schin }
5284887Schin 
5294887Schin struct Walk
5304887Schin {
5314887Schin 	Sfio_t	*out;
5324887Schin 	Dt_t	*root;
5334887Schin 	int	noscope;
5344887Schin 	int	indent;
535*8462SApril.Chin@Sun.COM 	int	nofollow;
536*8462SApril.Chin@Sun.COM 	int	array;
537*8462SApril.Chin@Sun.COM 	int	flags;
5384887Schin };
5394887Schin 
540*8462SApril.Chin@Sun.COM void nv_outnode(Namval_t *np, Sfio_t* out, int indent, int special)
541*8462SApril.Chin@Sun.COM {
542*8462SApril.Chin@Sun.COM 	char		*fmtq,*ep,*xp;
543*8462SApril.Chin@Sun.COM 	Namval_t	*mp;
544*8462SApril.Chin@Sun.COM 	Namarr_t	*ap = nv_arrayptr(np);
545*8462SApril.Chin@Sun.COM 	int		tabs=0,c,more,associative = 0;
546*8462SApril.Chin@Sun.COM 	if(ap)
547*8462SApril.Chin@Sun.COM 	{
548*8462SApril.Chin@Sun.COM 		if(!(ap->nelem&ARRAY_SCAN))
549*8462SApril.Chin@Sun.COM 			nv_putsub(np,NIL(char*),ARRAY_SCAN);
550*8462SApril.Chin@Sun.COM 		sfputc(out,'(');
551*8462SApril.Chin@Sun.COM 		if(indent>=0)
552*8462SApril.Chin@Sun.COM 		{
553*8462SApril.Chin@Sun.COM 			sfputc(out,'\n');
554*8462SApril.Chin@Sun.COM 			tabs=1;
555*8462SApril.Chin@Sun.COM 		}
556*8462SApril.Chin@Sun.COM 		if(!(associative =(array_assoc(ap)!=0)))
557*8462SApril.Chin@Sun.COM 		{
558*8462SApril.Chin@Sun.COM 			if(array_elem(ap) < nv_aimax(np)+1)
559*8462SApril.Chin@Sun.COM 				associative=1;
560*8462SApril.Chin@Sun.COM 		}
561*8462SApril.Chin@Sun.COM 	}
562*8462SApril.Chin@Sun.COM 	mp = nv_opensub(np);
563*8462SApril.Chin@Sun.COM 	while(1)
564*8462SApril.Chin@Sun.COM 	{
565*8462SApril.Chin@Sun.COM 		if(mp && special && nv_isvtree(mp))
566*8462SApril.Chin@Sun.COM 		{
567*8462SApril.Chin@Sun.COM 			if(!nv_nextsub(np))
568*8462SApril.Chin@Sun.COM 				break;
569*8462SApril.Chin@Sun.COM 			mp = nv_opensub(np);
570*8462SApril.Chin@Sun.COM 			continue;
571*8462SApril.Chin@Sun.COM 		}
572*8462SApril.Chin@Sun.COM 		if(tabs)
573*8462SApril.Chin@Sun.COM 			sfnputc(out,'\t',++indent);
574*8462SApril.Chin@Sun.COM 		tabs=0;
575*8462SApril.Chin@Sun.COM 		if(associative||special)
576*8462SApril.Chin@Sun.COM 		{
577*8462SApril.Chin@Sun.COM 			if(!(fmtq = nv_getsub(np)))
578*8462SApril.Chin@Sun.COM 				break;
579*8462SApril.Chin@Sun.COM 			sfprintf(out,"[%s]",sh_fmtq(fmtq));
580*8462SApril.Chin@Sun.COM 			sfputc(out,'=');
581*8462SApril.Chin@Sun.COM 		}
582*8462SApril.Chin@Sun.COM 		if(mp && nv_isarray(mp))
583*8462SApril.Chin@Sun.COM 		{
584*8462SApril.Chin@Sun.COM 			nv_outnode(mp, out, indent+(indent>=0),0);
585*8462SApril.Chin@Sun.COM 			if(indent>0)
586*8462SApril.Chin@Sun.COM 				sfnputc(out,'\t',indent);
587*8462SApril.Chin@Sun.COM 			sfputc(out,')');
588*8462SApril.Chin@Sun.COM 			sfputc(out,indent>=0?'\n':' ');
589*8462SApril.Chin@Sun.COM 			more = nv_nextsub(np);
590*8462SApril.Chin@Sun.COM 			goto skip;
591*8462SApril.Chin@Sun.COM 		}
592*8462SApril.Chin@Sun.COM 		if(mp && nv_isvtree(mp))
593*8462SApril.Chin@Sun.COM 			nv_onattr(mp,NV_EXPORT);
594*8462SApril.Chin@Sun.COM 		ep = nv_getval(mp?mp:np);
595*8462SApril.Chin@Sun.COM 		xp = 0;
596*8462SApril.Chin@Sun.COM 		if(!ap && nv_isattr(np,NV_INTEGER|NV_LJUST)==NV_LJUST)
597*8462SApril.Chin@Sun.COM 		{
598*8462SApril.Chin@Sun.COM 			xp = ep+nv_size(np);
599*8462SApril.Chin@Sun.COM 			while(--xp>ep && *xp==' ');
600*8462SApril.Chin@Sun.COM 			if(xp>ep || *xp!=' ')
601*8462SApril.Chin@Sun.COM 				xp++;
602*8462SApril.Chin@Sun.COM 			if(xp < (ep+nv_size(np)))
603*8462SApril.Chin@Sun.COM 				*xp = 0;
604*8462SApril.Chin@Sun.COM 			else
605*8462SApril.Chin@Sun.COM 				xp = 0;
606*8462SApril.Chin@Sun.COM 		}
607*8462SApril.Chin@Sun.COM 		if(mp && nv_isvtree(mp))
608*8462SApril.Chin@Sun.COM 			fmtq = ep;
609*8462SApril.Chin@Sun.COM 		else if(!(fmtq = sh_fmtq(ep)))
610*8462SApril.Chin@Sun.COM 			fmtq = "";
611*8462SApril.Chin@Sun.COM 		else if(!associative && (ep=strchr(fmtq,'=')))
612*8462SApril.Chin@Sun.COM 		{
613*8462SApril.Chin@Sun.COM 			char *qp = strchr(fmtq,'\'');
614*8462SApril.Chin@Sun.COM 			if(!qp || qp>ep)
615*8462SApril.Chin@Sun.COM 			{
616*8462SApril.Chin@Sun.COM 				sfwrite(out,fmtq,ep-fmtq);
617*8462SApril.Chin@Sun.COM 				sfputc(out,'\\');
618*8462SApril.Chin@Sun.COM 				fmtq = ep;
619*8462SApril.Chin@Sun.COM 			}
620*8462SApril.Chin@Sun.COM 		}
621*8462SApril.Chin@Sun.COM 		more = nv_nextsub(np);
622*8462SApril.Chin@Sun.COM 		c = '\n';
623*8462SApril.Chin@Sun.COM 		if(indent<0)
624*8462SApril.Chin@Sun.COM 		{
625*8462SApril.Chin@Sun.COM 			c = ';';
626*8462SApril.Chin@Sun.COM 			if(ap)
627*8462SApril.Chin@Sun.COM 				c = more?' ':-1;
628*8462SApril.Chin@Sun.COM 		}
629*8462SApril.Chin@Sun.COM 		sfputr(out,fmtq,c);
630*8462SApril.Chin@Sun.COM 		if(xp)
631*8462SApril.Chin@Sun.COM 			*xp = ' ';
632*8462SApril.Chin@Sun.COM 	skip:
633*8462SApril.Chin@Sun.COM 		if(!more)
634*8462SApril.Chin@Sun.COM 			return;
635*8462SApril.Chin@Sun.COM 		mp = nv_opensub(np);
636*8462SApril.Chin@Sun.COM 		if(indent>0 && !(mp && special && nv_isvtree(mp)))
637*8462SApril.Chin@Sun.COM 			sfnputc(out,'\t',indent);
638*8462SApril.Chin@Sun.COM 	}
639*8462SApril.Chin@Sun.COM }
640*8462SApril.Chin@Sun.COM 
6414887Schin static void outval(char *name, const char *vname, struct Walk *wp)
6424887Schin {
6434887Schin 	register Namval_t *np, *nq;
6444887Schin         register Namfun_t *fp;
645*8462SApril.Chin@Sun.COM 	int isarray=0, special=0,mode=0;
646*8462SApril.Chin@Sun.COM 	if(*name!='.' || vname[strlen(vname)-1]==']')
647*8462SApril.Chin@Sun.COM 		mode = NV_ARRAY;
648*8462SApril.Chin@Sun.COM 	if(!(np=nv_open(vname,wp->root,mode|NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope)))
6494887Schin 		return;
650*8462SApril.Chin@Sun.COM 	fp = nv_hasdisc(np,&treedisc);
651*8462SApril.Chin@Sun.COM 	if(*name=='.')
6524887Schin 	{
653*8462SApril.Chin@Sun.COM 		if(nv_isattr(np,NV_BINARY))
654*8462SApril.Chin@Sun.COM 			return;
655*8462SApril.Chin@Sun.COM 		if(fp && np->nvalue.cp && np->nvalue.cp!=Empty)
656*8462SApril.Chin@Sun.COM 		{
657*8462SApril.Chin@Sun.COM 			nv_local = 1;
658*8462SApril.Chin@Sun.COM 			fp = 0;
659*8462SApril.Chin@Sun.COM 		}
660*8462SApril.Chin@Sun.COM 		if(fp)
661*8462SApril.Chin@Sun.COM 			return;
662*8462SApril.Chin@Sun.COM 		if(nv_isarray(np))
663*8462SApril.Chin@Sun.COM 			return;
664*8462SApril.Chin@Sun.COM 	}
665*8462SApril.Chin@Sun.COM 	if(!special && fp && !nv_isarray(np))
666*8462SApril.Chin@Sun.COM 	{
667*8462SApril.Chin@Sun.COM 		Namfun_t *xp;
6684887Schin 		if(!wp->out)
6694887Schin 		{
6704887Schin 			fp = nv_stack(np,fp);
6714887Schin 			if(fp = nv_stack(np,NIL(Namfun_t*)))
6724887Schin 				free((void*)fp);
6734887Schin 			np->nvfun = 0;
674*8462SApril.Chin@Sun.COM 			return;
6754887Schin 		}
676*8462SApril.Chin@Sun.COM 		for(xp=fp->next; xp; xp = xp->next)
677*8462SApril.Chin@Sun.COM 		{
678*8462SApril.Chin@Sun.COM 			if(xp->disc && (xp->disc->getval || xp->disc->getnum))
679*8462SApril.Chin@Sun.COM 				break;
680*8462SApril.Chin@Sun.COM 		}
681*8462SApril.Chin@Sun.COM 		if(!xp)
682*8462SApril.Chin@Sun.COM 			return;
6834887Schin 	}
684*8462SApril.Chin@Sun.COM 	if((nv_isnull(np) || np->nvalue.cp==Empty) && !nv_isarray(np))
6854887Schin 		return;
686*8462SApril.Chin@Sun.COM 	if(special || (nv_isarray(np) && nv_arrayptr(np)))
6874887Schin 	{
6884887Schin 		isarray=1;
6894887Schin 		if(array_elem(nv_arrayptr(np))==0)
6904887Schin 			isarray=2;
6914887Schin 		else
6924887Schin 			nq = nv_putsub(np,NIL(char*),ARRAY_SCAN|(wp->out?ARRAY_NOCHILD:0));
6934887Schin 	}
6944887Schin 	if(!wp->out)
6954887Schin 	{
6964887Schin 		_nv_unset(np,NV_RDONLY);
6974887Schin 		nv_close(np);
698*8462SApril.Chin@Sun.COM #if 0
699*8462SApril.Chin@Sun.COM 		if(sh.subshell==0 && !(wp->flags&NV_RDONLY) && !nv_isattr(np,NV_MINIMAL|NV_NOFREE))
700*8462SApril.Chin@Sun.COM 			nv_delete(np,wp->root,0);
701*8462SApril.Chin@Sun.COM #endif
7024887Schin 		return;
7034887Schin 	}
7044887Schin 	if(isarray==1 && !nq)
705*8462SApril.Chin@Sun.COM 	{
706*8462SApril.Chin@Sun.COM 		sfputc(wp->out,'(');
707*8462SApril.Chin@Sun.COM 		if(wp->indent>=0)
708*8462SApril.Chin@Sun.COM 			sfputc(wp->out,'\n');
7094887Schin 		return;
7104887Schin 	}
711*8462SApril.Chin@Sun.COM 	if(isarray==0 && nv_isarray(np) && nv_isnull(np))  /* empty array */
712*8462SApril.Chin@Sun.COM 		isarray = 2;
713*8462SApril.Chin@Sun.COM 	special |= wp->nofollow;
714*8462SApril.Chin@Sun.COM 	if(!wp->array && wp->indent>0)
7154887Schin 		sfnputc(wp->out,'\t',wp->indent);
716*8462SApril.Chin@Sun.COM 	if(!special)
7174887Schin 	{
718*8462SApril.Chin@Sun.COM 		if(*name!='.')
719*8462SApril.Chin@Sun.COM 			nv_attribute(np,wp->out,"typeset",'=');
720*8462SApril.Chin@Sun.COM 		nv_outname(wp->out,name,-1);
721*8462SApril.Chin@Sun.COM 		if(np->nvalue.cp || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)) || nv_isvtree(np))
722*8462SApril.Chin@Sun.COM 			sfputc(wp->out,(isarray==2?'\n':'='));
723*8462SApril.Chin@Sun.COM 		if(isarray==2)
724*8462SApril.Chin@Sun.COM 			return;
7254887Schin 	}
726*8462SApril.Chin@Sun.COM 	fp = np->nvfun;
727*8462SApril.Chin@Sun.COM 	if(*name=='.' && !isarray)
728*8462SApril.Chin@Sun.COM 		np->nvfun = 0;
729*8462SApril.Chin@Sun.COM 	nv_outnode(np, wp->out, wp->indent, special);
730*8462SApril.Chin@Sun.COM 	if(*name=='.' && !isarray)
731*8462SApril.Chin@Sun.COM 		np->nvfun = fp;
7324887Schin 	if(isarray && !special)
7334887Schin 	{
734*8462SApril.Chin@Sun.COM 		if(wp->indent>0)
735*8462SApril.Chin@Sun.COM 		{
736*8462SApril.Chin@Sun.COM 			sfnputc(wp->out,'\t',wp->indent);
737*8462SApril.Chin@Sun.COM 			sfwrite(wp->out,")\n",2);
738*8462SApril.Chin@Sun.COM 		}
739*8462SApril.Chin@Sun.COM 		else
740*8462SApril.Chin@Sun.COM 			sfwrite(wp->out,");",2);
7414887Schin 	}
7424887Schin }
7434887Schin 
7444887Schin /*
7454887Schin  * format initialization list given a list of assignments <argp>
7464887Schin  */
7474887Schin static char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp)
7484887Schin {
7494887Schin 	register char *cp,*nextcp,*arg;
7504887Schin 	register Sfio_t *outfile = wp->out;
751*8462SApril.Chin@Sun.COM 	register int m,r,l;
7524887Schin 	if(n==0)
7534887Schin 		m = strlen(prefix);
7544887Schin 	else if(cp=nextdot(prefix))
7554887Schin 		m = cp-prefix;
7564887Schin 	else
7574887Schin 		m = strlen(prefix)-1;
7584887Schin 	m++;
759*8462SApril.Chin@Sun.COM 	if(outfile && !wp->array)
7604887Schin 	{
761*8462SApril.Chin@Sun.COM 		sfputc(outfile,'(');
762*8462SApril.Chin@Sun.COM 		if(wp->indent>=0)
763*8462SApril.Chin@Sun.COM 		{
764*8462SApril.Chin@Sun.COM 			wp->indent++;
765*8462SApril.Chin@Sun.COM 			sfputc(outfile,'\n');
766*8462SApril.Chin@Sun.COM 		}
7674887Schin 	}
7684887Schin 	for(; arg= *argv; argv++)
7694887Schin 	{
7704887Schin 		cp = arg + n;
7714887Schin 		if(n==0 && cp[m-1]!='.')
7724887Schin 			continue;
7734887Schin 		if(n && cp[m-1]==0)
7744887Schin 			break;
7754887Schin 		if(n==0 || strncmp(arg,prefix-n,m+n)==0)
7764887Schin 		{
7774887Schin 			cp +=m;
7784887Schin 			r = 0;
7794887Schin 			if(*cp=='.')
7804887Schin 				cp++,r++;
7814887Schin 			if(nextcp=nextdot(cp))
7824887Schin 			{
7834887Schin 				if(outfile)
7844887Schin 				{
785*8462SApril.Chin@Sun.COM 					Namval_t *np,*tp;
786*8462SApril.Chin@Sun.COM 					*nextcp = 0;
787*8462SApril.Chin@Sun.COM 					np=nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope);
788*8462SApril.Chin@Sun.COM 					if(!np || (nv_isarray(np) && (!(tp=nv_opensub(np)) || !nv_isvtree(tp))))
789*8462SApril.Chin@Sun.COM 					{
790*8462SApril.Chin@Sun.COM 						*nextcp = '.';
791*8462SApril.Chin@Sun.COM 						continue;
792*8462SApril.Chin@Sun.COM 					}
793*8462SApril.Chin@Sun.COM 					if(wp->indent>=0)
794*8462SApril.Chin@Sun.COM 						sfnputc(outfile,'\t',wp->indent);
795*8462SApril.Chin@Sun.COM 					if(*cp!='[' && (tp = nv_type(np)))
796*8462SApril.Chin@Sun.COM 					{
797*8462SApril.Chin@Sun.COM 						char *sp;
798*8462SApril.Chin@Sun.COM 						if(sp = strrchr(tp->nvname,'.'))
799*8462SApril.Chin@Sun.COM 							sp++;
800*8462SApril.Chin@Sun.COM 						else
801*8462SApril.Chin@Sun.COM 							sp = tp->nvname;
802*8462SApril.Chin@Sun.COM 						sfputr(outfile,sp,' ');
803*8462SApril.Chin@Sun.COM 					}
8044887Schin 					nv_outname(outfile,cp,nextcp-cp);
8054887Schin 					sfputc(outfile,'=');
806*8462SApril.Chin@Sun.COM 					*nextcp = '.';
807*8462SApril.Chin@Sun.COM 				}
808*8462SApril.Chin@Sun.COM 				else
809*8462SApril.Chin@Sun.COM 				{
810*8462SApril.Chin@Sun.COM 					outval(cp,arg,wp);
811*8462SApril.Chin@Sun.COM 					continue;
8124887Schin 				}
8134887Schin 				argv = genvalue(argv,cp,n+m+r,wp);
814*8462SApril.Chin@Sun.COM 				if(wp->indent>=0)
8154887Schin 					sfputc(outfile,'\n');
8164887Schin 				if(*argv)
8174887Schin 					continue;
8184887Schin 				break;
8194887Schin 			}
820*8462SApril.Chin@Sun.COM 			else if(outfile && !wp->nofollow && argv[1] && memcmp(arg,argv[1],l=strlen(arg))==0 && argv[1][l]=='[')
8214887Schin 			{
8224887Schin 				Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope);
8234887Schin 				if(!np)
8244887Schin 					continue;
825*8462SApril.Chin@Sun.COM 				wp->array = nv_isarray(np);
826*8462SApril.Chin@Sun.COM 				if(wp->indent>0)
827*8462SApril.Chin@Sun.COM 					sfnputc(outfile,'\t',wp->indent);
8284887Schin 				nv_attribute(np,outfile,"typeset",1);
8294887Schin 				nv_close(np);
830*8462SApril.Chin@Sun.COM 				sfputr(outfile,arg+m+r+(n?n:0),'=');
831*8462SApril.Chin@Sun.COM 				wp->nofollow=1;
832*8462SApril.Chin@Sun.COM 				argv = genvalue(argv,cp,cp-arg ,wp);
833*8462SApril.Chin@Sun.COM 				sfputc(outfile,wp->indent<0?';':'\n');
8344887Schin 			}
8354887Schin 			else if(outfile && *cp=='[')
8364887Schin 			{
837*8462SApril.Chin@Sun.COM 				if(wp->indent)
838*8462SApril.Chin@Sun.COM 					sfnputc(outfile,'\t',wp->indent);
8394887Schin 				sfputr(outfile,cp,'=');
8404887Schin 				argv = genvalue(++argv,cp,cp-arg ,wp);
8414887Schin 				sfputc(outfile,'\n');
8424887Schin 			}
8434887Schin 			else
844*8462SApril.Chin@Sun.COM 			{
8454887Schin 				outval(cp,arg,wp);
846*8462SApril.Chin@Sun.COM 				if(wp->array)
847*8462SApril.Chin@Sun.COM 				{
848*8462SApril.Chin@Sun.COM 					if(wp->indent>=0)
849*8462SApril.Chin@Sun.COM 						wp->indent++;
850*8462SApril.Chin@Sun.COM 					else
851*8462SApril.Chin@Sun.COM 						sfputc(outfile,' ');
852*8462SApril.Chin@Sun.COM 					wp->array = 0;
853*8462SApril.Chin@Sun.COM 				}
854*8462SApril.Chin@Sun.COM 			}
8554887Schin 		}
8564887Schin 		else
8574887Schin 			break;
858*8462SApril.Chin@Sun.COM 		wp->nofollow = 0;
8594887Schin 	}
860*8462SApril.Chin@Sun.COM 	wp->array = 0;
8614887Schin 	if(outfile)
8624887Schin 	{
8634887Schin 		int c = prefix[m-1];
8644887Schin 		cp = (char*)prefix;
8654887Schin 		if(c=='.')
8664887Schin 			cp[m-1] = 0;
8674887Schin 		outval(".",prefix-n,wp);
8684887Schin 		if(c=='.')
8694887Schin 			cp[m-1] = c;
870*8462SApril.Chin@Sun.COM 		if(wp->indent>0)
871*8462SApril.Chin@Sun.COM 			sfnputc(outfile,'\t',--wp->indent);
8724887Schin 		sfputc(outfile,')');
8734887Schin 	}
8744887Schin 	return(--argv);
8754887Schin }
8764887Schin 
8774887Schin /*
8784887Schin  * walk the virtual tree and print or delete name-value pairs
8794887Schin  */
880*8462SApril.Chin@Sun.COM static char *walk_tree(register Namval_t *np, Namval_t *xp, int flags)
8814887Schin {
8824887Schin 	static Sfio_t *out;
8834887Schin 	struct Walk walk;
8844887Schin 	Sfio_t *outfile;
885*8462SApril.Chin@Sun.COM 	int len, savtop = staktell();
8864887Schin 	char *savptr = stakfreeze(0);
8874887Schin 	register struct argnod *ap=0;
8884887Schin 	struct argnod *arglist=0;
8894887Schin 	char *name,*cp, **argv;
8904887Schin 	char *subscript=0;
8914887Schin 	void *dir;
892*8462SApril.Chin@Sun.COM 	int n=0, noscope=(flags&NV_NOSCOPE);
893*8462SApril.Chin@Sun.COM 	Namarr_t *arp = nv_arrayptr(np);
894*8462SApril.Chin@Sun.COM 	Dt_t	*save_tree = sh.var_tree;
895*8462SApril.Chin@Sun.COM 	Namval_t	*mp=0;
896*8462SApril.Chin@Sun.COM 	Shell_t		*shp = sh_getinterp();
897*8462SApril.Chin@Sun.COM 	char		*xpname = xp?stakcopy(nv_name(xp)):0;
898*8462SApril.Chin@Sun.COM 	if(xp)
899*8462SApril.Chin@Sun.COM 	{
900*8462SApril.Chin@Sun.COM 		shp->last_root = shp->prev_root;
901*8462SApril.Chin@Sun.COM 		shp->last_table = shp->prev_table;
902*8462SApril.Chin@Sun.COM 	}
903*8462SApril.Chin@Sun.COM 	if(shp->last_table)
904*8462SApril.Chin@Sun.COM 		shp->last_root = nv_dict(shp->last_table);
905*8462SApril.Chin@Sun.COM 	if(shp->last_root)
906*8462SApril.Chin@Sun.COM 		shp->var_tree = shp->last_root;
9074887Schin 	stakputs(nv_name(np));
908*8462SApril.Chin@Sun.COM 	if(arp && !(arp->nelem&ARRAY_SCAN) && (subscript = nv_getsub(np)))
9094887Schin 	{
910*8462SApril.Chin@Sun.COM 		mp = nv_opensub(np);
9114887Schin 		stakputc('[');
9124887Schin 		stakputs(subscript);
9134887Schin 		stakputc(']');
9144887Schin 		stakputc('.');
9154887Schin 	}
916*8462SApril.Chin@Sun.COM 	else if(*stakptr(staktell()-1) == ']')
917*8462SApril.Chin@Sun.COM 		mp = np;
9184887Schin 	name = stakfreeze(1);
919*8462SApril.Chin@Sun.COM 	len = strlen(name);
920*8462SApril.Chin@Sun.COM 	shp->last_root = 0;
921*8462SApril.Chin@Sun.COM 	dir = nv_diropen(mp,name);
922*8462SApril.Chin@Sun.COM 	walk.root = shp->last_root?shp->last_root:shp->var_tree;
9234887Schin 	if(subscript)
9244887Schin 		name[strlen(name)-1] = 0;
9254887Schin 	while(cp = nv_dirnext(dir))
9264887Schin 	{
927*8462SApril.Chin@Sun.COM 		if(cp[len]!='.')
928*8462SApril.Chin@Sun.COM 			continue;
929*8462SApril.Chin@Sun.COM 		if(xp)
930*8462SApril.Chin@Sun.COM 		{
931*8462SApril.Chin@Sun.COM 			Dt_t		*dp = shp->var_tree;
932*8462SApril.Chin@Sun.COM 			Namval_t	*nq, *mq;
933*8462SApril.Chin@Sun.COM 			if(strlen(cp)<=len)
934*8462SApril.Chin@Sun.COM 				continue;
935*8462SApril.Chin@Sun.COM 			nq = nv_open(cp,walk.root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL);
936*8462SApril.Chin@Sun.COM 			if(!nq && (flags&NV_MOVE))
937*8462SApril.Chin@Sun.COM 				nq = nv_search(cp,walk.root,NV_NOADD);
938*8462SApril.Chin@Sun.COM 			stakseek(0);
939*8462SApril.Chin@Sun.COM 			stakputs(xpname);
940*8462SApril.Chin@Sun.COM 			stakputs(cp+len);
941*8462SApril.Chin@Sun.COM 			stakputc(0);
942*8462SApril.Chin@Sun.COM 			shp->var_tree = save_tree;
943*8462SApril.Chin@Sun.COM 			mq = nv_open(stakptr(0),save_tree,NV_VARNAME|NV_NOASSIGN|NV_NOFAIL);
944*8462SApril.Chin@Sun.COM 			shp->var_tree = dp;
945*8462SApril.Chin@Sun.COM 			if(nq && mq)
946*8462SApril.Chin@Sun.COM 			{
947*8462SApril.Chin@Sun.COM 				nv_clone(nq,mq,flags|NV_RAW);
948*8462SApril.Chin@Sun.COM 				if(flags&NV_MOVE)
949*8462SApril.Chin@Sun.COM 					nv_delete(nq,walk.root,0);
950*8462SApril.Chin@Sun.COM 			}
951*8462SApril.Chin@Sun.COM 			continue;
952*8462SApril.Chin@Sun.COM 		}
9534887Schin 		stakseek(ARGVAL);
9544887Schin 		stakputs(cp);
9554887Schin 		ap = (struct argnod*)stakfreeze(1);
9564887Schin 		ap->argflag = ARG_RAW;
9574887Schin 		ap->argchn.ap = arglist;
9584887Schin 		n++;
9594887Schin 		arglist = ap;
9604887Schin 	}
961*8462SApril.Chin@Sun.COM 	nv_dirclose(dir);
962*8462SApril.Chin@Sun.COM 	if(xp)
963*8462SApril.Chin@Sun.COM 	{
964*8462SApril.Chin@Sun.COM 		shp->var_tree = save_tree;
965*8462SApril.Chin@Sun.COM 		return((char*)0);
966*8462SApril.Chin@Sun.COM 	}
9674887Schin 	argv = (char**)stakalloc((n+1)*sizeof(char*));
9684887Schin 	argv += n;
9694887Schin 	*argv = 0;
9704887Schin 	for(; ap; ap=ap->argchn.ap)
9714887Schin 		*--argv = ap->argval;
972*8462SApril.Chin@Sun.COM 	if(flags&1)
9734887Schin 		outfile = 0;
9744887Schin 	else if(!(outfile=out))
9754887Schin 		outfile = out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
9764887Schin 	else
9774887Schin 		sfseek(outfile,0L,SEEK_SET);
9784887Schin 	walk.out = outfile;
979*8462SApril.Chin@Sun.COM 	walk.indent = (flags&NV_EXPORT)?-1:0;
980*8462SApril.Chin@Sun.COM 	walk.nofollow = 0;
9814887Schin 	walk.noscope = noscope;
982*8462SApril.Chin@Sun.COM 	walk.array = 0;
983*8462SApril.Chin@Sun.COM 	walk.flags = flags;
9844887Schin 	genvalue(argv,name,0,&walk);
9854887Schin 	stakset(savptr,savtop);
986*8462SApril.Chin@Sun.COM 	shp->var_tree = save_tree;
9874887Schin 	if(!outfile)
9884887Schin 		return((char*)0);
9894887Schin 	sfputc(out,0);
9904887Schin 	return((char*)out->_data);
9914887Schin }
9924887Schin 
993*8462SApril.Chin@Sun.COM Namfun_t *nv_isvtree(Namval_t *np)
994*8462SApril.Chin@Sun.COM {
995*8462SApril.Chin@Sun.COM 	if(np)
996*8462SApril.Chin@Sun.COM 		return(nv_hasdisc(np,&treedisc));
997*8462SApril.Chin@Sun.COM 	return(0);
998*8462SApril.Chin@Sun.COM }
999*8462SApril.Chin@Sun.COM 
10004887Schin /*
10014887Schin  * get discipline for compound initializations
10024887Schin  */
10034887Schin char *nv_getvtree(register Namval_t *np, Namfun_t *fp)
10044887Schin {
1005*8462SApril.Chin@Sun.COM 	int flags=0;
1006*8462SApril.Chin@Sun.COM 	for(; fp && fp->next; fp=fp->next)
1007*8462SApril.Chin@Sun.COM 	{
1008*8462SApril.Chin@Sun.COM 		if(fp->next->disc && (fp->next->disc->getnum || fp->next->disc->getval))
1009*8462SApril.Chin@Sun.COM 			return(nv_getv(np,fp));
1010*8462SApril.Chin@Sun.COM 	}
1011*8462SApril.Chin@Sun.COM 	if(nv_isattr(np,NV_BINARY) &&  !nv_isattr(np,NV_RAW))
10124887Schin 		return(nv_getv(np,fp));
1013*8462SApril.Chin@Sun.COM 	if(nv_isattr(np,NV_ARRAY) && !nv_type(np) && nv_arraychild(np,(Namval_t*)0,0)==np)
10144887Schin 		return(nv_getv(np,fp));
1015*8462SApril.Chin@Sun.COM 	if(flags = nv_isattr(np,NV_EXPORT))
1016*8462SApril.Chin@Sun.COM 		nv_offattr(np,NV_EXPORT);
1017*8462SApril.Chin@Sun.COM 	return(walk_tree(np,(Namval_t*)0,flags));
10184887Schin }
10194887Schin 
10204887Schin /*
10214887Schin  * put discipline for compound initializations
10224887Schin  */
10234887Schin static void put_tree(register Namval_t *np, const char *val, int flags,Namfun_t *fp)
10244887Schin {
10254887Schin 	struct Namarray *ap;
10264887Schin 	int nleft = 0;
1027*8462SApril.Chin@Sun.COM 	if(!val && !fp->next && nv_isattr(np,NV_NOFREE))
1028*8462SApril.Chin@Sun.COM 		return;
1029*8462SApril.Chin@Sun.COM 	if(!nv_isattr(np,(NV_INTEGER|NV_BINARY)))
1030*8462SApril.Chin@Sun.COM 	{
1031*8462SApril.Chin@Sun.COM 		Shell_t		*shp = sh_getinterp();
1032*8462SApril.Chin@Sun.COM 		Namval_t	*last_table = shp->last_table;
1033*8462SApril.Chin@Sun.COM 		Dt_t		*last_root = shp->last_root;
1034*8462SApril.Chin@Sun.COM 		Namval_t 	*mp = val?nv_open(val,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL):0;
1035*8462SApril.Chin@Sun.COM 		if(mp && nv_isvtree(mp))
1036*8462SApril.Chin@Sun.COM 		{
1037*8462SApril.Chin@Sun.COM 			shp->prev_table = shp->last_table;
1038*8462SApril.Chin@Sun.COM 			shp->prev_root = shp->last_root;
1039*8462SApril.Chin@Sun.COM 			shp->last_table = last_table;
1040*8462SApril.Chin@Sun.COM 			shp->last_root = last_root;
1041*8462SApril.Chin@Sun.COM 			if(!(flags&NV_APPEND))
1042*8462SApril.Chin@Sun.COM 				walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1);
1043*8462SApril.Chin@Sun.COM 			nv_clone(mp,np,NV_COMVAR);
1044*8462SApril.Chin@Sun.COM 			return;
1045*8462SApril.Chin@Sun.COM 		}
1046*8462SApril.Chin@Sun.COM 		walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1);
1047*8462SApril.Chin@Sun.COM 	}
10484887Schin 	nv_putv(np, val, flags,fp);
1049*8462SApril.Chin@Sun.COM 	if(val && nv_isattr(np,(NV_INTEGER|NV_BINARY)))
10504887Schin 		return;
10514887Schin 	if(ap= nv_arrayptr(np))
10524887Schin 		nleft = array_elem(ap);
10534887Schin 	if(nleft==0)
10544887Schin 	{
10554887Schin 		fp = nv_stack(np,fp);
10564887Schin 		if(fp = nv_stack(np,NIL(Namfun_t*)))
10574887Schin 			free((void*)fp);
10584887Schin 	}
10594887Schin }
10604887Schin 
10614887Schin /*
10624887Schin  * Insert discipline to cause $x to print current tree
10634887Schin  */
10644887Schin void nv_setvtree(register Namval_t *np)
10654887Schin {
10664887Schin 	register Namfun_t *nfp;
1067*8462SApril.Chin@Sun.COM 	if(sh.subshell)
1068*8462SApril.Chin@Sun.COM 		sh_assignok(np,1);
10694887Schin 	if(nv_hasdisc(np, &treedisc))
10704887Schin 		return;
10714887Schin 	nfp = newof(NIL(void*),Namfun_t,1,0);
10724887Schin 	nfp->disc = &treedisc;
10734887Schin 	nv_stack(np, nfp);
10744887Schin }
10754887Schin 
1076