14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 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
nv_compare(Dt_t * dict,Void_t * sp,Void_t * dp,Dtdisc_t * disc)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 */
nv_getv(Namval_t * np,register Namfun_t * nfp)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 */
nv_getn(Namval_t * np,register Namfun_t * nfp)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 */
nv_putv(Namval_t * np,const char * value,int flags,register Namfun_t * nfp)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
15310898Sroland.mainz@nrubsig.org #define LOOKUPS 0
1544887Schin #define ASSIGN 1
1554887Schin #define APPEND 2
1564887Schin #define UNASSIGN 3
15710898Sroland.mainz@nrubsig.org #define LOOKUPN 4
1584887Schin #define BLOCKED ((Namval_t*)&nv_local)
1594887Schin
1604887Schin struct vardisc
1614887Schin {
1624887Schin Namfun_t fun;
16310898Sroland.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 */
block_info(Namval_t * np,struct blocked * pp)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
block_done(struct blocked * bp)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 */
chktfree(register Namval_t * np,register struct vardisc * vp)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 */
assign(Namval_t * np,const char * val,int flags,Namfun_t * handle)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);
28510898Sroland.mainz@nrubsig.org if (type==APPEND && (bflag= !isblocked(bp,LOOKUPS)))
28610898Sroland.mainz@nrubsig.org block(bp,LOOKUPS);
2874887Schin sh_fun(nq,np,(char**)0);
2884887Schin unblock(bp,type);
2894887Schin if(bflag)
29010898Sroland.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 */
lookup(Namval_t * np,int type,Sfdouble_t * dp,Namfun_t * handle)35510898Sroland.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);
35910898Sroland.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;
36310898Sroland.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 }
37110898Sroland.mainz@nrubsig.org if(type==LOOKUPN)
37210898Sroland.mainz@nrubsig.org {
37310898Sroland.mainz@nrubsig.org nv_onattr(SH_VALNOD,NV_DOUBLE|NV_INTEGER);
37410898Sroland.mainz@nrubsig.org nv_setsize(SH_VALNOD,10);
37510898Sroland.mainz@nrubsig.org }
37610898Sroland.mainz@nrubsig.org block(bp,type);
3774887Schin sh_fun(nq,np,(char**)0);
37810898Sroland.mainz@nrubsig.org unblock(bp,type);
37910898Sroland.mainz@nrubsig.org if(!vp->disc[type])
3804887Schin chktfree(np,vp);
38110898Sroland.mainz@nrubsig.org if(type==LOOKUPN)
3828462SApril.Chin@Sun.COM {
38310898Sroland.mainz@nrubsig.org cp = (char*)(SH_VALNOD->nvalue.cp);
38410898Sroland.mainz@nrubsig.org *dp = nv_getnum(SH_VALNOD);
38510898Sroland.mainz@nrubsig.org }
38610898Sroland.mainz@nrubsig.org else if(cp = nv_getval(SH_VALNOD))
3878462SApril.Chin@Sun.COM cp = stkcopy(stkstd,cp);
38810898Sroland.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)
39810898Sroland.mainz@nrubsig.org {
39910898Sroland.mainz@nrubsig.org if(type==LOOKUPS)
40010898Sroland.mainz@nrubsig.org cp = nv_getv(np,handle);
40110898Sroland.mainz@nrubsig.org else
40210898Sroland.mainz@nrubsig.org *dp = nv_getn(np,handle);
40310898Sroland.mainz@nrubsig.org }
4044887Schin if(bp== &block)
4054887Schin block_done(bp);
4064887Schin return(cp);
4074887Schin }
4084887Schin
lookups(Namval_t * np,Namfun_t * handle)40910898Sroland.mainz@nrubsig.org static char* lookups(Namval_t *np, Namfun_t *handle)
4104887Schin {
41110898Sroland.mainz@nrubsig.org return(lookup(np,LOOKUPS,(Sfdouble_t*)0,handle));
41210898Sroland.mainz@nrubsig.org }
41310898Sroland.mainz@nrubsig.org
lookupn(Namval_t * np,Namfun_t * handle)41410898Sroland.mainz@nrubsig.org static Sfdouble_t lookupn(Namval_t *np, Namfun_t *handle)
41510898Sroland.mainz@nrubsig.org {
41610898Sroland.mainz@nrubsig.org Sfdouble_t d;
41710898Sroland.mainz@nrubsig.org lookup(np,LOOKUPN, &d ,handle);
41810898Sroland.mainz@nrubsig.org return(d);
41910898Sroland.mainz@nrubsig.org }
42010898Sroland.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 */
nv_setdisc(register Namval_t * np,register const char * event,Namval_t * action,register Namfun_t * fp)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 = "";
434*12068SRoger.Faulkner@Oracle.COM while(vp)
435*12068SRoger.Faulkner@Oracle.COM {
436*12068SRoger.Faulkner@Oracle.COM if(vp->fun.disc && (vp->fun.disc->setdisc || vp->fun.disc->putval == assign))
437*12068SRoger.Faulkner@Oracle.COM break;
438*12068SRoger.Faulkner@Oracle.COM vp = (struct vardisc*)vp->fun.next;
439*12068SRoger.Faulkner@Oracle.COM }
4408462SApril.Chin@Sun.COM if(vp && !vp->fun.disc)
4418462SApril.Chin@Sun.COM vp = 0;
4424887Schin if(np == (Namval_t*)fp)
4434887Schin {
4444887Schin register const char *name;
4454887Schin register int getname=0;
4464887Schin /* top level call, check for get/set */
4474887Schin if(!event)
4484887Schin {
4494887Schin if(!action)
4508462SApril.Chin@Sun.COM return((char*)nv_discnames[0]);
4514887Schin getname=1;
4524887Schin event = (char*)action;
4534887Schin }
4548462SApril.Chin@Sun.COM for(type=0; name=nv_discnames[type]; type++)
4554887Schin {
4564887Schin if(strcmp(event,name)==0)
4574887Schin break;
4584887Schin }
4594887Schin if(getname)
4604887Schin {
4614887Schin event = 0;
4628462SApril.Chin@Sun.COM if(name && !(name = nv_discnames[++type]))
4634887Schin action = 0;
4644887Schin }
4654887Schin if(!name)
4664887Schin {
4678462SApril.Chin@Sun.COM for(fp=(Namfun_t*)vp; fp; fp=fp->next)
4688462SApril.Chin@Sun.COM {
4698462SApril.Chin@Sun.COM if(fp->disc && fp->disc->setdisc)
4708462SApril.Chin@Sun.COM return((*fp->disc->setdisc)(np,event,action,fp));
4718462SApril.Chin@Sun.COM }
4724887Schin }
4734887Schin else if(getname)
4744887Schin return((char*)name);
4754887Schin }
4764887Schin if(!fp)
4774887Schin return(NIL(char*));
4784887Schin if(np != (Namval_t*)fp)
4794887Schin {
4804887Schin /* not the top level */
4814887Schin while(fp = fp->next)
4824887Schin {
4838462SApril.Chin@Sun.COM if(fp->disc && fp->disc->setdisc)
4844887Schin return((*fp->disc->setdisc)(np,event,action,fp));
4854887Schin }
4864887Schin return(NIL(char*));
4874887Schin }
4884887Schin /* Handle GET/SET/APPEND/UNSET disc */
4894887Schin if(vp && vp->fun.disc->putval!=assign)
4904887Schin vp = 0;
4914887Schin if(!vp)
4924887Schin {
49310898Sroland.mainz@nrubsig.org Namdisc_t *dp;
4944887Schin if(action==np)
4954887Schin return((char*)action);
49610898Sroland.mainz@nrubsig.org if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,sizeof(Namdisc_t))))
4974887Schin return(0);
49810898Sroland.mainz@nrubsig.org dp = (Namdisc_t*)(vp+1);
49910898Sroland.mainz@nrubsig.org vp->fun.disc = dp;
50010898Sroland.mainz@nrubsig.org memset(dp,0,sizeof(*dp));
50110898Sroland.mainz@nrubsig.org dp->dsize = sizeof(struct vardisc);
50210898Sroland.mainz@nrubsig.org dp->putval = assign;
503*12068SRoger.Faulkner@Oracle.COM if(nv_isarray(np) && !nv_arrayptr(np))
504*12068SRoger.Faulkner@Oracle.COM nv_putsub(np,(char*)0, 1);
5054887Schin nv_stack(np, (Namfun_t*)vp);
5064887Schin }
5074887Schin if(action==np)
5084887Schin {
5094887Schin action = vp->disc[type];
5104887Schin empty = 0;
5114887Schin }
5124887Schin else if(action)
51310898Sroland.mainz@nrubsig.org {
51410898Sroland.mainz@nrubsig.org Namdisc_t *dp = (Namdisc_t*)vp->fun.disc;
51510898Sroland.mainz@nrubsig.org if(type==LOOKUPS)
51610898Sroland.mainz@nrubsig.org dp->getval = lookups;
51710898Sroland.mainz@nrubsig.org else if(type==LOOKUPN)
51810898Sroland.mainz@nrubsig.org dp->getnum = lookupn;
5194887Schin vp->disc[type] = action;
52010898Sroland.mainz@nrubsig.org }
5214887Schin else
5224887Schin {
5234887Schin struct blocked *bp;
5244887Schin action = vp->disc[type];
5254887Schin vp->disc[type] = 0;
5264887Schin if(!(bp=block_info(np,(struct blocked*)0)) || !isblocked(bp,UNASSIGN))
5274887Schin chktfree(np,vp);
5284887Schin }
5294887Schin return(action?(char*)action:empty);
5304887Schin }
5314887Schin
5324887Schin /*
5334887Schin * Set disc on given <event> to <action>
5344887Schin * If action==np, the current disc is returned
5354887Schin * A null return value indicates that no <event> is known for <np>
5364887Schin * If <event> is NULL, then return the event name after <action>
5374887Schin * If <event> is NULL, and <action> is NULL, return the first event
5384887Schin */
setdisc(register Namval_t * np,register const char * event,Namval_t * action,register Namfun_t * fp)5394887Schin static char *setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp)
5404887Schin {
5414887Schin register Nambfun_t *vp = (Nambfun_t*)fp;
5424887Schin register int type,getname=0;
5434887Schin register const char *name;
5444887Schin const char **discnames = vp->bnames;
5454887Schin /* top level call, check for discipline match */
5464887Schin if(!event)
5474887Schin {
5484887Schin if(!action)
5494887Schin return((char*)discnames[0]);
5504887Schin getname=1;
5514887Schin event = (char*)action;
5524887Schin }
5534887Schin for(type=0; name=discnames[type]; type++)
5544887Schin {
5554887Schin if(strcmp(event,name)==0)
5564887Schin break;
5574887Schin }
5584887Schin if(getname)
5594887Schin {
5604887Schin event = 0;
5614887Schin if(name && !(name = discnames[++type]))
5624887Schin action = 0;
5634887Schin }
5644887Schin if(!name)
5654887Schin return(nv_setdisc(np,event,action,fp));
5664887Schin else if(getname)
5674887Schin return((char*)name);
5684887Schin /* Handle the disciplines */
5694887Schin if(action==np)
5704887Schin action = vp->bltins[type];
5714887Schin else if(action)
5724887Schin vp->bltins[type] = action;
5734887Schin else
5744887Schin {
5754887Schin action = vp->bltins[type];
5764887Schin vp->bltins[type] = 0;
5774887Schin }
5784887Schin return(action?(char*)action:"");
5794887Schin }
5804887Schin
putdisc(Namval_t * np,const char * val,int flag,Namfun_t * fp)5814887Schin static void putdisc(Namval_t* np, const char* val, int flag, Namfun_t* fp)
5824887Schin {
5834887Schin nv_putv(np,val,flag,fp);
5848462SApril.Chin@Sun.COM if(!val && !(flag&NV_NOFREE))
5854887Schin {
5864887Schin register Nambfun_t *vp = (Nambfun_t*)fp;
5874887Schin register int i;
5884887Schin for(i=0; vp->bnames[i]; i++)
5894887Schin {
5904887Schin register Namval_t *mp;
5914887Schin if((mp=vp->bltins[i]) && !nv_isattr(mp,NV_NOFREE))
5924887Schin {
5934887Schin if(is_abuiltin(mp))
5944887Schin {
5954887Schin if(mp->nvfun && !nv_isattr(mp,NV_NOFREE))
5964887Schin free((void*)mp->nvfun);
5974887Schin dtdelete(sh.bltin_tree,mp);
5984887Schin free((void*)mp);
5994887Schin }
6004887Schin }
6014887Schin }
6024887Schin nv_disc(np,fp,NV_POP);
6038462SApril.Chin@Sun.COM if(!(fp->nofree&1))
6044887Schin free((void*)fp);
6054887Schin
6064887Schin }
6074887Schin }
6084887Schin
6094887Schin static const Namdisc_t Nv_bdisc = { 0, putdisc, 0, 0, setdisc };
6104887Schin
nv_clone_disc(register Namfun_t * fp,int flags)6118462SApril.Chin@Sun.COM Namfun_t *nv_clone_disc(register Namfun_t *fp, int flags)
6124887Schin {
6134887Schin register Namfun_t *nfp;
6144887Schin register int size;
61510898Sroland.mainz@nrubsig.org if(!fp->disc && !fp->next && (fp->nofree&1))
61610898Sroland.mainz@nrubsig.org return(fp);
6174887Schin if(!(size=fp->dsize) && (!fp->disc || !(size=fp->disc->dsize)))
6184887Schin size = sizeof(Namfun_t);
6194887Schin if(!(nfp=newof(NIL(Namfun_t*),Namfun_t,1,size-sizeof(Namfun_t))))
6204887Schin return(0);
6214887Schin memcpy(nfp,fp,size);
62210898Sroland.mainz@nrubsig.org nfp->nofree &= ~1;
6238462SApril.Chin@Sun.COM nfp->nofree |= (flags&NV_RDONLY)?1:0;
6244887Schin return(nfp);
6254887Schin }
6264887Schin
nv_adddisc(Namval_t * np,const char ** names,Namval_t ** funs)6274887Schin int nv_adddisc(Namval_t *np, const char **names, Namval_t **funs)
6284887Schin {
6294887Schin register Nambfun_t *vp;
6304887Schin register int n=0;
6314887Schin register const char **av=names;
6324887Schin if(av)
6334887Schin {
6344887Schin while(*av++)
6354887Schin n++;
6364887Schin }
6374887Schin if(!(vp = newof(NIL(Nambfun_t*),Nambfun_t,1,n*sizeof(Namval_t*))))
6384887Schin return(0);
6394887Schin vp->fun.dsize = sizeof(Nambfun_t)+n*sizeof(Namval_t*);
6408462SApril.Chin@Sun.COM vp->fun.nofree |= 2;
6418462SApril.Chin@Sun.COM vp->num = n;
6424887Schin if(funs)
6434887Schin memcpy((void*)vp->bltins, (void*)funs,n*sizeof(Namval_t*));
6444887Schin else while(n>=0)
6454887Schin vp->bltins[n--] = 0;
6464887Schin vp->fun.disc = &Nv_bdisc;
6474887Schin vp->bnames = names;
6484887Schin nv_stack(np,&vp->fun);
6494887Schin return(1);
6504887Schin }
6514887Schin
6524887Schin /*
6538462SApril.Chin@Sun.COM * push, pop, clne, or reorder disciplines onto node <np>
6544887Schin * mode can be one of
6554887Schin * NV_FIRST: Move or push <fp> to top of the stack or delete top
6564887Schin * NV_LAST: Move or push <fp> to bottom of stack or delete last
6574887Schin * NV_POP: Delete <fp> from top of the stack
6584887Schin * NV_CLONE: Replace fp with a copy created my malloc() and return it
6594887Schin */
nv_disc(register Namval_t * np,register Namfun_t * fp,int mode)6604887Schin Namfun_t *nv_disc(register Namval_t *np, register Namfun_t* fp, int mode)
6614887Schin {
6624887Schin Namfun_t *lp, **lpp;
6634887Schin if(nv_isref(np))
6644887Schin return(0);
6654887Schin if(mode==NV_CLONE && !fp)
6664887Schin return(0);
6674887Schin if(fp)
6684887Schin {
6698462SApril.Chin@Sun.COM fp->subshell = sh.subshell;
6704887Schin if((lp=np->nvfun)==fp)
6714887Schin {
6724887Schin if(mode==NV_CLONE)
6734887Schin {
6748462SApril.Chin@Sun.COM lp = nv_clone_disc(fp,0);
6754887Schin return(np->nvfun=lp);
6764887Schin }
6774887Schin if(mode==NV_FIRST || mode==0)
6784887Schin return(fp);
6794887Schin np->nvfun = lp->next;
6804887Schin if(mode==NV_POP)
6814887Schin return(fp);
6828462SApril.Chin@Sun.COM if(mode==NV_LAST && (lp->next==0 || lp->next->disc==0))
6838462SApril.Chin@Sun.COM return(fp);
6844887Schin }
6854887Schin /* see if <fp> is on the list already */
6864887Schin lpp = &np->nvfun;
6874887Schin if(lp)
6884887Schin {
6898462SApril.Chin@Sun.COM while(lp->next && lp->next->disc)
6904887Schin {
6914887Schin if(lp->next==fp)
6924887Schin {
6938462SApril.Chin@Sun.COM if(mode==NV_LAST && fp->next==0)
6948462SApril.Chin@Sun.COM return(fp);
6954887Schin if(mode==NV_CLONE)
6964887Schin {
6978462SApril.Chin@Sun.COM fp = nv_clone_disc(fp,0);
6984887Schin lp->next = fp;
6994887Schin return(fp);
7004887Schin }
7014887Schin lp->next = fp->next;
7024887Schin if(mode==NV_POP)
7034887Schin return(fp);
7044887Schin if(mode!=NV_LAST)
7054887Schin break;
7064887Schin }
7074887Schin lp = lp->next;
7084887Schin }
7094887Schin if(mode==NV_LAST)
7104887Schin lpp = &lp->next;
7114887Schin }
7124887Schin if(mode==NV_POP)
7134887Schin return(0);
7144887Schin /* push */
7154887Schin nv_offattr(np,NV_NODISC);
7164887Schin if(mode==NV_LAST)
7174887Schin fp->next = 0;
7184887Schin else
7194887Schin {
7208462SApril.Chin@Sun.COM if((fp->nofree&1) && *lpp)
7218462SApril.Chin@Sun.COM fp = nv_clone_disc(fp,0);
7224887Schin fp->next = *lpp;
7234887Schin }
7244887Schin *lpp = fp;
7254887Schin }
7264887Schin else
7274887Schin {
7284887Schin if(mode==NV_FIRST)
7294887Schin return(np->nvfun);
7304887Schin else if(mode==NV_LAST)
7314887Schin for(lp=np->nvfun; lp; fp=lp,lp=lp->next);
7324887Schin else if(fp = np->nvfun)
7334887Schin np->nvfun = fp->next;
7344887Schin }
7354887Schin return(fp);
7364887Schin }
7374887Schin
7384887Schin /*
7394887Schin * returns discipline pointer if discipline with specified functions
7404887Schin * is on the discipline stack
7414887Schin */
nv_hasdisc(Namval_t * np,const Namdisc_t * dp)7424887Schin Namfun_t *nv_hasdisc(Namval_t *np, const Namdisc_t *dp)
7434887Schin {
7444887Schin register Namfun_t *fp;
7454887Schin for(fp=np->nvfun; fp; fp = fp->next)
7464887Schin {
7474887Schin if(fp->disc== dp)
7484887Schin return(fp);
7494887Schin }
7504887Schin return(0);
7514887Schin }
7524887Schin
7534887Schin struct notify
7544887Schin {
7554887Schin Namfun_t hdr;
7564887Schin char **ptr;
7574887Schin };
7584887Schin
put_notify(Namval_t * np,const char * val,int flags,Namfun_t * fp)7594887Schin static void put_notify(Namval_t* np,const char *val,int flags,Namfun_t *fp)
7604887Schin {
7614887Schin struct notify *pp = (struct notify*)fp;
7624887Schin nv_putv(np,val,flags,fp);
7634887Schin nv_stack(np,fp);
7644887Schin nv_stack(np,(Namfun_t*)0);
7654887Schin *pp->ptr = 0;
7668462SApril.Chin@Sun.COM if(!(fp->nofree&1))
7674887Schin free((void*)fp);
7684887Schin }
7694887Schin
7704887Schin static const Namdisc_t notify_disc = { 0, put_notify };
7714887Schin
nv_unsetnotify(Namval_t * np,char ** addr)7724887Schin int nv_unsetnotify(Namval_t *np, char **addr)
7734887Schin {
7744887Schin register Namfun_t *fp;
7754887Schin for(fp=np->nvfun;fp;fp=fp->next)
7764887Schin {
7774887Schin if(fp->disc->putval==put_notify && ((struct notify*)fp)->ptr==addr)
7784887Schin {
7794887Schin nv_stack(np,fp);
7804887Schin nv_stack(np,(Namfun_t*)0);
7818462SApril.Chin@Sun.COM if(!(fp->nofree&1))
7824887Schin free((void*)fp);
7834887Schin return(1);
7844887Schin }
7854887Schin }
7864887Schin return(0);
7874887Schin }
7884887Schin
nv_setnotify(Namval_t * np,char ** addr)7894887Schin int nv_setnotify(Namval_t *np, char **addr)
7904887Schin {
7914887Schin struct notify *pp = newof(0,struct notify, 1,0);
7924887Schin if(!pp)
7934887Schin return(0);
7944887Schin pp->ptr = addr;
7954887Schin pp->hdr.disc = ¬ify_disc;
7964887Schin nv_stack(np,&pp->hdr);
7974887Schin return(1);
7984887Schin }
7994887Schin
newnode(const char * name)8004887Schin static void *newnode(const char *name)
8014887Schin {
8024887Schin register int s;
8034887Schin register Namval_t *np = newof(0,Namval_t,1,s=strlen(name)+1);
8044887Schin if(np)
8054887Schin {
8064887Schin np->nvname = (char*)np+sizeof(Namval_t);
8074887Schin memcpy(np->nvname,name,s);
8084887Schin }
8094887Schin return((void*)np);
8104887Schin }
8114887Schin
8124887Schin #if SHOPT_NAMESPACE
8134887Schin /*
8144887Schin * clone a numeric value
8154887Schin */
num_clone(register Namval_t * np,void * val)8164887Schin static void *num_clone(register Namval_t *np, void *val)
8174887Schin {
8184887Schin register int size;
8194887Schin void *nval;
8204887Schin if(!val)
8214887Schin return(0);
8228462SApril.Chin@Sun.COM if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
8234887Schin {
8244887Schin if(nv_isattr(np,NV_LONG))
8254887Schin size = sizeof(Sfdouble_t);
8264887Schin else if(nv_isattr(np,NV_SHORT))
8274887Schin size = sizeof(float);
8284887Schin else
8294887Schin size = sizeof(double);
8304887Schin }
8314887Schin else
8324887Schin {
8334887Schin if(nv_isattr(np,NV_LONG))
8344887Schin size = sizeof(Sflong_t);
8354887Schin else if(nv_isattr(np,NV_SHORT))
8368462SApril.Chin@Sun.COM {
8378462SApril.Chin@Sun.COM if(nv_isattr(np,NV_INT16P)==NV_INT16P)
8388462SApril.Chin@Sun.COM size = sizeof(short);
8398462SApril.Chin@Sun.COM else
8408462SApril.Chin@Sun.COM return((void*)np->nvalue.ip);
8418462SApril.Chin@Sun.COM }
8424887Schin else
8434887Schin size = sizeof(int32_t);
8444887Schin }
8454887Schin if(!(nval = malloc(size)))
8464887Schin return(0);
8474887Schin memcpy(nval,val,size);
8484887Schin return(nval);
8494887Schin }
8504887Schin
clone_all_disc(Namval_t * np,Namval_t * mp,int flags)8518462SApril.Chin@Sun.COM void clone_all_disc( Namval_t *np, Namval_t *mp, int flags)
8524887Schin {
8538462SApril.Chin@Sun.COM register Namfun_t *fp, **mfp = &mp->nvfun, *nfp, *fpnext;
8548462SApril.Chin@Sun.COM for(fp=np->nvfun; fp;fp=fpnext)
8554887Schin {
8568462SApril.Chin@Sun.COM fpnext = fp->next;
8578462SApril.Chin@Sun.COM if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
8588462SApril.Chin@Sun.COM return;
8598462SApril.Chin@Sun.COM if((fp->nofree&2) && (flags&NV_NODISC))
8604887Schin nfp = 0;
8614887Schin if(fp->disc && fp->disc->clonef)
8624887Schin nfp = (*fp->disc->clonef)(np,mp,flags,fp);
8638462SApril.Chin@Sun.COM else if(flags&NV_MOVE)
8648462SApril.Chin@Sun.COM nfp = fp;
8654887Schin else
8668462SApril.Chin@Sun.COM nfp = nv_clone_disc(fp,flags);
8674887Schin if(!nfp)
8684887Schin continue;
8694887Schin nfp->next = 0;
8704887Schin *mfp = nfp;
8714887Schin mfp = &nfp->next;
8724887Schin }
8734887Schin }
8744887Schin
8754887Schin /*
8764887Schin * clone <mp> from <np> flags can be one of the following
8774887Schin * NV_APPEND - append <np> onto <mp>
8784887Schin * NV_MOVE - move <np> to <mp>
8794887Schin * NV_NOFREE - mark the new node as nofree
8804887Schin * NV_NODISC - discplines with funs non-zero will not be copied
8818462SApril.Chin@Sun.COM * NV_COMVAR - cloning a compound variable
8824887Schin */
nv_clone(Namval_t * np,Namval_t * mp,int flags)8834887Schin int nv_clone(Namval_t *np, Namval_t *mp, int flags)
8844887Schin {
8858462SApril.Chin@Sun.COM Namfun_t *fp, *fpnext;
8868462SApril.Chin@Sun.COM const char *val = mp->nvalue.cp;
8878462SApril.Chin@Sun.COM unsigned short flag = mp->nvflag;
8888462SApril.Chin@Sun.COM unsigned short size = mp->nvsize;
8898462SApril.Chin@Sun.COM for(fp=mp->nvfun; fp; fp=fpnext)
8908462SApril.Chin@Sun.COM {
8918462SApril.Chin@Sun.COM fpnext = fp->next;
8928462SApril.Chin@Sun.COM if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
8938462SApril.Chin@Sun.COM break;
8948462SApril.Chin@Sun.COM if(!(fp->nofree&1))
8958462SApril.Chin@Sun.COM free((void*)fp);
8968462SApril.Chin@Sun.COM }
8978462SApril.Chin@Sun.COM mp->nvfun = fp;
8984887Schin if(fp=np->nvfun)
8994887Schin {
9008462SApril.Chin@Sun.COM if(nv_isattr(mp,NV_EXPORT|NV_MINIMAL) == (NV_EXPORT|NV_MINIMAL))
9014887Schin {
9028462SApril.Chin@Sun.COM mp->nvenv = 0;
9038462SApril.Chin@Sun.COM nv_offattr(mp,NV_MINIMAL);
9044887Schin }
9058462SApril.Chin@Sun.COM if(!(flags&NV_COMVAR) && !nv_isattr(np,NV_MINIMAL) && np->nvenv && !(nv_isattr(mp,NV_MINIMAL)))
9068462SApril.Chin@Sun.COM mp->nvenv = np->nvenv;
9078462SApril.Chin@Sun.COM mp->nvflag &= NV_MINIMAL;
9088462SApril.Chin@Sun.COM mp->nvflag |= np->nvflag&~(NV_ARRAY|NV_MINIMAL|NV_NOFREE);
9098462SApril.Chin@Sun.COM flag = mp->nvflag;
9104887Schin clone_all_disc(np, mp, flags);
9114887Schin }
9124887Schin if(flags&NV_APPEND)
9134887Schin return(1);
9148462SApril.Chin@Sun.COM if(mp->nvsize == size)
9158462SApril.Chin@Sun.COM nv_setsize(mp,nv_size(np));
9168462SApril.Chin@Sun.COM if(mp->nvflag == flag)
9178462SApril.Chin@Sun.COM mp->nvflag = (np->nvflag&~(NV_MINIMAL))|(mp->nvflag&NV_MINIMAL);
918*12068SRoger.Faulkner@Oracle.COM if(nv_isattr(np,NV_EXPORT))
919*12068SRoger.Faulkner@Oracle.COM mp->nvflag |= (np->nvflag&NV_MINIMAL);
9208462SApril.Chin@Sun.COM if(mp->nvalue.cp==val && !nv_isattr(np,NV_INTEGER))
9218462SApril.Chin@Sun.COM {
9228462SApril.Chin@Sun.COM if(np->nvalue.cp && np->nvalue.cp!=Empty && (flags&NV_COMVAR) && !(flags&NV_MOVE))
9238462SApril.Chin@Sun.COM {
9248462SApril.Chin@Sun.COM if(size)
9258462SApril.Chin@Sun.COM mp->nvalue.cp = (char*)memdup(np->nvalue.cp,size);
9268462SApril.Chin@Sun.COM else
9278462SApril.Chin@Sun.COM mp->nvalue.cp = strdup(np->nvalue.cp);
9288462SApril.Chin@Sun.COM nv_offattr(mp,NV_NOFREE);
9298462SApril.Chin@Sun.COM }
9308462SApril.Chin@Sun.COM else if(!(mp->nvalue.cp = np->nvalue.cp))
9318462SApril.Chin@Sun.COM nv_offattr(mp,NV_NOFREE);
9328462SApril.Chin@Sun.COM }
9334887Schin if(flags&NV_MOVE)
9344887Schin {
9358462SApril.Chin@Sun.COM if(nv_isattr(np,NV_INTEGER))
9368462SApril.Chin@Sun.COM mp->nvalue.ip = np->nvalue.ip;
9374887Schin np->nvfun = 0;
9384887Schin np->nvalue.cp = 0;
9394887Schin if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(mp,NV_EXPORT))
940*12068SRoger.Faulkner@Oracle.COM {
941*12068SRoger.Faulkner@Oracle.COM mp->nvenv = np->nvenv;
9424887Schin np->nvenv = 0;
943*12068SRoger.Faulkner@Oracle.COM np->nvflag = 0;
944*12068SRoger.Faulkner@Oracle.COM }
945*12068SRoger.Faulkner@Oracle.COM else
946*12068SRoger.Faulkner@Oracle.COM np->nvflag &= NV_MINIMAL;
9474887Schin nv_setsize(np,0);
9484887Schin return(1);
9494887Schin }
9508462SApril.Chin@Sun.COM if(nv_isattr(np,NV_INTEGER) && mp->nvalue.ip!=np->nvalue.ip)
95110898Sroland.mainz@nrubsig.org {
9524887Schin mp->nvalue.ip = (int*)num_clone(np,(void*)np->nvalue.ip);
95310898Sroland.mainz@nrubsig.org nv_offattr(mp,NV_NOFREE);
95410898Sroland.mainz@nrubsig.org }
9554887Schin else if(flags&NV_NOFREE)
9564887Schin nv_onattr(np,NV_NOFREE);
9574887Schin return(1);
9584887Schin }
9594887Schin
9604887Schin /*
9614887Schin * The following discipline is for copy-on-write semantics
9624887Schin */
clone_getv(Namval_t * np,Namfun_t * handle)9634887Schin static char* clone_getv(Namval_t *np, Namfun_t *handle)
9644887Schin {
9654887Schin return(np->nvalue.np?nv_getval(np->nvalue.np):0);
9664887Schin }
9674887Schin
clone_getn(Namval_t * np,Namfun_t * handle)9684887Schin static Sfdouble_t clone_getn(Namval_t *np, Namfun_t *handle)
9694887Schin {
9704887Schin return(np->nvalue.np?nv_getnum(np->nvalue.np):0);
9714887Schin }
9724887Schin
clone_putv(Namval_t * np,const char * val,int flags,Namfun_t * handle)9734887Schin static void clone_putv(Namval_t *np,const char* val,int flags,Namfun_t *handle)
9744887Schin {
9754887Schin Namfun_t *dp = nv_stack(np,(Namfun_t*)0);
9764887Schin Namval_t *mp = np->nvalue.np;
9774887Schin if(!sh.subshell)
9784887Schin free((void*)dp);
9794887Schin if(val)
9804887Schin nv_clone(mp,np,NV_NOFREE);
9814887Schin np->nvalue.cp = 0;
9824887Schin nv_putval(np,val,flags);
9834887Schin }
9844887Schin
9854887Schin static const Namdisc_t clone_disc =
9864887Schin {
9874887Schin 0,
9884887Schin clone_putv,
9894887Schin clone_getv,
9904887Schin clone_getn
9914887Schin };
9924887Schin
nv_mkclone(Namval_t * mp)9934887Schin Namval_t *nv_mkclone(Namval_t *mp)
9944887Schin {
9954887Schin Namval_t *np;
9964887Schin Namfun_t *dp;
9974887Schin np = newof(0,Namval_t,1,0);
9984887Schin np->nvflag = mp->nvflag;
9994887Schin np->nvsize = mp->nvsize;
10004887Schin np->nvname = mp->nvname;
10014887Schin np->nvalue.np = mp;
10024887Schin np->nvflag = mp->nvflag;
10034887Schin dp = newof(0,Namfun_t,1,0);
10044887Schin dp->disc = &clone_disc;
10054887Schin nv_stack(np,dp);
10064887Schin dtinsert(nv_dict(sh.namespace),np);
10074887Schin return(np);
10084887Schin }
10094887Schin #endif /* SHOPT_NAMESPACE */
10104887Schin
nv_search(const char * name,Dt_t * root,int mode)10114887Schin Namval_t *nv_search(const char *name, Dt_t *root, int mode)
10124887Schin {
10134887Schin register Namval_t *np;
10144887Schin register Dt_t *dp = 0;
10154887Schin if(mode&HASH_NOSCOPE)
10164887Schin dp = dtview(root,0);
10174887Schin if(mode&HASH_BUCKET)
10184887Schin {
10194887Schin Namval_t *mp = (void*)name;
10204887Schin if(!(np = dtsearch(root,mp)) && (mode&NV_ADD))
10214887Schin name = nv_name(mp);
10224887Schin }
10234887Schin else
10244887Schin {
102510898Sroland.mainz@nrubsig.org if(*name=='.' && root==sh.var_tree && !dp)
10264887Schin root = sh.var_base;
10274887Schin np = dtmatch(root,(void*)name);
10284887Schin }
10294887Schin if(!np && (mode&NV_ADD))
10304887Schin {
10314887Schin if(sh.namespace && !(mode&HASH_NOSCOPE) && root==sh.var_tree)
10324887Schin root = nv_dict(sh.namespace);
10334887Schin else if(!dp && !(mode&HASH_NOSCOPE))
10344887Schin {
10354887Schin register Dt_t *next;
10364887Schin while(next=dtvnext(root))
10374887Schin root = next;
10384887Schin }
10394887Schin np = (Namval_t*)dtinsert(root,newnode(name));
10404887Schin }
10414887Schin if(dp)
10424887Schin dtview(root,dp);
10434887Schin return(np);
10444887Schin }
10454887Schin
10464887Schin /*
10474887Schin * finds function or builtin for given name and the discipline variable
10484887Schin * if var!=0 the variable pointer is returned and the built-in name
10494887Schin * is put onto the stack at the current offset.
10504887Schin * otherwise, a pointer to the builtin (variable or type) is returned
10514887Schin * and var contains the poiner to the variable
10524887Schin * if last==0 and first component of name is a reference, nv_bfsearch()
10534887Schin will return 0.
10544887Schin */
nv_bfsearch(const char * name,Dt_t * root,Namval_t ** var,char ** last)10554887Schin Namval_t *nv_bfsearch(const char *name, Dt_t *root, Namval_t **var, char **last)
10564887Schin {
10578462SApril.Chin@Sun.COM int c,offset = staktell();
10584887Schin register char *sp, *cp=0;
10594887Schin Namval_t *np, *nq;
10608462SApril.Chin@Sun.COM char *dname=0;
10614887Schin if(var)
10624887Schin *var = 0;
10634887Schin /* check for . in the name before = */
10644887Schin for(sp=(char*)name+1; *sp; sp++)
10654887Schin {
10664887Schin if(*sp=='=')
10674887Schin return(0);
10688462SApril.Chin@Sun.COM if(*sp=='[')
10698462SApril.Chin@Sun.COM {
10708462SApril.Chin@Sun.COM if(sp[-1]!='.')
10718462SApril.Chin@Sun.COM dname = sp;
10728462SApril.Chin@Sun.COM while(*sp=='[')
10738462SApril.Chin@Sun.COM {
10748462SApril.Chin@Sun.COM sp = nv_endsubscript((Namval_t*)0,(char*)sp,0);
10758462SApril.Chin@Sun.COM if(sp[-1]!=']')
10768462SApril.Chin@Sun.COM return(0);
10778462SApril.Chin@Sun.COM }
10788462SApril.Chin@Sun.COM if(*sp==0)
10798462SApril.Chin@Sun.COM break;
10808462SApril.Chin@Sun.COM if(*sp!='.')
10818462SApril.Chin@Sun.COM return(0);
10828462SApril.Chin@Sun.COM if(dname)
10838462SApril.Chin@Sun.COM {
10848462SApril.Chin@Sun.COM cp = dname;
10858462SApril.Chin@Sun.COM dname = sp+1;
10868462SApril.Chin@Sun.COM }
10878462SApril.Chin@Sun.COM }
10888462SApril.Chin@Sun.COM else if(*sp=='.')
10894887Schin cp = sp;
10904887Schin }
10914887Schin if(!cp)
10924887Schin return(var?nv_search(name,root,0):0);
10934887Schin stakputs(name);
10944887Schin stakputc(0);
10958462SApril.Chin@Sun.COM if(!dname)
10968462SApril.Chin@Sun.COM dname = cp+1;
10974887Schin cp = stakptr(offset) + (cp-name);
10984887Schin if(last)
10994887Schin *last = cp;
11008462SApril.Chin@Sun.COM c = *cp;
11014887Schin *cp = 0;
11028462SApril.Chin@Sun.COM nq=nv_open(stakptr(offset),0,NV_VARNAME|NV_ARRAY|NV_NOASSIGN|NV_NOADD|NV_NOFAIL);
11038462SApril.Chin@Sun.COM *cp = c;
11044887Schin if(!nq)
11054887Schin {
11064887Schin np = 0;
11074887Schin goto done;
11084887Schin }
11094887Schin if(!var)
11104887Schin {
11114887Schin np = nq;
11124887Schin goto done;
11134887Schin }
11144887Schin *var = nq;
11158462SApril.Chin@Sun.COM if(c=='[')
11168462SApril.Chin@Sun.COM nv_endsubscript(nq, cp,NV_NOADD);
11178462SApril.Chin@Sun.COM return((Namval_t*)nv_setdisc(nq,dname,nq,(Namfun_t*)nq));
11184887Schin done:
11194887Schin stakseek(offset);
11204887Schin return(np);
11214887Schin }
11224887Schin
11234887Schin /*
11248462SApril.Chin@Sun.COM * add or replace built-in version of command corresponding to <path>
11254887Schin * The <bltin> argument is a pointer to the built-in
11264887Schin * if <extra>==1, the built-in will be deleted
11274887Schin * Special builtins cannot be added or deleted return failure
11284887Schin * The return value for adding builtins is a pointer to the node or NULL on
11294887Schin * failure. For delete NULL means success and the node that cannot be
11304887Schin * deleted is returned on failure.
11314887Schin */
sh_addbuiltin(const char * path,int (* bltin)(int,char * [],void *),void * extra)11324887Schin Namval_t *sh_addbuiltin(const char *path, int (*bltin)(int, char*[],void*),void *extra)
11334887Schin {
11348462SApril.Chin@Sun.COM register const char *name = path_basename(path);
11358462SApril.Chin@Sun.COM char *cp;
11368462SApril.Chin@Sun.COM register Namval_t *np, *nq=0;
11378462SApril.Chin@Sun.COM int offset=staktell();
11384887Schin if(name==path && (nq=nv_bfsearch(name,sh.bltin_tree,(Namval_t**)0,&cp)))
11394887Schin path = name = stakptr(offset);
11404887Schin if(np = nv_search(path,sh.bltin_tree,0))
11414887Schin {
11424887Schin /* exists without a path */
11434887Schin if(extra == (void*)1)
11444887Schin {
11454887Schin if(np->nvfun && !nv_isattr(np,NV_NOFREE))
11464887Schin free((void*)np->nvfun);
11474887Schin dtdelete(sh.bltin_tree,np);
11484887Schin return(0);
11494887Schin }
11504887Schin if(!bltin)
11514887Schin return(np);
11524887Schin }
11534887Schin else for(np=(Namval_t*)dtfirst(sh.bltin_tree);np;np=(Namval_t*)dtnext(sh.bltin_tree,np))
11544887Schin {
11554887Schin if(strcmp(name,path_basename(nv_name(np))))
11564887Schin continue;
11574887Schin /* exists probably with different path so delete it */
11584887Schin if(strcmp(path,nv_name(np)))
11594887Schin {
11604887Schin if(nv_isattr(np,BLT_SPC))
11614887Schin return(np);
11624887Schin if(!bltin)
11634887Schin bltin = np->nvalue.bfp;
11644887Schin if(np->nvenv)
11654887Schin dtdelete(sh.bltin_tree,np);
11664887Schin if(extra == (void*)1)
11674887Schin return(0);
11684887Schin np = 0;
11694887Schin }
11704887Schin break;
11714887Schin }
11724887Schin if(!np && !(np = nv_search(path,sh.bltin_tree,bltin?NV_ADD:0)))
11734887Schin return(0);
11744887Schin if(nv_isattr(np,BLT_SPC))
11758462SApril.Chin@Sun.COM {
11768462SApril.Chin@Sun.COM if(extra)
11778462SApril.Chin@Sun.COM np->nvfun = (Namfun_t*)extra;
11784887Schin return(np);
11798462SApril.Chin@Sun.COM }
11804887Schin np->nvenv = 0;
11814887Schin np->nvfun = 0;
11824887Schin if(bltin)
11834887Schin {
11844887Schin np->nvalue.bfp = bltin;
11854887Schin nv_onattr(np,NV_BLTIN|NV_NOFREE);
11864887Schin np->nvfun = (Namfun_t*)extra;
11874887Schin }
11884887Schin if(nq)
11894887Schin {
11904887Schin cp=nv_setdisc(nq,cp+1,np,(Namfun_t*)nq);
11914887Schin nv_close(nq);
11924887Schin if(!cp)
11934887Schin errormsg(SH_DICT,ERROR_exit(1),e_baddisc,name);
11944887Schin }
11954887Schin if(extra == (void*)1)
11964887Schin return(0);
11974887Schin return(np);
11984887Schin }
11994887Schin
12004887Schin #undef nv_stack
nv_stack(register Namval_t * np,register Namfun_t * fp)12014887Schin extern Namfun_t *nv_stack(register Namval_t *np, register Namfun_t* fp)
12024887Schin {
12034887Schin return(nv_disc(np,fp,0));
12044887Schin }
12054887Schin
12064887Schin struct table
12074887Schin {
12084887Schin Namfun_t fun;
12094887Schin Namval_t *parent;
12104887Schin Shell_t *shp;
12114887Schin Dt_t *dict;
12124887Schin };
12134887Schin
next_table(register Namval_t * np,Dt_t * root,Namfun_t * fp)12144887Schin static Namval_t *next_table(register Namval_t* np, Dt_t *root,Namfun_t *fp)
12154887Schin {
12164887Schin struct table *tp = (struct table *)fp;
12174887Schin if(root)
12184887Schin return((Namval_t*)dtnext(root,np));
12194887Schin else
12204887Schin return((Namval_t*)dtfirst(tp->dict));
12214887Schin }
12224887Schin
create_table(Namval_t * np,const char * name,int flags,Namfun_t * fp)12234887Schin static Namval_t *create_table(Namval_t *np,const char *name,int flags,Namfun_t *fp)
12244887Schin {
12254887Schin struct table *tp = (struct table *)fp;
12264887Schin tp->shp->last_table = np;
12274887Schin return(nv_create(name, tp->dict, flags, fp));
12284887Schin }
12294887Schin
clone_table(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)12304887Schin static Namfun_t *clone_table(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
12314887Schin {
12324887Schin struct table *tp = (struct table*)fp;
12338462SApril.Chin@Sun.COM struct table *ntp = (struct table*)nv_clone_disc(fp,0);
12344887Schin Dt_t *oroot=tp->dict,*nroot=dtopen(&_Nvdisc,Dtoset);
12354887Schin if(!nroot)
12364887Schin return(0);
12374887Schin memcpy((void*)ntp,(void*)fp,sizeof(struct table));
12384887Schin ntp->dict = nroot;
12394887Schin ntp->parent = nv_lastdict();
12404887Schin for(np=(Namval_t*)dtfirst(oroot);np;np=(Namval_t*)dtnext(oroot,np))
12414887Schin {
12424887Schin mp = (Namval_t*)dtinsert(nroot,newnode(np->nvname));
12434887Schin nv_clone(np,mp,flags);
12444887Schin }
12454887Schin return(&ntp->fun);
12464887Schin }
12474887Schin
put_table(register Namval_t * np,const char * val,int flags,Namfun_t * fp)12484887Schin static void put_table(register Namval_t* np, const char* val, int flags, Namfun_t* fp)
12494887Schin {
12504887Schin register Dt_t *root = ((struct table*)fp)->dict;
12514887Schin register Namval_t *nq, *mp;
12524887Schin Namarr_t *ap;
12534887Schin nv_putv(np,val,flags,fp);
12544887Schin if(val)
12554887Schin return;
12564887Schin if(nv_isarray(np) && (ap=nv_arrayptr(np)) && array_elem(ap))
12574887Schin return;
12584887Schin for(mp=(Namval_t*)dtfirst(root);mp;mp=nq)
12594887Schin {
12604887Schin _nv_unset(mp,flags);
12614887Schin nq = (Namval_t*)dtnext(root,mp);
12624887Schin dtdelete(root,mp);
12634887Schin free((void*)mp);
12644887Schin }
12654887Schin dtclose(root);
12668462SApril.Chin@Sun.COM if(!(fp->nofree&1))
12674887Schin free((void*)fp);
12684887Schin }
12694887Schin
12704887Schin /*
12714887Schin * return space separated list of names of variables in given tree
12724887Schin */
get_table(Namval_t * np,Namfun_t * fp)12734887Schin static char *get_table(Namval_t *np, Namfun_t *fp)
12744887Schin {
12754887Schin register Dt_t *root = ((struct table*)fp)->dict;
12764887Schin static Sfio_t *out;
12774887Schin register int first=1;
12784887Schin register Dt_t *base = dtview(root,0);
12794887Schin if(out)
12804887Schin sfseek(out,(Sfoff_t)0,SEEK_SET);
12814887Schin else
12824887Schin out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
12834887Schin for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
12844887Schin {
12854887Schin if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
12864887Schin {
12874887Schin if(!first)
12884887Schin sfputc(out,' ');
12894887Schin else
12904887Schin first = 0;
12914887Schin sfputr(out,np->nvname,-1);
12924887Schin }
12934887Schin }
12944887Schin sfputc(out,0);
12954887Schin if(base)
12964887Schin dtview(root,base);
12974887Schin return((char*)out->_data);
12984887Schin }
12994887Schin
13004887Schin static const Namdisc_t table_disc =
13014887Schin {
13024887Schin sizeof(struct table),
13034887Schin put_table,
13044887Schin get_table,
13054887Schin 0,
13064887Schin 0,
13074887Schin create_table,
13084887Schin clone_table,
13094887Schin 0,
13104887Schin next_table,
13114887Schin };
13124887Schin
nv_parent(Namval_t * np)13138462SApril.Chin@Sun.COM Namval_t *nv_parent(Namval_t *np)
13148462SApril.Chin@Sun.COM {
13158462SApril.Chin@Sun.COM struct table *tp = (struct table *)nv_hasdisc(np,&table_disc);
13168462SApril.Chin@Sun.COM if(tp)
13178462SApril.Chin@Sun.COM return(tp->parent);
13188462SApril.Chin@Sun.COM return(0);
13198462SApril.Chin@Sun.COM }
13208462SApril.Chin@Sun.COM
nv_dict(Namval_t * np)13214887Schin Dt_t *nv_dict(Namval_t* np)
13224887Schin {
13234887Schin struct table *tp = (struct table*)nv_hasdisc(np,&table_disc);
13244887Schin if(tp)
13254887Schin return(tp->dict);
13264887Schin np = sh.last_table;
13274887Schin while(np)
13284887Schin {
13294887Schin if(tp = (struct table*)nv_hasdisc(np,&table_disc))
13304887Schin return(tp->dict);
13314887Schin #if 0
13324887Schin np = nv_create(np,(const char*)0, NV_FIRST, (Namfun_t*)0);
13338462SApril.Chin@Sun.COM #else
13348462SApril.Chin@Sun.COM break;
13354887Schin #endif
13364887Schin }
13374887Schin return(sh.var_tree);
13384887Schin }
13394887Schin
13404887Schin /*
13414887Schin * create a mountable name-value pair tree
13424887Schin */
nv_mount(Namval_t * np,const char * name,Dt_t * dict)13434887Schin Namval_t *nv_mount(Namval_t *np, const char *name, Dt_t *dict)
13444887Schin {
13454887Schin Namval_t *mp, *pp=0;
13464887Schin struct table *tp = newof((struct table*)0, struct table,1,0);
13474887Schin if(name)
13484887Schin {
13494887Schin if(nv_istable(np))
13504887Schin pp = np;
13514887Schin else
13524887Schin pp = nv_lastdict();
13534887Schin }
13544887Schin if(!(tp = newof((struct table*)0, struct table,1,0)))
13554887Schin return(0);
13564887Schin if(name)
13574887Schin {
13584887Schin Namfun_t *fp = pp->nvfun;
13594887Schin mp = (*fp->disc->createf)(pp,name,0,fp);
13604887Schin }
13614887Schin else
13624887Schin mp = np;
13634887Schin if(!nv_isnull(mp))
13644887Schin nv_unset(mp);
13654887Schin tp->shp = sh_getinterp();
13664887Schin tp->dict = dict;
13674887Schin tp->parent = pp;
13684887Schin tp->fun.disc = &table_disc;
13694887Schin nv_onattr(mp,NV_TABLE);
13708462SApril.Chin@Sun.COM nv_disc(mp, &tp->fun, NV_FIRST);
13714887Schin return(mp);
13724887Schin }
13734887Schin
nv_discfun(int which)13744887Schin const Namdisc_t *nv_discfun(int which)
13754887Schin {
13764887Schin switch(which)
13774887Schin {
13784887Schin case NV_DCADD:
13794887Schin return(&Nv_bdisc);
13804887Schin case NV_DCRESTRICT:
13814887Schin return(&RESTRICTED_disc);
13824887Schin }
13834887Schin return(0);
13844887Schin }
13854887Schin
nv_hasget(Namval_t * np)1386*12068SRoger.Faulkner@Oracle.COM int nv_hasget(Namval_t *np)
1387*12068SRoger.Faulkner@Oracle.COM {
1388*12068SRoger.Faulkner@Oracle.COM register Namfun_t *fp;
1389*12068SRoger.Faulkner@Oracle.COM for(fp=np->nvfun; fp; fp=fp->next)
1390*12068SRoger.Faulkner@Oracle.COM {
1391*12068SRoger.Faulkner@Oracle.COM if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
1392*12068SRoger.Faulkner@Oracle.COM continue;
1393*12068SRoger.Faulkner@Oracle.COM return(1);
1394*12068SRoger.Faulkner@Oracle.COM }
1395*12068SRoger.Faulkner@Oracle.COM return(0);
1396*12068SRoger.Faulkner@Oracle.COM }
1397