14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1982-2009 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.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  * AT&T Labs
234887Schin  *
244887Schin  */
254887Schin 
264887Schin #include        "defs.h"
274887Schin #include        "variables.h"
284887Schin #include        "builtins.h"
294887Schin #include        "path.h"
304887Schin 
314887Schin int nv_compare(Dt_t* dict, Void_t *sp, Void_t *dp, Dtdisc_t *disc)
324887Schin {
334887Schin 	if(sp==dp)
344887Schin 		return(0);
354887Schin 	return(strcmp((char*)sp,(char*)dp));
364887Schin }
374887Schin 
384887Schin /*
394887Schin  * call the next getval function in the chain
404887Schin  */
414887Schin char *nv_getv(Namval_t *np, register Namfun_t *nfp)
424887Schin {
434887Schin 	register Namfun_t	*fp;
444887Schin 	register char *cp;
454887Schin 	if((fp = nfp) != NIL(Namfun_t*) && !nv_local)
464887Schin 		fp = nfp = nfp->next;
474887Schin 	nv_local=0;
484887Schin 	for(; fp; fp=fp->next)
494887Schin 	{
504887Schin 		if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
514887Schin 			continue;
524887Schin 		if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
534887Schin 			break;
544887Schin 	}
554887Schin 	if(fp && fp->disc->getval)
564887Schin 		cp = (*fp->disc->getval)(np,fp);
574887Schin 	else if(fp && fp->disc->getnum)
584887Schin 	{
594887Schin 		sfprintf(sh.strbuf,"%.*Lg",12,(*fp->disc->getnum)(np,fp));
604887Schin 		cp = sfstruse(sh.strbuf);
614887Schin 	}
624887Schin 	else
634887Schin 	{
644887Schin 		nv_local=1;
654887Schin 		cp = nv_getval(np);
664887Schin 	}
674887Schin 	return(cp);
684887Schin }
694887Schin 
704887Schin /*
714887Schin  * call the next getnum function in the chain
724887Schin  */
734887Schin Sfdouble_t nv_getn(Namval_t *np, register Namfun_t *nfp)
744887Schin {
754887Schin 	register Namfun_t	*fp;
764887Schin 	register Sfdouble_t	d=0;
774887Schin 	char *str;
784887Schin 	if((fp = nfp) != NIL(Namfun_t*) && !nv_local)
794887Schin 		fp = nfp = nfp->next;
804887Schin 	nv_local=0;
814887Schin 	for(; fp; fp=fp->next)
824887Schin 	{
838462SApril.Chin@Sun.COM 		if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
844887Schin 			continue;
854887Schin 		if(!fp->disc->getnum && nv_isattr(np,NV_INTEGER))
864887Schin 			continue;
874887Schin 		if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
884887Schin 			break;
894887Schin 	}
908462SApril.Chin@Sun.COM 	if(fp && fp->disc && fp->disc->getnum)
914887Schin 		d = (*fp->disc->getnum)(np,fp);
924887Schin 	else if(nv_isattr(np,NV_INTEGER))
934887Schin 	{
944887Schin 		nv_local = 1;
954887Schin 		d =  nv_getnum(np);
964887Schin 	}
974887Schin 	else
984887Schin 	{
998462SApril.Chin@Sun.COM 		if(fp && fp->disc && fp->disc->getval)
1004887Schin 			str = (*fp->disc->getval)(np,fp);
1014887Schin 		else
1024887Schin 			str = nv_getv(np,fp?fp:nfp);
1034887Schin 		if(str && *str)
1044887Schin 		{
1054887Schin 			while(*str=='0')
1064887Schin 				str++;
1074887Schin 			d = sh_arith(str);
1084887Schin 		}
1094887Schin 	}
1104887Schin 	return(d);
1114887Schin }
1124887Schin 
1134887Schin /*
1144887Schin  * call the next assign function in the chain
1154887Schin  */
1164887Schin void nv_putv(Namval_t *np, const char *value, int flags, register Namfun_t *nfp)
1174887Schin {
1184887Schin 	register Namfun_t	*fp, *fpnext;
1194887Schin 	if((fp=nfp) != NIL(Namfun_t*) && !nv_local)
1204887Schin 		fp = nfp = nfp->next;
1214887Schin 	nv_local=0;
1228462SApril.Chin@Sun.COM 	if(flags&NV_NODISC)
1238462SApril.Chin@Sun.COM 		fp = 0;
1244887Schin 	for(; fp; fp=fpnext)
1254887Schin 	{
1264887Schin 		fpnext = fp->next;
1278462SApril.Chin@Sun.COM 		if(!fp->disc || !fp->disc->putval)
1284887Schin 		{
1294887Schin 			if(!value)
1304887Schin 			{
1318462SApril.Chin@Sun.COM 				if(fp->disc || !(fp->nofree&1))
1328462SApril.Chin@Sun.COM 					nv_disc(np,fp,NV_POP);
1338462SApril.Chin@Sun.COM 				if(!(fp->nofree&1))
1344887Schin 					free((void*)fp);
1354887Schin 			}
1364887Schin 			continue;
1374887Schin 		}
1384887Schin 		if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
1394887Schin 			break;
1404887Schin 	}
1414887Schin 	if(fp && fp->disc->putval)
1424887Schin 		(*fp->disc->putval)(np,value, flags, fp);
1434887Schin 	else
1444887Schin 	{
1454887Schin 		nv_local=1;
1464887Schin 		if(value)
1474887Schin 			nv_putval(np, value, flags);
1484887Schin 		else
1498462SApril.Chin@Sun.COM 			_nv_unset(np, flags&(NV_RDONLY|NV_EXPORT));
1504887Schin 	}
1514887Schin }
1524887Schin 
153*10898Sroland.mainz@nrubsig.org #define	LOOKUPS		0
1544887Schin #define	ASSIGN		1
1554887Schin #define	APPEND		2
1564887Schin #define	UNASSIGN	3
157*10898Sroland.mainz@nrubsig.org #define	LOOKUPN		4
1584887Schin #define BLOCKED		((Namval_t*)&nv_local)
1594887Schin 
1604887Schin struct	vardisc
1614887Schin {
1624887Schin 	Namfun_t	fun;
163*10898Sroland.mainz@nrubsig.org 	Namval_t	*disc[5];
1644887Schin };
1654887Schin 
1664887Schin struct blocked
1674887Schin {
1684887Schin 	struct blocked	*next;
1694887Schin 	Namval_t	*np;
1704887Schin 	int		flags;
1714887Schin 	void		*sub;
1724887Schin 	int		isub;
1734887Schin };
1744887Schin 
1754887Schin static struct blocked	*blist;
1764887Schin 
1774887Schin #define isblocked(bp,type)	((bp)->flags & (1<<(type)))
1784887Schin #define block(bp,type)		((bp)->flags |= (1<<(type)))
1794887Schin #define unblock(bp,type)	((bp)->flags &= ~(1<<(type)))
1804887Schin 
1814887Schin /*
1824887Schin  * returns pointer to blocking structure
1834887Schin  */
1844887Schin static struct blocked *block_info(Namval_t *np, struct blocked *pp)
1854887Schin {
1864887Schin 	register struct blocked	*bp;
1874887Schin 	void			*sub=0;
1884887Schin 	int			isub=0;
1894887Schin 	if(nv_isarray(np) && (isub=nv_aindex(np)) < 0)
1904887Schin 		sub = nv_associative(np,(const char*)0,NV_ACURRENT);
1914887Schin 	for(bp=blist ; bp; bp=bp->next)
1924887Schin 	{
1934887Schin 		if(bp->np==np && bp->sub==sub && bp->isub==isub)
1944887Schin 			return(bp);
1954887Schin 	}
1964887Schin 	if(pp)
1974887Schin 	{
1984887Schin 		pp->np = np;
1994887Schin 		pp->flags = 0;
2004887Schin 		pp->isub = isub;
2014887Schin 		pp->sub = sub;
2024887Schin 		pp->next = blist;
2034887Schin 		blist = pp;
2044887Schin 	}
2054887Schin 	return(pp);
2064887Schin }
2074887Schin 
2084887Schin static void block_done(struct blocked *bp)
2094887Schin {
2104887Schin 	blist = bp = bp->next;
2114887Schin 	if(bp && (bp->isub>=0 || bp->sub))
2124887Schin 		nv_putsub(bp->np, bp->sub,(bp->isub<0?0:bp->isub)|ARRAY_SETSUB);
2134887Schin }
2144887Schin 
2154887Schin /*
2164887Schin  * free discipline if no more discipline functions
2174887Schin  */
2184887Schin static void chktfree(register Namval_t *np, register struct vardisc *vp)
2194887Schin {
2204887Schin 	register int n;
2214887Schin 	for(n=0; n< sizeof(vp->disc)/sizeof(*vp->disc); n++)
2224887Schin 	{
2234887Schin 		if(vp->disc[n])
2244887Schin 			break;
2254887Schin 	}
2264887Schin 	if(n>=sizeof(vp->disc)/sizeof(*vp->disc))
2274887Schin 	{
2284887Schin 		/* no disc left so pop */
2294887Schin 		Namfun_t *fp;
2308462SApril.Chin@Sun.COM 		if((fp=nv_stack(np, NIL(Namfun_t*))) && !(fp->nofree&1))
2314887Schin 			free((void*)fp);
2324887Schin 	}
2334887Schin }
2344887Schin 
2354887Schin /*
2364887Schin  * This function performs an assignment disc on the given node <np>
2374887Schin  */
2384887Schin static void	assign(Namval_t *np,const char* val,int flags,Namfun_t *handle)
2394887Schin {
2404887Schin 	int		type = (flags&NV_APPEND)?APPEND:ASSIGN;
2414887Schin 	register	struct vardisc *vp = (struct vardisc*)handle;
2424887Schin 	register	Namval_t *nq =  vp->disc[type];
2434887Schin 	struct blocked	block, *bp = block_info(np, &block);
2444887Schin 	Namval_t	node;
2458462SApril.Chin@Sun.COM 	union Value	*up = np->nvalue.up;
2468462SApril.Chin@Sun.COM #if SHOPT_TYPEDEF
2478462SApril.Chin@Sun.COM 	Namval_t	*tp, *nr;
2488462SApril.Chin@Sun.COM 	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))
2498462SApril.Chin@Sun.COM 	{
2508462SApril.Chin@Sun.COM 		char *sub = nv_getsub(np);
2518462SApril.Chin@Sun.COM 		nv_unset(np);
2528462SApril.Chin@Sun.COM 		if(sub)
2538462SApril.Chin@Sun.COM 		{
2548462SApril.Chin@Sun.COM 			nv_putsub(np, sub, ARRAY_ADD);
2558462SApril.Chin@Sun.COM 			nv_putval(np,nv_getval(nr), 0);
2568462SApril.Chin@Sun.COM 		}
2578462SApril.Chin@Sun.COM 		else
2588462SApril.Chin@Sun.COM 			nv_clone(nr,np,0);
2598462SApril.Chin@Sun.COM 		goto done;
2608462SApril.Chin@Sun.COM 	}
2618462SApril.Chin@Sun.COM #endif /* SHOPT_TYPEDEF */
2624887Schin 	if(val || isblocked(bp,type))
2634887Schin 	{
2644887Schin 		if(!nq || isblocked(bp,type))
2654887Schin 		{
2664887Schin 			nv_putv(np,val,flags,handle);
2674887Schin 			goto done;
2684887Schin 		}
2694887Schin 		node = *SH_VALNOD;
2704887Schin 		if(!nv_isnull(SH_VALNOD))
2714887Schin 		{
2724887Schin 			nv_onattr(SH_VALNOD,NV_NOFREE);
2734887Schin 			nv_unset(SH_VALNOD);
2744887Schin 		}
2754887Schin 		if(flags&NV_INTEGER)
2768462SApril.Chin@Sun.COM 			nv_onattr(SH_VALNOD,(flags&(NV_LONG|NV_DOUBLE|NV_EXPNOTE|NV_HEXFLOAT|NV_SHORT)));
2774887Schin 		nv_putval(SH_VALNOD, val, (flags&NV_INTEGER)?flags:NV_NOFREE);
2784887Schin 	}
2794887Schin 	else
2804887Schin 		nq =  vp->disc[type=UNASSIGN];
2814887Schin 	if(nq && !isblocked(bp,type))
2824887Schin 	{
2834887Schin 		int bflag;
2844887Schin 		block(bp,type);
285*10898Sroland.mainz@nrubsig.org 		if (type==APPEND && (bflag= !isblocked(bp,LOOKUPS)))
286*10898Sroland.mainz@nrubsig.org 			block(bp,LOOKUPS);
2874887Schin 		sh_fun(nq,np,(char**)0);
2884887Schin 		unblock(bp,type);
2894887Schin 		if(bflag)
290*10898Sroland.mainz@nrubsig.org 			unblock(bp,LOOKUPS);
2914887Schin 		if(!vp->disc[type])
2924887Schin 			chktfree(np,vp);
2934887Schin 	}
2948462SApril.Chin@Sun.COM 	if(nv_isarray(np))
2958462SApril.Chin@Sun.COM 		np->nvalue.up = up;
2964887Schin 	if(val)
2974887Schin 	{
2984887Schin 		register char *cp;
2994887Schin 		Sfdouble_t d;
3004887Schin 		if(nv_isnull(SH_VALNOD))
3014887Schin 			cp=0;
3024887Schin 		else if(flags&NV_INTEGER)
3034887Schin 		{
3044887Schin 			d = nv_getnum(SH_VALNOD);
3054887Schin 			cp = (char*)(&d);
3064887Schin 			flags |= (NV_LONG|NV_DOUBLE);
3074887Schin 			flags &= ~NV_SHORT;
3084887Schin 		}
3094887Schin 		else
3104887Schin 			cp = nv_getval(SH_VALNOD);
3114887Schin 		if(cp)
3124887Schin 			nv_putv(np,cp,flags|NV_RDONLY,handle);
3134887Schin 		nv_unset(SH_VALNOD);
3144887Schin 		/* restore everything but the nvlink field */
3154887Schin 		memcpy(&SH_VALNOD->nvname,  &node.nvname, sizeof(node)-sizeof(node.nvlink));
3164887Schin 	}
3174887Schin 	else if(sh_isstate(SH_INIT))
3184887Schin 	{
3194887Schin 		/* don't free functions during reinitialization */
3204887Schin 		nv_putv(np,val,flags,handle);
3214887Schin 	}
3224887Schin 	else if(!nq || !isblocked(bp,type))
3234887Schin 	{
3244887Schin 		Dt_t *root = sh_subfuntree(1);
3254887Schin 		int n;
3264887Schin 		Namarr_t *ap;
3274887Schin 		block(bp,type);
3284887Schin 		nv_putv(np, val, flags, handle);
3298462SApril.Chin@Sun.COM 		if(sh.subshell)
3308462SApril.Chin@Sun.COM 			goto done;
3314887Schin 		if(nv_isarray(np) && (ap=nv_arrayptr(np)) && ap->nelem>0)
3324887Schin 			goto done;
3334887Schin 		for(n=0; n < sizeof(vp->disc)/sizeof(*vp->disc); n++)
3344887Schin 		{
3354887Schin 			if((nq=vp->disc[n]) && !nv_isattr(nq,NV_NOFREE))
3364887Schin 			{
3374887Schin 				nv_unset(nq);
3384887Schin 				dtdelete(root,nq);
3394887Schin 			}
3404887Schin 		}
3414887Schin 		unblock(bp,type);
3424887Schin 		nv_disc(np,handle,NV_POP);
3438462SApril.Chin@Sun.COM 		if(!(handle->nofree&1))
3444887Schin 			free(handle);
3454887Schin 	}
3464887Schin done:
3474887Schin 	if(bp== &block)
3484887Schin 		block_done(bp);
3494887Schin }
3504887Schin 
3514887Schin /*
3524887Schin  * This function executes a lookup disc and then performs
3534887Schin  * the lookup on the given node <np>
3544887Schin  */
355*10898Sroland.mainz@nrubsig.org static char*	lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
3564887Schin {
3574887Schin 	register struct vardisc	*vp = (struct vardisc*)handle;
3584887Schin 	struct blocked		block, *bp = block_info(np, &block);
359*10898Sroland.mainz@nrubsig.org 	register Namval_t	*nq = vp->disc[type];
3604887Schin 	register char		*cp=0;
3614887Schin 	Namval_t		node;
3628462SApril.Chin@Sun.COM 	union Value		*up = np->nvalue.up;
363*10898Sroland.mainz@nrubsig.org 	if(nq && !isblocked(bp,type))
3644887Schin 	{
3654887Schin 		node = *SH_VALNOD;
3664887Schin 		if(!nv_isnull(SH_VALNOD))
3674887Schin 		{
3684887Schin 			nv_onattr(SH_VALNOD,NV_NOFREE);
3694887Schin 			nv_unset(SH_VALNOD);
3704887Schin 		}
371*10898Sroland.mainz@nrubsig.org 		if(type==LOOKUPN)
372*10898Sroland.mainz@nrubsig.org 		{
373*10898Sroland.mainz@nrubsig.org 			nv_onattr(SH_VALNOD,NV_DOUBLE|NV_INTEGER);
374*10898Sroland.mainz@nrubsig.org 			nv_setsize(SH_VALNOD,10);
375*10898Sroland.mainz@nrubsig.org 		}
376*10898Sroland.mainz@nrubsig.org 		block(bp,type);
3774887Schin 		sh_fun(nq,np,(char**)0);
378*10898Sroland.mainz@nrubsig.org 		unblock(bp,type);
379*10898Sroland.mainz@nrubsig.org 		if(!vp->disc[type])
3804887Schin 			chktfree(np,vp);
381*10898Sroland.mainz@nrubsig.org 		if(type==LOOKUPN)
3828462SApril.Chin@Sun.COM 		{
383*10898Sroland.mainz@nrubsig.org 			cp = (char*)(SH_VALNOD->nvalue.cp);
384*10898Sroland.mainz@nrubsig.org 			*dp = nv_getnum(SH_VALNOD);
385*10898Sroland.mainz@nrubsig.org 		}
386*10898Sroland.mainz@nrubsig.org 		else if(cp = nv_getval(SH_VALNOD))
3878462SApril.Chin@Sun.COM 			cp = stkcopy(stkstd,cp);
388*10898Sroland.mainz@nrubsig.org 		_nv_unset(SH_VALNOD,NV_RDONLY);
3894887Schin 		if(!nv_isnull(&node))
3904887Schin 		{
3914887Schin 			/* restore everything but the nvlink field */
3924887Schin 			memcpy(&SH_VALNOD->nvname,  &node.nvname, sizeof(node)-sizeof(node.nvlink));
3934887Schin 		}
3944887Schin 	}
3958462SApril.Chin@Sun.COM 	if(nv_isarray(np))
3968462SApril.Chin@Sun.COM 		np->nvalue.up = up;
3974887Schin 	if(!cp)
398*10898Sroland.mainz@nrubsig.org 	{
399*10898Sroland.mainz@nrubsig.org 		if(type==LOOKUPS)
400*10898Sroland.mainz@nrubsig.org 			cp = nv_getv(np,handle);
401*10898Sroland.mainz@nrubsig.org 		else
402*10898Sroland.mainz@nrubsig.org 			*dp = nv_getn(np,handle);
403*10898Sroland.mainz@nrubsig.org 	}
4044887Schin 	if(bp== &block)
4054887Schin 		block_done(bp);
4064887Schin 	return(cp);
4074887Schin }
4084887Schin 
409*10898Sroland.mainz@nrubsig.org static char*	lookups(Namval_t *np, Namfun_t *handle)
4104887Schin {
411*10898Sroland.mainz@nrubsig.org 	return(lookup(np,LOOKUPS,(Sfdouble_t*)0,handle));
412*10898Sroland.mainz@nrubsig.org }
413*10898Sroland.mainz@nrubsig.org 
414*10898Sroland.mainz@nrubsig.org static Sfdouble_t lookupn(Namval_t *np, Namfun_t *handle)
415*10898Sroland.mainz@nrubsig.org {
416*10898Sroland.mainz@nrubsig.org 	Sfdouble_t	d;
417*10898Sroland.mainz@nrubsig.org 	lookup(np,LOOKUPN, &d ,handle);
418*10898Sroland.mainz@nrubsig.org 	return(d);
419*10898Sroland.mainz@nrubsig.org }
420*10898Sroland.mainz@nrubsig.org 
4214887Schin 
4224887Schin /*
4234887Schin  * Set disc on given <event> to <action>
4244887Schin  * If action==np, the current disc is returned
4254887Schin  * A null return value indicates that no <event> is known for <np>
4264887Schin  * If <event> is NULL, then return the event name after <action>
4274887Schin  * If <event> is NULL, and <action> is NULL, return the first event
4284887Schin  */
4294887Schin char *nv_setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp)
4304887Schin {
4314887Schin 	register struct vardisc *vp = (struct vardisc*)np->nvfun;
4324887Schin 	register int type;
4334887Schin 	char *empty = "";
4348462SApril.Chin@Sun.COM 	if(vp && !vp->fun.disc)
4358462SApril.Chin@Sun.COM 		vp = 0;
4364887Schin 	if(np == (Namval_t*)fp)
4374887Schin 	{
4384887Schin 		register const char *name;
4394887Schin 		register int getname=0;
4404887Schin 		/* top level call, check for get/set */
4414887Schin 		if(!event)
4424887Schin 		{
4434887Schin 			if(!action)
4448462SApril.Chin@Sun.COM 				return((char*)nv_discnames[0]);
4454887Schin 			getname=1;
4464887Schin 			event = (char*)action;
4474887Schin 		}
4488462SApril.Chin@Sun.COM 		for(type=0; name=nv_discnames[type]; type++)
4494887Schin 		{
4504887Schin 			if(strcmp(event,name)==0)
4514887Schin 				break;
4524887Schin 		}
4534887Schin 		if(getname)
4544887Schin 		{
4554887Schin 			event = 0;
4568462SApril.Chin@Sun.COM 			if(name && !(name = nv_discnames[++type]))
4574887Schin 				action = 0;
4584887Schin 		}
4594887Schin 		if(!name)
4604887Schin 		{
4618462SApril.Chin@Sun.COM 			for(fp=(Namfun_t*)vp; fp; fp=fp->next)
4628462SApril.Chin@Sun.COM 			{
4638462SApril.Chin@Sun.COM 				if(fp->disc && fp->disc->setdisc)
4648462SApril.Chin@Sun.COM 					return((*fp->disc->setdisc)(np,event,action,fp));
4658462SApril.Chin@Sun.COM 			}
4664887Schin 		}
4674887Schin 		else if(getname)
4684887Schin 			return((char*)name);
4694887Schin 	}
4704887Schin 	if(!fp)
4714887Schin 		return(NIL(char*));
4724887Schin 	if(np != (Namval_t*)fp)
4734887Schin 	{
4744887Schin 		/* not the top level */
4754887Schin 		while(fp = fp->next)
4764887Schin 		{
4778462SApril.Chin@Sun.COM 			if(fp->disc && fp->disc->setdisc)
4784887Schin 				return((*fp->disc->setdisc)(np,event,action,fp));
4794887Schin 		}
4804887Schin 		return(NIL(char*));
4814887Schin 	}
4824887Schin 	/* Handle GET/SET/APPEND/UNSET disc */
4834887Schin 	if(vp && vp->fun.disc->putval!=assign)
4844887Schin 		vp = 0;
4854887Schin 	if(!vp)
4864887Schin 	{
487*10898Sroland.mainz@nrubsig.org 		Namdisc_t	*dp;
4884887Schin 		if(action==np)
4894887Schin 			return((char*)action);
490*10898Sroland.mainz@nrubsig.org 		if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,sizeof(Namdisc_t))))
4914887Schin 			return(0);
492*10898Sroland.mainz@nrubsig.org 		dp = (Namdisc_t*)(vp+1);
493*10898Sroland.mainz@nrubsig.org 		vp->fun.disc = dp;
494*10898Sroland.mainz@nrubsig.org 		memset(dp,0,sizeof(*dp));
495*10898Sroland.mainz@nrubsig.org 		dp->dsize = sizeof(struct vardisc);
496*10898Sroland.mainz@nrubsig.org 		dp->putval = assign;
4974887Schin 		nv_stack(np, (Namfun_t*)vp);
4984887Schin 	}
4994887Schin 	if(action==np)
5004887Schin 	{
5014887Schin 		action = vp->disc[type];
5024887Schin 		empty = 0;
5034887Schin 	}
5044887Schin 	else if(action)
505*10898Sroland.mainz@nrubsig.org 	{
506*10898Sroland.mainz@nrubsig.org 		Namdisc_t *dp = (Namdisc_t*)vp->fun.disc;
507*10898Sroland.mainz@nrubsig.org 		if(type==LOOKUPS)
508*10898Sroland.mainz@nrubsig.org 			dp->getval = lookups;
509*10898Sroland.mainz@nrubsig.org 		else if(type==LOOKUPN)
510*10898Sroland.mainz@nrubsig.org 			dp->getnum = lookupn;
5114887Schin 		vp->disc[type] = action;
512*10898Sroland.mainz@nrubsig.org 	}
5134887Schin 	else
5144887Schin 	{
5154887Schin 		struct blocked *bp;
5164887Schin 		action = vp->disc[type];
5174887Schin 		vp->disc[type] = 0;
5184887Schin 		if(!(bp=block_info(np,(struct blocked*)0)) || !isblocked(bp,UNASSIGN))
5194887Schin 			chktfree(np,vp);
5204887Schin 	}
5214887Schin 	return(action?(char*)action:empty);
5224887Schin }
5234887Schin 
5244887Schin /*
5254887Schin  * Set disc on given <event> to <action>
5264887Schin  * If action==np, the current disc is returned
5274887Schin  * A null return value indicates that no <event> is known for <np>
5284887Schin  * If <event> is NULL, then return the event name after <action>
5294887Schin  * If <event> is NULL, and <action> is NULL, return the first event
5304887Schin  */
5314887Schin static char *setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp)
5324887Schin {
5334887Schin 	register Nambfun_t *vp = (Nambfun_t*)fp;
5344887Schin 	register int type,getname=0;
5354887Schin 	register const char *name;
5364887Schin 	const char **discnames = vp->bnames;
5374887Schin 	/* top level call, check for discipline match */
5384887Schin 	if(!event)
5394887Schin 	{
5404887Schin 		if(!action)
5414887Schin 			return((char*)discnames[0]);
5424887Schin 		getname=1;
5434887Schin 		event = (char*)action;
5444887Schin 	}
5454887Schin 	for(type=0; name=discnames[type]; type++)
5464887Schin 	{
5474887Schin 		if(strcmp(event,name)==0)
5484887Schin 			break;
5494887Schin 	}
5504887Schin 	if(getname)
5514887Schin 	{
5524887Schin 		event = 0;
5534887Schin 		if(name && !(name = discnames[++type]))
5544887Schin 			action = 0;
5554887Schin 	}
5564887Schin 	if(!name)
5574887Schin 		return(nv_setdisc(np,event,action,fp));
5584887Schin 	else if(getname)
5594887Schin 		return((char*)name);
5604887Schin 	/* Handle the disciplines */
5614887Schin 	if(action==np)
5624887Schin 		action = vp->bltins[type];
5634887Schin 	else if(action)
5644887Schin 		vp->bltins[type] = action;
5654887Schin 	else
5664887Schin 	{
5674887Schin 		action = vp->bltins[type];
5684887Schin 		vp->bltins[type] = 0;
5694887Schin 	}
5704887Schin 	return(action?(char*)action:"");
5714887Schin }
5724887Schin 
5734887Schin static void putdisc(Namval_t* np, const char* val, int flag, Namfun_t* fp)
5744887Schin {
5754887Schin 	nv_putv(np,val,flag,fp);
5768462SApril.Chin@Sun.COM 	if(!val && !(flag&NV_NOFREE))
5774887Schin 	{
5784887Schin 		register Nambfun_t *vp = (Nambfun_t*)fp;
5794887Schin 		register int i;
5804887Schin 		for(i=0; vp->bnames[i]; i++)
5814887Schin 		{
5824887Schin 			register Namval_t *mp;
5834887Schin 			if((mp=vp->bltins[i]) && !nv_isattr(mp,NV_NOFREE))
5844887Schin 			{
5854887Schin 				if(is_abuiltin(mp))
5864887Schin 				{
5874887Schin 					if(mp->nvfun && !nv_isattr(mp,NV_NOFREE))
5884887Schin 						free((void*)mp->nvfun);
5894887Schin 					dtdelete(sh.bltin_tree,mp);
5904887Schin 					free((void*)mp);
5914887Schin 				}
5924887Schin 			}
5934887Schin 		}
5944887Schin 		nv_disc(np,fp,NV_POP);
5958462SApril.Chin@Sun.COM 		if(!(fp->nofree&1))
5964887Schin 			free((void*)fp);
5974887Schin 
5984887Schin 	}
5994887Schin }
6004887Schin 
6014887Schin static const Namdisc_t Nv_bdisc	= {   0, putdisc, 0, 0, setdisc };
6024887Schin 
6038462SApril.Chin@Sun.COM Namfun_t *nv_clone_disc(register Namfun_t *fp, int flags)
6044887Schin {
6054887Schin 	register Namfun_t	*nfp;
6064887Schin 	register int		size;
607*10898Sroland.mainz@nrubsig.org 	if(!fp->disc && !fp->next && (fp->nofree&1))
608*10898Sroland.mainz@nrubsig.org 		return(fp);
6094887Schin 	if(!(size=fp->dsize) && (!fp->disc || !(size=fp->disc->dsize)))
6104887Schin 		size = sizeof(Namfun_t);
6114887Schin 	if(!(nfp=newof(NIL(Namfun_t*),Namfun_t,1,size-sizeof(Namfun_t))))
6124887Schin 		return(0);
6134887Schin 	memcpy(nfp,fp,size);
614*10898Sroland.mainz@nrubsig.org 	nfp->nofree &= ~1;
6158462SApril.Chin@Sun.COM 	nfp->nofree |= (flags&NV_RDONLY)?1:0;
6164887Schin 	return(nfp);
6174887Schin }
6184887Schin 
6194887Schin int nv_adddisc(Namval_t *np, const char **names, Namval_t **funs)
6204887Schin {
6214887Schin 	register Nambfun_t *vp;
6224887Schin 	register int n=0;
6234887Schin 	register const char **av=names;
6244887Schin 	if(av)
6254887Schin 	{
6264887Schin 		while(*av++)
6274887Schin 			n++;
6284887Schin 	}
6294887Schin 	if(!(vp = newof(NIL(Nambfun_t*),Nambfun_t,1,n*sizeof(Namval_t*))))
6304887Schin 		return(0);
6314887Schin 	vp->fun.dsize = sizeof(Nambfun_t)+n*sizeof(Namval_t*);
6328462SApril.Chin@Sun.COM 	vp->fun.nofree |= 2;
6338462SApril.Chin@Sun.COM 	vp->num = n;
6344887Schin 	if(funs)
6354887Schin 		memcpy((void*)vp->bltins, (void*)funs,n*sizeof(Namval_t*));
6364887Schin 	else while(n>=0)
6374887Schin 		vp->bltins[n--] = 0;
6384887Schin 	vp->fun.disc = &Nv_bdisc;
6394887Schin 	vp->bnames = names;
6404887Schin 	nv_stack(np,&vp->fun);
6414887Schin 	return(1);
6424887Schin }
6434887Schin 
6444887Schin /*
6458462SApril.Chin@Sun.COM  * push, pop, clne, or reorder disciplines onto node <np>
6464887Schin  * mode can be one of
6474887Schin  *    NV_FIRST:  Move or push <fp> to top of the stack or delete top
6484887Schin  *    NV_LAST:	 Move or push <fp> to bottom of stack or delete last
6494887Schin  *    NV_POP:	 Delete <fp> from top of the stack
6504887Schin  *    NV_CLONE:  Replace fp with a copy created my malloc() and return it
6514887Schin  */
6524887Schin Namfun_t *nv_disc(register Namval_t *np, register Namfun_t* fp, int mode)
6534887Schin {
6544887Schin 	Namfun_t *lp, **lpp;
6554887Schin 	if(nv_isref(np))
6564887Schin 		return(0);
6574887Schin 	if(mode==NV_CLONE && !fp)
6584887Schin 		return(0);
6594887Schin 	if(fp)
6604887Schin 	{
6618462SApril.Chin@Sun.COM 		fp->subshell = sh.subshell;
6624887Schin 		if((lp=np->nvfun)==fp)
6634887Schin 		{
6644887Schin 			if(mode==NV_CLONE)
6654887Schin 			{
6668462SApril.Chin@Sun.COM 				lp = nv_clone_disc(fp,0);
6674887Schin 				return(np->nvfun=lp);
6684887Schin 			}
6694887Schin 			if(mode==NV_FIRST || mode==0)
6704887Schin 				return(fp);
6714887Schin 			np->nvfun = lp->next;
6724887Schin 			if(mode==NV_POP)
6734887Schin 				return(fp);
6748462SApril.Chin@Sun.COM 			if(mode==NV_LAST && (lp->next==0 || lp->next->disc==0))
6758462SApril.Chin@Sun.COM 				return(fp);
6764887Schin 		}
6774887Schin 		/* see if <fp> is on the list already */
6784887Schin 		lpp = &np->nvfun;
6794887Schin 		if(lp)
6804887Schin 		{
6818462SApril.Chin@Sun.COM 			while(lp->next && lp->next->disc)
6824887Schin 			{
6834887Schin 				if(lp->next==fp)
6844887Schin 				{
6858462SApril.Chin@Sun.COM 					if(mode==NV_LAST && fp->next==0)
6868462SApril.Chin@Sun.COM 						return(fp);
6874887Schin 					if(mode==NV_CLONE)
6884887Schin 					{
6898462SApril.Chin@Sun.COM 						fp = nv_clone_disc(fp,0);
6904887Schin 						lp->next = fp;
6914887Schin 						return(fp);
6924887Schin 					}
6934887Schin 					lp->next = fp->next;
6944887Schin 					if(mode==NV_POP)
6954887Schin 						return(fp);
6964887Schin 					if(mode!=NV_LAST)
6974887Schin 						break;
6984887Schin 				}
6994887Schin 				lp = lp->next;
7004887Schin 			}
7014887Schin 			if(mode==NV_LAST)
7024887Schin 				lpp = &lp->next;
7034887Schin 		}
7044887Schin 		if(mode==NV_POP)
7054887Schin 			return(0);
7064887Schin 		/* push */
7074887Schin 		nv_offattr(np,NV_NODISC);
7084887Schin 		if(mode==NV_LAST)
7094887Schin 			fp->next = 0;
7104887Schin 		else
7114887Schin 		{
7128462SApril.Chin@Sun.COM 			if((fp->nofree&1) && *lpp)
7138462SApril.Chin@Sun.COM 				fp = nv_clone_disc(fp,0);
7144887Schin 			fp->next = *lpp;
7154887Schin 		}
7164887Schin 		*lpp = fp;
7174887Schin 	}
7184887Schin 	else
7194887Schin 	{
7204887Schin 		if(mode==NV_FIRST)
7214887Schin 			return(np->nvfun);
7224887Schin 		else if(mode==NV_LAST)
7234887Schin 			for(lp=np->nvfun; lp; fp=lp,lp=lp->next);
7244887Schin 		else if(fp = np->nvfun)
7254887Schin 			np->nvfun = fp->next;
7264887Schin 	}
7274887Schin 	return(fp);
7284887Schin }
7294887Schin 
7304887Schin /*
7314887Schin  * returns discipline pointer if discipline with specified functions
7324887Schin  * is on the discipline stack
7334887Schin  */
7344887Schin Namfun_t *nv_hasdisc(Namval_t *np, const Namdisc_t *dp)
7354887Schin {
7364887Schin 	register Namfun_t *fp;
7374887Schin 	for(fp=np->nvfun; fp; fp = fp->next)
7384887Schin 	{
7394887Schin 		if(fp->disc== dp)
7404887Schin 			return(fp);
7414887Schin 	}
7424887Schin 	return(0);
7434887Schin }
7444887Schin 
7454887Schin struct notify
7464887Schin {
7474887Schin 	Namfun_t	hdr;
7484887Schin 	char		**ptr;
7494887Schin };
7504887Schin 
7514887Schin static void put_notify(Namval_t* np,const char *val,int flags,Namfun_t *fp)
7524887Schin {
7534887Schin 	struct notify *pp = (struct notify*)fp;
7544887Schin 	nv_putv(np,val,flags,fp);
7554887Schin 	nv_stack(np,fp);
7564887Schin 	nv_stack(np,(Namfun_t*)0);
7574887Schin 	*pp->ptr = 0;
7588462SApril.Chin@Sun.COM 	if(!(fp->nofree&1))
7594887Schin 		free((void*)fp);
7604887Schin }
7614887Schin 
7624887Schin static const Namdisc_t notify_disc  = {  0, put_notify };
7634887Schin 
7644887Schin int nv_unsetnotify(Namval_t *np, char **addr)
7654887Schin {
7664887Schin 	register Namfun_t *fp;
7674887Schin 	for(fp=np->nvfun;fp;fp=fp->next)
7684887Schin 	{
7694887Schin 		if(fp->disc->putval==put_notify && ((struct notify*)fp)->ptr==addr)
7704887Schin 		{
7714887Schin 			nv_stack(np,fp);
7724887Schin 			nv_stack(np,(Namfun_t*)0);
7738462SApril.Chin@Sun.COM 			if(!(fp->nofree&1))
7744887Schin 				free((void*)fp);
7754887Schin 			return(1);
7764887Schin 		}
7774887Schin 	}
7784887Schin 	return(0);
7794887Schin }
7804887Schin 
7814887Schin int nv_setnotify(Namval_t *np, char **addr)
7824887Schin {
7834887Schin 	struct notify *pp = newof(0,struct notify, 1,0);
7844887Schin 	if(!pp)
7854887Schin 		return(0);
7864887Schin 	pp->ptr = addr;
7874887Schin 	pp->hdr.disc = &notify_disc;
7884887Schin 	nv_stack(np,&pp->hdr);
7894887Schin 	return(1);
7904887Schin }
7914887Schin 
7924887Schin static void *newnode(const char *name)
7934887Schin {
7944887Schin 	register int s;
7954887Schin 	register Namval_t *np = newof(0,Namval_t,1,s=strlen(name)+1);
7964887Schin 	if(np)
7974887Schin 	{
7984887Schin 		np->nvname = (char*)np+sizeof(Namval_t);
7994887Schin 		memcpy(np->nvname,name,s);
8004887Schin 	}
8014887Schin 	return((void*)np);
8024887Schin }
8034887Schin 
8044887Schin #if SHOPT_NAMESPACE
8054887Schin /*
8064887Schin  * clone a numeric value
8074887Schin  */
8084887Schin static void *num_clone(register Namval_t *np, void *val)
8094887Schin {
8104887Schin 	register int size;
8114887Schin 	void *nval;
8124887Schin 	if(!val)
8134887Schin 		return(0);
8148462SApril.Chin@Sun.COM 	if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
8154887Schin 	{
8164887Schin 		if(nv_isattr(np,NV_LONG))
8174887Schin 			size = sizeof(Sfdouble_t);
8184887Schin 		else if(nv_isattr(np,NV_SHORT))
8194887Schin 			size = sizeof(float);
8204887Schin 		else
8214887Schin 			size = sizeof(double);
8224887Schin 	}
8234887Schin 	else
8244887Schin 	{
8254887Schin 		if(nv_isattr(np,NV_LONG))
8264887Schin 			size = sizeof(Sflong_t);
8274887Schin 		else if(nv_isattr(np,NV_SHORT))
8288462SApril.Chin@Sun.COM 		{
8298462SApril.Chin@Sun.COM 			if(nv_isattr(np,NV_INT16P)==NV_INT16P)
8308462SApril.Chin@Sun.COM 				size = sizeof(short);
8318462SApril.Chin@Sun.COM 			else
8328462SApril.Chin@Sun.COM 				return((void*)np->nvalue.ip);
8338462SApril.Chin@Sun.COM 		}
8344887Schin 		else
8354887Schin 			size = sizeof(int32_t);
8364887Schin 	}
8374887Schin 	if(!(nval = malloc(size)))
8384887Schin 		return(0);
8394887Schin 	memcpy(nval,val,size);
8404887Schin 	return(nval);
8414887Schin }
8424887Schin 
8438462SApril.Chin@Sun.COM void clone_all_disc( Namval_t *np, Namval_t *mp, int flags)
8444887Schin {
8458462SApril.Chin@Sun.COM 	register Namfun_t *fp, **mfp = &mp->nvfun, *nfp, *fpnext;
8468462SApril.Chin@Sun.COM 	for(fp=np->nvfun; fp;fp=fpnext)
8474887Schin 	{
8488462SApril.Chin@Sun.COM 		fpnext = fp->next;
8498462SApril.Chin@Sun.COM 		if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
8508462SApril.Chin@Sun.COM 			return;
8518462SApril.Chin@Sun.COM 		if((fp->nofree&2) && (flags&NV_NODISC))
8524887Schin 			nfp = 0;
8534887Schin 		if(fp->disc && fp->disc->clonef)
8544887Schin 			nfp = (*fp->disc->clonef)(np,mp,flags,fp);
8558462SApril.Chin@Sun.COM 		else	if(flags&NV_MOVE)
8568462SApril.Chin@Sun.COM 			nfp = fp;
8574887Schin 		else
8588462SApril.Chin@Sun.COM 			nfp = nv_clone_disc(fp,flags);
8594887Schin 		if(!nfp)
8604887Schin 			continue;
8614887Schin 		nfp->next = 0;
8624887Schin 		*mfp = nfp;
8634887Schin 		mfp = &nfp->next;
8644887Schin 	}
8654887Schin }
8664887Schin 
8674887Schin /*
8684887Schin  * clone <mp> from <np> flags can be one of the following
8694887Schin  * NV_APPEND - append <np> onto <mp>
8704887Schin  * NV_MOVE - move <np> to <mp>
8714887Schin  * NV_NOFREE - mark the new node as nofree
8724887Schin  * NV_NODISC - discplines with funs non-zero will not be copied
8738462SApril.Chin@Sun.COM  * NV_COMVAR - cloning a compound variable
8744887Schin  */
8754887Schin int nv_clone(Namval_t *np, Namval_t *mp, int flags)
8764887Schin {
8778462SApril.Chin@Sun.COM 	Namfun_t	*fp, *fpnext;
8788462SApril.Chin@Sun.COM 	const char	*val = mp->nvalue.cp;
8798462SApril.Chin@Sun.COM 	unsigned short	flag = mp->nvflag;
8808462SApril.Chin@Sun.COM 	unsigned short	size = mp->nvsize;
8818462SApril.Chin@Sun.COM 	for(fp=mp->nvfun; fp; fp=fpnext)
8828462SApril.Chin@Sun.COM 	{
8838462SApril.Chin@Sun.COM 		fpnext = fp->next;
8848462SApril.Chin@Sun.COM 		if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
8858462SApril.Chin@Sun.COM 			break;
8868462SApril.Chin@Sun.COM 		if(!(fp->nofree&1))
8878462SApril.Chin@Sun.COM 			free((void*)fp);
8888462SApril.Chin@Sun.COM 	}
8898462SApril.Chin@Sun.COM 	mp->nvfun = fp;
8904887Schin 	if(fp=np->nvfun)
8914887Schin 	{
8928462SApril.Chin@Sun.COM 		if(nv_isattr(mp,NV_EXPORT|NV_MINIMAL) == (NV_EXPORT|NV_MINIMAL))
8934887Schin 		{
8948462SApril.Chin@Sun.COM 			mp->nvenv = 0;
8958462SApril.Chin@Sun.COM 			nv_offattr(mp,NV_MINIMAL);
8964887Schin 		}
8978462SApril.Chin@Sun.COM 		if(!(flags&NV_COMVAR) && !nv_isattr(np,NV_MINIMAL) && np->nvenv && !(nv_isattr(mp,NV_MINIMAL)))
8988462SApril.Chin@Sun.COM 			mp->nvenv = np->nvenv;
8998462SApril.Chin@Sun.COM 		mp->nvflag &= NV_MINIMAL;
9008462SApril.Chin@Sun.COM 	        mp->nvflag |= np->nvflag&~(NV_ARRAY|NV_MINIMAL|NV_NOFREE);
9018462SApril.Chin@Sun.COM 		flag = mp->nvflag;
9024887Schin 		clone_all_disc(np, mp, flags);
9034887Schin 	}
9044887Schin 	if(flags&NV_APPEND)
9054887Schin 		return(1);
9068462SApril.Chin@Sun.COM 	if(mp->nvsize == size)
9078462SApril.Chin@Sun.COM 	        nv_setsize(mp,nv_size(np));
9088462SApril.Chin@Sun.COM 	if(mp->nvflag == flag)
9098462SApril.Chin@Sun.COM 	        mp->nvflag = (np->nvflag&~(NV_MINIMAL))|(mp->nvflag&NV_MINIMAL);
9108462SApril.Chin@Sun.COM 	if(mp->nvalue.cp==val && !nv_isattr(np,NV_INTEGER))
9118462SApril.Chin@Sun.COM 	{
9128462SApril.Chin@Sun.COM 		if(np->nvalue.cp && np->nvalue.cp!=Empty && (flags&NV_COMVAR) && !(flags&NV_MOVE))
9138462SApril.Chin@Sun.COM 		{
9148462SApril.Chin@Sun.COM 			if(size)
9158462SApril.Chin@Sun.COM 				mp->nvalue.cp = (char*)memdup(np->nvalue.cp,size);
9168462SApril.Chin@Sun.COM 			else
9178462SApril.Chin@Sun.COM 			        mp->nvalue.cp = strdup(np->nvalue.cp);
9188462SApril.Chin@Sun.COM 			nv_offattr(mp,NV_NOFREE);
9198462SApril.Chin@Sun.COM 		}
9208462SApril.Chin@Sun.COM 		else if(!(mp->nvalue.cp = np->nvalue.cp))
9218462SApril.Chin@Sun.COM 			nv_offattr(mp,NV_NOFREE);
9228462SApril.Chin@Sun.COM 	}
9234887Schin 	if(flags&NV_MOVE)
9244887Schin 	{
9258462SApril.Chin@Sun.COM 		if(nv_isattr(np,NV_INTEGER))
9268462SApril.Chin@Sun.COM 			mp->nvalue.ip = np->nvalue.ip;
9274887Schin 		np->nvfun = 0;
9284887Schin 		np->nvalue.cp = 0;
9294887Schin 		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(mp,NV_EXPORT))
9304887Schin 		        np->nvenv = 0;
9318462SApril.Chin@Sun.COM 		np->nvflag &= NV_MINIMAL;
9324887Schin 	        nv_setsize(np,0);
9334887Schin 		return(1);
9344887Schin 	}
9358462SApril.Chin@Sun.COM 	if(nv_isattr(np,NV_INTEGER) && mp->nvalue.ip!=np->nvalue.ip)
936*10898Sroland.mainz@nrubsig.org 	{
9374887Schin 		mp->nvalue.ip = (int*)num_clone(np,(void*)np->nvalue.ip);
938*10898Sroland.mainz@nrubsig.org 		nv_offattr(mp,NV_NOFREE);
939*10898Sroland.mainz@nrubsig.org 	}
9404887Schin 	else if(flags&NV_NOFREE)
9414887Schin 	        nv_onattr(np,NV_NOFREE);
9424887Schin 	return(1);
9434887Schin }
9444887Schin 
9454887Schin /*
9464887Schin  *  The following discipline is for copy-on-write semantics
9474887Schin  */
9484887Schin static char* clone_getv(Namval_t *np, Namfun_t *handle)
9494887Schin {
9504887Schin 	return(np->nvalue.np?nv_getval(np->nvalue.np):0);
9514887Schin }
9524887Schin 
9534887Schin static Sfdouble_t clone_getn(Namval_t *np, Namfun_t *handle)
9544887Schin {
9554887Schin 	return(np->nvalue.np?nv_getnum(np->nvalue.np):0);
9564887Schin }
9574887Schin 
9584887Schin static void clone_putv(Namval_t *np,const char* val,int flags,Namfun_t *handle)
9594887Schin {
9604887Schin 	Namfun_t *dp = nv_stack(np,(Namfun_t*)0);
9614887Schin 	Namval_t *mp = np->nvalue.np;
9624887Schin 	if(!sh.subshell)
9634887Schin 		free((void*)dp);
9644887Schin 	if(val)
9654887Schin 		nv_clone(mp,np,NV_NOFREE);
9664887Schin 	np->nvalue.cp = 0;
9674887Schin 	nv_putval(np,val,flags);
9684887Schin }
9694887Schin 
9704887Schin static const Namdisc_t clone_disc =
9714887Schin {
9724887Schin 	0,
9734887Schin 	clone_putv,
9744887Schin 	clone_getv,
9754887Schin 	clone_getn
9764887Schin };
9774887Schin 
9784887Schin Namval_t *nv_mkclone(Namval_t *mp)
9794887Schin {
9804887Schin 	Namval_t *np;
9814887Schin 	Namfun_t *dp;
9824887Schin 	np = newof(0,Namval_t,1,0);
9834887Schin 	np->nvflag = mp->nvflag;
9844887Schin 	np->nvsize = mp->nvsize;
9854887Schin 	np->nvname = mp->nvname;
9864887Schin 	np->nvalue.np = mp;
9874887Schin 	np->nvflag = mp->nvflag;
9884887Schin 	dp = newof(0,Namfun_t,1,0);
9894887Schin 	dp->disc = &clone_disc;
9904887Schin 	nv_stack(np,dp);
9914887Schin 	dtinsert(nv_dict(sh.namespace),np);
9924887Schin 	return(np);
9934887Schin }
9944887Schin #endif /* SHOPT_NAMESPACE */
9954887Schin 
9964887Schin Namval_t *nv_search(const char *name, Dt_t *root, int mode)
9974887Schin {
9984887Schin 	register Namval_t *np;
9994887Schin 	register Dt_t *dp = 0;
10004887Schin 	if(mode&HASH_NOSCOPE)
10014887Schin 		dp = dtview(root,0);
10024887Schin 	if(mode&HASH_BUCKET)
10034887Schin 	{
10044887Schin 		Namval_t *mp = (void*)name;
10054887Schin 		if(!(np = dtsearch(root,mp)) && (mode&NV_ADD))
10064887Schin 			name = nv_name(mp);
10074887Schin 	}
10084887Schin 	else
10094887Schin 	{
1010*10898Sroland.mainz@nrubsig.org 		if(*name=='.' && root==sh.var_tree && !dp)
10114887Schin 			root = sh.var_base;
10124887Schin 		np = dtmatch(root,(void*)name);
10134887Schin 	}
10144887Schin 	if(!np && (mode&NV_ADD))
10154887Schin 	{
10164887Schin 		if(sh.namespace && !(mode&HASH_NOSCOPE) && root==sh.var_tree)
10174887Schin 			root = nv_dict(sh.namespace);
10184887Schin 		else if(!dp && !(mode&HASH_NOSCOPE))
10194887Schin 		{
10204887Schin 			register Dt_t *next;
10214887Schin 			while(next=dtvnext(root))
10224887Schin 				root = next;
10234887Schin 		}
10244887Schin 		np = (Namval_t*)dtinsert(root,newnode(name));
10254887Schin 	}
10264887Schin 	if(dp)
10274887Schin 		dtview(root,dp);
10284887Schin 	return(np);
10294887Schin }
10304887Schin 
10314887Schin /*
10324887Schin  * finds function or builtin for given name and the discipline variable
10334887Schin  * if var!=0 the variable pointer is returned and the built-in name
10344887Schin  *    is put onto the stack at the current offset.
10354887Schin  * otherwise, a pointer to the builtin (variable or type) is returned
10364887Schin  * and var contains the poiner to the variable
10374887Schin  * if last==0 and first component of name is a reference, nv_bfsearch()
10384887Schin 	will return 0.
10394887Schin  */
10404887Schin Namval_t *nv_bfsearch(const char *name, Dt_t *root, Namval_t **var, char **last)
10414887Schin {
10428462SApril.Chin@Sun.COM 	int		c,offset = staktell();
10434887Schin 	register char	*sp, *cp=0;
10444887Schin 	Namval_t	*np, *nq;
10458462SApril.Chin@Sun.COM 	char		*dname=0;
10464887Schin 	if(var)
10474887Schin 		*var = 0;
10484887Schin 	/* check for . in the name before = */
10494887Schin 	for(sp=(char*)name+1; *sp; sp++)
10504887Schin 	{
10514887Schin 		if(*sp=='=')
10524887Schin 			return(0);
10538462SApril.Chin@Sun.COM 		if(*sp=='[')
10548462SApril.Chin@Sun.COM 		{
10558462SApril.Chin@Sun.COM 			if(sp[-1]!='.')
10568462SApril.Chin@Sun.COM 				dname = sp;
10578462SApril.Chin@Sun.COM 			while(*sp=='[')
10588462SApril.Chin@Sun.COM 			{
10598462SApril.Chin@Sun.COM 				sp = nv_endsubscript((Namval_t*)0,(char*)sp,0);
10608462SApril.Chin@Sun.COM 				if(sp[-1]!=']')
10618462SApril.Chin@Sun.COM 					return(0);
10628462SApril.Chin@Sun.COM 			}
10638462SApril.Chin@Sun.COM 			if(*sp==0)
10648462SApril.Chin@Sun.COM 				break;
10658462SApril.Chin@Sun.COM 			if(*sp!='.')
10668462SApril.Chin@Sun.COM 				return(0);
10678462SApril.Chin@Sun.COM 			if(dname)
10688462SApril.Chin@Sun.COM 			{
10698462SApril.Chin@Sun.COM 				cp = dname;
10708462SApril.Chin@Sun.COM 				dname = sp+1;
10718462SApril.Chin@Sun.COM 			}
10728462SApril.Chin@Sun.COM 		}
10738462SApril.Chin@Sun.COM 		else if(*sp=='.')
10744887Schin 			cp = sp;
10754887Schin 	}
10764887Schin 	if(!cp)
10774887Schin 		return(var?nv_search(name,root,0):0);
10784887Schin 	stakputs(name);
10794887Schin 	stakputc(0);
10808462SApril.Chin@Sun.COM 	if(!dname)
10818462SApril.Chin@Sun.COM 		dname = cp+1;
10824887Schin 	cp = stakptr(offset) + (cp-name);
10834887Schin 	if(last)
10844887Schin 		*last = cp;
10858462SApril.Chin@Sun.COM 	c = *cp;
10864887Schin 	*cp = 0;
10878462SApril.Chin@Sun.COM 	nq=nv_open(stakptr(offset),0,NV_VARNAME|NV_ARRAY|NV_NOASSIGN|NV_NOADD|NV_NOFAIL);
10888462SApril.Chin@Sun.COM 	*cp = c;
10894887Schin 	if(!nq)
10904887Schin 	{
10914887Schin 		np = 0;
10924887Schin 		goto done;
10934887Schin 	}
10944887Schin 	if(!var)
10954887Schin 	{
10964887Schin 		np = nq;
10974887Schin 		goto done;
10984887Schin 	}
10994887Schin 	*var = nq;
11008462SApril.Chin@Sun.COM 	if(c=='[')
11018462SApril.Chin@Sun.COM 		nv_endsubscript(nq, cp,NV_NOADD);
11028462SApril.Chin@Sun.COM 	return((Namval_t*)nv_setdisc(nq,dname,nq,(Namfun_t*)nq));
11034887Schin done:
11044887Schin 	stakseek(offset);
11054887Schin 	return(np);
11064887Schin }
11074887Schin 
11084887Schin /*
11098462SApril.Chin@Sun.COM  * add or replace built-in version of command corresponding to <path>
11104887Schin  * The <bltin> argument is a pointer to the built-in
11114887Schin  * if <extra>==1, the built-in will be deleted
11124887Schin  * Special builtins cannot be added or deleted return failure
11134887Schin  * The return value for adding builtins is a pointer to the node or NULL on
11144887Schin  *   failure.  For delete NULL means success and the node that cannot be
11154887Schin  *   deleted is returned on failure.
11164887Schin  */
11174887Schin Namval_t *sh_addbuiltin(const char *path, int (*bltin)(int, char*[],void*),void *extra)
11184887Schin {
11198462SApril.Chin@Sun.COM 	register const char	*name = path_basename(path);
11208462SApril.Chin@Sun.COM 	char			*cp;
11218462SApril.Chin@Sun.COM 	register Namval_t	*np, *nq=0;
11228462SApril.Chin@Sun.COM 	int			offset=staktell();
11234887Schin 	if(name==path && (nq=nv_bfsearch(name,sh.bltin_tree,(Namval_t**)0,&cp)))
11244887Schin 		path = name = stakptr(offset);
11254887Schin 	if(np = nv_search(path,sh.bltin_tree,0))
11264887Schin 	{
11274887Schin 		/* exists without a path */
11284887Schin 		if(extra == (void*)1)
11294887Schin 		{
11304887Schin 			if(np->nvfun && !nv_isattr(np,NV_NOFREE))
11314887Schin 				free((void*)np->nvfun);
11324887Schin 			dtdelete(sh.bltin_tree,np);
11334887Schin 			return(0);
11344887Schin 		}
11354887Schin 		if(!bltin)
11364887Schin 			return(np);
11374887Schin 	}
11384887Schin 	else for(np=(Namval_t*)dtfirst(sh.bltin_tree);np;np=(Namval_t*)dtnext(sh.bltin_tree,np))
11394887Schin 	{
11404887Schin 		if(strcmp(name,path_basename(nv_name(np))))
11414887Schin 			continue;
11424887Schin 		/* exists probably with different path so delete it */
11434887Schin 		if(strcmp(path,nv_name(np)))
11444887Schin 		{
11454887Schin 			if(nv_isattr(np,BLT_SPC))
11464887Schin 				return(np);
11474887Schin 			if(!bltin)
11484887Schin 				bltin = np->nvalue.bfp;
11494887Schin 			if(np->nvenv)
11504887Schin 				dtdelete(sh.bltin_tree,np);
11514887Schin 			if(extra == (void*)1)
11524887Schin 				return(0);
11534887Schin 			np = 0;
11544887Schin 		}
11554887Schin 		break;
11564887Schin 	}
11574887Schin 	if(!np && !(np = nv_search(path,sh.bltin_tree,bltin?NV_ADD:0)))
11584887Schin 		return(0);
11594887Schin 	if(nv_isattr(np,BLT_SPC))
11608462SApril.Chin@Sun.COM 	{
11618462SApril.Chin@Sun.COM 		if(extra)
11628462SApril.Chin@Sun.COM 			np->nvfun = (Namfun_t*)extra;
11634887Schin 		return(np);
11648462SApril.Chin@Sun.COM 	}
11654887Schin 	np->nvenv = 0;
11664887Schin 	np->nvfun = 0;
11674887Schin 	if(bltin)
11684887Schin 	{
11694887Schin 		np->nvalue.bfp = bltin;
11704887Schin 		nv_onattr(np,NV_BLTIN|NV_NOFREE);
11714887Schin 		np->nvfun = (Namfun_t*)extra;
11724887Schin 	}
11734887Schin 	if(nq)
11744887Schin 	{
11754887Schin 		cp=nv_setdisc(nq,cp+1,np,(Namfun_t*)nq);
11764887Schin 		nv_close(nq);
11774887Schin 		if(!cp)
11784887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_baddisc,name);
11794887Schin 	}
11804887Schin 	if(extra == (void*)1)
11814887Schin 		return(0);
11824887Schin 	return(np);
11834887Schin }
11844887Schin 
11854887Schin #undef nv_stack
11864887Schin extern Namfun_t *nv_stack(register Namval_t *np, register Namfun_t* fp)
11874887Schin {
11884887Schin 	return(nv_disc(np,fp,0));
11894887Schin }
11904887Schin 
11914887Schin struct table
11924887Schin {
11934887Schin 	Namfun_t	fun;
11944887Schin 	Namval_t	*parent;
11954887Schin 	Shell_t		*shp;
11964887Schin 	Dt_t		*dict;
11974887Schin };
11984887Schin 
11994887Schin static Namval_t *next_table(register Namval_t* np, Dt_t *root,Namfun_t *fp)
12004887Schin {
12014887Schin 	struct table *tp = (struct table *)fp;
12024887Schin 	if(root)
12034887Schin 		return((Namval_t*)dtnext(root,np));
12044887Schin 	else
12054887Schin 		return((Namval_t*)dtfirst(tp->dict));
12064887Schin }
12074887Schin 
12084887Schin static Namval_t *create_table(Namval_t *np,const char *name,int flags,Namfun_t *fp)
12094887Schin {
12104887Schin 	struct table *tp = (struct table *)fp;
12114887Schin 	tp->shp->last_table = np;
12124887Schin 	return(nv_create(name, tp->dict, flags, fp));
12134887Schin }
12144887Schin 
12154887Schin static Namfun_t *clone_table(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
12164887Schin {
12174887Schin 	struct table	*tp = (struct table*)fp;
12188462SApril.Chin@Sun.COM 	struct table	*ntp = (struct table*)nv_clone_disc(fp,0);
12194887Schin 	Dt_t		*oroot=tp->dict,*nroot=dtopen(&_Nvdisc,Dtoset);
12204887Schin 	if(!nroot)
12214887Schin 		return(0);
12224887Schin 	memcpy((void*)ntp,(void*)fp,sizeof(struct table));
12234887Schin 	ntp->dict = nroot;
12244887Schin 	ntp->parent = nv_lastdict();
12254887Schin 	for(np=(Namval_t*)dtfirst(oroot);np;np=(Namval_t*)dtnext(oroot,np))
12264887Schin 	{
12274887Schin 		mp = (Namval_t*)dtinsert(nroot,newnode(np->nvname));
12284887Schin 		nv_clone(np,mp,flags);
12294887Schin 	}
12304887Schin 	return(&ntp->fun);
12314887Schin }
12324887Schin 
12334887Schin static void put_table(register Namval_t* np, const char* val, int flags, Namfun_t* fp)
12344887Schin {
12354887Schin 	register Dt_t		*root = ((struct table*)fp)->dict;
12364887Schin 	register Namval_t	*nq, *mp;
12374887Schin 	Namarr_t		*ap;
12384887Schin 	nv_putv(np,val,flags,fp);
12394887Schin 	if(val)
12404887Schin 		return;
12414887Schin 	if(nv_isarray(np) && (ap=nv_arrayptr(np)) && array_elem(ap))
12424887Schin 		return;
12434887Schin 	for(mp=(Namval_t*)dtfirst(root);mp;mp=nq)
12444887Schin 	{
12454887Schin 		_nv_unset(mp,flags);
12464887Schin 		nq = (Namval_t*)dtnext(root,mp);
12474887Schin 		dtdelete(root,mp);
12484887Schin 		free((void*)mp);
12494887Schin 	}
12504887Schin 	dtclose(root);
12518462SApril.Chin@Sun.COM 	if(!(fp->nofree&1))
12524887Schin 		free((void*)fp);
12534887Schin }
12544887Schin 
12554887Schin /*
12564887Schin  * return space separated list of names of variables in given tree
12574887Schin  */
12584887Schin static char *get_table(Namval_t *np, Namfun_t *fp)
12594887Schin {
12604887Schin 	register Dt_t *root = ((struct table*)fp)->dict;
12614887Schin 	static Sfio_t *out;
12624887Schin 	register int first=1;
12634887Schin 	register Dt_t *base = dtview(root,0);
12644887Schin         if(out)
12654887Schin                 sfseek(out,(Sfoff_t)0,SEEK_SET);
12664887Schin         else
12674887Schin                 out =  sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
12684887Schin 	for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
12694887Schin 	{
12704887Schin                 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
12714887Schin 		{
12724887Schin 			if(!first)
12734887Schin 				sfputc(out,' ');
12744887Schin 			else
12754887Schin 				first = 0;
12764887Schin 			sfputr(out,np->nvname,-1);
12774887Schin 		}
12784887Schin 	}
12794887Schin 	sfputc(out,0);
12804887Schin 	if(base)
12814887Schin 		dtview(root,base);
12824887Schin 	return((char*)out->_data);
12834887Schin }
12844887Schin 
12854887Schin static const Namdisc_t table_disc =
12864887Schin {
12874887Schin         sizeof(struct table),
12884887Schin         put_table,
12894887Schin         get_table,
12904887Schin         0,
12914887Schin         0,
12924887Schin         create_table,
12934887Schin         clone_table,
12944887Schin         0,
12954887Schin         next_table,
12964887Schin };
12974887Schin 
12988462SApril.Chin@Sun.COM Namval_t *nv_parent(Namval_t *np)
12998462SApril.Chin@Sun.COM {
13008462SApril.Chin@Sun.COM 	struct table *tp = (struct table *)nv_hasdisc(np,&table_disc);
13018462SApril.Chin@Sun.COM 	if(tp)
13028462SApril.Chin@Sun.COM 		return(tp->parent);
13038462SApril.Chin@Sun.COM 	return(0);
13048462SApril.Chin@Sun.COM }
13058462SApril.Chin@Sun.COM 
13064887Schin Dt_t *nv_dict(Namval_t* np)
13074887Schin {
13084887Schin 	struct table *tp = (struct table*)nv_hasdisc(np,&table_disc);
13094887Schin 	if(tp)
13104887Schin 		return(tp->dict);
13114887Schin 	np = sh.last_table;
13124887Schin 	while(np)
13134887Schin 	{
13144887Schin 		if(tp = (struct table*)nv_hasdisc(np,&table_disc))
13154887Schin 			return(tp->dict);
13164887Schin #if 0
13174887Schin 		np = nv_create(np,(const char*)0, NV_FIRST, (Namfun_t*)0);
13188462SApril.Chin@Sun.COM #else
13198462SApril.Chin@Sun.COM 		break;
13204887Schin #endif
13214887Schin 	}
13224887Schin 	return(sh.var_tree);
13234887Schin }
13244887Schin 
13254887Schin /*
13264887Schin  * create a mountable name-value pair tree
13274887Schin  */
13284887Schin Namval_t *nv_mount(Namval_t *np, const char *name, Dt_t *dict)
13294887Schin {
13304887Schin 	Namval_t *mp, *pp=0;
13314887Schin 	struct table *tp = newof((struct table*)0, struct table,1,0);
13324887Schin 	if(name)
13334887Schin 	{
13344887Schin 		if(nv_istable(np))
13354887Schin 			pp = np;
13364887Schin 		else
13374887Schin 			pp = nv_lastdict();
13384887Schin 	}
13394887Schin 	if(!(tp = newof((struct table*)0, struct table,1,0)))
13404887Schin 		return(0);
13414887Schin 	if(name)
13424887Schin 	{
13434887Schin 		Namfun_t *fp = pp->nvfun;
13444887Schin 		mp = (*fp->disc->createf)(pp,name,0,fp);
13454887Schin 	}
13464887Schin 	else
13474887Schin 		mp = np;
13484887Schin 	if(!nv_isnull(mp))
13494887Schin 		nv_unset(mp);
13504887Schin 	tp->shp = sh_getinterp();
13514887Schin 	tp->dict = dict;
13524887Schin 	tp->parent = pp;
13534887Schin 	tp->fun.disc = &table_disc;
13544887Schin 	nv_onattr(mp,NV_TABLE);
13558462SApril.Chin@Sun.COM 	nv_disc(mp, &tp->fun, NV_FIRST);
13564887Schin 	return(mp);
13574887Schin }
13584887Schin 
13594887Schin const Namdisc_t *nv_discfun(int which)
13604887Schin {
13614887Schin 	switch(which)
13624887Schin 	{
13634887Schin 	    case NV_DCADD:
13644887Schin 		return(&Nv_bdisc);
13654887Schin 	    case NV_DCRESTRICT:
13664887Schin 		return(&RESTRICTED_disc);
13674887Schin 	}
13684887Schin 	return(0);
13694887Schin }
13704887Schin 
1371