1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * David Korn <dgk@research.att.com> * 18*4887Schin * * 19*4887Schin ***********************************************************************/ 20*4887Schin #pragma prototyped 21*4887Schin /* 22*4887Schin * AT&T Labs 23*4887Schin * 24*4887Schin */ 25*4887Schin 26*4887Schin #include "defs.h" 27*4887Schin #include "variables.h" 28*4887Schin #include "builtins.h" 29*4887Schin #include "path.h" 30*4887Schin 31*4887Schin static const char *discnames[] = { "get", "set", "append", "unset", 0 }; 32*4887Schin 33*4887Schin int nv_compare(Dt_t* dict, Void_t *sp, Void_t *dp, Dtdisc_t *disc) 34*4887Schin { 35*4887Schin if(sp==dp) 36*4887Schin return(0); 37*4887Schin return(strcmp((char*)sp,(char*)dp)); 38*4887Schin } 39*4887Schin 40*4887Schin /* 41*4887Schin * call the next getval function in the chain 42*4887Schin */ 43*4887Schin char *nv_getv(Namval_t *np, register Namfun_t *nfp) 44*4887Schin { 45*4887Schin register Namfun_t *fp; 46*4887Schin register char *cp; 47*4887Schin if((fp = nfp) != NIL(Namfun_t*) && !nv_local) 48*4887Schin fp = nfp = nfp->next; 49*4887Schin nv_local=0; 50*4887Schin for(; fp; fp=fp->next) 51*4887Schin { 52*4887Schin if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval)) 53*4887Schin continue; 54*4887Schin if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np)) 55*4887Schin break; 56*4887Schin } 57*4887Schin if(fp && fp->disc->getval) 58*4887Schin cp = (*fp->disc->getval)(np,fp); 59*4887Schin else if(fp && fp->disc->getnum) 60*4887Schin { 61*4887Schin sfprintf(sh.strbuf,"%.*Lg",12,(*fp->disc->getnum)(np,fp)); 62*4887Schin cp = sfstruse(sh.strbuf); 63*4887Schin } 64*4887Schin else 65*4887Schin { 66*4887Schin nv_local=1; 67*4887Schin cp = nv_getval(np); 68*4887Schin } 69*4887Schin return(cp); 70*4887Schin } 71*4887Schin 72*4887Schin /* 73*4887Schin * call the next getnum function in the chain 74*4887Schin */ 75*4887Schin Sfdouble_t nv_getn(Namval_t *np, register Namfun_t *nfp) 76*4887Schin { 77*4887Schin register Namfun_t *fp; 78*4887Schin register Sfdouble_t d=0; 79*4887Schin char *str; 80*4887Schin if((fp = nfp) != NIL(Namfun_t*) && !nv_local) 81*4887Schin fp = nfp = nfp->next; 82*4887Schin nv_local=0; 83*4887Schin for(; fp; fp=fp->next) 84*4887Schin { 85*4887Schin if(!fp->disc->getnum && !fp->disc->getval) 86*4887Schin continue; 87*4887Schin if(!fp->disc->getnum && nv_isattr(np,NV_INTEGER)) 88*4887Schin continue; 89*4887Schin if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np)) 90*4887Schin break; 91*4887Schin } 92*4887Schin if(fp && fp->disc->getnum) 93*4887Schin d = (*fp->disc->getnum)(np,fp); 94*4887Schin else if(nv_isattr(np,NV_INTEGER)) 95*4887Schin { 96*4887Schin nv_local = 1; 97*4887Schin d = nv_getnum(np); 98*4887Schin } 99*4887Schin else 100*4887Schin { 101*4887Schin if(fp && fp->disc->getval) 102*4887Schin str = (*fp->disc->getval)(np,fp); 103*4887Schin else 104*4887Schin str = nv_getv(np,fp?fp:nfp); 105*4887Schin if(str && *str) 106*4887Schin { 107*4887Schin while(*str=='0') 108*4887Schin str++; 109*4887Schin d = sh_arith(str); 110*4887Schin } 111*4887Schin } 112*4887Schin return(d); 113*4887Schin } 114*4887Schin 115*4887Schin /* 116*4887Schin * call the next assign function in the chain 117*4887Schin */ 118*4887Schin void nv_putv(Namval_t *np, const char *value, int flags, register Namfun_t *nfp) 119*4887Schin { 120*4887Schin register Namfun_t *fp, *fpnext; 121*4887Schin if((fp=nfp) != NIL(Namfun_t*) && !nv_local) 122*4887Schin fp = nfp = nfp->next; 123*4887Schin nv_local=0; 124*4887Schin for(; fp; fp=fpnext) 125*4887Schin { 126*4887Schin fpnext = fp->next; 127*4887Schin if(!fp->disc->putval) 128*4887Schin { 129*4887Schin if(!value) 130*4887Schin { 131*4887Schin nv_disc(np,fp,NV_POP); 132*4887Schin if(!fp->nofree) 133*4887Schin free((void*)fp); 134*4887Schin } 135*4887Schin continue; 136*4887Schin } 137*4887Schin if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np)) 138*4887Schin break; 139*4887Schin } 140*4887Schin if(fp && fp->disc->putval) 141*4887Schin (*fp->disc->putval)(np,value, flags, fp); 142*4887Schin else 143*4887Schin { 144*4887Schin nv_local=1; 145*4887Schin if(value) 146*4887Schin nv_putval(np, value, flags); 147*4887Schin else 148*4887Schin _nv_unset(np, flags&NV_RDONLY); 149*4887Schin } 150*4887Schin } 151*4887Schin 152*4887Schin #if 0 153*4887Schin /* 154*4887Schin * node creation discipline 155*4887Schin */ 156*4887Schin Namval_t *nv_create(register Namval_t* np,const char *name,int flag,register Namfun_t *fp) 157*4887Schin { 158*4887Schin fp = fp?fp->next:np->nvfun; 159*4887Schin while(fp && fp->disc && !fp->disc->createf) 160*4887Schin fp = fp->next; 161*4887Schin if(fp && fp->disc->createf) 162*4887Schin return((*fp->disc->createf)(np,name,flag,fp)); 163*4887Schin return(NIL(Namval_t*)); 164*4887Schin } 165*4887Schin #endif 166*4887Schin 167*4887Schin #define LOOKUP 0 168*4887Schin #define ASSIGN 1 169*4887Schin #define APPEND 2 170*4887Schin #define UNASSIGN 3 171*4887Schin #define BLOCKED ((Namval_t*)&nv_local) 172*4887Schin 173*4887Schin struct vardisc 174*4887Schin { 175*4887Schin Namfun_t fun; 176*4887Schin Namval_t *disc[4]; 177*4887Schin }; 178*4887Schin 179*4887Schin struct blocked 180*4887Schin { 181*4887Schin struct blocked *next; 182*4887Schin Namval_t *np; 183*4887Schin int flags; 184*4887Schin void *sub; 185*4887Schin int isub; 186*4887Schin }; 187*4887Schin 188*4887Schin static struct blocked *blist; 189*4887Schin 190*4887Schin #define isblocked(bp,type) ((bp)->flags & (1<<(type))) 191*4887Schin #define block(bp,type) ((bp)->flags |= (1<<(type))) 192*4887Schin #define unblock(bp,type) ((bp)->flags &= ~(1<<(type))) 193*4887Schin 194*4887Schin /* 195*4887Schin * returns pointer to blocking structure 196*4887Schin */ 197*4887Schin static struct blocked *block_info(Namval_t *np, struct blocked *pp) 198*4887Schin { 199*4887Schin register struct blocked *bp; 200*4887Schin void *sub=0; 201*4887Schin int isub=0; 202*4887Schin if(nv_isarray(np) && (isub=nv_aindex(np)) < 0) 203*4887Schin sub = nv_associative(np,(const char*)0,NV_ACURRENT); 204*4887Schin for(bp=blist ; bp; bp=bp->next) 205*4887Schin { 206*4887Schin if(bp->np==np && bp->sub==sub && bp->isub==isub) 207*4887Schin return(bp); 208*4887Schin } 209*4887Schin if(pp) 210*4887Schin { 211*4887Schin pp->np = np; 212*4887Schin pp->flags = 0; 213*4887Schin pp->isub = isub; 214*4887Schin pp->sub = sub; 215*4887Schin pp->next = blist; 216*4887Schin blist = pp; 217*4887Schin } 218*4887Schin return(pp); 219*4887Schin } 220*4887Schin 221*4887Schin static void block_done(struct blocked *bp) 222*4887Schin { 223*4887Schin blist = bp = bp->next; 224*4887Schin if(bp && (bp->isub>=0 || bp->sub)) 225*4887Schin nv_putsub(bp->np, bp->sub,(bp->isub<0?0:bp->isub)|ARRAY_SETSUB); 226*4887Schin } 227*4887Schin 228*4887Schin /* 229*4887Schin * free discipline if no more discipline functions 230*4887Schin */ 231*4887Schin static void chktfree(register Namval_t *np, register struct vardisc *vp) 232*4887Schin { 233*4887Schin register int n; 234*4887Schin for(n=0; n< sizeof(vp->disc)/sizeof(*vp->disc); n++) 235*4887Schin { 236*4887Schin if(vp->disc[n]) 237*4887Schin break; 238*4887Schin } 239*4887Schin if(n>=sizeof(vp->disc)/sizeof(*vp->disc)) 240*4887Schin { 241*4887Schin /* no disc left so pop */ 242*4887Schin Namfun_t *fp; 243*4887Schin if((fp=nv_stack(np, NIL(Namfun_t*))) && !fp->nofree) 244*4887Schin free((void*)fp); 245*4887Schin } 246*4887Schin } 247*4887Schin 248*4887Schin /* 249*4887Schin * This function performs an assignment disc on the given node <np> 250*4887Schin */ 251*4887Schin static void assign(Namval_t *np,const char* val,int flags,Namfun_t *handle) 252*4887Schin { 253*4887Schin int type = (flags&NV_APPEND)?APPEND:ASSIGN; 254*4887Schin register struct vardisc *vp = (struct vardisc*)handle; 255*4887Schin register Namval_t *nq = vp->disc[type]; 256*4887Schin struct blocked block, *bp = block_info(np, &block); 257*4887Schin Namval_t node; 258*4887Schin if(val || isblocked(bp,type)) 259*4887Schin { 260*4887Schin if(!nq || isblocked(bp,type)) 261*4887Schin { 262*4887Schin nv_putv(np,val,flags,handle); 263*4887Schin goto done; 264*4887Schin } 265*4887Schin node = *SH_VALNOD; 266*4887Schin if(!nv_isnull(SH_VALNOD)) 267*4887Schin { 268*4887Schin nv_onattr(SH_VALNOD,NV_NOFREE); 269*4887Schin nv_unset(SH_VALNOD); 270*4887Schin } 271*4887Schin if(flags&NV_INTEGER) 272*4887Schin nv_onattr(SH_VALNOD,(flags&(NV_INTEGER|NV_LONG|NV_DOUBLE|NV_EXPNOTE|NV_SHORT))); 273*4887Schin nv_putval(SH_VALNOD, val, (flags&NV_INTEGER)?flags:NV_NOFREE); 274*4887Schin } 275*4887Schin else 276*4887Schin nq = vp->disc[type=UNASSIGN]; 277*4887Schin if(nq && !isblocked(bp,type)) 278*4887Schin { 279*4887Schin int bflag; 280*4887Schin block(bp,type); 281*4887Schin if (type==APPEND && (bflag= !isblocked(bp,LOOKUP))) 282*4887Schin block(bp,LOOKUP); 283*4887Schin sh_fun(nq,np,(char**)0); 284*4887Schin unblock(bp,type); 285*4887Schin if(bflag) 286*4887Schin unblock(bp,LOOKUP); 287*4887Schin if(!vp->disc[type]) 288*4887Schin chktfree(np,vp); 289*4887Schin } 290*4887Schin if(val) 291*4887Schin { 292*4887Schin register char *cp; 293*4887Schin Sfdouble_t d; 294*4887Schin if(nv_isnull(SH_VALNOD)) 295*4887Schin cp=0; 296*4887Schin else if(flags&NV_INTEGER) 297*4887Schin { 298*4887Schin d = nv_getnum(SH_VALNOD); 299*4887Schin cp = (char*)(&d); 300*4887Schin flags |= (NV_LONG|NV_DOUBLE); 301*4887Schin flags &= ~NV_SHORT; 302*4887Schin } 303*4887Schin else 304*4887Schin cp = nv_getval(SH_VALNOD); 305*4887Schin if(cp) 306*4887Schin nv_putv(np,cp,flags|NV_RDONLY,handle); 307*4887Schin nv_unset(SH_VALNOD); 308*4887Schin /* restore everything but the nvlink field */ 309*4887Schin memcpy(&SH_VALNOD->nvname, &node.nvname, sizeof(node)-sizeof(node.nvlink)); 310*4887Schin } 311*4887Schin else if(sh_isstate(SH_INIT)) 312*4887Schin { 313*4887Schin /* don't free functions during reinitialization */ 314*4887Schin nv_putv(np,val,flags,handle); 315*4887Schin } 316*4887Schin else if(!nq || !isblocked(bp,type)) 317*4887Schin { 318*4887Schin Dt_t *root = sh_subfuntree(1); 319*4887Schin int n; 320*4887Schin Namarr_t *ap; 321*4887Schin block(bp,type); 322*4887Schin nv_putv(np, val, flags, handle); 323*4887Schin if(nv_isarray(np) && (ap=nv_arrayptr(np)) && ap->nelem>0) 324*4887Schin goto done; 325*4887Schin for(n=0; n < sizeof(vp->disc)/sizeof(*vp->disc); n++) 326*4887Schin { 327*4887Schin if((nq=vp->disc[n]) && !nv_isattr(nq,NV_NOFREE)) 328*4887Schin { 329*4887Schin nv_unset(nq); 330*4887Schin dtdelete(root,nq); 331*4887Schin } 332*4887Schin } 333*4887Schin unblock(bp,type); 334*4887Schin nv_disc(np,handle,NV_POP); 335*4887Schin if(!handle->nofree) 336*4887Schin free(handle); 337*4887Schin } 338*4887Schin done: 339*4887Schin if(bp== &block) 340*4887Schin block_done(bp); 341*4887Schin } 342*4887Schin 343*4887Schin /* 344*4887Schin * This function executes a lookup disc and then performs 345*4887Schin * the lookup on the given node <np> 346*4887Schin */ 347*4887Schin static char* lookup(Namval_t *np, Namfun_t *handle) 348*4887Schin { 349*4887Schin register struct vardisc *vp = (struct vardisc*)handle; 350*4887Schin struct blocked block, *bp = block_info(np, &block); 351*4887Schin register Namval_t *nq = vp->disc[LOOKUP]; 352*4887Schin register char *cp=0; 353*4887Schin Namval_t node; 354*4887Schin if(nq && !isblocked(bp,LOOKUP)) 355*4887Schin { 356*4887Schin node = *SH_VALNOD; 357*4887Schin if(!nv_isnull(SH_VALNOD)) 358*4887Schin { 359*4887Schin nv_onattr(SH_VALNOD,NV_NOFREE); 360*4887Schin nv_unset(SH_VALNOD); 361*4887Schin } 362*4887Schin block(bp,LOOKUP); 363*4887Schin sh_fun(nq,np,(char**)0); 364*4887Schin unblock(bp,LOOKUP); 365*4887Schin if(!vp->disc[LOOKUP]) 366*4887Schin chktfree(np,vp); 367*4887Schin cp = nv_getval(SH_VALNOD); 368*4887Schin if(!nv_isnull(&node)) 369*4887Schin { 370*4887Schin if(cp) 371*4887Schin cp = strdup(cp); 372*4887Schin /* restore everything but the nvlink field */ 373*4887Schin memcpy(&SH_VALNOD->nvname, &node.nvname, sizeof(node)-sizeof(node.nvlink)); 374*4887Schin } 375*4887Schin } 376*4887Schin if(!cp) 377*4887Schin cp = nv_getv(np,handle); 378*4887Schin if(bp== &block) 379*4887Schin block_done(bp); 380*4887Schin return(cp); 381*4887Schin } 382*4887Schin 383*4887Schin static const Namdisc_t shdisc = 384*4887Schin { 385*4887Schin sizeof(struct vardisc), 386*4887Schin assign, 387*4887Schin lookup 388*4887Schin }; 389*4887Schin 390*4887Schin /* 391*4887Schin * Set disc on given <event> to <action> 392*4887Schin * If action==np, the current disc is returned 393*4887Schin * A null return value indicates that no <event> is known for <np> 394*4887Schin * If <event> is NULL, then return the event name after <action> 395*4887Schin * If <event> is NULL, and <action> is NULL, return the first event 396*4887Schin */ 397*4887Schin char *nv_setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp) 398*4887Schin { 399*4887Schin register struct vardisc *vp = (struct vardisc*)np->nvfun; 400*4887Schin register int type; 401*4887Schin char *empty = ""; 402*4887Schin if(np == (Namval_t*)fp) 403*4887Schin { 404*4887Schin register const char *name; 405*4887Schin register int getname=0; 406*4887Schin /* top level call, check for get/set */ 407*4887Schin if(!event) 408*4887Schin { 409*4887Schin if(!action) 410*4887Schin return((char*)discnames[0]); 411*4887Schin getname=1; 412*4887Schin event = (char*)action; 413*4887Schin } 414*4887Schin for(type=0; name=discnames[type]; type++) 415*4887Schin { 416*4887Schin if(strcmp(event,name)==0) 417*4887Schin break; 418*4887Schin } 419*4887Schin if(getname) 420*4887Schin { 421*4887Schin event = 0; 422*4887Schin if(name && !(name = discnames[++type])) 423*4887Schin action = 0; 424*4887Schin } 425*4887Schin if(!name) 426*4887Schin { 427*4887Schin if((fp=(Namfun_t*)vp) && fp->disc->setdisc) 428*4887Schin return((*fp->disc->setdisc)(np,event,action,fp)); 429*4887Schin } 430*4887Schin else if(getname) 431*4887Schin return((char*)name); 432*4887Schin } 433*4887Schin if(!fp) 434*4887Schin return(NIL(char*)); 435*4887Schin if(np != (Namval_t*)fp) 436*4887Schin { 437*4887Schin /* not the top level */ 438*4887Schin while(fp = fp->next) 439*4887Schin { 440*4887Schin if(fp->disc->setdisc) 441*4887Schin return((*fp->disc->setdisc)(np,event,action,fp)); 442*4887Schin } 443*4887Schin return(NIL(char*)); 444*4887Schin } 445*4887Schin /* Handle GET/SET/APPEND/UNSET disc */ 446*4887Schin if(vp && vp->fun.disc->putval!=assign) 447*4887Schin vp = 0; 448*4887Schin if(!vp) 449*4887Schin { 450*4887Schin if(action==np) 451*4887Schin return((char*)action); 452*4887Schin if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,0))) 453*4887Schin return(0); 454*4887Schin vp->fun.disc = &shdisc; 455*4887Schin nv_stack(np, (Namfun_t*)vp); 456*4887Schin } 457*4887Schin if(action==np) 458*4887Schin { 459*4887Schin action = vp->disc[type]; 460*4887Schin empty = 0; 461*4887Schin } 462*4887Schin else if(action) 463*4887Schin vp->disc[type] = action; 464*4887Schin else 465*4887Schin { 466*4887Schin struct blocked *bp; 467*4887Schin action = vp->disc[type]; 468*4887Schin vp->disc[type] = 0; 469*4887Schin if(!(bp=block_info(np,(struct blocked*)0)) || !isblocked(bp,UNASSIGN)) 470*4887Schin chktfree(np,vp); 471*4887Schin } 472*4887Schin return(action?(char*)action:empty); 473*4887Schin } 474*4887Schin 475*4887Schin 476*4887Schin /* 477*4887Schin * Set disc on given <event> to <action> 478*4887Schin * If action==np, the current disc is returned 479*4887Schin * A null return value indicates that no <event> is known for <np> 480*4887Schin * If <event> is NULL, then return the event name after <action> 481*4887Schin * If <event> is NULL, and <action> is NULL, return the first event 482*4887Schin */ 483*4887Schin static char *setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp) 484*4887Schin { 485*4887Schin register Nambfun_t *vp = (Nambfun_t*)fp; 486*4887Schin register int type,getname=0; 487*4887Schin register const char *name; 488*4887Schin const char **discnames = vp->bnames; 489*4887Schin /* top level call, check for discipline match */ 490*4887Schin if(!event) 491*4887Schin { 492*4887Schin if(!action) 493*4887Schin return((char*)discnames[0]); 494*4887Schin getname=1; 495*4887Schin event = (char*)action; 496*4887Schin } 497*4887Schin for(type=0; name=discnames[type]; type++) 498*4887Schin { 499*4887Schin if(strcmp(event,name)==0) 500*4887Schin break; 501*4887Schin } 502*4887Schin if(getname) 503*4887Schin { 504*4887Schin event = 0; 505*4887Schin if(name && !(name = discnames[++type])) 506*4887Schin action = 0; 507*4887Schin } 508*4887Schin if(!name) 509*4887Schin return(nv_setdisc(np,event,action,fp)); 510*4887Schin else if(getname) 511*4887Schin return((char*)name); 512*4887Schin /* Handle the disciplines */ 513*4887Schin if(action==np) 514*4887Schin action = vp->bltins[type]; 515*4887Schin else if(action) 516*4887Schin vp->bltins[type] = action; 517*4887Schin else 518*4887Schin { 519*4887Schin action = vp->bltins[type]; 520*4887Schin vp->bltins[type] = 0; 521*4887Schin } 522*4887Schin return(action?(char*)action:""); 523*4887Schin } 524*4887Schin 525*4887Schin static void putdisc(Namval_t* np, const char* val, int flag, Namfun_t* fp) 526*4887Schin { 527*4887Schin nv_putv(np,val,flag,fp); 528*4887Schin if(!val) 529*4887Schin { 530*4887Schin register Nambfun_t *vp = (Nambfun_t*)fp; 531*4887Schin register int i; 532*4887Schin for(i=0; vp->bnames[i]; i++) 533*4887Schin { 534*4887Schin register Namval_t *mp; 535*4887Schin if((mp=vp->bltins[i]) && !nv_isattr(mp,NV_NOFREE)) 536*4887Schin { 537*4887Schin if(is_abuiltin(mp)) 538*4887Schin { 539*4887Schin if(mp->nvfun && !nv_isattr(mp,NV_NOFREE)) 540*4887Schin free((void*)mp->nvfun); 541*4887Schin dtdelete(sh.bltin_tree,mp); 542*4887Schin free((void*)mp); 543*4887Schin } 544*4887Schin } 545*4887Schin } 546*4887Schin nv_disc(np,fp,NV_POP); 547*4887Schin if(!fp->nofree) 548*4887Schin free((void*)fp); 549*4887Schin 550*4887Schin } 551*4887Schin } 552*4887Schin 553*4887Schin static const Namdisc_t Nv_bdisc = { 0, putdisc, 0, 0, setdisc }; 554*4887Schin 555*4887Schin static Namfun_t *nv_clone_disc(register Namfun_t *fp) 556*4887Schin { 557*4887Schin register Namfun_t *nfp; 558*4887Schin register int size; 559*4887Schin if(!(size=fp->dsize) && (!fp->disc || !(size=fp->disc->dsize))) 560*4887Schin size = sizeof(Namfun_t); 561*4887Schin if(!(nfp=newof(NIL(Namfun_t*),Namfun_t,1,size-sizeof(Namfun_t)))) 562*4887Schin return(0); 563*4887Schin memcpy(nfp,fp,size); 564*4887Schin nfp->nofree = 0; 565*4887Schin return(nfp); 566*4887Schin } 567*4887Schin 568*4887Schin int nv_adddisc(Namval_t *np, const char **names, Namval_t **funs) 569*4887Schin { 570*4887Schin register Nambfun_t *vp; 571*4887Schin register int n=0; 572*4887Schin register const char **av=names; 573*4887Schin if(av) 574*4887Schin { 575*4887Schin while(*av++) 576*4887Schin n++; 577*4887Schin } 578*4887Schin if(!(vp = newof(NIL(Nambfun_t*),Nambfun_t,1,n*sizeof(Namval_t*)))) 579*4887Schin return(0); 580*4887Schin vp->fun.dsize = sizeof(Nambfun_t)+n*sizeof(Namval_t*); 581*4887Schin vp->fun.funs = 1; 582*4887Schin if(funs) 583*4887Schin memcpy((void*)vp->bltins, (void*)funs,n*sizeof(Namval_t*)); 584*4887Schin else while(n>=0) 585*4887Schin vp->bltins[n--] = 0; 586*4887Schin vp->fun.disc = &Nv_bdisc; 587*4887Schin vp->bnames = names; 588*4887Schin nv_stack(np,&vp->fun); 589*4887Schin return(1); 590*4887Schin } 591*4887Schin 592*4887Schin /* 593*4887Schin * push, pop, clone, or reorder disciplines onto node <np> 594*4887Schin * mode can be one of 595*4887Schin * NV_FIRST: Move or push <fp> to top of the stack or delete top 596*4887Schin * NV_LAST: Move or push <fp> to bottom of stack or delete last 597*4887Schin * NV_POP: Delete <fp> from top of the stack 598*4887Schin * NV_CLONE: Replace fp with a copy created my malloc() and return it 599*4887Schin */ 600*4887Schin Namfun_t *nv_disc(register Namval_t *np, register Namfun_t* fp, int mode) 601*4887Schin { 602*4887Schin Namfun_t *lp, **lpp; 603*4887Schin if(nv_isref(np)) 604*4887Schin return(0); 605*4887Schin if(mode==NV_CLONE && !fp) 606*4887Schin return(0); 607*4887Schin if(fp) 608*4887Schin { 609*4887Schin if((lp=np->nvfun)==fp) 610*4887Schin { 611*4887Schin if(mode==NV_CLONE) 612*4887Schin { 613*4887Schin lp = nv_clone_disc(fp); 614*4887Schin return(np->nvfun=lp); 615*4887Schin } 616*4887Schin if(mode==NV_FIRST || mode==0) 617*4887Schin return(fp); 618*4887Schin np->nvfun = lp->next; 619*4887Schin if(mode==NV_POP) 620*4887Schin return(fp); 621*4887Schin } 622*4887Schin /* see if <fp> is on the list already */ 623*4887Schin lpp = &np->nvfun; 624*4887Schin if(lp) 625*4887Schin { 626*4887Schin while(lp->next) 627*4887Schin { 628*4887Schin if(lp->next==fp) 629*4887Schin { 630*4887Schin if(mode==NV_CLONE) 631*4887Schin { 632*4887Schin fp = nv_clone_disc(fp); 633*4887Schin lp->next = fp; 634*4887Schin return(fp); 635*4887Schin } 636*4887Schin lp->next = fp->next; 637*4887Schin if(mode==NV_POP) 638*4887Schin return(fp); 639*4887Schin if(mode!=NV_LAST) 640*4887Schin break; 641*4887Schin } 642*4887Schin lp = lp->next; 643*4887Schin } 644*4887Schin if(mode==NV_LAST) 645*4887Schin lpp = &lp->next; 646*4887Schin } 647*4887Schin if(mode==NV_POP) 648*4887Schin return(0); 649*4887Schin /* push */ 650*4887Schin nv_offattr(np,NV_NODISC); 651*4887Schin if(mode==NV_LAST) 652*4887Schin fp->next = 0; 653*4887Schin else 654*4887Schin { 655*4887Schin if(fp->nofree && *lpp) 656*4887Schin fp = nv_clone_disc(fp); 657*4887Schin fp->next = *lpp; 658*4887Schin } 659*4887Schin *lpp = fp; 660*4887Schin } 661*4887Schin else 662*4887Schin { 663*4887Schin if(mode==NV_FIRST) 664*4887Schin return(np->nvfun); 665*4887Schin else if(mode==NV_LAST) 666*4887Schin for(lp=np->nvfun; lp; fp=lp,lp=lp->next); 667*4887Schin else if(fp = np->nvfun) 668*4887Schin np->nvfun = fp->next; 669*4887Schin } 670*4887Schin return(fp); 671*4887Schin } 672*4887Schin 673*4887Schin /* 674*4887Schin * returns discipline pointer if discipline with specified functions 675*4887Schin * is on the discipline stack 676*4887Schin */ 677*4887Schin Namfun_t *nv_hasdisc(Namval_t *np, const Namdisc_t *dp) 678*4887Schin { 679*4887Schin register Namfun_t *fp; 680*4887Schin for(fp=np->nvfun; fp; fp = fp->next) 681*4887Schin { 682*4887Schin if(fp->disc== dp) 683*4887Schin return(fp); 684*4887Schin } 685*4887Schin return(0); 686*4887Schin } 687*4887Schin 688*4887Schin struct notify 689*4887Schin { 690*4887Schin Namfun_t hdr; 691*4887Schin char **ptr; 692*4887Schin }; 693*4887Schin 694*4887Schin static void put_notify(Namval_t* np,const char *val,int flags,Namfun_t *fp) 695*4887Schin { 696*4887Schin struct notify *pp = (struct notify*)fp; 697*4887Schin nv_putv(np,val,flags,fp); 698*4887Schin nv_stack(np,fp); 699*4887Schin nv_stack(np,(Namfun_t*)0); 700*4887Schin *pp->ptr = 0; 701*4887Schin if(!fp->nofree) 702*4887Schin free((void*)fp); 703*4887Schin } 704*4887Schin 705*4887Schin static const Namdisc_t notify_disc = { 0, put_notify }; 706*4887Schin 707*4887Schin int nv_unsetnotify(Namval_t *np, char **addr) 708*4887Schin { 709*4887Schin register Namfun_t *fp; 710*4887Schin for(fp=np->nvfun;fp;fp=fp->next) 711*4887Schin { 712*4887Schin if(fp->disc->putval==put_notify && ((struct notify*)fp)->ptr==addr) 713*4887Schin { 714*4887Schin nv_stack(np,fp); 715*4887Schin nv_stack(np,(Namfun_t*)0); 716*4887Schin if(!fp->nofree) 717*4887Schin free((void*)fp); 718*4887Schin return(1); 719*4887Schin } 720*4887Schin } 721*4887Schin return(0); 722*4887Schin } 723*4887Schin 724*4887Schin int nv_setnotify(Namval_t *np, char **addr) 725*4887Schin { 726*4887Schin struct notify *pp = newof(0,struct notify, 1,0); 727*4887Schin if(!pp) 728*4887Schin return(0); 729*4887Schin pp->ptr = addr; 730*4887Schin pp->hdr.disc = ¬ify_disc; 731*4887Schin nv_stack(np,&pp->hdr); 732*4887Schin return(1); 733*4887Schin } 734*4887Schin 735*4887Schin static void *newnode(const char *name) 736*4887Schin { 737*4887Schin register int s; 738*4887Schin register Namval_t *np = newof(0,Namval_t,1,s=strlen(name)+1); 739*4887Schin if(np) 740*4887Schin { 741*4887Schin np->nvname = (char*)np+sizeof(Namval_t); 742*4887Schin memcpy(np->nvname,name,s); 743*4887Schin } 744*4887Schin return((void*)np); 745*4887Schin } 746*4887Schin 747*4887Schin #if SHOPT_NAMESPACE 748*4887Schin /* 749*4887Schin * clone a numeric value 750*4887Schin */ 751*4887Schin static void *num_clone(register Namval_t *np, void *val) 752*4887Schin { 753*4887Schin register int size; 754*4887Schin void *nval; 755*4887Schin if(!val) 756*4887Schin return(0); 757*4887Schin if(nv_isattr(np,NV_DOUBLE)) 758*4887Schin { 759*4887Schin if(nv_isattr(np,NV_LONG)) 760*4887Schin size = sizeof(Sfdouble_t); 761*4887Schin else if(nv_isattr(np,NV_SHORT)) 762*4887Schin size = sizeof(float); 763*4887Schin else 764*4887Schin size = sizeof(double); 765*4887Schin } 766*4887Schin else 767*4887Schin { 768*4887Schin if(nv_isattr(np,NV_LONG)) 769*4887Schin size = sizeof(Sflong_t); 770*4887Schin else if(nv_isattr(np,NV_SHORT)) 771*4887Schin size = sizeof(int16_t); 772*4887Schin else 773*4887Schin size = sizeof(int32_t); 774*4887Schin } 775*4887Schin if(!(nval = malloc(size))) 776*4887Schin return(0); 777*4887Schin memcpy(nval,val,size); 778*4887Schin return(nval); 779*4887Schin } 780*4887Schin 781*4887Schin static void clone_all_disc( Namval_t *np, Namval_t *mp, int flags) 782*4887Schin { 783*4887Schin register Namfun_t *fp, **mfp = &mp->nvfun, *nfp; 784*4887Schin for(fp=np->nvfun; fp;fp=fp->next) 785*4887Schin { 786*4887Schin if(fp->funs && (flags&NV_NODISC)) 787*4887Schin nfp = 0; 788*4887Schin if(fp->disc && fp->disc->clonef) 789*4887Schin nfp = (*fp->disc->clonef)(np,mp,flags,fp); 790*4887Schin else 791*4887Schin nfp = nv_clone_disc(fp); 792*4887Schin if(!nfp) 793*4887Schin continue; 794*4887Schin nfp->next = 0; 795*4887Schin *mfp = nfp; 796*4887Schin mfp = &nfp->next; 797*4887Schin } 798*4887Schin } 799*4887Schin 800*4887Schin /* 801*4887Schin * clone <mp> from <np> flags can be one of the following 802*4887Schin * NV_APPEND - append <np> onto <mp> 803*4887Schin * NV_MOVE - move <np> to <mp> 804*4887Schin * NV_NOFREE - mark the new node as nofree 805*4887Schin * NV_NODISC - discplines with funs non-zero will not be copied 806*4887Schin */ 807*4887Schin int nv_clone(Namval_t *np, Namval_t *mp, int flags) 808*4887Schin { 809*4887Schin Namfun_t *fp; 810*4887Schin if(fp=np->nvfun) 811*4887Schin { 812*4887Schin if(flags&NV_MOVE) 813*4887Schin { 814*4887Schin mp->nvfun = fp; 815*4887Schin goto skip; 816*4887Schin } 817*4887Schin clone_all_disc(np, mp, flags); 818*4887Schin } 819*4887Schin if(flags&NV_APPEND) 820*4887Schin return(1); 821*4887Schin skip: 822*4887Schin nv_setsize(mp,nv_size(np)); 823*4887Schin if(!nv_isattr(mp,NV_MINIMAL) || nv_isattr(mp,NV_EXPORT)) 824*4887Schin mp->nvenv = (!nv_isattr(np,NV_MINIMAL)||nv_isattr(np,NV_EXPORT))?np->nvenv:0; 825*4887Schin mp->nvalue.cp = np->nvalue.cp; 826*4887Schin mp->nvflag = np->nvflag; 827*4887Schin if(flags&NV_MOVE) 828*4887Schin { 829*4887Schin np->nvfun = 0; 830*4887Schin np->nvalue.cp = 0; 831*4887Schin if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(mp,NV_EXPORT)) 832*4887Schin np->nvenv = 0; 833*4887Schin np->nvflag = 0; 834*4887Schin nv_setsize(np,0); 835*4887Schin return(1); 836*4887Schin } 837*4887Schin if(nv_isattr(np,NV_INTEGER)) 838*4887Schin mp->nvalue.ip = (int*)num_clone(np,(void*)np->nvalue.ip); 839*4887Schin else if(flags&NV_NOFREE) 840*4887Schin nv_onattr(np,NV_NOFREE); 841*4887Schin return(1); 842*4887Schin } 843*4887Schin 844*4887Schin /* 845*4887Schin * The following discipline is for copy-on-write semantics 846*4887Schin */ 847*4887Schin static char* clone_getv(Namval_t *np, Namfun_t *handle) 848*4887Schin { 849*4887Schin return(np->nvalue.np?nv_getval(np->nvalue.np):0); 850*4887Schin } 851*4887Schin 852*4887Schin static Sfdouble_t clone_getn(Namval_t *np, Namfun_t *handle) 853*4887Schin { 854*4887Schin return(np->nvalue.np?nv_getnum(np->nvalue.np):0); 855*4887Schin } 856*4887Schin 857*4887Schin static void clone_putv(Namval_t *np,const char* val,int flags,Namfun_t *handle) 858*4887Schin { 859*4887Schin Namfun_t *dp = nv_stack(np,(Namfun_t*)0); 860*4887Schin Namval_t *mp = np->nvalue.np; 861*4887Schin if(!sh.subshell) 862*4887Schin free((void*)dp); 863*4887Schin if(val) 864*4887Schin nv_clone(mp,np,NV_NOFREE); 865*4887Schin np->nvalue.cp = 0; 866*4887Schin nv_putval(np,val,flags); 867*4887Schin } 868*4887Schin 869*4887Schin static const Namdisc_t clone_disc = 870*4887Schin { 871*4887Schin 0, 872*4887Schin clone_putv, 873*4887Schin clone_getv, 874*4887Schin clone_getn 875*4887Schin }; 876*4887Schin 877*4887Schin Namval_t *nv_mkclone(Namval_t *mp) 878*4887Schin { 879*4887Schin Namval_t *np; 880*4887Schin Namfun_t *dp; 881*4887Schin np = newof(0,Namval_t,1,0); 882*4887Schin np->nvflag = mp->nvflag; 883*4887Schin np->nvsize = mp->nvsize; 884*4887Schin np->nvname = mp->nvname; 885*4887Schin np->nvalue.np = mp; 886*4887Schin np->nvflag = mp->nvflag; 887*4887Schin dp = newof(0,Namfun_t,1,0); 888*4887Schin dp->disc = &clone_disc; 889*4887Schin nv_stack(np,dp); 890*4887Schin dtinsert(nv_dict(sh.namespace),np); 891*4887Schin return(np); 892*4887Schin } 893*4887Schin #endif /* SHOPT_NAMESPACE */ 894*4887Schin 895*4887Schin Namval_t *nv_search(const char *name, Dt_t *root, int mode) 896*4887Schin { 897*4887Schin register Namval_t *np; 898*4887Schin register Dt_t *dp = 0; 899*4887Schin if(mode&HASH_NOSCOPE) 900*4887Schin dp = dtview(root,0); 901*4887Schin if(mode&HASH_BUCKET) 902*4887Schin { 903*4887Schin Namval_t *mp = (void*)name; 904*4887Schin if(!(np = dtsearch(root,mp)) && (mode&NV_ADD)) 905*4887Schin name = nv_name(mp); 906*4887Schin } 907*4887Schin else 908*4887Schin { 909*4887Schin if(*name=='.' && root==sh.var_tree) 910*4887Schin root = sh.var_base; 911*4887Schin np = dtmatch(root,(void*)name); 912*4887Schin } 913*4887Schin if(!np && (mode&NV_ADD)) 914*4887Schin { 915*4887Schin 916*4887Schin if(sh.namespace && !(mode&HASH_NOSCOPE) && root==sh.var_tree) 917*4887Schin root = nv_dict(sh.namespace); 918*4887Schin else if(!dp && !(mode&HASH_NOSCOPE)) 919*4887Schin { 920*4887Schin register Dt_t *next; 921*4887Schin while(next=dtvnext(root)) 922*4887Schin root = next; 923*4887Schin } 924*4887Schin np = (Namval_t*)dtinsert(root,newnode(name)); 925*4887Schin } 926*4887Schin if(dp) 927*4887Schin dtview(root,dp); 928*4887Schin return(np); 929*4887Schin } 930*4887Schin 931*4887Schin /* 932*4887Schin * finds function or builtin for given name and the discipline variable 933*4887Schin * if var!=0 the variable pointer is returned and the built-in name 934*4887Schin * is put onto the stack at the current offset. 935*4887Schin * otherwise, a pointer to the builtin (variable or type) is returned 936*4887Schin * and var contains the poiner to the variable 937*4887Schin * if last==0 and first component of name is a reference, nv_bfsearch() 938*4887Schin will return 0. 939*4887Schin */ 940*4887Schin Namval_t *nv_bfsearch(const char *name, Dt_t *root, Namval_t **var, char **last) 941*4887Schin { 942*4887Schin int offset = staktell(); 943*4887Schin register char *sp, *cp=0; 944*4887Schin Namval_t *np, *nq; 945*4887Schin if(var) 946*4887Schin *var = 0; 947*4887Schin /* check for . in the name before = */ 948*4887Schin for(sp=(char*)name+1; *sp; sp++) 949*4887Schin { 950*4887Schin if(*sp=='=') 951*4887Schin return(0); 952*4887Schin if(*sp=='.') 953*4887Schin cp = sp; 954*4887Schin } 955*4887Schin if(!cp) 956*4887Schin return(var?nv_search(name,root,0):0); 957*4887Schin stakputs(name); 958*4887Schin stakputc(0); 959*4887Schin cp = stakptr(offset) + (cp-name); 960*4887Schin if(last) 961*4887Schin *last = cp; 962*4887Schin *cp = 0; 963*4887Schin nq=nv_open(stakptr(offset),0,NV_VARNAME|NV_NOASSIGN|NV_NOADD|NV_NOFAIL); 964*4887Schin *cp = '.'; 965*4887Schin if(!nq) 966*4887Schin { 967*4887Schin np = 0; 968*4887Schin goto done; 969*4887Schin } 970*4887Schin if(!var) 971*4887Schin { 972*4887Schin np = nq; 973*4887Schin goto done; 974*4887Schin } 975*4887Schin *var = nq; 976*4887Schin return((Namval_t*)nv_setdisc(nq,cp+1,nq,(Namfun_t*)nq)); 977*4887Schin done: 978*4887Schin stakseek(offset); 979*4887Schin return(np); 980*4887Schin } 981*4887Schin 982*4887Schin /* 983*4887Schin * add or replace built-in version of command commresponding to <path> 984*4887Schin * The <bltin> argument is a pointer to the built-in 985*4887Schin * if <extra>==1, the built-in will be deleted 986*4887Schin * Special builtins cannot be added or deleted return failure 987*4887Schin * The return value for adding builtins is a pointer to the node or NULL on 988*4887Schin * failure. For delete NULL means success and the node that cannot be 989*4887Schin * deleted is returned on failure. 990*4887Schin */ 991*4887Schin Namval_t *sh_addbuiltin(const char *path, int (*bltin)(int, char*[],void*),void *extra) 992*4887Schin { 993*4887Schin register const char *name = path_basename(path); 994*4887Schin char *cp; 995*4887Schin register Namval_t *np, *nq=0; 996*4887Schin int offset = staktell(); 997*4887Schin if(name==path && (nq=nv_bfsearch(name,sh.bltin_tree,(Namval_t**)0,&cp))) 998*4887Schin path = name = stakptr(offset); 999*4887Schin if(np = nv_search(path,sh.bltin_tree,0)) 1000*4887Schin { 1001*4887Schin /* exists without a path */ 1002*4887Schin if(extra == (void*)1) 1003*4887Schin { 1004*4887Schin if(np->nvfun && !nv_isattr(np,NV_NOFREE)) 1005*4887Schin free((void*)np->nvfun); 1006*4887Schin dtdelete(sh.bltin_tree,np); 1007*4887Schin return(0); 1008*4887Schin } 1009*4887Schin if(!bltin) 1010*4887Schin return(np); 1011*4887Schin } 1012*4887Schin else for(np=(Namval_t*)dtfirst(sh.bltin_tree);np;np=(Namval_t*)dtnext(sh.bltin_tree,np)) 1013*4887Schin { 1014*4887Schin if(strcmp(name,path_basename(nv_name(np)))) 1015*4887Schin continue; 1016*4887Schin /* exists probably with different path so delete it */ 1017*4887Schin if(strcmp(path,nv_name(np))) 1018*4887Schin { 1019*4887Schin if(nv_isattr(np,BLT_SPC)) 1020*4887Schin return(np); 1021*4887Schin if(!bltin) 1022*4887Schin bltin = np->nvalue.bfp; 1023*4887Schin if(np->nvenv) 1024*4887Schin dtdelete(sh.bltin_tree,np); 1025*4887Schin if(extra == (void*)1) 1026*4887Schin return(0); 1027*4887Schin np = 0; 1028*4887Schin } 1029*4887Schin break; 1030*4887Schin } 1031*4887Schin if(!np && !(np = nv_search(path,sh.bltin_tree,bltin?NV_ADD:0))) 1032*4887Schin return(0); 1033*4887Schin if(nv_isattr(np,BLT_SPC)) 1034*4887Schin return(np); 1035*4887Schin np->nvenv = 0; 1036*4887Schin np->nvfun = 0; 1037*4887Schin nv_setattr(np,0); 1038*4887Schin if(bltin) 1039*4887Schin { 1040*4887Schin np->nvalue.bfp = bltin; 1041*4887Schin nv_onattr(np,NV_BLTIN|NV_NOFREE); 1042*4887Schin np->nvfun = (Namfun_t*)extra; 1043*4887Schin } 1044*4887Schin if(nq) 1045*4887Schin { 1046*4887Schin cp=nv_setdisc(nq,cp+1,np,(Namfun_t*)nq); 1047*4887Schin nv_close(nq); 1048*4887Schin if(!cp) 1049*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_baddisc,name); 1050*4887Schin } 1051*4887Schin if(extra == (void*)1) 1052*4887Schin return(0); 1053*4887Schin return(np); 1054*4887Schin } 1055*4887Schin 1056*4887Schin #undef nv_stack 1057*4887Schin extern Namfun_t *nv_stack(register Namval_t *np, register Namfun_t* fp) 1058*4887Schin { 1059*4887Schin return(nv_disc(np,fp,0)); 1060*4887Schin } 1061*4887Schin 1062*4887Schin struct table 1063*4887Schin { 1064*4887Schin Namfun_t fun; 1065*4887Schin Namval_t *parent; 1066*4887Schin Shell_t *shp; 1067*4887Schin Dt_t *dict; 1068*4887Schin }; 1069*4887Schin 1070*4887Schin Namval_t *nv_parent(Namval_t *np) 1071*4887Schin { 1072*4887Schin if(!nv_istable(np)) 1073*4887Schin return(0); 1074*4887Schin return(((struct table*)(np->nvfun))->parent); 1075*4887Schin } 1076*4887Schin 1077*4887Schin static Namval_t *next_table(register Namval_t* np, Dt_t *root,Namfun_t *fp) 1078*4887Schin { 1079*4887Schin struct table *tp = (struct table *)fp; 1080*4887Schin if(root) 1081*4887Schin return((Namval_t*)dtnext(root,np)); 1082*4887Schin else 1083*4887Schin return((Namval_t*)dtfirst(tp->dict)); 1084*4887Schin } 1085*4887Schin 1086*4887Schin static Namval_t *create_table(Namval_t *np,const char *name,int flags,Namfun_t *fp) 1087*4887Schin { 1088*4887Schin struct table *tp = (struct table *)fp; 1089*4887Schin tp->shp->last_table = np; 1090*4887Schin return(nv_create(name, tp->dict, flags, fp)); 1091*4887Schin } 1092*4887Schin 1093*4887Schin static Namfun_t *clone_table(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) 1094*4887Schin { 1095*4887Schin struct table *tp = (struct table*)fp; 1096*4887Schin struct table *ntp = (struct table*)nv_clone_disc(fp); 1097*4887Schin Dt_t *oroot=tp->dict,*nroot=dtopen(&_Nvdisc,Dtoset); 1098*4887Schin if(!nroot) 1099*4887Schin return(0); 1100*4887Schin memcpy((void*)ntp,(void*)fp,sizeof(struct table)); 1101*4887Schin ntp->dict = nroot; 1102*4887Schin ntp->parent = nv_lastdict(); 1103*4887Schin for(np=(Namval_t*)dtfirst(oroot);np;np=(Namval_t*)dtnext(oroot,np)) 1104*4887Schin { 1105*4887Schin mp = (Namval_t*)dtinsert(nroot,newnode(np->nvname)); 1106*4887Schin nv_clone(np,mp,flags); 1107*4887Schin } 1108*4887Schin return(&ntp->fun); 1109*4887Schin } 1110*4887Schin 1111*4887Schin static void put_table(register Namval_t* np, const char* val, int flags, Namfun_t* fp) 1112*4887Schin { 1113*4887Schin register Dt_t *root = ((struct table*)fp)->dict; 1114*4887Schin register Namval_t *nq, *mp; 1115*4887Schin Namarr_t *ap; 1116*4887Schin nv_putv(np,val,flags,fp); 1117*4887Schin if(val) 1118*4887Schin return; 1119*4887Schin if(nv_isarray(np) && (ap=nv_arrayptr(np)) && array_elem(ap)) 1120*4887Schin return; 1121*4887Schin for(mp=(Namval_t*)dtfirst(root);mp;mp=nq) 1122*4887Schin { 1123*4887Schin _nv_unset(mp,flags); 1124*4887Schin nq = (Namval_t*)dtnext(root,mp); 1125*4887Schin dtdelete(root,mp); 1126*4887Schin free((void*)mp); 1127*4887Schin } 1128*4887Schin dtclose(root); 1129*4887Schin if(!fp->nofree) 1130*4887Schin free((void*)fp); 1131*4887Schin } 1132*4887Schin 1133*4887Schin /* 1134*4887Schin * return space separated list of names of variables in given tree 1135*4887Schin */ 1136*4887Schin static char *get_table(Namval_t *np, Namfun_t *fp) 1137*4887Schin { 1138*4887Schin register Dt_t *root = ((struct table*)fp)->dict; 1139*4887Schin static Sfio_t *out; 1140*4887Schin register int first=1; 1141*4887Schin register Dt_t *base = dtview(root,0); 1142*4887Schin if(out) 1143*4887Schin sfseek(out,(Sfoff_t)0,SEEK_SET); 1144*4887Schin else 1145*4887Schin out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); 1146*4887Schin for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np)) 1147*4887Schin { 1148*4887Schin if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)) 1149*4887Schin { 1150*4887Schin if(!first) 1151*4887Schin sfputc(out,' '); 1152*4887Schin else 1153*4887Schin first = 0; 1154*4887Schin sfputr(out,np->nvname,-1); 1155*4887Schin } 1156*4887Schin } 1157*4887Schin sfputc(out,0); 1158*4887Schin if(base) 1159*4887Schin dtview(root,base); 1160*4887Schin return((char*)out->_data); 1161*4887Schin } 1162*4887Schin 1163*4887Schin static const Namdisc_t table_disc = 1164*4887Schin { 1165*4887Schin sizeof(struct table), 1166*4887Schin put_table, 1167*4887Schin get_table, 1168*4887Schin 0, 1169*4887Schin 0, 1170*4887Schin create_table, 1171*4887Schin clone_table, 1172*4887Schin 0, 1173*4887Schin next_table, 1174*4887Schin }; 1175*4887Schin 1176*4887Schin Dt_t *nv_dict(Namval_t* np) 1177*4887Schin { 1178*4887Schin struct table *tp = (struct table*)nv_hasdisc(np,&table_disc); 1179*4887Schin if(tp) 1180*4887Schin return(tp->dict); 1181*4887Schin np = sh.last_table; 1182*4887Schin while(np) 1183*4887Schin { 1184*4887Schin if(tp = (struct table*)nv_hasdisc(np,&table_disc)) 1185*4887Schin return(tp->dict); 1186*4887Schin #if 0 1187*4887Schin np = nv_create(np,(const char*)0, NV_FIRST, (Namfun_t*)0); 1188*4887Schin #endif 1189*4887Schin } 1190*4887Schin return(sh.var_tree); 1191*4887Schin } 1192*4887Schin 1193*4887Schin /* 1194*4887Schin * create a mountable name-value pair tree 1195*4887Schin */ 1196*4887Schin Namval_t *nv_mount(Namval_t *np, const char *name, Dt_t *dict) 1197*4887Schin { 1198*4887Schin Namval_t *mp, *pp=0; 1199*4887Schin struct table *tp = newof((struct table*)0, struct table,1,0); 1200*4887Schin if(name) 1201*4887Schin { 1202*4887Schin if(nv_istable(np)) 1203*4887Schin pp = np; 1204*4887Schin else 1205*4887Schin pp = nv_lastdict(); 1206*4887Schin } 1207*4887Schin if(!(tp = newof((struct table*)0, struct table,1,0))) 1208*4887Schin return(0); 1209*4887Schin if(name) 1210*4887Schin { 1211*4887Schin Namfun_t *fp = pp->nvfun; 1212*4887Schin mp = (*fp->disc->createf)(pp,name,0,fp); 1213*4887Schin } 1214*4887Schin else 1215*4887Schin mp = np; 1216*4887Schin if(!nv_isnull(mp)) 1217*4887Schin nv_unset(mp); 1218*4887Schin tp->shp = sh_getinterp(); 1219*4887Schin tp->dict = dict; 1220*4887Schin tp->parent = pp; 1221*4887Schin tp->fun.disc = &table_disc; 1222*4887Schin nv_onattr(mp,NV_TABLE); 1223*4887Schin nv_disc(mp, &tp->fun, NV_LAST); 1224*4887Schin return(mp); 1225*4887Schin } 1226*4887Schin 1227*4887Schin const Namdisc_t *nv_discfun(int which) 1228*4887Schin { 1229*4887Schin switch(which) 1230*4887Schin { 1231*4887Schin case NV_DCADD: 1232*4887Schin return(&Nv_bdisc); 1233*4887Schin case NV_DCRESTRICT: 1234*4887Schin return(&RESTRICTED_disc); 1235*4887Schin } 1236*4887Schin return(0); 1237*4887Schin } 1238*4887Schin 1239*4887Schin /* 1240*4887Schin * This function turns variable <np> to the type <tp> 1241*4887Schin */ 1242*4887Schin int nv_settype(Namval_t* np, Namval_t *tp, int flags) 1243*4887Schin { 1244*4887Schin int isnull = nv_isnull(np); 1245*4887Schin char *val=0; 1246*4887Schin if(isnull) 1247*4887Schin flags &= ~NV_APPEND; 1248*4887Schin else 1249*4887Schin { 1250*4887Schin val = strdup(nv_getval(np)); 1251*4887Schin if(!(flags&NV_APPEND)) 1252*4887Schin _nv_unset(np, NV_RDONLY); 1253*4887Schin } 1254*4887Schin if(!nv_clone(tp,np,flags|NV_NOFREE)) 1255*4887Schin return(0); 1256*4887Schin if(val) 1257*4887Schin { 1258*4887Schin nv_putval(np,val,NV_RDONLY); 1259*4887Schin free((void*)val); 1260*4887Schin } 1261*4887Schin return(0); 1262*4887Schin } 1263*4887Schin 1264