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