xref: /titanic_51/usr/src/lib/libshell/common/sh/nvdisc.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
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  * AT&T Labs
23da2e3ebdSchin  *
24da2e3ebdSchin  */
25da2e3ebdSchin 
26da2e3ebdSchin #include        "defs.h"
27da2e3ebdSchin #include        "variables.h"
28da2e3ebdSchin #include        "builtins.h"
29da2e3ebdSchin #include        "path.h"
30da2e3ebdSchin 
nv_compare(Dt_t * dict,Void_t * sp,Void_t * dp,Dtdisc_t * disc)31da2e3ebdSchin int nv_compare(Dt_t* dict, Void_t *sp, Void_t *dp, Dtdisc_t *disc)
32da2e3ebdSchin {
33da2e3ebdSchin 	if(sp==dp)
34da2e3ebdSchin 		return(0);
35da2e3ebdSchin 	return(strcmp((char*)sp,(char*)dp));
36da2e3ebdSchin }
37da2e3ebdSchin 
38da2e3ebdSchin /*
39da2e3ebdSchin  * call the next getval function in the chain
40da2e3ebdSchin  */
nv_getv(Namval_t * np,register Namfun_t * nfp)41da2e3ebdSchin char *nv_getv(Namval_t *np, register Namfun_t *nfp)
42da2e3ebdSchin {
43da2e3ebdSchin 	register Namfun_t	*fp;
44da2e3ebdSchin 	register char *cp;
45da2e3ebdSchin 	if((fp = nfp) != NIL(Namfun_t*) && !nv_local)
46da2e3ebdSchin 		fp = nfp = nfp->next;
47da2e3ebdSchin 	nv_local=0;
48da2e3ebdSchin 	for(; fp; fp=fp->next)
49da2e3ebdSchin 	{
50da2e3ebdSchin 		if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
51da2e3ebdSchin 			continue;
52da2e3ebdSchin 		if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
53da2e3ebdSchin 			break;
54da2e3ebdSchin 	}
55da2e3ebdSchin 	if(fp && fp->disc->getval)
56da2e3ebdSchin 		cp = (*fp->disc->getval)(np,fp);
57da2e3ebdSchin 	else if(fp && fp->disc->getnum)
58da2e3ebdSchin 	{
59da2e3ebdSchin 		sfprintf(sh.strbuf,"%.*Lg",12,(*fp->disc->getnum)(np,fp));
60da2e3ebdSchin 		cp = sfstruse(sh.strbuf);
61da2e3ebdSchin 	}
62da2e3ebdSchin 	else
63da2e3ebdSchin 	{
64da2e3ebdSchin 		nv_local=1;
65da2e3ebdSchin 		cp = nv_getval(np);
66da2e3ebdSchin 	}
67da2e3ebdSchin 	return(cp);
68da2e3ebdSchin }
69da2e3ebdSchin 
70da2e3ebdSchin /*
71da2e3ebdSchin  * call the next getnum function in the chain
72da2e3ebdSchin  */
nv_getn(Namval_t * np,register Namfun_t * nfp)73da2e3ebdSchin Sfdouble_t nv_getn(Namval_t *np, register Namfun_t *nfp)
74da2e3ebdSchin {
75da2e3ebdSchin 	register Namfun_t	*fp;
76da2e3ebdSchin 	register Sfdouble_t	d=0;
77da2e3ebdSchin 	char *str;
78da2e3ebdSchin 	if((fp = nfp) != NIL(Namfun_t*) && !nv_local)
79da2e3ebdSchin 		fp = nfp = nfp->next;
80da2e3ebdSchin 	nv_local=0;
81da2e3ebdSchin 	for(; fp; fp=fp->next)
82da2e3ebdSchin 	{
837c2fbfb3SApril Chin 		if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
84da2e3ebdSchin 			continue;
85da2e3ebdSchin 		if(!fp->disc->getnum && nv_isattr(np,NV_INTEGER))
86da2e3ebdSchin 			continue;
87da2e3ebdSchin 		if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
88da2e3ebdSchin 			break;
89da2e3ebdSchin 	}
907c2fbfb3SApril Chin 	if(fp && fp->disc && fp->disc->getnum)
91da2e3ebdSchin 		d = (*fp->disc->getnum)(np,fp);
92da2e3ebdSchin 	else if(nv_isattr(np,NV_INTEGER))
93da2e3ebdSchin 	{
94da2e3ebdSchin 		nv_local = 1;
95da2e3ebdSchin 		d =  nv_getnum(np);
96da2e3ebdSchin 	}
97da2e3ebdSchin 	else
98da2e3ebdSchin 	{
997c2fbfb3SApril Chin 		if(fp && fp->disc && fp->disc->getval)
100da2e3ebdSchin 			str = (*fp->disc->getval)(np,fp);
101da2e3ebdSchin 		else
102da2e3ebdSchin 			str = nv_getv(np,fp?fp:nfp);
103da2e3ebdSchin 		if(str && *str)
104da2e3ebdSchin 		{
105da2e3ebdSchin 			while(*str=='0')
106da2e3ebdSchin 				str++;
107da2e3ebdSchin 			d = sh_arith(str);
108da2e3ebdSchin 		}
109da2e3ebdSchin 	}
110da2e3ebdSchin 	return(d);
111da2e3ebdSchin }
112da2e3ebdSchin 
113da2e3ebdSchin /*
114da2e3ebdSchin  * call the next assign function in the chain
115da2e3ebdSchin  */
nv_putv(Namval_t * np,const char * value,int flags,register Namfun_t * nfp)116da2e3ebdSchin void nv_putv(Namval_t *np, const char *value, int flags, register Namfun_t *nfp)
117da2e3ebdSchin {
118da2e3ebdSchin 	register Namfun_t	*fp, *fpnext;
119da2e3ebdSchin 	if((fp=nfp) != NIL(Namfun_t*) && !nv_local)
120da2e3ebdSchin 		fp = nfp = nfp->next;
121da2e3ebdSchin 	nv_local=0;
1227c2fbfb3SApril Chin 	if(flags&NV_NODISC)
1237c2fbfb3SApril Chin 		fp = 0;
124da2e3ebdSchin 	for(; fp; fp=fpnext)
125da2e3ebdSchin 	{
126da2e3ebdSchin 		fpnext = fp->next;
1277c2fbfb3SApril Chin 		if(!fp->disc || !fp->disc->putval)
128da2e3ebdSchin 		{
129da2e3ebdSchin 			if(!value)
130da2e3ebdSchin 			{
1317c2fbfb3SApril Chin 				if(fp->disc || !(fp->nofree&1))
132da2e3ebdSchin 					nv_disc(np,fp,NV_POP);
1337c2fbfb3SApril Chin 				if(!(fp->nofree&1))
134da2e3ebdSchin 					free((void*)fp);
135da2e3ebdSchin 			}
136da2e3ebdSchin 			continue;
137da2e3ebdSchin 		}
138da2e3ebdSchin 		if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
139da2e3ebdSchin 			break;
140da2e3ebdSchin 	}
141da2e3ebdSchin 	if(fp && fp->disc->putval)
142da2e3ebdSchin 		(*fp->disc->putval)(np,value, flags, fp);
143da2e3ebdSchin 	else
144da2e3ebdSchin 	{
145da2e3ebdSchin 		nv_local=1;
146da2e3ebdSchin 		if(value)
147da2e3ebdSchin 			nv_putval(np, value, flags);
148da2e3ebdSchin 		else
1497c2fbfb3SApril Chin 			_nv_unset(np, flags&(NV_RDONLY|NV_EXPORT));
150da2e3ebdSchin 	}
151da2e3ebdSchin }
152da2e3ebdSchin 
15334f9b3eeSRoland Mainz #define	LOOKUPS		0
154da2e3ebdSchin #define	ASSIGN		1
155da2e3ebdSchin #define	APPEND		2
156da2e3ebdSchin #define	UNASSIGN	3
15734f9b3eeSRoland Mainz #define	LOOKUPN		4
158da2e3ebdSchin #define BLOCKED		((Namval_t*)&nv_local)
159da2e3ebdSchin 
160da2e3ebdSchin struct	vardisc
161da2e3ebdSchin {
162da2e3ebdSchin 	Namfun_t	fun;
16334f9b3eeSRoland Mainz 	Namval_t	*disc[5];
164da2e3ebdSchin };
165da2e3ebdSchin 
166da2e3ebdSchin struct blocked
167da2e3ebdSchin {
168da2e3ebdSchin 	struct blocked	*next;
169da2e3ebdSchin 	Namval_t	*np;
170da2e3ebdSchin 	int		flags;
171da2e3ebdSchin 	void		*sub;
172da2e3ebdSchin 	int		isub;
173da2e3ebdSchin };
174da2e3ebdSchin 
175da2e3ebdSchin static struct blocked	*blist;
176da2e3ebdSchin 
177da2e3ebdSchin #define isblocked(bp,type)	((bp)->flags & (1<<(type)))
178da2e3ebdSchin #define block(bp,type)		((bp)->flags |= (1<<(type)))
179da2e3ebdSchin #define unblock(bp,type)	((bp)->flags &= ~(1<<(type)))
180da2e3ebdSchin 
181da2e3ebdSchin /*
182da2e3ebdSchin  * returns pointer to blocking structure
183da2e3ebdSchin  */
block_info(Namval_t * np,struct blocked * pp)184da2e3ebdSchin static struct blocked *block_info(Namval_t *np, struct blocked *pp)
185da2e3ebdSchin {
186da2e3ebdSchin 	register struct blocked	*bp;
187da2e3ebdSchin 	void			*sub=0;
188da2e3ebdSchin 	int			isub=0;
189da2e3ebdSchin 	if(nv_isarray(np) && (isub=nv_aindex(np)) < 0)
190da2e3ebdSchin 		sub = nv_associative(np,(const char*)0,NV_ACURRENT);
191da2e3ebdSchin 	for(bp=blist ; bp; bp=bp->next)
192da2e3ebdSchin 	{
193da2e3ebdSchin 		if(bp->np==np && bp->sub==sub && bp->isub==isub)
194da2e3ebdSchin 			return(bp);
195da2e3ebdSchin 	}
196da2e3ebdSchin 	if(pp)
197da2e3ebdSchin 	{
198da2e3ebdSchin 		pp->np = np;
199da2e3ebdSchin 		pp->flags = 0;
200da2e3ebdSchin 		pp->isub = isub;
201da2e3ebdSchin 		pp->sub = sub;
202da2e3ebdSchin 		pp->next = blist;
203da2e3ebdSchin 		blist = pp;
204da2e3ebdSchin 	}
205da2e3ebdSchin 	return(pp);
206da2e3ebdSchin }
207da2e3ebdSchin 
block_done(struct blocked * bp)208da2e3ebdSchin static void block_done(struct blocked *bp)
209da2e3ebdSchin {
210da2e3ebdSchin 	blist = bp = bp->next;
211da2e3ebdSchin 	if(bp && (bp->isub>=0 || bp->sub))
212da2e3ebdSchin 		nv_putsub(bp->np, bp->sub,(bp->isub<0?0:bp->isub)|ARRAY_SETSUB);
213da2e3ebdSchin }
214da2e3ebdSchin 
215da2e3ebdSchin /*
216da2e3ebdSchin  * free discipline if no more discipline functions
217da2e3ebdSchin  */
chktfree(register Namval_t * np,register struct vardisc * vp)218da2e3ebdSchin static void chktfree(register Namval_t *np, register struct vardisc *vp)
219da2e3ebdSchin {
220da2e3ebdSchin 	register int n;
221da2e3ebdSchin 	for(n=0; n< sizeof(vp->disc)/sizeof(*vp->disc); n++)
222da2e3ebdSchin 	{
223da2e3ebdSchin 		if(vp->disc[n])
224da2e3ebdSchin 			break;
225da2e3ebdSchin 	}
226da2e3ebdSchin 	if(n>=sizeof(vp->disc)/sizeof(*vp->disc))
227da2e3ebdSchin 	{
228da2e3ebdSchin 		/* no disc left so pop */
229da2e3ebdSchin 		Namfun_t *fp;
2307c2fbfb3SApril Chin 		if((fp=nv_stack(np, NIL(Namfun_t*))) && !(fp->nofree&1))
231da2e3ebdSchin 			free((void*)fp);
232da2e3ebdSchin 	}
233da2e3ebdSchin }
234da2e3ebdSchin 
235da2e3ebdSchin /*
236da2e3ebdSchin  * This function performs an assignment disc on the given node <np>
237da2e3ebdSchin  */
assign(Namval_t * np,const char * val,int flags,Namfun_t * handle)238da2e3ebdSchin static void	assign(Namval_t *np,const char* val,int flags,Namfun_t *handle)
239da2e3ebdSchin {
240da2e3ebdSchin 	int		type = (flags&NV_APPEND)?APPEND:ASSIGN;
241da2e3ebdSchin 	register	struct vardisc *vp = (struct vardisc*)handle;
242da2e3ebdSchin 	register	Namval_t *nq =  vp->disc[type];
243da2e3ebdSchin 	struct blocked	block, *bp = block_info(np, &block);
244da2e3ebdSchin 	Namval_t	node;
2457c2fbfb3SApril Chin 	union Value	*up = np->nvalue.up;
2467c2fbfb3SApril Chin #if SHOPT_TYPEDEF
2477c2fbfb3SApril Chin 	Namval_t	*tp, *nr;
2487c2fbfb3SApril Chin 	if(val && (tp=nv_type(np)) && (nr=nv_open(val,sh.var_tree,NV_VARNAME|NV_ARRAY|NV_NOADD|NV_NOFAIL)) && tp==nv_type(nr))
2497c2fbfb3SApril Chin 	{
2507c2fbfb3SApril Chin 		char *sub = nv_getsub(np);
2517c2fbfb3SApril Chin 		nv_unset(np);
2527c2fbfb3SApril Chin 		if(sub)
2537c2fbfb3SApril Chin 		{
2547c2fbfb3SApril Chin 			nv_putsub(np, sub, ARRAY_ADD);
2557c2fbfb3SApril Chin 			nv_putval(np,nv_getval(nr), 0);
2567c2fbfb3SApril Chin 		}
2577c2fbfb3SApril Chin 		else
2587c2fbfb3SApril Chin 			nv_clone(nr,np,0);
2597c2fbfb3SApril Chin 		goto done;
2607c2fbfb3SApril Chin 	}
2617c2fbfb3SApril Chin #endif /* SHOPT_TYPEDEF */
262da2e3ebdSchin 	if(val || isblocked(bp,type))
263da2e3ebdSchin 	{
264da2e3ebdSchin 		if(!nq || isblocked(bp,type))
265da2e3ebdSchin 		{
266da2e3ebdSchin 			nv_putv(np,val,flags,handle);
267da2e3ebdSchin 			goto done;
268da2e3ebdSchin 		}
269da2e3ebdSchin 		node = *SH_VALNOD;
270da2e3ebdSchin 		if(!nv_isnull(SH_VALNOD))
271da2e3ebdSchin 		{
272da2e3ebdSchin 			nv_onattr(SH_VALNOD,NV_NOFREE);
273da2e3ebdSchin 			nv_unset(SH_VALNOD);
274da2e3ebdSchin 		}
275da2e3ebdSchin 		if(flags&NV_INTEGER)
2767c2fbfb3SApril Chin 			nv_onattr(SH_VALNOD,(flags&(NV_LONG|NV_DOUBLE|NV_EXPNOTE|NV_HEXFLOAT|NV_SHORT)));
277da2e3ebdSchin 		nv_putval(SH_VALNOD, val, (flags&NV_INTEGER)?flags:NV_NOFREE);
278da2e3ebdSchin 	}
279da2e3ebdSchin 	else
280da2e3ebdSchin 		nq =  vp->disc[type=UNASSIGN];
281da2e3ebdSchin 	if(nq && !isblocked(bp,type))
282da2e3ebdSchin 	{
283da2e3ebdSchin 		int bflag;
284da2e3ebdSchin 		block(bp,type);
28534f9b3eeSRoland Mainz 		if (type==APPEND && (bflag= !isblocked(bp,LOOKUPS)))
28634f9b3eeSRoland Mainz 			block(bp,LOOKUPS);
287da2e3ebdSchin 		sh_fun(nq,np,(char**)0);
288da2e3ebdSchin 		unblock(bp,type);
289da2e3ebdSchin 		if(bflag)
29034f9b3eeSRoland Mainz 			unblock(bp,LOOKUPS);
291da2e3ebdSchin 		if(!vp->disc[type])
292da2e3ebdSchin 			chktfree(np,vp);
293da2e3ebdSchin 	}
2947c2fbfb3SApril Chin 	if(nv_isarray(np))
2957c2fbfb3SApril Chin 		np->nvalue.up = up;
296da2e3ebdSchin 	if(val)
297da2e3ebdSchin 	{
298da2e3ebdSchin 		register char *cp;
299da2e3ebdSchin 		Sfdouble_t d;
300da2e3ebdSchin 		if(nv_isnull(SH_VALNOD))
301da2e3ebdSchin 			cp=0;
302da2e3ebdSchin 		else if(flags&NV_INTEGER)
303da2e3ebdSchin 		{
304da2e3ebdSchin 			d = nv_getnum(SH_VALNOD);
305da2e3ebdSchin 			cp = (char*)(&d);
306da2e3ebdSchin 			flags |= (NV_LONG|NV_DOUBLE);
307da2e3ebdSchin 			flags &= ~NV_SHORT;
308da2e3ebdSchin 		}
309da2e3ebdSchin 		else
310da2e3ebdSchin 			cp = nv_getval(SH_VALNOD);
311da2e3ebdSchin 		if(cp)
312da2e3ebdSchin 			nv_putv(np,cp,flags|NV_RDONLY,handle);
313da2e3ebdSchin 		nv_unset(SH_VALNOD);
314da2e3ebdSchin 		/* restore everything but the nvlink field */
315da2e3ebdSchin 		memcpy(&SH_VALNOD->nvname,  &node.nvname, sizeof(node)-sizeof(node.nvlink));
316da2e3ebdSchin 	}
317da2e3ebdSchin 	else if(sh_isstate(SH_INIT))
318da2e3ebdSchin 	{
319da2e3ebdSchin 		/* don't free functions during reinitialization */
320da2e3ebdSchin 		nv_putv(np,val,flags,handle);
321da2e3ebdSchin 	}
322da2e3ebdSchin 	else if(!nq || !isblocked(bp,type))
323da2e3ebdSchin 	{
324da2e3ebdSchin 		Dt_t *root = sh_subfuntree(1);
325da2e3ebdSchin 		int n;
326da2e3ebdSchin 		Namarr_t *ap;
327da2e3ebdSchin 		block(bp,type);
328da2e3ebdSchin 		nv_putv(np, val, flags, handle);
3297c2fbfb3SApril Chin 		if(sh.subshell)
3307c2fbfb3SApril Chin 			goto done;
331da2e3ebdSchin 		if(nv_isarray(np) && (ap=nv_arrayptr(np)) && ap->nelem>0)
332da2e3ebdSchin 			goto done;
333da2e3ebdSchin 		for(n=0; n < sizeof(vp->disc)/sizeof(*vp->disc); n++)
334da2e3ebdSchin 		{
335da2e3ebdSchin 			if((nq=vp->disc[n]) && !nv_isattr(nq,NV_NOFREE))
336da2e3ebdSchin 			{
337da2e3ebdSchin 				nv_unset(nq);
338da2e3ebdSchin 				dtdelete(root,nq);
339da2e3ebdSchin 			}
340da2e3ebdSchin 		}
341da2e3ebdSchin 		unblock(bp,type);
342da2e3ebdSchin 		nv_disc(np,handle,NV_POP);
3437c2fbfb3SApril Chin 		if(!(handle->nofree&1))
344da2e3ebdSchin 			free(handle);
345da2e3ebdSchin 	}
346da2e3ebdSchin done:
347da2e3ebdSchin 	if(bp== &block)
348da2e3ebdSchin 		block_done(bp);
349da2e3ebdSchin }
350da2e3ebdSchin 
351da2e3ebdSchin /*
352da2e3ebdSchin  * This function executes a lookup disc and then performs
353da2e3ebdSchin  * the lookup on the given node <np>
354da2e3ebdSchin  */
lookup(Namval_t * np,int type,Sfdouble_t * dp,Namfun_t * handle)35534f9b3eeSRoland Mainz static char*	lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
356da2e3ebdSchin {
357da2e3ebdSchin 	register struct vardisc	*vp = (struct vardisc*)handle;
358da2e3ebdSchin 	struct blocked		block, *bp = block_info(np, &block);
35934f9b3eeSRoland Mainz 	register Namval_t	*nq = vp->disc[type];
360da2e3ebdSchin 	register char		*cp=0;
361da2e3ebdSchin 	Namval_t		node;
3627c2fbfb3SApril Chin 	union Value		*up = np->nvalue.up;
36334f9b3eeSRoland Mainz 	if(nq && !isblocked(bp,type))
364da2e3ebdSchin 	{
365da2e3ebdSchin 		node = *SH_VALNOD;
366da2e3ebdSchin 		if(!nv_isnull(SH_VALNOD))
367da2e3ebdSchin 		{
368da2e3ebdSchin 			nv_onattr(SH_VALNOD,NV_NOFREE);
369da2e3ebdSchin 			nv_unset(SH_VALNOD);
370da2e3ebdSchin 		}
37134f9b3eeSRoland Mainz 		if(type==LOOKUPN)
3727c2fbfb3SApril Chin 		{
37334f9b3eeSRoland Mainz 			nv_onattr(SH_VALNOD,NV_DOUBLE|NV_INTEGER);
37434f9b3eeSRoland Mainz 			nv_setsize(SH_VALNOD,10);
37534f9b3eeSRoland Mainz 		}
37634f9b3eeSRoland Mainz 		block(bp,type);
37734f9b3eeSRoland Mainz 		sh_fun(nq,np,(char**)0);
37834f9b3eeSRoland Mainz 		unblock(bp,type);
37934f9b3eeSRoland Mainz 		if(!vp->disc[type])
38034f9b3eeSRoland Mainz 			chktfree(np,vp);
38134f9b3eeSRoland Mainz 		if(type==LOOKUPN)
38234f9b3eeSRoland Mainz 		{
38334f9b3eeSRoland Mainz 			cp = (char*)(SH_VALNOD->nvalue.cp);
38434f9b3eeSRoland Mainz 			*dp = nv_getnum(SH_VALNOD);
38534f9b3eeSRoland Mainz 		}
38634f9b3eeSRoland Mainz 		else if(cp = nv_getval(SH_VALNOD))
3877c2fbfb3SApril Chin 			cp = stkcopy(stkstd,cp);
3887c2fbfb3SApril Chin 		_nv_unset(SH_VALNOD,NV_RDONLY);
389da2e3ebdSchin 		if(!nv_isnull(&node))
390da2e3ebdSchin 		{
391da2e3ebdSchin 			/* restore everything but the nvlink field */
392da2e3ebdSchin 			memcpy(&SH_VALNOD->nvname,  &node.nvname, sizeof(node)-sizeof(node.nvlink));
393da2e3ebdSchin 		}
394da2e3ebdSchin 	}
3957c2fbfb3SApril Chin 	if(nv_isarray(np))
3967c2fbfb3SApril Chin 		np->nvalue.up = up;
397da2e3ebdSchin 	if(!cp)
39834f9b3eeSRoland Mainz 	{
39934f9b3eeSRoland Mainz 		if(type==LOOKUPS)
400da2e3ebdSchin 			cp = nv_getv(np,handle);
40134f9b3eeSRoland Mainz 		else
40234f9b3eeSRoland Mainz 			*dp = nv_getn(np,handle);
40334f9b3eeSRoland Mainz 	}
404da2e3ebdSchin 	if(bp== &block)
405da2e3ebdSchin 		block_done(bp);
406da2e3ebdSchin 	return(cp);
407da2e3ebdSchin }
408da2e3ebdSchin 
lookups(Namval_t * np,Namfun_t * handle)40934f9b3eeSRoland Mainz static char*	lookups(Namval_t *np, Namfun_t *handle)
410da2e3ebdSchin {
41134f9b3eeSRoland Mainz 	return(lookup(np,LOOKUPS,(Sfdouble_t*)0,handle));
41234f9b3eeSRoland Mainz }
41334f9b3eeSRoland Mainz 
lookupn(Namval_t * np,Namfun_t * handle)41434f9b3eeSRoland Mainz static Sfdouble_t lookupn(Namval_t *np, Namfun_t *handle)
41534f9b3eeSRoland Mainz {
41634f9b3eeSRoland Mainz 	Sfdouble_t	d;
41734f9b3eeSRoland Mainz 	lookup(np,LOOKUPN, &d ,handle);
41834f9b3eeSRoland Mainz 	return(d);
41934f9b3eeSRoland Mainz }
42034f9b3eeSRoland Mainz 
421da2e3ebdSchin 
422da2e3ebdSchin /*
423da2e3ebdSchin  * Set disc on given <event> to <action>
424da2e3ebdSchin  * If action==np, the current disc is returned
425da2e3ebdSchin  * A null return value indicates that no <event> is known for <np>
426da2e3ebdSchin  * If <event> is NULL, then return the event name after <action>
427da2e3ebdSchin  * If <event> is NULL, and <action> is NULL, return the first event
428da2e3ebdSchin  */
nv_setdisc(register Namval_t * np,register const char * event,Namval_t * action,register Namfun_t * fp)429da2e3ebdSchin char *nv_setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp)
430da2e3ebdSchin {
431da2e3ebdSchin 	register struct vardisc *vp = (struct vardisc*)np->nvfun;
432da2e3ebdSchin 	register int type;
433da2e3ebdSchin 	char *empty = "";
434*3e14f97fSRoger A. Faulkner 	while(vp)
435*3e14f97fSRoger A. Faulkner 	{
436*3e14f97fSRoger A. Faulkner 		if(vp->fun.disc && (vp->fun.disc->setdisc || vp->fun.disc->putval == assign))
437*3e14f97fSRoger A. Faulkner 			break;
438*3e14f97fSRoger A. Faulkner 		vp = (struct vardisc*)vp->fun.next;
439*3e14f97fSRoger A. Faulkner 	}
4407c2fbfb3SApril Chin 	if(vp && !vp->fun.disc)
4417c2fbfb3SApril Chin 		vp = 0;
442da2e3ebdSchin 	if(np == (Namval_t*)fp)
443da2e3ebdSchin 	{
444da2e3ebdSchin 		register const char *name;
445da2e3ebdSchin 		register int getname=0;
446da2e3ebdSchin 		/* top level call, check for get/set */
447da2e3ebdSchin 		if(!event)
448da2e3ebdSchin 		{
449da2e3ebdSchin 			if(!action)
4507c2fbfb3SApril Chin 				return((char*)nv_discnames[0]);
451da2e3ebdSchin 			getname=1;
452da2e3ebdSchin 			event = (char*)action;
453da2e3ebdSchin 		}
4547c2fbfb3SApril Chin 		for(type=0; name=nv_discnames[type]; type++)
455da2e3ebdSchin 		{
456da2e3ebdSchin 			if(strcmp(event,name)==0)
457da2e3ebdSchin 				break;
458da2e3ebdSchin 		}
459da2e3ebdSchin 		if(getname)
460da2e3ebdSchin 		{
461da2e3ebdSchin 			event = 0;
4627c2fbfb3SApril Chin 			if(name && !(name = nv_discnames[++type]))
463da2e3ebdSchin 				action = 0;
464da2e3ebdSchin 		}
465da2e3ebdSchin 		if(!name)
466da2e3ebdSchin 		{
4677c2fbfb3SApril Chin 			for(fp=(Namfun_t*)vp; fp; fp=fp->next)
4687c2fbfb3SApril Chin 			{
4697c2fbfb3SApril Chin 				if(fp->disc && fp->disc->setdisc)
470da2e3ebdSchin 					return((*fp->disc->setdisc)(np,event,action,fp));
471da2e3ebdSchin 			}
4727c2fbfb3SApril Chin 		}
473da2e3ebdSchin 		else if(getname)
474da2e3ebdSchin 			return((char*)name);
475da2e3ebdSchin 	}
476da2e3ebdSchin 	if(!fp)
477da2e3ebdSchin 		return(NIL(char*));
478da2e3ebdSchin 	if(np != (Namval_t*)fp)
479da2e3ebdSchin 	{
480da2e3ebdSchin 		/* not the top level */
481da2e3ebdSchin 		while(fp = fp->next)
482da2e3ebdSchin 		{
4837c2fbfb3SApril Chin 			if(fp->disc && fp->disc->setdisc)
484da2e3ebdSchin 				return((*fp->disc->setdisc)(np,event,action,fp));
485da2e3ebdSchin 		}
486da2e3ebdSchin 		return(NIL(char*));
487da2e3ebdSchin 	}
488da2e3ebdSchin 	/* Handle GET/SET/APPEND/UNSET disc */
489da2e3ebdSchin 	if(vp && vp->fun.disc->putval!=assign)
490da2e3ebdSchin 		vp = 0;
491da2e3ebdSchin 	if(!vp)
492da2e3ebdSchin 	{
49334f9b3eeSRoland Mainz 		Namdisc_t	*dp;
494da2e3ebdSchin 		if(action==np)
495da2e3ebdSchin 			return((char*)action);
49634f9b3eeSRoland Mainz 		if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,sizeof(Namdisc_t))))
497da2e3ebdSchin 			return(0);
49834f9b3eeSRoland Mainz 		dp = (Namdisc_t*)(vp+1);
49934f9b3eeSRoland Mainz 		vp->fun.disc = dp;
50034f9b3eeSRoland Mainz 		memset(dp,0,sizeof(*dp));
50134f9b3eeSRoland Mainz 		dp->dsize = sizeof(struct vardisc);
50234f9b3eeSRoland Mainz 		dp->putval = assign;
503*3e14f97fSRoger A. Faulkner 		if(nv_isarray(np) && !nv_arrayptr(np))
504*3e14f97fSRoger A. Faulkner 			nv_putsub(np,(char*)0, 1);
505da2e3ebdSchin 		nv_stack(np, (Namfun_t*)vp);
506da2e3ebdSchin 	}
507da2e3ebdSchin 	if(action==np)
508da2e3ebdSchin 	{
509da2e3ebdSchin 		action = vp->disc[type];
510da2e3ebdSchin 		empty = 0;
511da2e3ebdSchin 	}
512da2e3ebdSchin 	else if(action)
51334f9b3eeSRoland Mainz 	{
51434f9b3eeSRoland Mainz 		Namdisc_t *dp = (Namdisc_t*)vp->fun.disc;
51534f9b3eeSRoland Mainz 		if(type==LOOKUPS)
51634f9b3eeSRoland Mainz 			dp->getval = lookups;
51734f9b3eeSRoland Mainz 		else if(type==LOOKUPN)
51834f9b3eeSRoland Mainz 			dp->getnum = lookupn;
519da2e3ebdSchin 		vp->disc[type] = action;
52034f9b3eeSRoland Mainz 	}
521da2e3ebdSchin 	else
522da2e3ebdSchin 	{
523da2e3ebdSchin 		struct blocked *bp;
524da2e3ebdSchin 		action = vp->disc[type];
525da2e3ebdSchin 		vp->disc[type] = 0;
526da2e3ebdSchin 		if(!(bp=block_info(np,(struct blocked*)0)) || !isblocked(bp,UNASSIGN))
527da2e3ebdSchin 			chktfree(np,vp);
528da2e3ebdSchin 	}
529da2e3ebdSchin 	return(action?(char*)action:empty);
530da2e3ebdSchin }
531da2e3ebdSchin 
532da2e3ebdSchin /*
533da2e3ebdSchin  * Set disc on given <event> to <action>
534da2e3ebdSchin  * If action==np, the current disc is returned
535da2e3ebdSchin  * A null return value indicates that no <event> is known for <np>
536da2e3ebdSchin  * If <event> is NULL, then return the event name after <action>
537da2e3ebdSchin  * If <event> is NULL, and <action> is NULL, return the first event
538da2e3ebdSchin  */
setdisc(register Namval_t * np,register const char * event,Namval_t * action,register Namfun_t * fp)539da2e3ebdSchin static char *setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp)
540da2e3ebdSchin {
541da2e3ebdSchin 	register Nambfun_t *vp = (Nambfun_t*)fp;
542da2e3ebdSchin 	register int type,getname=0;
543da2e3ebdSchin 	register const char *name;
544da2e3ebdSchin 	const char **discnames = vp->bnames;
545da2e3ebdSchin 	/* top level call, check for discipline match */
546da2e3ebdSchin 	if(!event)
547da2e3ebdSchin 	{
548da2e3ebdSchin 		if(!action)
549da2e3ebdSchin 			return((char*)discnames[0]);
550da2e3ebdSchin 		getname=1;
551da2e3ebdSchin 		event = (char*)action;
552da2e3ebdSchin 	}
553da2e3ebdSchin 	for(type=0; name=discnames[type]; type++)
554da2e3ebdSchin 	{
555da2e3ebdSchin 		if(strcmp(event,name)==0)
556da2e3ebdSchin 			break;
557da2e3ebdSchin 	}
558da2e3ebdSchin 	if(getname)
559da2e3ebdSchin 	{
560da2e3ebdSchin 		event = 0;
561da2e3ebdSchin 		if(name && !(name = discnames[++type]))
562da2e3ebdSchin 			action = 0;
563da2e3ebdSchin 	}
564da2e3ebdSchin 	if(!name)
565da2e3ebdSchin 		return(nv_setdisc(np,event,action,fp));
566da2e3ebdSchin 	else if(getname)
567da2e3ebdSchin 		return((char*)name);
568da2e3ebdSchin 	/* Handle the disciplines */
569da2e3ebdSchin 	if(action==np)
570da2e3ebdSchin 		action = vp->bltins[type];
571da2e3ebdSchin 	else if(action)
572da2e3ebdSchin 		vp->bltins[type] = action;
573da2e3ebdSchin 	else
574da2e3ebdSchin 	{
575da2e3ebdSchin 		action = vp->bltins[type];
576da2e3ebdSchin 		vp->bltins[type] = 0;
577da2e3ebdSchin 	}
578da2e3ebdSchin 	return(action?(char*)action:"");
579da2e3ebdSchin }
580da2e3ebdSchin 
putdisc(Namval_t * np,const char * val,int flag,Namfun_t * fp)581da2e3ebdSchin static void putdisc(Namval_t* np, const char* val, int flag, Namfun_t* fp)
582da2e3ebdSchin {
583da2e3ebdSchin 	nv_putv(np,val,flag,fp);
5847c2fbfb3SApril Chin 	if(!val && !(flag&NV_NOFREE))
585da2e3ebdSchin 	{
586da2e3ebdSchin 		register Nambfun_t *vp = (Nambfun_t*)fp;
587da2e3ebdSchin 		register int i;
588da2e3ebdSchin 		for(i=0; vp->bnames[i]; i++)
589da2e3ebdSchin 		{
590da2e3ebdSchin 			register Namval_t *mp;
591da2e3ebdSchin 			if((mp=vp->bltins[i]) && !nv_isattr(mp,NV_NOFREE))
592da2e3ebdSchin 			{
593da2e3ebdSchin 				if(is_abuiltin(mp))
594da2e3ebdSchin 				{
595da2e3ebdSchin 					if(mp->nvfun && !nv_isattr(mp,NV_NOFREE))
596da2e3ebdSchin 						free((void*)mp->nvfun);
597da2e3ebdSchin 					dtdelete(sh.bltin_tree,mp);
598da2e3ebdSchin 					free((void*)mp);
599da2e3ebdSchin 				}
600da2e3ebdSchin 			}
601da2e3ebdSchin 		}
602da2e3ebdSchin 		nv_disc(np,fp,NV_POP);
6037c2fbfb3SApril Chin 		if(!(fp->nofree&1))
604da2e3ebdSchin 			free((void*)fp);
605da2e3ebdSchin 
606da2e3ebdSchin 	}
607da2e3ebdSchin }
608da2e3ebdSchin 
609da2e3ebdSchin static const Namdisc_t Nv_bdisc	= {   0, putdisc, 0, 0, setdisc };
610da2e3ebdSchin 
nv_clone_disc(register Namfun_t * fp,int flags)6117c2fbfb3SApril Chin Namfun_t *nv_clone_disc(register Namfun_t *fp, int flags)
612da2e3ebdSchin {
613da2e3ebdSchin 	register Namfun_t	*nfp;
614da2e3ebdSchin 	register int		size;
61534f9b3eeSRoland Mainz 	if(!fp->disc && !fp->next && (fp->nofree&1))
61634f9b3eeSRoland Mainz 		return(fp);
617da2e3ebdSchin 	if(!(size=fp->dsize) && (!fp->disc || !(size=fp->disc->dsize)))
618da2e3ebdSchin 		size = sizeof(Namfun_t);
619da2e3ebdSchin 	if(!(nfp=newof(NIL(Namfun_t*),Namfun_t,1,size-sizeof(Namfun_t))))
620da2e3ebdSchin 		return(0);
621da2e3ebdSchin 	memcpy(nfp,fp,size);
6227c2fbfb3SApril Chin 	nfp->nofree &= ~1;
6237c2fbfb3SApril Chin 	nfp->nofree |= (flags&NV_RDONLY)?1:0;
624da2e3ebdSchin 	return(nfp);
625da2e3ebdSchin }
626da2e3ebdSchin 
nv_adddisc(Namval_t * np,const char ** names,Namval_t ** funs)627da2e3ebdSchin int nv_adddisc(Namval_t *np, const char **names, Namval_t **funs)
628da2e3ebdSchin {
629da2e3ebdSchin 	register Nambfun_t *vp;
630da2e3ebdSchin 	register int n=0;
631da2e3ebdSchin 	register const char **av=names;
632da2e3ebdSchin 	if(av)
633da2e3ebdSchin 	{
634da2e3ebdSchin 		while(*av++)
635da2e3ebdSchin 			n++;
636da2e3ebdSchin 	}
637da2e3ebdSchin 	if(!(vp = newof(NIL(Nambfun_t*),Nambfun_t,1,n*sizeof(Namval_t*))))
638da2e3ebdSchin 		return(0);
639da2e3ebdSchin 	vp->fun.dsize = sizeof(Nambfun_t)+n*sizeof(Namval_t*);
6407c2fbfb3SApril Chin 	vp->fun.nofree |= 2;
6417c2fbfb3SApril Chin 	vp->num = n;
642da2e3ebdSchin 	if(funs)
643da2e3ebdSchin 		memcpy((void*)vp->bltins, (void*)funs,n*sizeof(Namval_t*));
644da2e3ebdSchin 	else while(n>=0)
645da2e3ebdSchin 		vp->bltins[n--] = 0;
646da2e3ebdSchin 	vp->fun.disc = &Nv_bdisc;
647da2e3ebdSchin 	vp->bnames = names;
648da2e3ebdSchin 	nv_stack(np,&vp->fun);
649da2e3ebdSchin 	return(1);
650da2e3ebdSchin }
651da2e3ebdSchin 
652da2e3ebdSchin /*
6537c2fbfb3SApril Chin  * push, pop, clne, or reorder disciplines onto node <np>
654da2e3ebdSchin  * mode can be one of
655da2e3ebdSchin  *    NV_FIRST:  Move or push <fp> to top of the stack or delete top
656da2e3ebdSchin  *    NV_LAST:	 Move or push <fp> to bottom of stack or delete last
657da2e3ebdSchin  *    NV_POP:	 Delete <fp> from top of the stack
658da2e3ebdSchin  *    NV_CLONE:  Replace fp with a copy created my malloc() and return it
659da2e3ebdSchin  */
nv_disc(register Namval_t * np,register Namfun_t * fp,int mode)660da2e3ebdSchin Namfun_t *nv_disc(register Namval_t *np, register Namfun_t* fp, int mode)
661da2e3ebdSchin {
662da2e3ebdSchin 	Namfun_t *lp, **lpp;
663da2e3ebdSchin 	if(nv_isref(np))
664da2e3ebdSchin 		return(0);
665da2e3ebdSchin 	if(mode==NV_CLONE && !fp)
666da2e3ebdSchin 		return(0);
667da2e3ebdSchin 	if(fp)
668da2e3ebdSchin 	{
6697c2fbfb3SApril Chin 		fp->subshell = sh.subshell;
670da2e3ebdSchin 		if((lp=np->nvfun)==fp)
671da2e3ebdSchin 		{
672da2e3ebdSchin 			if(mode==NV_CLONE)
673da2e3ebdSchin 			{
6747c2fbfb3SApril Chin 				lp = nv_clone_disc(fp,0);
675da2e3ebdSchin 				return(np->nvfun=lp);
676da2e3ebdSchin 			}
677da2e3ebdSchin 			if(mode==NV_FIRST || mode==0)
678da2e3ebdSchin 				return(fp);
679da2e3ebdSchin 			np->nvfun = lp->next;
680da2e3ebdSchin 			if(mode==NV_POP)
681da2e3ebdSchin 				return(fp);
6827c2fbfb3SApril Chin 			if(mode==NV_LAST && (lp->next==0 || lp->next->disc==0))
6837c2fbfb3SApril Chin 				return(fp);
684da2e3ebdSchin 		}
685da2e3ebdSchin 		/* see if <fp> is on the list already */
686da2e3ebdSchin 		lpp = &np->nvfun;
687da2e3ebdSchin 		if(lp)
688da2e3ebdSchin 		{
6897c2fbfb3SApril Chin 			while(lp->next && lp->next->disc)
690da2e3ebdSchin 			{
691da2e3ebdSchin 				if(lp->next==fp)
692da2e3ebdSchin 				{
6937c2fbfb3SApril Chin 					if(mode==NV_LAST && fp->next==0)
6947c2fbfb3SApril Chin 						return(fp);
695da2e3ebdSchin 					if(mode==NV_CLONE)
696da2e3ebdSchin 					{
6977c2fbfb3SApril Chin 						fp = nv_clone_disc(fp,0);
698da2e3ebdSchin 						lp->next = fp;
699da2e3ebdSchin 						return(fp);
700da2e3ebdSchin 					}
701da2e3ebdSchin 					lp->next = fp->next;
702da2e3ebdSchin 					if(mode==NV_POP)
703da2e3ebdSchin 						return(fp);
704da2e3ebdSchin 					if(mode!=NV_LAST)
705da2e3ebdSchin 						break;
706da2e3ebdSchin 				}
707da2e3ebdSchin 				lp = lp->next;
708da2e3ebdSchin 			}
709da2e3ebdSchin 			if(mode==NV_LAST)
710da2e3ebdSchin 				lpp = &lp->next;
711da2e3ebdSchin 		}
712da2e3ebdSchin 		if(mode==NV_POP)
713da2e3ebdSchin 			return(0);
714da2e3ebdSchin 		/* push */
715da2e3ebdSchin 		nv_offattr(np,NV_NODISC);
716da2e3ebdSchin 		if(mode==NV_LAST)
717da2e3ebdSchin 			fp->next = 0;
718da2e3ebdSchin 		else
719da2e3ebdSchin 		{
7207c2fbfb3SApril Chin 			if((fp->nofree&1) && *lpp)
7217c2fbfb3SApril Chin 				fp = nv_clone_disc(fp,0);
722da2e3ebdSchin 			fp->next = *lpp;
723da2e3ebdSchin 		}
724da2e3ebdSchin 		*lpp = fp;
725da2e3ebdSchin 	}
726da2e3ebdSchin 	else
727da2e3ebdSchin 	{
728da2e3ebdSchin 		if(mode==NV_FIRST)
729da2e3ebdSchin 			return(np->nvfun);
730da2e3ebdSchin 		else if(mode==NV_LAST)
731da2e3ebdSchin 			for(lp=np->nvfun; lp; fp=lp,lp=lp->next);
732da2e3ebdSchin 		else if(fp = np->nvfun)
733da2e3ebdSchin 			np->nvfun = fp->next;
734da2e3ebdSchin 	}
735da2e3ebdSchin 	return(fp);
736da2e3ebdSchin }
737da2e3ebdSchin 
738da2e3ebdSchin /*
739da2e3ebdSchin  * returns discipline pointer if discipline with specified functions
740da2e3ebdSchin  * is on the discipline stack
741da2e3ebdSchin  */
nv_hasdisc(Namval_t * np,const Namdisc_t * dp)742da2e3ebdSchin Namfun_t *nv_hasdisc(Namval_t *np, const Namdisc_t *dp)
743da2e3ebdSchin {
744da2e3ebdSchin 	register Namfun_t *fp;
745da2e3ebdSchin 	for(fp=np->nvfun; fp; fp = fp->next)
746da2e3ebdSchin 	{
747da2e3ebdSchin 		if(fp->disc== dp)
748da2e3ebdSchin 			return(fp);
749da2e3ebdSchin 	}
750da2e3ebdSchin 	return(0);
751da2e3ebdSchin }
752da2e3ebdSchin 
753da2e3ebdSchin struct notify
754da2e3ebdSchin {
755da2e3ebdSchin 	Namfun_t	hdr;
756da2e3ebdSchin 	char		**ptr;
757da2e3ebdSchin };
758da2e3ebdSchin 
put_notify(Namval_t * np,const char * val,int flags,Namfun_t * fp)759da2e3ebdSchin static void put_notify(Namval_t* np,const char *val,int flags,Namfun_t *fp)
760da2e3ebdSchin {
761da2e3ebdSchin 	struct notify *pp = (struct notify*)fp;
762da2e3ebdSchin 	nv_putv(np,val,flags,fp);
763da2e3ebdSchin 	nv_stack(np,fp);
764da2e3ebdSchin 	nv_stack(np,(Namfun_t*)0);
765da2e3ebdSchin 	*pp->ptr = 0;
7667c2fbfb3SApril Chin 	if(!(fp->nofree&1))
767da2e3ebdSchin 		free((void*)fp);
768da2e3ebdSchin }
769da2e3ebdSchin 
770da2e3ebdSchin static const Namdisc_t notify_disc  = {  0, put_notify };
771da2e3ebdSchin 
nv_unsetnotify(Namval_t * np,char ** addr)772da2e3ebdSchin int nv_unsetnotify(Namval_t *np, char **addr)
773da2e3ebdSchin {
774da2e3ebdSchin 	register Namfun_t *fp;
775da2e3ebdSchin 	for(fp=np->nvfun;fp;fp=fp->next)
776da2e3ebdSchin 	{
777da2e3ebdSchin 		if(fp->disc->putval==put_notify && ((struct notify*)fp)->ptr==addr)
778da2e3ebdSchin 		{
779da2e3ebdSchin 			nv_stack(np,fp);
780da2e3ebdSchin 			nv_stack(np,(Namfun_t*)0);
7817c2fbfb3SApril Chin 			if(!(fp->nofree&1))
782da2e3ebdSchin 				free((void*)fp);
783da2e3ebdSchin 			return(1);
784da2e3ebdSchin 		}
785da2e3ebdSchin 	}
786da2e3ebdSchin 	return(0);
787da2e3ebdSchin }
788da2e3ebdSchin 
nv_setnotify(Namval_t * np,char ** addr)789da2e3ebdSchin int nv_setnotify(Namval_t *np, char **addr)
790da2e3ebdSchin {
791da2e3ebdSchin 	struct notify *pp = newof(0,struct notify, 1,0);
792da2e3ebdSchin 	if(!pp)
793da2e3ebdSchin 		return(0);
794da2e3ebdSchin 	pp->ptr = addr;
795da2e3ebdSchin 	pp->hdr.disc = &notify_disc;
796da2e3ebdSchin 	nv_stack(np,&pp->hdr);
797da2e3ebdSchin 	return(1);
798da2e3ebdSchin }
799da2e3ebdSchin 
newnode(const char * name)800da2e3ebdSchin static void *newnode(const char *name)
801da2e3ebdSchin {
802da2e3ebdSchin 	register int s;
803da2e3ebdSchin 	register Namval_t *np = newof(0,Namval_t,1,s=strlen(name)+1);
804da2e3ebdSchin 	if(np)
805da2e3ebdSchin 	{
806da2e3ebdSchin 		np->nvname = (char*)np+sizeof(Namval_t);
807da2e3ebdSchin 		memcpy(np->nvname,name,s);
808da2e3ebdSchin 	}
809da2e3ebdSchin 	return((void*)np);
810da2e3ebdSchin }
811da2e3ebdSchin 
812da2e3ebdSchin #if SHOPT_NAMESPACE
813da2e3ebdSchin /*
814da2e3ebdSchin  * clone a numeric value
815da2e3ebdSchin  */
num_clone(register Namval_t * np,void * val)816da2e3ebdSchin static void *num_clone(register Namval_t *np, void *val)
817da2e3ebdSchin {
818da2e3ebdSchin 	register int size;
819da2e3ebdSchin 	void *nval;
820da2e3ebdSchin 	if(!val)
821da2e3ebdSchin 		return(0);
8227c2fbfb3SApril Chin 	if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
823da2e3ebdSchin 	{
824da2e3ebdSchin 		if(nv_isattr(np,NV_LONG))
825da2e3ebdSchin 			size = sizeof(Sfdouble_t);
826da2e3ebdSchin 		else if(nv_isattr(np,NV_SHORT))
827da2e3ebdSchin 			size = sizeof(float);
828da2e3ebdSchin 		else
829da2e3ebdSchin 			size = sizeof(double);
830da2e3ebdSchin 	}
831da2e3ebdSchin 	else
832da2e3ebdSchin 	{
833da2e3ebdSchin 		if(nv_isattr(np,NV_LONG))
834da2e3ebdSchin 			size = sizeof(Sflong_t);
835da2e3ebdSchin 		else if(nv_isattr(np,NV_SHORT))
8367c2fbfb3SApril Chin 		{
8377c2fbfb3SApril Chin 			if(nv_isattr(np,NV_INT16P)==NV_INT16P)
8387c2fbfb3SApril Chin 				size = sizeof(short);
8397c2fbfb3SApril Chin 			else
8407c2fbfb3SApril Chin 				return((void*)np->nvalue.ip);
8417c2fbfb3SApril Chin 		}
842da2e3ebdSchin 		else
843da2e3ebdSchin 			size = sizeof(int32_t);
844da2e3ebdSchin 	}
845da2e3ebdSchin 	if(!(nval = malloc(size)))
846da2e3ebdSchin 		return(0);
847da2e3ebdSchin 	memcpy(nval,val,size);
848da2e3ebdSchin 	return(nval);
849da2e3ebdSchin }
850da2e3ebdSchin 
clone_all_disc(Namval_t * np,Namval_t * mp,int flags)8517c2fbfb3SApril Chin void clone_all_disc( Namval_t *np, Namval_t *mp, int flags)
852da2e3ebdSchin {
8537c2fbfb3SApril Chin 	register Namfun_t *fp, **mfp = &mp->nvfun, *nfp, *fpnext;
8547c2fbfb3SApril Chin 	for(fp=np->nvfun; fp;fp=fpnext)
855da2e3ebdSchin 	{
8567c2fbfb3SApril Chin 		fpnext = fp->next;
8577c2fbfb3SApril Chin 		if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
8587c2fbfb3SApril Chin 			return;
8597c2fbfb3SApril Chin 		if((fp->nofree&2) && (flags&NV_NODISC))
860da2e3ebdSchin 			nfp = 0;
861da2e3ebdSchin 		if(fp->disc && fp->disc->clonef)
862da2e3ebdSchin 			nfp = (*fp->disc->clonef)(np,mp,flags,fp);
8637c2fbfb3SApril Chin 		else	if(flags&NV_MOVE)
8647c2fbfb3SApril Chin 			nfp = fp;
865da2e3ebdSchin 		else
8667c2fbfb3SApril Chin 			nfp = nv_clone_disc(fp,flags);
867da2e3ebdSchin 		if(!nfp)
868da2e3ebdSchin 			continue;
869da2e3ebdSchin 		nfp->next = 0;
870da2e3ebdSchin 		*mfp = nfp;
871da2e3ebdSchin 		mfp = &nfp->next;
872da2e3ebdSchin 	}
873da2e3ebdSchin }
874da2e3ebdSchin 
875da2e3ebdSchin /*
876da2e3ebdSchin  * clone <mp> from <np> flags can be one of the following
877da2e3ebdSchin  * NV_APPEND - append <np> onto <mp>
878da2e3ebdSchin  * NV_MOVE - move <np> to <mp>
879da2e3ebdSchin  * NV_NOFREE - mark the new node as nofree
880da2e3ebdSchin  * NV_NODISC - discplines with funs non-zero will not be copied
8817c2fbfb3SApril Chin  * NV_COMVAR - cloning a compound variable
882da2e3ebdSchin  */
nv_clone(Namval_t * np,Namval_t * mp,int flags)883da2e3ebdSchin int nv_clone(Namval_t *np, Namval_t *mp, int flags)
884da2e3ebdSchin {
8857c2fbfb3SApril Chin 	Namfun_t	*fp, *fpnext;
8867c2fbfb3SApril Chin 	const char	*val = mp->nvalue.cp;
8877c2fbfb3SApril Chin 	unsigned short	flag = mp->nvflag;
8887c2fbfb3SApril Chin 	unsigned short	size = mp->nvsize;
8897c2fbfb3SApril Chin 	for(fp=mp->nvfun; fp; fp=fpnext)
8907c2fbfb3SApril Chin 	{
8917c2fbfb3SApril Chin 		fpnext = fp->next;
8927c2fbfb3SApril Chin 		if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
8937c2fbfb3SApril Chin 			break;
8947c2fbfb3SApril Chin 		if(!(fp->nofree&1))
8957c2fbfb3SApril Chin 			free((void*)fp);
8967c2fbfb3SApril Chin 	}
8977c2fbfb3SApril Chin 	mp->nvfun = fp;
898da2e3ebdSchin 	if(fp=np->nvfun)
899da2e3ebdSchin 	{
9007c2fbfb3SApril Chin 		if(nv_isattr(mp,NV_EXPORT|NV_MINIMAL) == (NV_EXPORT|NV_MINIMAL))
901da2e3ebdSchin 		{
9027c2fbfb3SApril Chin 			mp->nvenv = 0;
9037c2fbfb3SApril Chin 			nv_offattr(mp,NV_MINIMAL);
904da2e3ebdSchin 		}
9057c2fbfb3SApril Chin 		if(!(flags&NV_COMVAR) && !nv_isattr(np,NV_MINIMAL) && np->nvenv && !(nv_isattr(mp,NV_MINIMAL)))
9067c2fbfb3SApril Chin 			mp->nvenv = np->nvenv;
9077c2fbfb3SApril Chin 		mp->nvflag &= NV_MINIMAL;
9087c2fbfb3SApril Chin 	        mp->nvflag |= np->nvflag&~(NV_ARRAY|NV_MINIMAL|NV_NOFREE);
9097c2fbfb3SApril Chin 		flag = mp->nvflag;
910da2e3ebdSchin 		clone_all_disc(np, mp, flags);
911da2e3ebdSchin 	}
912da2e3ebdSchin 	if(flags&NV_APPEND)
913da2e3ebdSchin 		return(1);
9147c2fbfb3SApril Chin 	if(mp->nvsize == size)
915da2e3ebdSchin 	        nv_setsize(mp,nv_size(np));
9167c2fbfb3SApril Chin 	if(mp->nvflag == flag)
9177c2fbfb3SApril Chin 	        mp->nvflag = (np->nvflag&~(NV_MINIMAL))|(mp->nvflag&NV_MINIMAL);
918*3e14f97fSRoger A. Faulkner 		if(nv_isattr(np,NV_EXPORT))
919*3e14f97fSRoger A. Faulkner 			mp->nvflag |= (np->nvflag&NV_MINIMAL);
9207c2fbfb3SApril Chin 	if(mp->nvalue.cp==val && !nv_isattr(np,NV_INTEGER))
9217c2fbfb3SApril Chin 	{
9227c2fbfb3SApril Chin 		if(np->nvalue.cp && np->nvalue.cp!=Empty && (flags&NV_COMVAR) && !(flags&NV_MOVE))
9237c2fbfb3SApril Chin 		{
9247c2fbfb3SApril Chin 			if(size)
9257c2fbfb3SApril Chin 				mp->nvalue.cp = (char*)memdup(np->nvalue.cp,size);
9267c2fbfb3SApril Chin 			else
9277c2fbfb3SApril Chin 			        mp->nvalue.cp = strdup(np->nvalue.cp);
9287c2fbfb3SApril Chin 			nv_offattr(mp,NV_NOFREE);
9297c2fbfb3SApril Chin 		}
9307c2fbfb3SApril Chin 		else if(!(mp->nvalue.cp = np->nvalue.cp))
9317c2fbfb3SApril Chin 			nv_offattr(mp,NV_NOFREE);
9327c2fbfb3SApril Chin 	}
933da2e3ebdSchin 	if(flags&NV_MOVE)
934da2e3ebdSchin 	{
9357c2fbfb3SApril Chin 		if(nv_isattr(np,NV_INTEGER))
9367c2fbfb3SApril Chin 			mp->nvalue.ip = np->nvalue.ip;
937da2e3ebdSchin 		np->nvfun = 0;
938da2e3ebdSchin 		np->nvalue.cp = 0;
939da2e3ebdSchin 		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(mp,NV_EXPORT))
940*3e14f97fSRoger A. Faulkner 		{
941*3e14f97fSRoger A. Faulkner 			mp->nvenv = np->nvenv;
942da2e3ebdSchin 		        np->nvenv = 0;
943*3e14f97fSRoger A. Faulkner 			np->nvflag = 0;
944*3e14f97fSRoger A. Faulkner 		}
945*3e14f97fSRoger A. Faulkner 		else
9467c2fbfb3SApril Chin 			np->nvflag &= NV_MINIMAL;
947da2e3ebdSchin 	        nv_setsize(np,0);
948da2e3ebdSchin 		return(1);
949da2e3ebdSchin 	}
9507c2fbfb3SApril Chin 	if(nv_isattr(np,NV_INTEGER) && mp->nvalue.ip!=np->nvalue.ip)
95134f9b3eeSRoland Mainz 	{
952da2e3ebdSchin 		mp->nvalue.ip = (int*)num_clone(np,(void*)np->nvalue.ip);
95334f9b3eeSRoland Mainz 		nv_offattr(mp,NV_NOFREE);
95434f9b3eeSRoland Mainz 	}
955da2e3ebdSchin 	else if(flags&NV_NOFREE)
956da2e3ebdSchin 	        nv_onattr(np,NV_NOFREE);
957da2e3ebdSchin 	return(1);
958da2e3ebdSchin }
959da2e3ebdSchin 
960da2e3ebdSchin /*
961da2e3ebdSchin  *  The following discipline is for copy-on-write semantics
962da2e3ebdSchin  */
clone_getv(Namval_t * np,Namfun_t * handle)963da2e3ebdSchin static char* clone_getv(Namval_t *np, Namfun_t *handle)
964da2e3ebdSchin {
965da2e3ebdSchin 	return(np->nvalue.np?nv_getval(np->nvalue.np):0);
966da2e3ebdSchin }
967da2e3ebdSchin 
clone_getn(Namval_t * np,Namfun_t * handle)968da2e3ebdSchin static Sfdouble_t clone_getn(Namval_t *np, Namfun_t *handle)
969da2e3ebdSchin {
970da2e3ebdSchin 	return(np->nvalue.np?nv_getnum(np->nvalue.np):0);
971da2e3ebdSchin }
972da2e3ebdSchin 
clone_putv(Namval_t * np,const char * val,int flags,Namfun_t * handle)973da2e3ebdSchin static void clone_putv(Namval_t *np,const char* val,int flags,Namfun_t *handle)
974da2e3ebdSchin {
975da2e3ebdSchin 	Namfun_t *dp = nv_stack(np,(Namfun_t*)0);
976da2e3ebdSchin 	Namval_t *mp = np->nvalue.np;
977da2e3ebdSchin 	if(!sh.subshell)
978da2e3ebdSchin 		free((void*)dp);
979da2e3ebdSchin 	if(val)
980da2e3ebdSchin 		nv_clone(mp,np,NV_NOFREE);
981da2e3ebdSchin 	np->nvalue.cp = 0;
982da2e3ebdSchin 	nv_putval(np,val,flags);
983da2e3ebdSchin }
984da2e3ebdSchin 
985da2e3ebdSchin static const Namdisc_t clone_disc =
986da2e3ebdSchin {
987da2e3ebdSchin 	0,
988da2e3ebdSchin 	clone_putv,
989da2e3ebdSchin 	clone_getv,
990da2e3ebdSchin 	clone_getn
991da2e3ebdSchin };
992da2e3ebdSchin 
nv_mkclone(Namval_t * mp)993da2e3ebdSchin Namval_t *nv_mkclone(Namval_t *mp)
994da2e3ebdSchin {
995da2e3ebdSchin 	Namval_t *np;
996da2e3ebdSchin 	Namfun_t *dp;
997da2e3ebdSchin 	np = newof(0,Namval_t,1,0);
998da2e3ebdSchin 	np->nvflag = mp->nvflag;
999da2e3ebdSchin 	np->nvsize = mp->nvsize;
1000da2e3ebdSchin 	np->nvname = mp->nvname;
1001da2e3ebdSchin 	np->nvalue.np = mp;
1002da2e3ebdSchin 	np->nvflag = mp->nvflag;
1003da2e3ebdSchin 	dp = newof(0,Namfun_t,1,0);
1004da2e3ebdSchin 	dp->disc = &clone_disc;
1005da2e3ebdSchin 	nv_stack(np,dp);
1006da2e3ebdSchin 	dtinsert(nv_dict(sh.namespace),np);
1007da2e3ebdSchin 	return(np);
1008da2e3ebdSchin }
1009da2e3ebdSchin #endif /* SHOPT_NAMESPACE */
1010da2e3ebdSchin 
nv_search(const char * name,Dt_t * root,int mode)1011da2e3ebdSchin Namval_t *nv_search(const char *name, Dt_t *root, int mode)
1012da2e3ebdSchin {
1013da2e3ebdSchin 	register Namval_t *np;
1014da2e3ebdSchin 	register Dt_t *dp = 0;
1015da2e3ebdSchin 	if(mode&HASH_NOSCOPE)
1016da2e3ebdSchin 		dp = dtview(root,0);
1017da2e3ebdSchin 	if(mode&HASH_BUCKET)
1018da2e3ebdSchin 	{
1019da2e3ebdSchin 		Namval_t *mp = (void*)name;
1020da2e3ebdSchin 		if(!(np = dtsearch(root,mp)) && (mode&NV_ADD))
1021da2e3ebdSchin 			name = nv_name(mp);
1022da2e3ebdSchin 	}
1023da2e3ebdSchin 	else
1024da2e3ebdSchin 	{
102534f9b3eeSRoland Mainz 		if(*name=='.' && root==sh.var_tree && !dp)
1026da2e3ebdSchin 			root = sh.var_base;
1027da2e3ebdSchin 		np = dtmatch(root,(void*)name);
1028da2e3ebdSchin 	}
1029da2e3ebdSchin 	if(!np && (mode&NV_ADD))
1030da2e3ebdSchin 	{
1031da2e3ebdSchin 		if(sh.namespace && !(mode&HASH_NOSCOPE) && root==sh.var_tree)
1032da2e3ebdSchin 			root = nv_dict(sh.namespace);
1033da2e3ebdSchin 		else if(!dp && !(mode&HASH_NOSCOPE))
1034da2e3ebdSchin 		{
1035da2e3ebdSchin 			register Dt_t *next;
1036da2e3ebdSchin 			while(next=dtvnext(root))
1037da2e3ebdSchin 				root = next;
1038da2e3ebdSchin 		}
1039da2e3ebdSchin 		np = (Namval_t*)dtinsert(root,newnode(name));
1040da2e3ebdSchin 	}
1041da2e3ebdSchin 	if(dp)
1042da2e3ebdSchin 		dtview(root,dp);
1043da2e3ebdSchin 	return(np);
1044da2e3ebdSchin }
1045da2e3ebdSchin 
1046da2e3ebdSchin /*
1047da2e3ebdSchin  * finds function or builtin for given name and the discipline variable
1048da2e3ebdSchin  * if var!=0 the variable pointer is returned and the built-in name
1049da2e3ebdSchin  *    is put onto the stack at the current offset.
1050da2e3ebdSchin  * otherwise, a pointer to the builtin (variable or type) is returned
1051da2e3ebdSchin  * and var contains the poiner to the variable
1052da2e3ebdSchin  * if last==0 and first component of name is a reference, nv_bfsearch()
1053da2e3ebdSchin 	will return 0.
1054da2e3ebdSchin  */
nv_bfsearch(const char * name,Dt_t * root,Namval_t ** var,char ** last)1055da2e3ebdSchin Namval_t *nv_bfsearch(const char *name, Dt_t *root, Namval_t **var, char **last)
1056da2e3ebdSchin {
10577c2fbfb3SApril Chin 	int		c,offset = staktell();
1058da2e3ebdSchin 	register char	*sp, *cp=0;
1059da2e3ebdSchin 	Namval_t	*np, *nq;
10607c2fbfb3SApril Chin 	char		*dname=0;
1061da2e3ebdSchin 	if(var)
1062da2e3ebdSchin 		*var = 0;
1063da2e3ebdSchin 	/* check for . in the name before = */
1064da2e3ebdSchin 	for(sp=(char*)name+1; *sp; sp++)
1065da2e3ebdSchin 	{
1066da2e3ebdSchin 		if(*sp=='=')
1067da2e3ebdSchin 			return(0);
10687c2fbfb3SApril Chin 		if(*sp=='[')
10697c2fbfb3SApril Chin 		{
10707c2fbfb3SApril Chin 			if(sp[-1]!='.')
10717c2fbfb3SApril Chin 				dname = sp;
10727c2fbfb3SApril Chin 			while(*sp=='[')
10737c2fbfb3SApril Chin 			{
10747c2fbfb3SApril Chin 				sp = nv_endsubscript((Namval_t*)0,(char*)sp,0);
10757c2fbfb3SApril Chin 				if(sp[-1]!=']')
10767c2fbfb3SApril Chin 					return(0);
10777c2fbfb3SApril Chin 			}
10787c2fbfb3SApril Chin 			if(*sp==0)
10797c2fbfb3SApril Chin 				break;
10807c2fbfb3SApril Chin 			if(*sp!='.')
10817c2fbfb3SApril Chin 				return(0);
10827c2fbfb3SApril Chin 			if(dname)
10837c2fbfb3SApril Chin 			{
10847c2fbfb3SApril Chin 				cp = dname;
10857c2fbfb3SApril Chin 				dname = sp+1;
10867c2fbfb3SApril Chin 			}
10877c2fbfb3SApril Chin 		}
10887c2fbfb3SApril Chin 		else if(*sp=='.')
1089da2e3ebdSchin 			cp = sp;
1090da2e3ebdSchin 	}
1091da2e3ebdSchin 	if(!cp)
1092da2e3ebdSchin 		return(var?nv_search(name,root,0):0);
1093da2e3ebdSchin 	stakputs(name);
1094da2e3ebdSchin 	stakputc(0);
10957c2fbfb3SApril Chin 	if(!dname)
10967c2fbfb3SApril Chin 		dname = cp+1;
1097da2e3ebdSchin 	cp = stakptr(offset) + (cp-name);
1098da2e3ebdSchin 	if(last)
1099da2e3ebdSchin 		*last = cp;
11007c2fbfb3SApril Chin 	c = *cp;
1101da2e3ebdSchin 	*cp = 0;
11027c2fbfb3SApril Chin 	nq=nv_open(stakptr(offset),0,NV_VARNAME|NV_ARRAY|NV_NOASSIGN|NV_NOADD|NV_NOFAIL);
11037c2fbfb3SApril Chin 	*cp = c;
1104da2e3ebdSchin 	if(!nq)
1105da2e3ebdSchin 	{
1106da2e3ebdSchin 		np = 0;
1107da2e3ebdSchin 		goto done;
1108da2e3ebdSchin 	}
1109da2e3ebdSchin 	if(!var)
1110da2e3ebdSchin 	{
1111da2e3ebdSchin 		np = nq;
1112da2e3ebdSchin 		goto done;
1113da2e3ebdSchin 	}
1114da2e3ebdSchin 	*var = nq;
11157c2fbfb3SApril Chin 	if(c=='[')
11167c2fbfb3SApril Chin 		nv_endsubscript(nq, cp,NV_NOADD);
11177c2fbfb3SApril Chin 	return((Namval_t*)nv_setdisc(nq,dname,nq,(Namfun_t*)nq));
1118da2e3ebdSchin done:
1119da2e3ebdSchin 	stakseek(offset);
1120da2e3ebdSchin 	return(np);
1121da2e3ebdSchin }
1122da2e3ebdSchin 
1123da2e3ebdSchin /*
11247c2fbfb3SApril Chin  * add or replace built-in version of command corresponding to <path>
1125da2e3ebdSchin  * The <bltin> argument is a pointer to the built-in
1126da2e3ebdSchin  * if <extra>==1, the built-in will be deleted
1127da2e3ebdSchin  * Special builtins cannot be added or deleted return failure
1128da2e3ebdSchin  * The return value for adding builtins is a pointer to the node or NULL on
1129da2e3ebdSchin  *   failure.  For delete NULL means success and the node that cannot be
1130da2e3ebdSchin  *   deleted is returned on failure.
1131da2e3ebdSchin  */
sh_addbuiltin(const char * path,int (* bltin)(int,char * [],void *),void * extra)1132da2e3ebdSchin Namval_t *sh_addbuiltin(const char *path, int (*bltin)(int, char*[],void*),void *extra)
1133da2e3ebdSchin {
1134da2e3ebdSchin 	register const char	*name = path_basename(path);
1135da2e3ebdSchin 	char			*cp;
1136da2e3ebdSchin 	register Namval_t	*np, *nq=0;
1137da2e3ebdSchin 	int			offset=staktell();
1138da2e3ebdSchin 	if(name==path && (nq=nv_bfsearch(name,sh.bltin_tree,(Namval_t**)0,&cp)))
1139da2e3ebdSchin 		path = name = stakptr(offset);
1140da2e3ebdSchin 	if(np = nv_search(path,sh.bltin_tree,0))
1141da2e3ebdSchin 	{
1142da2e3ebdSchin 		/* exists without a path */
1143da2e3ebdSchin 		if(extra == (void*)1)
1144da2e3ebdSchin 		{
1145da2e3ebdSchin 			if(np->nvfun && !nv_isattr(np,NV_NOFREE))
1146da2e3ebdSchin 				free((void*)np->nvfun);
1147da2e3ebdSchin 			dtdelete(sh.bltin_tree,np);
1148da2e3ebdSchin 			return(0);
1149da2e3ebdSchin 		}
1150da2e3ebdSchin 		if(!bltin)
1151da2e3ebdSchin 			return(np);
1152da2e3ebdSchin 	}
1153da2e3ebdSchin 	else for(np=(Namval_t*)dtfirst(sh.bltin_tree);np;np=(Namval_t*)dtnext(sh.bltin_tree,np))
1154da2e3ebdSchin 	{
1155da2e3ebdSchin 		if(strcmp(name,path_basename(nv_name(np))))
1156da2e3ebdSchin 			continue;
1157da2e3ebdSchin 		/* exists probably with different path so delete it */
1158da2e3ebdSchin 		if(strcmp(path,nv_name(np)))
1159da2e3ebdSchin 		{
1160da2e3ebdSchin 			if(nv_isattr(np,BLT_SPC))
1161da2e3ebdSchin 				return(np);
1162da2e3ebdSchin 			if(!bltin)
1163da2e3ebdSchin 				bltin = np->nvalue.bfp;
1164da2e3ebdSchin 			if(np->nvenv)
1165da2e3ebdSchin 				dtdelete(sh.bltin_tree,np);
1166da2e3ebdSchin 			if(extra == (void*)1)
1167da2e3ebdSchin 				return(0);
1168da2e3ebdSchin 			np = 0;
1169da2e3ebdSchin 		}
1170da2e3ebdSchin 		break;
1171da2e3ebdSchin 	}
1172da2e3ebdSchin 	if(!np && !(np = nv_search(path,sh.bltin_tree,bltin?NV_ADD:0)))
1173da2e3ebdSchin 		return(0);
1174da2e3ebdSchin 	if(nv_isattr(np,BLT_SPC))
11757c2fbfb3SApril Chin 	{
11767c2fbfb3SApril Chin 		if(extra)
11777c2fbfb3SApril Chin 			np->nvfun = (Namfun_t*)extra;
1178da2e3ebdSchin 		return(np);
11797c2fbfb3SApril Chin 	}
1180da2e3ebdSchin 	np->nvenv = 0;
1181da2e3ebdSchin 	np->nvfun = 0;
1182da2e3ebdSchin 	if(bltin)
1183da2e3ebdSchin 	{
1184da2e3ebdSchin 		np->nvalue.bfp = bltin;
1185da2e3ebdSchin 		nv_onattr(np,NV_BLTIN|NV_NOFREE);
1186da2e3ebdSchin 		np->nvfun = (Namfun_t*)extra;
1187da2e3ebdSchin 	}
1188da2e3ebdSchin 	if(nq)
1189da2e3ebdSchin 	{
1190da2e3ebdSchin 		cp=nv_setdisc(nq,cp+1,np,(Namfun_t*)nq);
1191da2e3ebdSchin 		nv_close(nq);
1192da2e3ebdSchin 		if(!cp)
1193da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_baddisc,name);
1194da2e3ebdSchin 	}
1195da2e3ebdSchin 	if(extra == (void*)1)
1196da2e3ebdSchin 		return(0);
1197da2e3ebdSchin 	return(np);
1198da2e3ebdSchin }
1199da2e3ebdSchin 
1200da2e3ebdSchin #undef nv_stack
nv_stack(register Namval_t * np,register Namfun_t * fp)1201da2e3ebdSchin extern Namfun_t *nv_stack(register Namval_t *np, register Namfun_t* fp)
1202da2e3ebdSchin {
1203da2e3ebdSchin 	return(nv_disc(np,fp,0));
1204da2e3ebdSchin }
1205da2e3ebdSchin 
1206da2e3ebdSchin struct table
1207da2e3ebdSchin {
1208da2e3ebdSchin 	Namfun_t	fun;
1209da2e3ebdSchin 	Namval_t	*parent;
1210da2e3ebdSchin 	Shell_t		*shp;
1211da2e3ebdSchin 	Dt_t		*dict;
1212da2e3ebdSchin };
1213da2e3ebdSchin 
next_table(register Namval_t * np,Dt_t * root,Namfun_t * fp)1214da2e3ebdSchin static Namval_t *next_table(register Namval_t* np, Dt_t *root,Namfun_t *fp)
1215da2e3ebdSchin {
1216da2e3ebdSchin 	struct table *tp = (struct table *)fp;
1217da2e3ebdSchin 	if(root)
1218da2e3ebdSchin 		return((Namval_t*)dtnext(root,np));
1219da2e3ebdSchin 	else
1220da2e3ebdSchin 		return((Namval_t*)dtfirst(tp->dict));
1221da2e3ebdSchin }
1222da2e3ebdSchin 
create_table(Namval_t * np,const char * name,int flags,Namfun_t * fp)1223da2e3ebdSchin static Namval_t *create_table(Namval_t *np,const char *name,int flags,Namfun_t *fp)
1224da2e3ebdSchin {
1225da2e3ebdSchin 	struct table *tp = (struct table *)fp;
1226da2e3ebdSchin 	tp->shp->last_table = np;
1227da2e3ebdSchin 	return(nv_create(name, tp->dict, flags, fp));
1228da2e3ebdSchin }
1229da2e3ebdSchin 
clone_table(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)1230da2e3ebdSchin static Namfun_t *clone_table(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
1231da2e3ebdSchin {
1232da2e3ebdSchin 	struct table	*tp = (struct table*)fp;
12337c2fbfb3SApril Chin 	struct table	*ntp = (struct table*)nv_clone_disc(fp,0);
1234da2e3ebdSchin 	Dt_t		*oroot=tp->dict,*nroot=dtopen(&_Nvdisc,Dtoset);
1235da2e3ebdSchin 	if(!nroot)
1236da2e3ebdSchin 		return(0);
1237da2e3ebdSchin 	memcpy((void*)ntp,(void*)fp,sizeof(struct table));
1238da2e3ebdSchin 	ntp->dict = nroot;
1239da2e3ebdSchin 	ntp->parent = nv_lastdict();
1240da2e3ebdSchin 	for(np=(Namval_t*)dtfirst(oroot);np;np=(Namval_t*)dtnext(oroot,np))
1241da2e3ebdSchin 	{
1242da2e3ebdSchin 		mp = (Namval_t*)dtinsert(nroot,newnode(np->nvname));
1243da2e3ebdSchin 		nv_clone(np,mp,flags);
1244da2e3ebdSchin 	}
1245da2e3ebdSchin 	return(&ntp->fun);
1246da2e3ebdSchin }
1247da2e3ebdSchin 
put_table(register Namval_t * np,const char * val,int flags,Namfun_t * fp)1248da2e3ebdSchin static void put_table(register Namval_t* np, const char* val, int flags, Namfun_t* fp)
1249da2e3ebdSchin {
1250da2e3ebdSchin 	register Dt_t		*root = ((struct table*)fp)->dict;
1251da2e3ebdSchin 	register Namval_t	*nq, *mp;
1252da2e3ebdSchin 	Namarr_t		*ap;
1253da2e3ebdSchin 	nv_putv(np,val,flags,fp);
1254da2e3ebdSchin 	if(val)
1255da2e3ebdSchin 		return;
1256da2e3ebdSchin 	if(nv_isarray(np) && (ap=nv_arrayptr(np)) && array_elem(ap))
1257da2e3ebdSchin 		return;
1258da2e3ebdSchin 	for(mp=(Namval_t*)dtfirst(root);mp;mp=nq)
1259da2e3ebdSchin 	{
1260da2e3ebdSchin 		_nv_unset(mp,flags);
1261da2e3ebdSchin 		nq = (Namval_t*)dtnext(root,mp);
1262da2e3ebdSchin 		dtdelete(root,mp);
1263da2e3ebdSchin 		free((void*)mp);
1264da2e3ebdSchin 	}
1265da2e3ebdSchin 	dtclose(root);
12667c2fbfb3SApril Chin 	if(!(fp->nofree&1))
1267da2e3ebdSchin 		free((void*)fp);
1268da2e3ebdSchin }
1269da2e3ebdSchin 
1270da2e3ebdSchin /*
1271da2e3ebdSchin  * return space separated list of names of variables in given tree
1272da2e3ebdSchin  */
get_table(Namval_t * np,Namfun_t * fp)1273da2e3ebdSchin static char *get_table(Namval_t *np, Namfun_t *fp)
1274da2e3ebdSchin {
1275da2e3ebdSchin 	register Dt_t *root = ((struct table*)fp)->dict;
1276da2e3ebdSchin 	static Sfio_t *out;
1277da2e3ebdSchin 	register int first=1;
1278da2e3ebdSchin 	register Dt_t *base = dtview(root,0);
1279da2e3ebdSchin         if(out)
1280da2e3ebdSchin                 sfseek(out,(Sfoff_t)0,SEEK_SET);
1281da2e3ebdSchin         else
1282da2e3ebdSchin                 out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
1283da2e3ebdSchin 	for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
1284da2e3ebdSchin 	{
1285da2e3ebdSchin                 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
1286da2e3ebdSchin 		{
1287da2e3ebdSchin 			if(!first)
1288da2e3ebdSchin 				sfputc(out,' ');
1289da2e3ebdSchin 			else
1290da2e3ebdSchin 				first = 0;
1291da2e3ebdSchin 			sfputr(out,np->nvname,-1);
1292da2e3ebdSchin 		}
1293da2e3ebdSchin 	}
1294da2e3ebdSchin 	sfputc(out,0);
1295da2e3ebdSchin 	if(base)
1296da2e3ebdSchin 		dtview(root,base);
1297da2e3ebdSchin 	return((char*)out->_data);
1298da2e3ebdSchin }
1299da2e3ebdSchin 
1300da2e3ebdSchin static const Namdisc_t table_disc =
1301da2e3ebdSchin {
1302da2e3ebdSchin         sizeof(struct table),
1303da2e3ebdSchin         put_table,
1304da2e3ebdSchin         get_table,
1305da2e3ebdSchin         0,
1306da2e3ebdSchin         0,
1307da2e3ebdSchin         create_table,
1308da2e3ebdSchin         clone_table,
1309da2e3ebdSchin         0,
1310da2e3ebdSchin         next_table,
1311da2e3ebdSchin };
1312da2e3ebdSchin 
nv_parent(Namval_t * np)13137c2fbfb3SApril Chin Namval_t *nv_parent(Namval_t *np)
13147c2fbfb3SApril Chin {
13157c2fbfb3SApril Chin 	struct table *tp = (struct table *)nv_hasdisc(np,&table_disc);
13167c2fbfb3SApril Chin 	if(tp)
13177c2fbfb3SApril Chin 		return(tp->parent);
13187c2fbfb3SApril Chin 	return(0);
13197c2fbfb3SApril Chin }
13207c2fbfb3SApril Chin 
nv_dict(Namval_t * np)1321da2e3ebdSchin Dt_t *nv_dict(Namval_t* np)
1322da2e3ebdSchin {
1323da2e3ebdSchin 	struct table *tp = (struct table*)nv_hasdisc(np,&table_disc);
1324da2e3ebdSchin 	if(tp)
1325da2e3ebdSchin 		return(tp->dict);
1326da2e3ebdSchin 	np = sh.last_table;
1327da2e3ebdSchin 	while(np)
1328da2e3ebdSchin 	{
1329da2e3ebdSchin 		if(tp = (struct table*)nv_hasdisc(np,&table_disc))
1330da2e3ebdSchin 			return(tp->dict);
1331da2e3ebdSchin #if 0
1332da2e3ebdSchin 		np = nv_create(np,(const char*)0, NV_FIRST, (Namfun_t*)0);
13337c2fbfb3SApril Chin #else
13347c2fbfb3SApril Chin 		break;
1335da2e3ebdSchin #endif
1336da2e3ebdSchin 	}
1337da2e3ebdSchin 	return(sh.var_tree);
1338da2e3ebdSchin }
1339da2e3ebdSchin 
1340da2e3ebdSchin /*
1341da2e3ebdSchin  * create a mountable name-value pair tree
1342da2e3ebdSchin  */
nv_mount(Namval_t * np,const char * name,Dt_t * dict)1343da2e3ebdSchin Namval_t *nv_mount(Namval_t *np, const char *name, Dt_t *dict)
1344da2e3ebdSchin {
1345da2e3ebdSchin 	Namval_t *mp, *pp=0;
1346da2e3ebdSchin 	struct table *tp = newof((struct table*)0, struct table,1,0);
1347da2e3ebdSchin 	if(name)
1348da2e3ebdSchin 	{
1349da2e3ebdSchin 		if(nv_istable(np))
1350da2e3ebdSchin 			pp = np;
1351da2e3ebdSchin 		else
1352da2e3ebdSchin 			pp = nv_lastdict();
1353da2e3ebdSchin 	}
1354da2e3ebdSchin 	if(!(tp = newof((struct table*)0, struct table,1,0)))
1355da2e3ebdSchin 		return(0);
1356da2e3ebdSchin 	if(name)
1357da2e3ebdSchin 	{
1358da2e3ebdSchin 		Namfun_t *fp = pp->nvfun;
1359da2e3ebdSchin 		mp = (*fp->disc->createf)(pp,name,0,fp);
1360da2e3ebdSchin 	}
1361da2e3ebdSchin 	else
1362da2e3ebdSchin 		mp = np;
1363da2e3ebdSchin 	if(!nv_isnull(mp))
1364da2e3ebdSchin 		nv_unset(mp);
1365da2e3ebdSchin 	tp->shp = sh_getinterp();
1366da2e3ebdSchin 	tp->dict = dict;
1367da2e3ebdSchin 	tp->parent = pp;
1368da2e3ebdSchin 	tp->fun.disc = &table_disc;
1369da2e3ebdSchin 	nv_onattr(mp,NV_TABLE);
13707c2fbfb3SApril Chin 	nv_disc(mp, &tp->fun, NV_FIRST);
1371da2e3ebdSchin 	return(mp);
1372da2e3ebdSchin }
1373da2e3ebdSchin 
nv_discfun(int which)1374da2e3ebdSchin const Namdisc_t *nv_discfun(int which)
1375da2e3ebdSchin {
1376da2e3ebdSchin 	switch(which)
1377da2e3ebdSchin 	{
1378da2e3ebdSchin 	    case NV_DCADD:
1379da2e3ebdSchin 		return(&Nv_bdisc);
1380da2e3ebdSchin 	    case NV_DCRESTRICT:
1381da2e3ebdSchin 		return(&RESTRICTED_disc);
1382da2e3ebdSchin 	}
1383da2e3ebdSchin 	return(0);
1384da2e3ebdSchin }
1385da2e3ebdSchin 
nv_hasget(Namval_t * np)1386*3e14f97fSRoger A. Faulkner int nv_hasget(Namval_t *np)
1387*3e14f97fSRoger A. Faulkner {
1388*3e14f97fSRoger A. Faulkner 	register Namfun_t	*fp;
1389*3e14f97fSRoger A. Faulkner 	for(fp=np->nvfun; fp; fp=fp->next)
1390*3e14f97fSRoger A. Faulkner 	{
1391*3e14f97fSRoger A. Faulkner 		if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
1392*3e14f97fSRoger A. Faulkner 			continue;
1393*3e14f97fSRoger A. Faulkner 		return(1);
1394*3e14f97fSRoger A. Faulkner 	}
1395*3e14f97fSRoger A. Faulkner 	return(0);
1396*3e14f97fSRoger A. Faulkner }
1397