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 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 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 */ 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); 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 */ 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 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 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 */ 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 */ 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 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 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 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 */ 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 */ 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 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 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 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 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 */ 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 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 */ 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 */ 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 */ 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 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 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 */ 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 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 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