1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1982-2011 AT&T Intellectual Property * 5* and is licensed under the * 6* Common Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.opensource.org/licenses/cpl1.0.txt * 11* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 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#define putenv ___putenv 27 28#include "defs.h" 29#include "variables.h" 30#include "path.h" 31#include "lexstates.h" 32#include "timeout.h" 33#include "FEATURE/externs" 34#include "streval.h" 35 36#define NVCACHE 8 /* must be a power of 2 */ 37#define Empty ((char*)(e_sptbnl+3)) 38static char *savesub = 0; 39static char Null[1]; 40static Namval_t NullNode; 41static Dt_t *Refdict; 42static Dtdisc_t _Refdisc = 43{ 44 offsetof(struct Namref,np),sizeof(struct Namval_t*),sizeof(struct Namref) 45}; 46 47#if !_lib_pathnative && _lib_uwin_path 48 49#define _lib_pathnative 1 50 51extern int uwin_path(const char*, char*, int); 52 53size_t 54pathnative(const char* path, char* buf, size_t siz) 55{ 56 return uwin_path(path, buf, siz); 57} 58 59#endif /* _lib_pathnative */ 60 61static void attstore(Namval_t*,void*); 62#ifndef _ENV_H 63 static void pushnam(Namval_t*,void*); 64 static char *staknam(Namval_t*, char*); 65#endif 66static void rightjust(char*, int, int); 67static char *lastdot(char*, int); 68 69struct adata 70{ 71 Shell_t *sh; 72 Namval_t *tp; 73 char *mapname; 74 char **argnam; 75 int attsize; 76 char *attval; 77}; 78 79#if SHOPT_TYPEDEF 80 struct sh_type 81 { 82 void *previous; 83 Namval_t **nodes; 84 Namval_t *rp; 85 short numnodes; 86 short maxnodes; 87 }; 88#endif /*SHOPT_TYPEDEF */ 89 90#if NVCACHE 91 struct Namcache 92 { 93 struct Cache_entry 94 { 95 Dt_t *root; 96 Dt_t *last_root; 97 char *name; 98 Namval_t *np; 99 Namval_t *last_table; 100 int flags; 101 short size; 102 short len; 103 } entries[NVCACHE]; 104 short index; 105 short ok; 106 }; 107 static struct Namcache nvcache; 108#endif 109 110char nv_local = 0; 111#ifndef _ENV_H 112static void(*nullscan)(Namval_t*,void*); 113#endif 114 115#if ( SFIO_VERSION <= 20010201L ) 116# define _data data 117#endif 118 119#if !SHOPT_MULTIBYTE 120# define mbchar(p) (*(unsigned char*)p++) 121#endif /* SHOPT_MULTIBYTE */ 122 123/* ======== name value pair routines ======== */ 124 125#include "shnodes.h" 126#include "builtins.h" 127 128static char *getbuf(size_t len) 129{ 130 static char *buf; 131 static size_t buflen; 132 if(buflen < len) 133 { 134 if(buflen==0) 135 buf = (char*)malloc(len); 136 else 137 buf = (char*)realloc(buf,len); 138 buflen = len; 139 } 140 return(buf); 141} 142 143#ifdef _ENV_H 144void sh_envput(Env_t* ep,Namval_t *np) 145{ 146 int offset = staktell(); 147 Namarr_t *ap = nv_arrayptr(np); 148 char *val; 149 if(ap) 150 { 151 if(ap->nelem&ARRAY_UNDEF) 152 nv_putsub(np,"0",0L); 153 else if(!(val=nv_getsub(np)) || strcmp(val,"0")) 154 return; 155 } 156 if(!(val = nv_getval(np))) 157 return; 158 stakputs(nv_name(np)); 159 stakputc('='); 160 stakputs(val); 161 stakseek(offset); 162 env_add(ep,stakptr(offset),ENV_STRDUP); 163} 164#endif 165 166/* 167 * output variable name in format for re-input 168 */ 169void nv_outname(Sfio_t *out, char *name, int len) 170{ 171 const char *cp=name, *sp; 172 int c, offset = staktell(); 173 while(sp= strchr(cp,'[')) 174 { 175 if(len>0 && cp+len <= sp) 176 break; 177 sfwrite(out,cp,++sp-cp); 178 stakseek(offset); 179 while(c= *sp++) 180 { 181 if(c==']') 182 break; 183 else if(c=='\\') 184 { 185 if(*sp=='[' || *sp==']' || *sp=='\\') 186 c = *sp++; 187 } 188 stakputc(c); 189 } 190 stakputc(0); 191 sfputr(out,sh_fmtq(stakptr(offset)),-1); 192 if(len>0) 193 { 194 sfputc(out,']'); 195 return; 196 } 197 cp = sp-1; 198 } 199 if(*cp) 200 { 201 if(len>0) 202 sfwrite(out,cp,len); 203 else 204 sfputr(out,cp,-1); 205 } 206 stakseek(offset); 207} 208 209#if SHOPT_TYPEDEF 210Namval_t *nv_addnode(Namval_t* np, int remove) 211{ 212 Shell_t *shp = sh_getinterp(); 213 register struct sh_type *sp = (struct sh_type*)shp->mktype; 214 register int i; 215 register char *name=0; 216 if(sp->numnodes==0 && !nv_isnull(np) && shp->last_table) 217 { 218 /* could be an redefine */ 219 Dt_t *root = nv_dict(shp->last_table); 220 sp->rp = np; 221 nv_delete(np,root,NV_NOFREE); 222 np = nv_search(sp->rp->nvname,root,NV_ADD); 223 } 224 if(sp->numnodes && memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1)) 225 { 226 name = (sp->nodes[0])->nvname; 227 i = strlen(name); 228 if(memcmp(np->nvname,name,i)) 229 return(np); 230 } 231 if(sp->rp && sp->numnodes) 232 { 233 /* check for a redefine */ 234 if(name && np->nvname[i]=='.' && np->nvname[i+1]=='_' && np->nvname[i+2]==0) 235 sp->rp = 0; 236 else 237 { 238 Dt_t *root = nv_dict(shp->last_table); 239 nv_delete(sp->nodes[0],root,NV_NOFREE); 240 dtinsert(root,sp->rp); 241 errormsg(SH_DICT,ERROR_exit(1),e_redef,sp->nodes[0]->nvname); 242 } 243 } 244 for(i=0; i < sp->numnodes; i++) 245 { 246 if(np == sp->nodes[i]) 247 { 248 if(remove) 249 { 250 while(++i < sp->numnodes) 251 sp->nodes[i-1] = sp->nodes[i]; 252 sp->numnodes--; 253 } 254 return(np); 255 } 256 } 257 if(remove) 258 return(np); 259 if(sp->numnodes==sp->maxnodes) 260 { 261 sp->maxnodes += 20; 262 sp->nodes = (Namval_t**)realloc(sp->nodes,sizeof(Namval_t*)*sp->maxnodes); 263 } 264 sp->nodes[sp->numnodes++] = np; 265 return(np); 266} 267#endif /* SHOPT_TYPEDEF */ 268 269/* 270 * given a list of assignments, determine <name> is on the list 271 returns a pointer to the argnod on the list or NULL 272 */ 273struct argnod *nv_onlist(struct argnod *arg, const char *name) 274{ 275 char *cp; 276 int len = strlen(name); 277 for(;arg; arg=arg->argnxt.ap) 278 { 279 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE))) 280 cp = ((struct fornod*)arg->argchn.ap)->fornam; 281 else 282 cp = arg->argval; 283 if(memcmp(cp,name,len)==0 && (cp[len]==0 || cp[len]=='=')) 284 return(arg); 285 } 286 return(0); 287} 288 289/* 290 * Perform parameter assignment for a linked list of parameters 291 * <flags> contains attributes for the parameters 292 */ 293void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ) 294{ 295 Shell_t *shp = sh_getinterp(); 296 register char *cp; 297 register Namval_t *np, *mp; 298 char *trap=shp->st.trap[SH_DEBUGTRAP]; 299 char *prefix = shp->prefix; 300 int traceon = (sh_isoption(SH_XTRACE)!=0); 301 int array = (flags&(NV_ARRAY|NV_IARRAY)); 302 Namarr_t *ap; 303 Namval_t node; 304 struct Namref nr; 305#if SHOPT_TYPEDEF 306 int maketype = flags&NV_TYPE; 307 struct sh_type shtp; 308 if(maketype) 309 { 310 shtp.previous = shp->mktype; 311 shp->mktype=(void*)&shtp; 312 shtp.numnodes=0; 313 shtp.maxnodes = 20; 314 shtp.rp = 0; 315 shtp.nodes =(Namval_t**)malloc(shtp.maxnodes*sizeof(Namval_t*)); 316 } 317#endif /* SHOPT_TYPEDEF*/ 318#if SHOPT_NAMESPACE 319 if(shp->namespace && nv_dict(shp->namespace)==shp->var_tree) 320 flags |= NV_NOSCOPE; 321#endif /* SHOPT_NAMESPACE */ 322 flags &= ~(NV_TYPE|NV_ARRAY|NV_IARRAY); 323 if(sh_isoption(SH_ALLEXPORT)) 324 flags |= NV_EXPORT; 325 if(shp->prefix) 326 { 327 flags &= ~(NV_IDENT|NV_EXPORT); 328 flags |= NV_VARNAME; 329 } 330 for(;arg; arg=arg->argnxt.ap) 331 { 332 shp->used_pos = 0; 333 if(arg->argflag&ARG_MAC) 334 { 335 shp->prefix = 0; 336 cp = sh_mactrim(shp,arg->argval,(flags&NV_NOREF)?-3:-1); 337 shp->prefix = prefix; 338 } 339 else 340 { 341 stakseek(0); 342 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE))) 343 { 344 int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN); 345 int sub=0; 346 struct fornod *fp=(struct fornod*)arg->argchn.ap; 347 register Shnode_t *tp=fp->fortre; 348 flag |= (flags&(NV_NOSCOPE|NV_STATIC|NV_FARRAY)); 349 if(arg->argflag&ARG_QUOTED) 350 cp = sh_mactrim(shp,fp->fornam,-1); 351 else 352 cp = fp->fornam; 353 error_info.line = fp->fortyp-shp->st.firstline; 354 if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[') 355 array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY; 356 if(shp->fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET) 357 flag |= NV_NOSCOPE; 358 if(prefix && tp->com.comset && *cp=='[') 359 { 360 shp->prefix = 0; 361 np = nv_open(prefix,shp->var_tree,flag); 362 shp->prefix = prefix; 363 if(np) 364 { 365 if(nv_isvtree(np) && !nv_isarray(np)) 366 { 367 stakputc('.'); 368 stakputs(cp); 369 cp = stakfreeze(1); 370 } 371 nv_close(np); 372 } 373 } 374 np = nv_open(cp,shp->var_tree,flag|NV_ASSIGN); 375 if(nv_isattr(np,NV_NOFREE) && nv_isnull(np)) 376 nv_offattr(np,NV_NOFREE); 377 if(nv_istable(np)) 378 _nv_unset(np,0); 379 if(typ && !array && (!shp->prefix || nv_isnull(np) || nv_isarray(np))) 380 { 381 if(!(nv_isnull(np)) && !nv_isarray(np)) 382 _nv_unset(np,0); 383 nv_settype(np,typ,0); 384 } 385 if((flags&NV_STATIC) && !nv_isattr(np,NV_EXPORT) && !nv_isnull(np)) 386#if SHOPT_TYPEDEF 387 goto check_type; 388#else 389 continue; 390#endif /* SHOPT_TYPEDEF */ 391#if SHOPT_FIXEDARRAY 392 if((ap=nv_arrayptr(np)) && ap->fixed) 393 flags |= NV_FARRAY; 394 if(array && (!ap || !ap->hdr.type)) 395 { 396 if(!(arg->argflag&ARG_APPEND) && (!ap || !ap->fixed)) 397#else 398 if(array && (!(ap=nv_arrayptr(np)) || !ap->hdr.type)) 399 { 400 if(!(arg->argflag&ARG_APPEND)) 401#endif /* SHOPT_FIXEDARRAY */ 402 _nv_unset(np,NV_EXPORT); 403 if(array&NV_ARRAY) 404 { 405 nv_setarray(np,nv_associative); 406 } 407 else 408 { 409 nv_onattr(np,NV_ARRAY); 410 } 411 } 412 if(array && tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg) 413 { 414#if SHOPT_TYPEDEF 415 goto check_type; 416#else 417 continue; 418#endif /* SHOPT_TYPEDEF */ 419 } 420 /* check for array assignment */ 421 if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && ((array&NV_IARRAY) || !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL)))) 422 { 423 int argc; 424 Dt_t *last_root = shp->last_root; 425 char **argv = sh_argbuild(shp,&argc,&tp->com,0); 426 shp->last_root = last_root; 427#if SHOPT_TYPEDEF 428 if(shp->mktype && shp->dot_depth==0 && np==((struct sh_type*)shp->mktype)->nodes[0]) 429 { 430 shp->mktype = 0; 431 errormsg(SH_DICT,ERROR_exit(1),"%s: not a known type name",argv[0]); 432 } 433#endif /* SHOPT_TYPEDEF */ 434 if(!(arg->argflag&ARG_APPEND)) 435 { 436#if SHOPT_FIXEDARRAY 437 if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && !ap->fixed && (ap->nelem&ARRAY_MASK))) 438#else 439 if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && (ap->nelem&ARRAY_MASK))) 440#endif /* SHOPT_FIXEDARRAY */ 441 _nv_unset(np,0); 442 } 443 nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv); 444 if(traceon || trap) 445 { 446 int n = -1; 447 char *name = nv_name(np); 448 if(arg->argflag&ARG_APPEND) 449 n = '+'; 450 if(trap) 451 sh_debug(shp,trap,name,(char*)0,argv,(arg->argflag&ARG_APPEND)|ARG_ASSIGN); 452 if(traceon) 453 { 454 sh_trace(shp,NIL(char**),0); 455 sfputr(sfstderr,name,n); 456 sfwrite(sfstderr,"=( ",3); 457 while(cp= *argv++) 458 sfputr(sfstderr,sh_fmtq(cp),' '); 459 sfwrite(sfstderr,")\n",2); 460 } 461 } 462#if SHOPT_TYPEDEF 463 goto check_type; 464#else 465 continue; 466#endif /* SHOPT_TYPEDEF */ 467 } 468 if((tp->tre.tretyp&COMMSK)==TFUN) 469 goto skip; 470 if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[') 471 { 472 if(tp->tre.tretyp!=TLST && !tp->com.comnamp && tp->com.comset && tp->com.comset->argval[0]==0 && tp->com.comset->argchn.ap) 473 { 474 if(prefix) 475 cp = stakcopy(nv_name(np)); 476 shp->prefix = cp; 477 if(tp->com.comset->argval[1]=='[') 478 { 479 if((arg->argflag&ARG_APPEND) && (!nv_isarray(np) || (nv_aindex(np)>=0))) 480 _nv_unset(np,0); 481 if(!(array&NV_IARRAY) && !(tp->com.comset->argflag&ARG_MESSAGE)) 482 nv_setarray(np,nv_associative); 483 } 484 nv_setlist(tp->com.comset,flags&~NV_STATIC,0); 485 shp->prefix = prefix; 486 if(tp->com.comset->argval[1]!='[') 487 nv_setvtree(np); 488 nv_close(np); 489#if SHOPT_TYPEDEF 490 goto check_type; 491#else 492 continue; 493#endif /* SHOPT_TYPEDEF */ 494 } 495 if(*cp!='.' && *cp!='[' && strchr(cp,'[')) 496 { 497 nv_close(np); 498 np = nv_open(cp,shp->var_tree,flag); 499 } 500 if(arg->argflag&ARG_APPEND) 501 { 502 if(nv_isarray(np)) 503 { 504 if((sub=nv_aimax(np)) < 0 && nv_arrayptr(np)) 505 errormsg(SH_DICT,ERROR_exit(1),e_badappend,nv_name(np)); 506 if(sub>=0) 507 sub++; 508 } 509 if(!nv_isnull(np) && np->nvalue.cp!=Empty && !nv_isvtree(np)) 510 sub=1; 511 } 512 else if(((np->nvalue.cp && np->nvalue.cp!=Empty)||nv_isvtree(np)) && !nv_type(np)) 513 _nv_unset(np,NV_EXPORT); 514 } 515 else 516 { 517 if(!(arg->argflag&ARG_APPEND)) 518 _nv_unset(np,NV_EXPORT); 519 if(!sh_isoption(SH_BASH) && !(array&NV_IARRAY) && !nv_isarray(np)) 520 nv_setarray(np,nv_associative); 521 } 522 skip: 523 if(sub>0) 524 { 525 sfprintf(stkstd,"%s[%d]",prefix?nv_name(np):cp,sub); 526 shp->prefix = stakfreeze(1); 527 nv_putsub(np,(char*)0,ARRAY_ADD|ARRAY_FILL|sub); 528 } 529 else if(prefix) 530 shp->prefix = stakcopy(nv_name(np)); 531 else 532 shp->prefix = cp; 533 shp->last_table = 0; 534 if(shp->prefix) 535 { 536 if(*shp->prefix=='_' && shp->prefix[1]=='.' && nv_isref(L_ARGNOD)) 537 { 538 sfprintf(stkstd,"%s%s",nv_name(L_ARGNOD->nvalue.nrp->np),shp->prefix+1); 539 shp->prefix = stkfreeze(stkstd,1); 540 } 541 memset(&nr,0,sizeof(nr)); 542 memcpy(&node,L_ARGNOD,sizeof(node)); 543 L_ARGNOD->nvalue.nrp = &nr; 544 nr.np = np; 545 nr.root = shp->last_root; 546 nr.table = shp->last_table; 547 L_ARGNOD->nvflag = NV_REF|NV_NOFREE; 548 L_ARGNOD->nvfun = 0; 549 } 550 sh_exec(tp,sh_isstate(SH_ERREXIT)); 551#if SHOPT_TYPEDEF 552 if(shp->prefix) 553#endif 554 { 555 L_ARGNOD->nvalue.nrp = node.nvalue.nrp; 556 L_ARGNOD->nvflag = node.nvflag; 557 L_ARGNOD->nvfun = node.nvfun; 558 } 559 shp->prefix = prefix; 560 if(nv_isarray(np) && (mp=nv_opensub(np))) 561 np = mp; 562 while(tp->tre.tretyp==TLST) 563 { 564 if(!tp->lst.lstlef || !tp->lst.lstlef->tre.tretyp==TCOM || tp->lst.lstlef->com.comarg || tp->lst.lstlef->com.comset && tp->lst.lstlef->com.comset->argval[0]!='[') 565 break; 566 tp = tp->lst.lstrit; 567 568 } 569 if(!nv_isarray(np) && !typ && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='[')) 570 { 571 nv_setvtree(np); 572 if(tp->com.comarg || tp->com.comset) 573 np->nvfun->dsize = 0; 574 } 575#if SHOPT_TYPEDEF 576 goto check_type; 577#else 578 continue; 579#endif /* SHOPT_TYPEDEF */ 580 } 581 cp = arg->argval; 582 mp = 0; 583 } 584 np = nv_open(cp,shp->var_tree,flags); 585 if(!np->nvfun && (flags&NV_NOREF)) 586 { 587 if(shp->used_pos) 588 nv_onattr(np,NV_PARAM); 589 else 590 nv_offattr(np,NV_PARAM); 591 } 592 if(traceon || trap) 593 { 594 register char *sp=cp; 595 char *name=nv_name(np); 596 char *sub=0; 597 int append = 0; 598 if(nv_isarray(np)) 599 sub = savesub; 600 if(cp=lastdot(sp,'=')) 601 { 602 if(cp[-1]=='+') 603 append = ARG_APPEND; 604 cp++; 605 } 606 if(traceon) 607 { 608 sh_trace(shp,NIL(char**),0); 609 nv_outname(sfstderr,name,-1); 610 if(sub) 611 sfprintf(sfstderr,"[%s]",sh_fmtq(sub)); 612 if(cp) 613 { 614 if(append) 615 sfputc(sfstderr,'+'); 616 sfprintf(sfstderr,"=%s\n",sh_fmtq(cp)); 617 } 618 } 619 if(trap) 620 { 621 char *av[2]; 622 av[0] = cp; 623 av[1] = 0; 624 sh_debug(shp,trap,name,sub,av,append); 625 } 626 } 627#if SHOPT_TYPEDEF 628 check_type: 629 if(maketype) 630 { 631 nv_open(shtp.nodes[0]->nvname,shp->var_tree,NV_ASSIGN|NV_VARNAME|NV_NOADD|NV_NOFAIL); 632 np = nv_mktype(shtp.nodes,shtp.numnodes); 633 free((void*)shtp.nodes); 634 shp->mktype = shtp.previous; 635 maketype = 0; 636 shp->prefix = 0; 637 if(nr.np == np) 638 { 639 L_ARGNOD->nvalue.nrp = node.nvalue.nrp; 640 L_ARGNOD->nvflag = node.nvflag; 641 L_ARGNOD->nvfun = node.nvfun; 642 } 643 } 644#endif /* SHOPT_TYPEDEF */ 645 } 646} 647 648/* 649 * copy the subscript onto the stack 650 */ 651static void stak_subscript(const char *sub, int last) 652{ 653 register int c; 654 stakputc('['); 655 while(c= *sub++) 656 { 657 if(c=='[' || c==']' || c=='\\') 658 stakputc('\\'); 659 stakputc(c); 660 } 661 stakputc(last); 662} 663 664/* 665 * construct a new name from a prefix and base name on the stack 666 */ 667static char *copystack(const char *prefix, register const char *name, const char *sub) 668{ 669 register int last=0,offset = staktell(); 670 if(prefix) 671 { 672 stakputs(prefix); 673 if(*stakptr(staktell()-1)=='.') 674 stakseek(staktell()-1); 675 if(*name=='.' && name[1]=='[') 676 last = staktell()+2; 677 if(*name!='[' && *name!='.' && *name!='=' && *name!='+') 678 stakputc('.'); 679 if(*name=='.' && (name[1]=='=' || name[1]==0)) 680 stakputc('.'); 681 } 682 if(last) 683 { 684 stakputs(name); 685 if(sh_checkid(stakptr(last),(char*)0)) 686 stakseek(staktell()-2); 687 } 688 if(sub) 689 stak_subscript(sub,']'); 690 if(!last) 691 stakputs(name); 692 stakputc(0); 693 return(stakptr(offset)); 694} 695 696/* 697 * grow this stack string <name> by <n> bytes and move from cp-1 to end 698 * right by <n>. Returns beginning of string on the stack 699 */ 700static char *stack_extend(const char *cname, char *cp, int n) 701{ 702 register char *name = (char*)cname; 703 int offset = name - stakptr(0); 704 int m = cp-name; 705 stakseek(strlen(name)+n+1); 706 name = stakptr(offset); 707 cp = name + m; 708 m = strlen(cp)+1; 709 while(m-->0) 710 cp[n+m]=cp[m]; 711 return((char*)name); 712} 713 714Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) 715{ 716 Shell_t *shp = sh_getinterp(); 717 char *cp=(char*)name, *sp, *xp; 718 register int c; 719 register Namval_t *np=0, *nq=0; 720 Namfun_t *fp=0; 721 long mode, add=0; 722 int copy=0,isref,top=0,noscope=(flags&NV_NOSCOPE); 723#if SHOPT_FIXEDARRAY 724 Namarr_t *ap; 725#endif /* SHOPT_FIXEDARRAY */ 726 if(root==shp->var_tree) 727 { 728 if(dtvnext(root)) 729 top = 1; 730 else 731 flags &= ~NV_NOSCOPE; 732 } 733 if(!dp->disc) 734 copy = dp->nofree&1; 735 if(*cp=='.') 736 cp++; 737 while(1) 738 { 739 switch(c = *(unsigned char*)(sp = cp)) 740 { 741 case '[': 742 if(flags&NV_NOARRAY) 743 { 744 dp->last = cp; 745 return(np); 746 } 747 cp = nv_endsubscript((Namval_t*)0,sp,0); 748 if(sp==name || sp[-1]=='.') 749 c = *(sp = cp); 750 goto skip; 751 case '.': 752 if(flags&NV_IDENT) 753 return(0); 754 if(root==shp->var_tree) 755 flags &= ~NV_EXPORT; 756 if(!copy && !(flags&NV_NOREF)) 757 { 758 c = sp-name; 759 copy = cp-name; 760 dp->nofree |= 1; 761 name = copystack((const char*)0, name,(const char*)0); 762 cp = (char*)name+copy; 763 sp = (char*)name+c; 764 c = '.'; 765 } 766 skip: 767 case '+': 768 case '=': 769 *sp = 0; 770 case 0: 771 isref = 0; 772 dp->last = cp; 773 mode = (c=='.' || (flags&NV_NOADD))?add:NV_ADD; 774 if((flags&NV_NOSCOPE) && c!='.') 775 mode |= HASH_NOSCOPE; 776 np=0; 777 if(top) 778 { 779 struct Ufunction *rp; 780 if((rp=shp->st.real_fun) && !rp->sdict && (flags&NV_STATIC)) 781 { 782 Dt_t *dp = dtview(shp->var_tree,(Dt_t*)0); 783 rp->sdict = dtopen(&_Nvdisc,Dtoset); 784 dtview(rp->sdict,dp); 785 dtview(shp->var_tree,rp->sdict); 786 } 787 if(np = nv_search(name,shp->var_tree,0)) 788 { 789#if SHOPT_NAMESPACE 790 if(shp->var_tree->walk==shp->var_base || (shp->var_tree->walk!=shp->var_tree && shp->namespace && nv_dict(shp->namespace)==shp->var_tree->walk)) 791#else 792 if(shp->var_tree->walk==shp->var_base) 793#endif /* SHOPT_NAMESPACE */ 794 { 795#if SHOPT_NAMESPACE 796 if(!(nq = nv_search((char*)np,shp->var_base,HASH_BUCKET))) 797#endif /* SHOPT_NAMESPACE */ 798 nq = np; 799 shp->last_root = shp->var_tree->walk; 800 if((flags&NV_NOSCOPE) && *cp!='.') 801 { 802 if(mode==0) 803 root = shp->var_tree->walk; 804 else 805 { 806 nv_delete(np,(Dt_t*)0,NV_NOFREE); 807 np = 0; 808 } 809 } 810 } 811 else 812 { 813 if(shp->var_tree->walk) 814 root = shp->var_tree->walk; 815 flags |= NV_NOSCOPE; 816 noscope = 1; 817 } 818 } 819 if(rp && rp->sdict && (flags&NV_STATIC)) 820 { 821 root = rp->sdict; 822 if(np && shp->var_tree->walk==shp->var_tree) 823 { 824 _nv_unset(np,0); 825 nv_delete(np,shp->var_tree,0); 826 np = 0; 827 } 828 if(!np || shp->var_tree->walk!=root) 829 np = nv_search(name,root,HASH_NOSCOPE|NV_ADD); 830 } 831 } 832#if SHOPT_NAMESPACE 833 if(!np && !noscope && *name!='.' && shp->namespace && root==shp->var_tree) 834 root = nv_dict(shp->namespace); 835#endif /* SHOPT_NAMESPACE */ 836 if(np || (np = nv_search(name,root,mode))) 837 { 838 isref = nv_isref(np); 839 if(top) 840 { 841 if(nq==np) 842 { 843 flags &= ~NV_NOSCOPE; 844 root = shp->last_root; 845 } 846 else if(nq) 847 { 848 if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq))) 849 np->nvname = nq->nvname; 850 flags |= NV_NOSCOPE; 851 } 852 } 853 else if(add && nv_isnull(np) && c=='.' && cp[1]!='.') 854 nv_setvtree(np); 855#if SHOPT_NAMESPACE 856 if(shp->namespace && root==nv_dict(shp->namespace)) 857 { 858 flags |= NV_NOSCOPE; 859 shp->last_table = shp->namespace; 860 } 861#endif /* SHOPT_NAMESPACE */ 862 } 863 if(c) 864 *sp = c; 865 top = 0; 866 if(isref) 867 { 868#if SHOPT_FIXEDARRAY 869 int n=0,dim; 870#endif /* SHOPT_FIXEDARRAY */ 871 char *sub=0; 872#if NVCACHE 873 nvcache.ok = 0; 874#endif 875 if(c=='.') /* don't optimize */ 876 shp->argaddr = 0; 877 else if((flags&NV_NOREF) && (c!='[' && *cp!='.')) 878 { 879 if(c && !(flags&NV_NOADD)) 880 nv_unref(np); 881 return(np); 882 } 883 while(nv_isref(np) && np->nvalue.cp) 884 { 885 root = nv_reftree(np); 886 shp->last_root = root; 887 shp->last_table = nv_reftable(np); 888 sub = nv_refsub(np); 889#if SHOPT_FIXEDARRAY 890 n = nv_refindex(np); 891 dim = nv_refdimen(np); 892#endif /* SHOPT_FIXEDARRAY */ 893 np = nv_refnode(np); 894#if SHOPT_FIXEDARRAY 895 if(n) 896 { 897 ap = nv_arrayptr(np); 898 ap->nelem = dim; 899 nv_putsub(np,(char*)0,n); 900 } 901 else 902#endif /* SHOPT_FIXEDARRAY */ 903 if(sub && c!='.') 904 nv_putsub(np,sub,0L); 905 flags |= NV_NOSCOPE; 906 noscope = 1; 907 } 908 if(nv_isref(np) && (c=='[' || c=='.' || !(flags&NV_ASSIGN))) 909 errormsg(SH_DICT,ERROR_exit(1),e_noref,nv_name(np)); 910 911 if(sub && c==0 && !(flags&NV_ARRAY)) 912 return(np); 913 if(np==nq) 914 flags &= ~(noscope?0:NV_NOSCOPE); 915#if SHOPT_FIXEDARRAY 916 else if(c || n) 917 { 918 static char null[1] = ""; 919#else 920 else if(c) 921 { 922#endif /* SHOPT_FIXEDARRAY */ 923 c = (cp-sp); 924 copy = strlen(cp=nv_name(np)); 925 dp->nofree |= 1; 926#if SHOPT_FIXEDARRAY 927 if(*sp==0) 928 name = cp; 929 else 930#endif /* SHOPT_FIXEDARRAY */ 931 name = copystack(cp,sp,sub); 932 sp = (char*)name + copy; 933 cp = sp+c; 934 c = *sp; 935 if(!noscope) 936 flags &= ~NV_NOSCOPE; 937#if SHOPT_FIXEDARRAY 938 if(c==0) 939 nv_endsubscript(np,null,NV_ADD); 940#endif /* SHOPT_FIXEDARRAY */ 941 } 942 flags |= NV_NOREF; 943 if(nv_isnull(np) && !nv_isarray(np)) 944 nv_onattr(np,NV_NOFREE); 945 } 946 shp->last_root = root; 947 if(*cp && cp[1]=='.') 948 cp++; 949 if(c=='.' && (cp[1]==0 || cp[1]=='=' || cp[1]=='+')) 950 { 951 nv_local = 1; 952 return(np); 953 } 954 if(cp[-1]=='.') 955 cp--; 956 do 957 { 958#if SHOPT_FIXEDARRAY 959 int fixed; 960#endif /* SHOPT_FIXEDARRAY */ 961 if(!np) 962 { 963 if(!nq && *sp=='[' && *cp==0 && cp[-1]==']') 964 { 965 /* 966 * for backward compatibility 967 * evaluate subscript for 968 * possible side effects 969 */ 970 cp[-1] = 0; 971 sh_arith(shp,sp+1); 972 cp[-1] = ']'; 973 } 974 return(np); 975 } 976#if SHOPT_FIXEDARRAY 977 fixed = 0; 978 if((ap=nv_arrayptr(np)) && ap->fixed) 979 fixed = 1; 980#endif /* SHOPT_FIXEDARRAY */ 981 if(c=='[' || (c=='.' && nv_isarray(np))) 982 { 983 char *sub=0; 984 int n = 0; 985 mode &= ~HASH_NOSCOPE; 986 if(c=='[') 987 { 988#if SHOPT_FIXEDARRAY 989 Namarr_t *ap = nv_arrayptr(np); 990#endif /* SHOPT_FIXEDARRAY */ 991#if 0 992 int scan = ap?(ap->nelem&ARRAY_SCAN):0; 993#endif 994 n = mode|nv_isarray(np); 995 if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']') 996 { 997 /* not implemented yet */ 998 dp->last = cp; 999 return(np); 1000 } 1001#if SHOPT_FIXEDARRAY 1002 if(fixed) 1003 flags |= NV_FARRAY; 1004 else 1005#endif /* SHOPT_FIXEDARRAY */ 1006 if((n&NV_ADD)&&(flags&NV_ARRAY)) 1007 n |= ARRAY_FILL; 1008 if(flags&NV_ASSIGN) 1009 n |= NV_ADD; 1010 cp = nv_endsubscript(np,sp,n|(flags&(NV_ASSIGN|NV_FARRAY))); 1011#if SHOPT_FIXEDARRAY 1012 flags &= ~NV_FARRAY; 1013 if(fixed) 1014 flags &= ~NV_ARRAY; 1015 1016#endif /* SHOPT_FIXEDARRAY */ 1017#if 0 1018 if(scan) 1019 nv_putsub(np,NIL(char*),ARRAY_SCAN); 1020#endif 1021 } 1022 else 1023 cp = sp; 1024 if((c = *cp)=='.' || (c=='[' && nv_isarray(np)) || (n&ARRAY_FILL) || (flags&NV_ARRAY)) 1025 1026 { 1027 int m = cp-sp; 1028 sub = m?nv_getsub(np):0; 1029 if(!sub) 1030 { 1031 if(m && !(n&NV_ADD)) 1032 return(0); 1033 sub = "0"; 1034 } 1035 n = strlen(sub)+2; 1036 if(!copy) 1037 { 1038 copy = cp-name; 1039 dp->nofree |= 1; 1040 name = copystack((const char*)0, name,(const char*)0); 1041 cp = (char*)name+copy; 1042 sp = cp-m; 1043 } 1044 if(n <= m) 1045 { 1046 if(n) 1047 { 1048 memcpy(sp+1,sub,n-2); 1049 sp[n-1] = ']'; 1050 } 1051 if(n < m) 1052 { 1053 char *dp = sp+n; 1054 while(*dp++=*cp++); 1055 cp = sp+n; 1056 } 1057 } 1058 else 1059 { 1060 int r = n-m; 1061 m = sp-name; 1062 name = stack_extend(name, cp-1, r); 1063 sp = (char*)name + m; 1064 *sp = '['; 1065 memcpy(sp+1,sub,n-2); 1066 sp[n-1] = ']'; 1067 cp = sp+n; 1068 1069 } 1070 } 1071 else if(c==0 && mode && (n=nv_aindex(np))>0) 1072 nv_putsub(np,(char*)0,n); 1073#if SHOPT_FIXEDARRAY 1074 else if(n==0 && !fixed && (c==0 || (c=='[' && !nv_isarray(np)))) 1075#else 1076 else if(n==0 && (c==0 || (c=='[' && !nv_isarray(np)))) 1077#endif /* SHOPT_FIXEDARRAY */ 1078 { 1079 /* subscript must be 0*/ 1080 cp[-1] = 0; 1081 n = sh_arith(shp,sp+1); 1082 cp[-1] = ']'; 1083 if(n) 1084 return(0); 1085 if(c) 1086 sp = cp; 1087 } 1088 dp->last = cp; 1089 if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY))) 1090 { 1091 sp = cp; 1092 if(!(nq = nv_opensub(np))) 1093 { 1094 Namarr_t *ap = nv_arrayptr(np); 1095 if(!sub && (flags&NV_NOADD)) 1096 return(0); 1097 n = mode|((flags&NV_NOADD)?0:NV_ADD); 1098 if(!ap && (n&NV_ADD)) 1099 { 1100 nv_putsub(np,sub,ARRAY_FILL); 1101 ap = nv_arrayptr(np); 1102 } 1103 if(n && ap && !ap->table) 1104 ap->table = dtopen(&_Nvdisc,Dtoset); 1105 if(ap && ap->table && (nq=nv_search(sub,ap->table,n))) 1106 nq->nvenv = (char*)np; 1107 if(nq && nv_isnull(nq)) 1108 nq = nv_arraychild(np,nq,c); 1109 } 1110 if(nq) 1111 { 1112 if(c=='.' && !nv_isvtree(nq)) 1113 { 1114 if(flags&NV_NOADD) 1115 return(0); 1116 nv_setvtree(nq); 1117 } 1118 np = nq; 1119 } 1120 else if(memcmp(cp,"[0]",3)) 1121 return(nq); 1122 else 1123 { 1124 /* ignore [0] */ 1125 dp->last = cp += 3; 1126 c = *cp; 1127 } 1128 } 1129 } 1130#if SHOPT_FIXEDARRAY 1131 else if(nv_isarray(np) && (!fixed || cp[-1]!=']')) 1132#else 1133 else if(nv_isarray(np)) 1134#endif /* SHOPT_FIXEDARRAY */ 1135 { 1136 if(c==0 && (flags&NV_MOVE)) 1137 return(np); 1138 nv_putsub(np,NIL(char*),ARRAY_UNDEF); 1139 } 1140 if(c=='.' && (fp=np->nvfun)) 1141 { 1142 for(; fp; fp=fp->next) 1143 { 1144 if(fp->disc && fp->disc->createf) 1145 break; 1146 } 1147 if(fp) 1148 { 1149 if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np) 1150 { 1151 add = NV_ADD; 1152 shp->last_table = 0; 1153 break; 1154 } 1155 else if(np=nq) 1156 { 1157 if((c = *(sp=cp=dp->last=fp->last))==0) 1158 { 1159 if(nv_isarray(np) && sp[-1]!=']') 1160 nv_putsub(np,NIL(char*),ARRAY_UNDEF); 1161 return(np); 1162 } 1163 } 1164 } 1165 } 1166 } 1167 while(c=='['); 1168 if(c!='.' || cp[1]=='.') 1169 return(np); 1170 cp++; 1171 break; 1172 default: 1173 dp->last = cp; 1174 if((c = mbchar(cp)) && !isaletter(c)) 1175 return(np); 1176 while(xp=cp, c=mbchar(cp), isaname(c)); 1177 cp = xp; 1178 } 1179 } 1180 return(np); 1181} 1182 1183/* 1184 * delete the node <np> from the dictionary <root> and clear from the cache 1185 * if <root> is NULL, only the cache is cleared 1186 * if flags does not contain NV_NOFREE, the node is freed 1187 */ 1188void nv_delete(Namval_t* np, Dt_t *root, int flags) 1189{ 1190#if NVCACHE 1191 register int c; 1192 struct Cache_entry *xp; 1193 for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c]) 1194 { 1195 if(xp->np==np) 1196 xp->root = 0; 1197 } 1198#endif 1199 if(root || !(flags&NV_NOFREE)) 1200 { 1201 if(!(flags&NV_FUNCTION) && Refdict) 1202 { 1203 Namval_t **key = &np; 1204 struct Namref *rp; 1205 while(rp = (struct Namref*)dtmatch(Refdict,(void*)key)) 1206 { 1207 rp->np = &NullNode; 1208 if(rp->sub) 1209 free(rp->sub); 1210 rp->sub = 0; 1211 dtdelete(Refdict,(void*)rp); 1212 } 1213 } 1214 } 1215 if(root) 1216 { 1217 if(dtdelete(root,np)) 1218 { 1219 if(!(flags&NV_NOFREE) && ((flags&NV_FUNCTION) || !nv_subsaved(np))) 1220 free((void*)np); 1221 } 1222#if 0 1223 else 1224 { 1225 sfprintf(sfstderr,"%s not deleted\n",nv_name(np)); 1226 sfsync(sfstderr); 1227 } 1228#endif 1229 } 1230} 1231 1232/* 1233 * Put <arg> into associative memory. 1234 * If <flags> & NV_ARRAY then follow array to next subscript 1235 * If <flags> & NV_NOARRAY then subscript is not allowed 1236 * If <flags> & NV_NOSCOPE then use the current scope only 1237 * If <flags> & NV_ASSIGN then assignment is allowed 1238 * If <flags> & NV_IDENT then name must be an identifier 1239 * If <flags> & NV_VARNAME then name must be a valid variable name 1240 * If <flags> & NV_NOADD then node will not be added if not found 1241 * If <flags> & NV_NOREF then don't follow reference 1242 * If <flags> & NV_NOFAIL then don't generate an error message on failure 1243 * If <flags> & NV_STATIC then unset before an assignment 1244 * If <flags> & NV_UNJUST then unset attributes before assignment 1245 * SH_INIT is only set while initializing the environment 1246 */ 1247Namval_t *nv_open(const char *name, Dt_t *root, int flags) 1248{ 1249 Shell_t *shp = sh_getinterp(); 1250 register char *cp=(char*)name; 1251 register int c; 1252 register Namval_t *np=0; 1253 Namfun_t fun; 1254 int append=0; 1255 const char *msg = e_varname; 1256 char *fname = 0; 1257 int offset = staktell(); 1258 Dt_t *funroot; 1259#if NVCACHE 1260 struct Cache_entry *xp; 1261#endif 1262 1263 sh_stats(STAT_NVOPEN); 1264 memset(&fun,0,sizeof(fun)); 1265 shp->last_table = 0; 1266 if(!root) 1267 root = shp->var_tree; 1268 shp->last_root = root; 1269 if(root==shp->fun_tree) 1270 { 1271 flags |= NV_NOREF; 1272 msg = e_badfun; 1273 if(strchr(name,'.')) 1274 { 1275 name = cp = copystack(0,name,(const char*)0); 1276 fname = strrchr(cp,'.'); 1277 *fname = 0; 1278 fun.nofree |= 1; 1279 flags &= ~NV_IDENT; 1280 funroot = root; 1281 root = shp->var_tree; 1282 } 1283 } 1284 else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN))) 1285 { 1286 long mode = ((flags&NV_NOADD)?0:NV_ADD); 1287 if(flags&NV_NOSCOPE) 1288 mode |= HASH_SCOPE|HASH_NOSCOPE; 1289 np = nv_search(name,root,mode); 1290 if(np && !(flags&NV_REF)) 1291 { 1292 while(nv_isref(np)) 1293 { 1294 shp->last_table = nv_reftable(np); 1295 np = nv_refnode(np); 1296 } 1297 } 1298 return(np); 1299 } 1300 else if(shp->prefix && (flags&NV_ASSIGN)) 1301 { 1302 name = cp = copystack(shp->prefix,name,(const char*)0); 1303 fun.nofree |= 1; 1304 } 1305 c = *(unsigned char*)cp; 1306 if(root==shp->alias_tree) 1307 { 1308 msg = e_aliname; 1309 while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') && 1310 (c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON)); 1311 if(shp->subshell && c=='=') 1312 root = sh_subaliastree(1); 1313 if(c= *--cp) 1314 *cp = 0; 1315 np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD); 1316 if(c) 1317 *cp = c; 1318 goto skip; 1319 } 1320 else if(flags&NV_IDENT) 1321 msg = e_ident; 1322 else if(c=='.') 1323 { 1324 c = *++cp; 1325 flags |= NV_NOREF; 1326 if(root==shp->var_tree) 1327 root = shp->var_base; 1328 shp->last_table = 0; 1329 } 1330 if(c= !isaletter(c)) 1331 goto skip; 1332#if NVCACHE 1333 for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c]) 1334 { 1335 if(xp->root!=root) 1336 continue; 1337 if(*name==*xp->name && (flags&(NV_ARRAY|NV_NOSCOPE))==xp->flags && memcmp(xp->name,name,xp->len)==0 && (name[xp->len]==0 || name[xp->len]=='=' || name[xp->len]=='+')) 1338 { 1339 sh_stats(STAT_NVHITS); 1340 np = xp->np; 1341 cp = (char*)name+xp->len; 1342 if(nv_isarray(np) && !(flags&NV_MOVE)) 1343 nv_putsub(np,NIL(char*),ARRAY_UNDEF); 1344 shp->last_table = xp->last_table; 1345 shp->last_root = xp->last_root; 1346 goto nocache; 1347 } 1348 } 1349 nvcache.ok = 1; 1350#endif 1351 np = nv_create(name, root, flags, &fun); 1352 cp = fun.last; 1353#if NVCACHE 1354 if(np && nvcache.ok && cp[-1]!=']') 1355 { 1356 xp = &nvcache.entries[nvcache.index]; 1357 if(*cp) 1358 { 1359 char *sp = strchr(name,*cp); 1360 if(!sp) 1361 goto nocache; 1362 xp->len = sp-name; 1363 } 1364 else 1365 xp->len = strlen(name); 1366 c = roundof(xp->len+1,32); 1367 if(c > xp->size) 1368 { 1369 if(xp->size==0) 1370 xp->name = malloc(c); 1371 else 1372 xp->name = realloc(xp->name,c); 1373 xp->size = c; 1374 } 1375 memcpy(xp->name,name,xp->len); 1376 xp->name[xp->len] = 0; 1377 xp->root = root; 1378 xp->np = np; 1379 xp->last_table = shp->last_table; 1380 xp->last_root = shp->last_root; 1381 xp->flags = (flags&(NV_ARRAY|NV_NOSCOPE)); 1382 nvcache.index = (nvcache.index+1)&(NVCACHE-1); 1383 } 1384nocache: 1385 nvcache.ok = 0; 1386#endif 1387 if(fname) 1388 { 1389 c = ((flags&NV_NOSCOPE)?HASH_NOSCOPE:0)|((flags&NV_NOADD)?0:NV_ADD); 1390 *fname = '.'; 1391 np = nv_search(name, funroot, c); 1392 *fname = 0; 1393 } 1394 else 1395 { 1396 if(*cp=='.' && cp[1]=='.') 1397 { 1398 append |= NV_NODISC; 1399 cp+=2; 1400 } 1401 if(*cp=='+' && cp[1]=='=') 1402 { 1403 append |= NV_APPEND; 1404 cp++; 1405 } 1406 } 1407 c = *cp; 1408skip: 1409#if SHOPT_TYPEDEF 1410 if(np && shp->mktype) 1411 np = nv_addnode(np,0); 1412#endif /* SHOPT_TYPEDEF */ 1413 if(c=='=' && np && (flags&NV_ASSIGN)) 1414 { 1415 cp++; 1416 if(sh_isstate(SH_INIT)) 1417 { 1418 nv_putval(np, cp, NV_RDONLY); 1419 if(np==PWDNOD) 1420 nv_onattr(np,NV_TAGGED); 1421 } 1422 else 1423 { 1424 char *sub=0, *prefix= shp->prefix; 1425 Namval_t *mp; 1426 Namarr_t *ap; 1427 int isref; 1428 shp->prefix = 0; 1429 if((flags&NV_STATIC) && !shp->mktype) 1430 { 1431 if(!nv_isnull(np)) 1432 { 1433 shp->prefix = prefix; 1434 return(np); 1435 } 1436 } 1437 isref = nv_isref(np); 1438#if SHOPT_FIXEDARRAY 1439 if(sh_isoption(SH_XTRACE) && (ap=nv_arrayptr(np)) && !ap->fixed) 1440#else 1441 if(sh_isoption(SH_XTRACE) && nv_isarray(np)) 1442#endif /* SHOPT_FIXEDARRAY */ 1443 sub = nv_getsub(np); 1444 c = msg==e_aliname? 0: (append | (flags&NV_EXPORT)); 1445 if(isref) 1446 nv_offattr(np,NV_REF); 1447 if(!append && (flags&NV_UNJUST)) 1448 { 1449 nv_offattr(np,NV_LJUST|NV_RJUST|NV_ZFILL); 1450 np->nvsize = 0; 1451 } 1452 if((flags&NV_MOVE) && (ap=nv_arrayptr(np)) && (mp=nv_opensub(np))) 1453 { 1454 _nv_unset(mp,NV_EXPORT); 1455 np = mp; 1456 } 1457 nv_putval(np, cp, c); 1458 if(isref) 1459 { 1460 if(nv_search((char*)np,shp->var_base,HASH_BUCKET)) 1461 shp->last_root = shp->var_base; 1462 nv_setref(np,(Dt_t*)0,NV_VARNAME); 1463 } 1464 savesub = sub; 1465 shp->prefix = prefix; 1466 } 1467 nv_onattr(np, flags&NV_ATTRIBUTES); 1468 } 1469 else if(c) 1470 { 1471 if(flags&NV_NOFAIL) 1472 return(0); 1473 if(c=='.') 1474 msg = e_noparent; 1475 else if(c=='[') 1476 msg = e_noarray; 1477 errormsg(SH_DICT,ERROR_exit(1),msg,name); 1478 } 1479 if(fun.nofree&1) 1480 stakseek(offset); 1481 return(np); 1482} 1483 1484#if SHOPT_MULTIBYTE 1485 static int ja_size(char*, int, int); 1486 static void ja_restore(void); 1487 static char *savep; 1488 static char savechars[8+1]; 1489#endif /* SHOPT_MULTIBYTE */ 1490 1491/* 1492 * put value <string> into name-value node <np>. 1493 * If <np> is an array, then the element given by the 1494 * current index is assigned to. 1495 * If <flags> contains NV_RDONLY, readonly attribute is ignored 1496 * If <flags> contains NV_INTEGER, string is a pointer to a number 1497 * If <flags> contains NV_NOFREE, previous value is freed, and <string> 1498 * becomes value of node and <flags> becomes attributes 1499 */ 1500void nv_putval(register Namval_t *np, const char *string, int flags) 1501{ 1502 Shell_t *shp = sh_getinterp(); 1503 register const char *sp=string; 1504 register union Value *up; 1505 register char *cp; 1506 register int size = 0; 1507 register int dot; 1508 int was_local = nv_local; 1509 union Value u; 1510#if SHOPT_FIXEDARRAY 1511 Namarr_t *ap; 1512#endif /* SHOPT_FIXEDARRAY */ 1513 if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY)) 1514 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np)); 1515 /* The following could cause the shell to fork if assignment 1516 * would cause a side effect 1517 */ 1518 shp->argaddr = 0; 1519 if(shp->subshell && !nv_local) 1520 np = sh_assignok(np,1); 1521 if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isref(np)) 1522 { 1523 /* This function contains disc */ 1524 if(!nv_local) 1525 { 1526 nv_local=1; 1527 nv_putv(np,sp,flags,np->nvfun); 1528 if(sp && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT))) 1529 sh_envput(shp->env,np); 1530 return; 1531 } 1532 /* called from disc, assign the actual value */ 1533 } 1534 flags &= ~NV_NODISC; 1535 nv_local=0; 1536 if(flags&(NV_NOREF|NV_NOFREE)) 1537 { 1538 if(np->nvalue.cp && np->nvalue.cp!=sp && !nv_isattr(np,NV_NOFREE)) 1539 free((void*)np->nvalue.cp); 1540 np->nvalue.cp = (char*)sp; 1541 nv_setattr(np,(flags&~NV_RDONLY)|NV_NOFREE); 1542 return; 1543 } 1544 up= &np->nvalue; 1545 if(nv_isattr(np,NV_INT16P) == NV_INT16) 1546 { 1547 if(!np->nvalue.up || !nv_isarray(np)) 1548 { 1549 up = &u; 1550 up->up = &np->nvalue; 1551 } 1552 } 1553#if SHOPT_FIXEDARRAY 1554 else if(np->nvalue.up && nv_isarray(np) && (ap=nv_arrayptr(np)) && !ap->fixed) 1555#else 1556 else if(np->nvalue.up && nv_isarray(np) && nv_arrayptr(np)) 1557#endif /* SHOPT_FIXEDARRAY */ 1558 up = np->nvalue.up; 1559 if(up && up->cp==Empty) 1560 up->cp = 0; 1561 if(nv_isattr(np,NV_EXPORT)) 1562 nv_offattr(np,NV_IMPORT); 1563 if(nv_isattr (np, NV_INTEGER)) 1564 { 1565 if(nv_isattr(np, NV_DOUBLE) == NV_DOUBLE) 1566 { 1567 if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t)) 1568 { 1569 Sfdouble_t ld, old=0; 1570 if(flags&NV_INTEGER) 1571 { 1572 if(flags&NV_LONG) 1573 ld = *((Sfdouble_t*)sp); 1574 else if(flags&NV_SHORT) 1575 ld = *((float*)sp); 1576 else 1577 ld = *((double*)sp); 1578 } 1579 else 1580 ld = sh_arith(shp,sp); 1581 if(!up->ldp) 1582 up->ldp = new_of(Sfdouble_t,0); 1583 else if(flags&NV_APPEND) 1584 old = *(up->ldp); 1585 *(up->ldp) = old?ld+old:ld; 1586 } 1587 else 1588 { 1589 double d,od=0; 1590 if(flags&NV_INTEGER) 1591 { 1592 if(flags&NV_LONG) 1593 d = (double)(*(Sfdouble_t*)sp); 1594 else if(flags&NV_SHORT) 1595 d = (double)(*(float*)sp); 1596 else 1597 d = *(double*)sp; 1598 } 1599 else 1600 d = sh_arith(shp,sp); 1601 if(!up->dp) 1602 up->dp = new_of(double,0); 1603 else if(flags&NV_APPEND) 1604 od = *(up->dp); 1605 *(up->dp) = od?d+od:d; 1606 } 1607 } 1608 else 1609 { 1610 if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t)) 1611 { 1612 Sflong_t ll=0,oll=0; 1613 if(flags&NV_INTEGER) 1614 { 1615 if((flags&NV_DOUBLE) == NV_DOUBLE) 1616 { 1617 if(flags&NV_LONG) 1618 ll = *((Sfdouble_t*)sp); 1619 else if(flags&NV_SHORT) 1620 ll = *((float*)sp); 1621 else 1622 ll = *((double*)sp); 1623 } 1624 else if(nv_isattr(np,NV_UNSIGN)) 1625 { 1626 if(flags&NV_LONG) 1627 ll = *((Sfulong_t*)sp); 1628 else if(flags&NV_SHORT) 1629 ll = *((uint16_t*)sp); 1630 else 1631 ll = *((uint32_t*)sp); 1632 } 1633 else 1634 { 1635 if(flags&NV_LONG) 1636 ll = *((Sflong_t*)sp); 1637 else if(flags&NV_SHORT) 1638 ll = *((uint16_t*)sp); 1639 else 1640 ll = *((uint32_t*)sp); 1641 } 1642 } 1643 else if(sp) 1644 ll = (Sflong_t)sh_arith(shp,sp); 1645 if(!up->llp) 1646 up->llp = new_of(Sflong_t,0); 1647 else if(flags&NV_APPEND) 1648 oll = *(up->llp); 1649 *(up->llp) = ll+oll; 1650 } 1651 else 1652 { 1653 int32_t l=0,ol=0; 1654 if(flags&NV_INTEGER) 1655 { 1656 if((flags&NV_DOUBLE) == NV_DOUBLE) 1657 { 1658 Sflong_t ll; 1659 if(flags&NV_LONG) 1660 ll = *((Sfdouble_t*)sp); 1661 else if(flags&NV_SHORT) 1662 ll = *((float*)sp); 1663 else 1664 ll = *((double*)sp); 1665 l = (int32_t)ll; 1666 } 1667 else if(nv_isattr(np,NV_UNSIGN)) 1668 { 1669 if(flags&NV_LONG) 1670 l = *((Sfulong_t*)sp); 1671 else if(flags&NV_SHORT) 1672 l = *((uint16_t*)sp); 1673 else 1674 l = *(uint32_t*)sp; 1675 } 1676 else 1677 { 1678 if(flags&NV_LONG) 1679 l = *((Sflong_t*)sp); 1680 else if(flags&NV_SHORT) 1681 l = *((int16_t*)sp); 1682 else 1683 l = *(int32_t*)sp; 1684 } 1685 } 1686 else if(sp) 1687 { 1688 Sfdouble_t ld = sh_arith(shp,sp); 1689 if(ld<0) 1690 l = (int32_t)ld; 1691 else 1692 l = (uint32_t)ld; 1693 } 1694 if(nv_size(np) <= 1) 1695 nv_setsize(np,10); 1696 if(nv_isattr (np, NV_SHORT)) 1697 { 1698 int16_t s=0; 1699 if(flags&NV_APPEND) 1700 s = *up->sp; 1701 *(up->sp) = s+(int16_t)l; 1702 nv_onattr(np,NV_NOFREE); 1703 } 1704 else 1705 { 1706 if(!up->lp) 1707 up->lp = new_of(int32_t,0); 1708 else if(flags&NV_APPEND) 1709 ol = *(up->lp); 1710 *(up->lp) = l+ol; 1711 } 1712 } 1713 } 1714 } 1715 else 1716 { 1717 const char *tofree=0; 1718 int offset; 1719#if _lib_pathnative 1720 char buff[PATH_MAX]; 1721#endif /* _lib_pathnative */ 1722 if(flags&NV_INTEGER) 1723 { 1724 if((flags&NV_DOUBLE)==NV_DOUBLE) 1725 { 1726 if(flags&NV_LONG) 1727 sfprintf(shp->strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp)); 1728 else 1729 sfprintf(shp->strbuf,"%.*g",DBL_DIG,*((double*)sp)); 1730 } 1731 else if(flags&NV_UNSIGN) 1732 { 1733 if(flags&NV_LONG) 1734 sfprintf(shp->strbuf,"%I*lu",sizeof(Sfulong_t),*((Sfulong_t*)sp)); 1735 else 1736 sfprintf(shp->strbuf,"%lu",(unsigned long)((flags&NV_SHORT)?*((uint16_t*)sp):*((uint32_t*)sp))); 1737 } 1738 else 1739 { 1740 if(flags&NV_LONG) 1741 sfprintf(shp->strbuf,"%I*ld",sizeof(Sflong_t),*((Sflong_t*)sp)); 1742 else 1743 sfprintf(shp->strbuf,"%ld",(long)((flags&NV_SHORT)?*((int16_t*)sp):*((int32_t*)sp))); 1744 } 1745 sp = sfstruse(shp->strbuf); 1746 } 1747 if(nv_isattr(np, NV_HOST|NV_INTEGER)==NV_HOST && sp) 1748 { 1749#ifdef _lib_pathnative 1750 /* 1751 * return the host file name given the UNIX name 1752 */ 1753 pathnative(sp,buff,sizeof(buff)); 1754 if(buff[1]==':' && buff[2]=='/') 1755 { 1756 buff[2] = '\\'; 1757 if(*buff>='A' && *buff<='Z') 1758 *buff += 'a'-'A'; 1759 } 1760 sp = buff; 1761#else 1762 ; 1763#endif /* _lib_pathnative */ 1764 } 1765 else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp) 1766 { 1767 for(;*sp == ' '|| *sp=='\t';sp++); 1768 if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST))) 1769 for(;*sp=='0';sp++); 1770 size = nv_size(np); 1771#if SHOPT_MULTIBYTE 1772 if(size) 1773 size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL)); 1774#endif /* SHOPT_MULTIBYTE */ 1775 } 1776 if(!up->cp) 1777 flags &= ~NV_APPEND; 1778 if((flags&NV_APPEND) && !nv_isattr(np,NV_BINARY)) 1779 { 1780 offset = staktell(); 1781 stakputs(up->cp); 1782 stakputs(sp); 1783 stakputc(0); 1784 sp = stakptr(offset); 1785 } 1786 if(!nv_isattr(np, NV_NOFREE)) 1787 { 1788 /* delay free in case <sp> points into free region */ 1789 tofree = up->cp; 1790 } 1791 if(nv_isattr(np,NV_BINARY) && !(flags&NV_RAW)) 1792 tofree = 0; 1793 if(nv_isattr(np,NV_LJUST|NV_RJUST) && nv_isattr(np,NV_LJUST|NV_RJUST)!=(NV_LJUST|NV_RJUST)) 1794 tofree = 0; 1795 if (sp) 1796 { 1797 dot = strlen(sp); 1798#if (_AST_VERSION>=20030127L) 1799 if(nv_isattr(np,NV_BINARY)) 1800 { 1801 int oldsize = (flags&NV_APPEND)?nv_size(np):0; 1802 if(flags&NV_RAW) 1803 { 1804 if(tofree) 1805 { 1806 free((void*)tofree); 1807 nv_offattr(np,NV_NOFREE); 1808 } 1809 up->cp = sp; 1810 return; 1811 } 1812 size = 0; 1813 if(nv_isattr(np,NV_ZFILL)) 1814 size = nv_size(np); 1815 if(size==0) 1816 size = oldsize + (3*dot/4); 1817 cp = (char*)malloc(size+1); 1818 nv_offattr(np,NV_NOFREE); 1819 if(oldsize) 1820 memcpy((void*)cp,(void*)up->cp,oldsize); 1821 up->cp = cp; 1822 if(size <= oldsize) 1823 return; 1824 dot = base64decode(sp,dot, (void**)0, cp+oldsize, size-oldsize,(void**)0); 1825 dot += oldsize; 1826 if(!nv_isattr(np,NV_ZFILL) || nv_size(np)==0) 1827 nv_setsize(np,dot); 1828 else if(nv_isattr(np,NV_ZFILL) && (size>dot)) 1829 memset((void*)&cp[dot],0,size-dot); 1830 return; 1831 } 1832 else 1833#endif 1834 if(size==0 && nv_isattr(np,NV_HOST)!=NV_HOST &&nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL)) 1835 nv_setsize(np,size=dot); 1836 else if(size > dot) 1837 dot = size; 1838 else if(nv_isattr(np,NV_LJUST|NV_RJUST)==NV_LJUST && dot>size) 1839 dot = size; 1840 if(size==0 || tofree || !(cp=(char*)up->cp)) 1841 { 1842 if(dot==0 && !nv_isattr(np,NV_LJUST|NV_RJUST)) 1843 { 1844 cp = Null; 1845 nv_onattr(np,NV_NOFREE); 1846 } 1847 else 1848 { 1849 cp = (char*)malloc(((unsigned)dot+1)); 1850 cp[dot] = 0; 1851 nv_offattr(np,NV_NOFREE); 1852 } 1853 } 1854 1855 } 1856 else 1857 cp = 0; 1858 up->cp = cp; 1859 if(sp) 1860 { 1861 int c = cp[dot]; 1862 memmove(cp,sp,dot); 1863 cp[dot] = c; 1864 if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL)) 1865 rightjust(cp,size,'0'); 1866 else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_RJUST) 1867 rightjust(cp,size,' '); 1868 else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_LJUST) 1869 { 1870 register char *dp; 1871 dp = strlen (cp) + cp; 1872 cp = cp+size; 1873 for (; dp < cp; *dp++ = ' '); 1874 } 1875#if SHOPT_MULTIBYTE 1876 /* restore original string */ 1877 if(savep) 1878 ja_restore(); 1879#endif /* SHOPT_MULTIBYTE */ 1880 } 1881 if(flags&NV_APPEND) 1882 stakseek(offset); 1883 if(tofree && tofree!=Empty && tofree!=Null) 1884 free((void*)tofree); 1885 } 1886 if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT))) 1887 sh_envput(shp->env,np); 1888 return; 1889} 1890 1891/* 1892 * 1893 * Right-justify <str> so that it contains no more than 1894 * <size> characters. If <str> contains fewer than <size> 1895 * characters, left-pad with <fill>. Trailing blanks 1896 * in <str> will be ignored. 1897 * 1898 * If the leftmost digit in <str> is not a digit, <fill> 1899 * will default to a blank. 1900 */ 1901static void rightjust(char *str, int size, int fill) 1902{ 1903 register int n; 1904 register char *cp,*sp; 1905 n = strlen(str); 1906 1907 /* ignore trailing blanks */ 1908 for(cp=str+n;n && *--cp == ' ';n--); 1909 if (n == size) 1910 return; 1911 if(n > size) 1912 { 1913 *(str+n) = 0; 1914 for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++); 1915 return; 1916 } 1917 else *(sp = str+size) = 0; 1918 if (n == 0) 1919 { 1920 while (sp > str) 1921 *--sp = ' '; 1922 return; 1923 } 1924 while(n--) 1925 { 1926 sp--; 1927 *sp = *cp--; 1928 } 1929 if(!isdigit(*str)) 1930 fill = ' '; 1931 while(sp>str) 1932 *--sp = fill; 1933 return; 1934} 1935 1936#if SHOPT_MULTIBYTE 1937 /* 1938 * handle left and right justified fields for multi-byte chars 1939 * given physical size, return a logical size which reflects the 1940 * screen width of multi-byte characters 1941 * Multi-width characters replaced by spaces if they cross the boundary 1942 * <type> is non-zero for right justified fields 1943 */ 1944 1945 static int ja_size(char *str,int size,int type) 1946 { 1947 register char *cp = str; 1948 register int c, n=size; 1949 register int outsize; 1950 register char *oldcp=cp; 1951 int oldn; 1952 wchar_t w; 1953 while(*cp) 1954 { 1955 oldn = n; 1956 w = mbchar(cp); 1957 outsize = mbwidth(w); 1958 size -= outsize; 1959 c = cp-oldcp; 1960 n += (c-outsize); 1961 oldcp = cp; 1962 if(size<=0 && type==0) 1963 break; 1964 } 1965 /* check for right justified fields that need truncating */ 1966 if(size <0) 1967 { 1968 if(type==0) 1969 { 1970 /* left justified and character crosses field boundary */ 1971 n = oldn; 1972 /* save boundary char and replace with spaces */ 1973 size = c; 1974 savechars[size] = 0; 1975 while(size--) 1976 { 1977 savechars[size] = cp[size]; 1978 cp[size] = ' '; 1979 } 1980 savep = cp; 1981 } 1982 size = -size; 1983 if(type) 1984 n -= (ja_size(str,size,0)-size); 1985 } 1986 return(n); 1987 } 1988 1989 static void ja_restore(void) 1990 { 1991 register char *cp = savechars; 1992 while(*cp) 1993 *savep++ = *cp++; 1994 savep = 0; 1995 } 1996#endif /* SHOPT_MULTIBYTE */ 1997 1998#ifndef _ENV_H 1999static char *staknam(register Namval_t *np, char *value) 2000{ 2001 register char *p,*q; 2002 q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2); 2003 p=strcopy(q,nv_name(np)); 2004 if(value) 2005 { 2006 *p++ = '='; 2007 strcpy(p,value); 2008 } 2009 return(q); 2010} 2011#endif 2012 2013/* 2014 * put the name and attribute into value of attributes variable 2015 */ 2016#ifdef _ENV_H 2017static void attstore(register Namval_t *np, void *data) 2018{ 2019 register int flag, c = ' '; 2020 NOT_USED(data); 2021 if(!(nv_isattr(np,NV_EXPORT))) 2022 return; 2023 flag = nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER); 2024 stakputc('='); 2025 if((flag&NV_DOUBLE) == NV_DOUBLE) 2026 { 2027 /* export doubles as integers for ksh88 compatibility */ 2028 stakputc(c+NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE))); 2029 } 2030 else 2031 { 2032 stakputc(c+flag); 2033 if(flag&NV_INTEGER) 2034 c += nv_size(np); 2035 } 2036 stakputc(c); 2037 stakputs(nv_name(np)); 2038} 2039#else 2040static void attstore(register Namval_t *np, void *data) 2041{ 2042 register int flag = np->nvflag; 2043 register struct adata *ap = (struct adata*)data; 2044 ap->sh = sh_getinterp(); 2045 ap->tp = 0; 2046 if(!(flag&NV_EXPORT) || (flag&NV_FUNCT)) 2047 return; 2048 if((flag&(NV_UTOL|NV_LTOU|NV_INTEGER)) == (NV_UTOL|NV_LTOU)) 2049 { 2050 data = (void*)nv_mapchar(np,0); 2051 if(strcmp(data,e_tolower) && strcmp(data,e_toupper)) 2052 return; 2053 } 2054 flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER); 2055 *ap->attval++ = '='; 2056 if((flag&NV_DOUBLE) == NV_DOUBLE) 2057 { 2058 /* export doubles as integers for ksh88 compatibility */ 2059 *ap->attval++ = ' '+ NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE)); 2060 *ap->attval = ' '; 2061 } 2062 else 2063 { 2064 *ap->attval++ = ' '+flag; 2065 if(flag&NV_INTEGER) 2066 *ap->attval = ' ' + nv_size(np); 2067 else 2068 *ap->attval = ' '; 2069 } 2070 ap->attval = strcopy(++ap->attval,nv_name(np)); 2071} 2072#endif 2073 2074#ifndef _ENV_H 2075static void pushnam(Namval_t *np, void *data) 2076{ 2077 register char *value; 2078 register struct adata *ap = (struct adata*)data; 2079 ap->sh = sh_getinterp(); 2080 ap->tp = 0; 2081 if(nv_isattr(np,NV_IMPORT) && np->nvenv) 2082 *ap->argnam++ = np->nvenv; 2083 else if(value=nv_getval(np)) 2084 *ap->argnam++ = staknam(np,value); 2085 if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER)) 2086 ap->attsize += (strlen(nv_name(np))+4); 2087} 2088#endif 2089 2090/* 2091 * Generate the environment list for the child. 2092 */ 2093 2094#ifdef _ENV_H 2095char **sh_envgen(void) 2096{ 2097 Shell_t *shp = sh_getinterp(); 2098 int offset,tell; 2099 register char **er; 2100 env_delete(shp->env,"_"); 2101 er = env_get(shp->env); 2102 offset = staktell(); 2103 stakputs(e_envmarker); 2104 tell = staktell(); 2105 nv_scan(shp->var_tree, attstore,(void*)0,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER)); 2106 if(tell ==staktell()) 2107 stakseek(offset); 2108 else 2109 *--er = stakfreeze(1)+offset; 2110 return(er); 2111} 2112#else 2113char **sh_envgen(void) 2114{ 2115 register char **er; 2116 register int namec; 2117 register char *cp; 2118 struct adata data; 2119 Shell_t *shp = sh_getinterp(); 2120 data.sh = shp; 2121 data.tp = 0; 2122 data.mapname = 0; 2123 /* L_ARGNOD gets generated automatically as full path name of command */ 2124 nv_offattr(L_ARGNOD,NV_EXPORT); 2125 data.attsize = 6; 2126 namec = nv_scan(shp->var_tree,nullscan,(void*)0,NV_EXPORT,NV_EXPORT); 2127 namec += shp->nenv; 2128 er = (char**)stakalloc((namec+4)*sizeof(char*)); 2129 data.argnam = (er+=2) + shp->nenv; 2130 if(shp->nenv) 2131 memcpy((void*)er,environ,shp->nenv*sizeof(char*)); 2132 nv_scan(shp->var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT); 2133 *data.argnam = (char*)stakalloc(data.attsize); 2134 cp = data.attval = strcopy(*data.argnam,e_envmarker); 2135 nv_scan(shp->var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER)); 2136 *data.attval = 0; 2137 if(cp!=data.attval) 2138 data.argnam++; 2139 *data.argnam = 0; 2140 return(er); 2141} 2142#endif 2143 2144struct scan 2145{ 2146 void (*scanfn)(Namval_t*, void*); 2147 int scanmask; 2148 int scanflags; 2149 int scancount; 2150 void *scandata; 2151}; 2152 2153static int scanfilter(Dt_t *dict, void *arg, void *data) 2154{ 2155 register Namval_t *np = (Namval_t*)arg; 2156 register int k=np->nvflag; 2157 register struct scan *sp = (struct scan*)data; 2158 register struct adata *tp = (struct adata*)sp->scandata; 2159 char *cp; 2160 NOT_USED(dict); 2161#if SHOPT_TYPEDEF 2162 if(!is_abuiltin(np) && tp && tp->tp && nv_type(np)!=tp->tp) 2163 return(0); 2164#endif /*SHOPT_TYPEDEF */ 2165 if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags))) 2166 { 2167 if(tp && tp->mapname && (sp->scanflags==NV_UTOL||sp->scanflags==NV_LTOU) && (cp=(char*)nv_mapchar(np,0)) && strcmp(cp,tp->mapname)) 2168 return(0); 2169 if(!np->nvalue.cp && !np->nvfun && !nv_isattr(np,~NV_DEFAULT)) 2170 return(0); 2171 if(sp->scanfn) 2172 { 2173 if(nv_isarray(np)) 2174 nv_putsub(np,NIL(char*),0L); 2175 (*sp->scanfn)(np,sp->scandata); 2176 } 2177 sp->scancount++; 2178 } 2179 return(0); 2180} 2181 2182/* 2183 * Walk through the name-value pairs 2184 * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags 2185 * are visited 2186 * If <mask> is zero, and <flags> non-zero, then nodes with one or 2187 * more of <flags> is visited 2188 * If <mask> and <flags> are zero, then all nodes are visted 2189 */ 2190int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags) 2191{ 2192 Dt_t *base=0; 2193 struct scan sdata; 2194 int (*hashfn)(Dt_t*, void*, void*); 2195 sdata.scanmask = mask; 2196 sdata.scanflags = flags&~NV_NOSCOPE; 2197 sdata.scanfn = fn; 2198 sdata.scancount = 0; 2199 sdata.scandata = data; 2200 hashfn = scanfilter; 2201 if(flags&NV_NOSCOPE) 2202 base = dtview((Dt_t*)root,0); 2203 dtwalk(root, hashfn,&sdata); 2204 if(base) 2205 dtview((Dt_t*)root,base); 2206 return(sdata.scancount); 2207} 2208 2209/* 2210 * create a new environment scope 2211 */ 2212void sh_scope(Shell_t *shp, struct argnod *envlist, int fun) 2213{ 2214 register Dt_t *newscope, *newroot=shp->var_base; 2215 struct Ufunction *rp; 2216#if SHOPT_NAMESPACE 2217 if(shp->namespace) 2218 { 2219 newroot = nv_dict(shp->namespace); 2220 dtview(newroot,(Dt_t*)shp->var_base); 2221 } 2222#endif /* SHOPT_NAMESPACE */ 2223 newscope = dtopen(&_Nvdisc,Dtoset); 2224 if(envlist) 2225 { 2226 dtview(newscope,(Dt_t*)shp->var_tree); 2227 shp->var_tree = newscope; 2228 nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN,0); 2229 if(!fun) 2230 return; 2231 shp->var_tree = dtview(newscope,0); 2232 } 2233 if((rp=shp->st.real_fun) && rp->sdict) 2234 { 2235 dtview(rp->sdict,newroot); 2236 newroot = rp->sdict; 2237 2238 } 2239 dtview(newscope,(Dt_t*)newroot); 2240 shp->var_tree = newscope; 2241} 2242 2243/* 2244 * Remove freeable local space associated with the nvalue field 2245 * of nnod. This includes any strings representing the value(s) of the 2246 * node, as well as its dope vector, if it is an array. 2247 */ 2248 2249void sh_envnolocal (register Namval_t *np, void *data) 2250{ 2251 struct adata *tp = (struct adata*)data; 2252 char *cp=0; 2253 if(np==VERSIONNOD && nv_isref(np)) 2254 return; 2255 if(np==L_ARGNOD) 2256 return; 2257 if(np == tp->sh->namespace) 2258 return; 2259 if(nv_isattr(np,NV_EXPORT) && nv_isarray(np)) 2260 { 2261 nv_putsub(np,NIL(char*),0); 2262 if(cp = nv_getval(np)) 2263 cp = strdup(cp); 2264 } 2265 if(nv_isattr(np,NV_EXPORT|NV_NOFREE)) 2266 { 2267 if(nv_isref(np) && np!=VERSIONNOD) 2268 { 2269 nv_offattr(np,NV_NOFREE|NV_REF); 2270 free((void*)np->nvalue.nrp); 2271 np->nvalue.cp = 0; 2272 } 2273 if(!cp) 2274 return; 2275 } 2276 if(nv_isarray(np)) 2277 nv_putsub(np,NIL(char*),ARRAY_UNDEF); 2278 _nv_unset(np,NV_RDONLY); 2279 nv_setattr(np,0); 2280 if(cp) 2281 { 2282 nv_putval(np,cp,0); 2283 free((void*)cp); 2284 } 2285} 2286 2287/* 2288 * Currently this is a dummy, but someday will be needed 2289 * for reference counting 2290 */ 2291void nv_close(Namval_t *np) 2292{ 2293 NOT_USED(np); 2294} 2295 2296static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroot) 2297{ 2298 register Namval_t *np,*nq, *npnext; 2299 for(np=(Namval_t*)dtfirst(root);np;np=npnext) 2300 { 2301 if(nq=dtsearch(oroot,np)) 2302 { 2303 if(nv_cover(nq)) 2304 { 2305 int subshell = shp->subshell; 2306 shp->subshell = 0; 2307 if(nv_isattr(nq, NV_INTEGER)) 2308 { 2309 Sfdouble_t d = nv_getnum(nq); 2310 nv_putval(nq,(char*)&d,NV_LDOUBLE); 2311 } 2312 else if(shp->test&4) 2313 nv_putval(nq, strdup(nv_getval(nq)), NV_RDONLY); 2314 else 2315 nv_putval(nq, nv_getval(nq), NV_RDONLY); 2316 shp->subshell = subshell; 2317 np->nvfun = 0; 2318 } 2319 if(nv_isattr(nq,NV_EXPORT)) 2320 sh_envput(shp->env,nq); 2321 } 2322 npnext = (Namval_t*)dtnext(root,np); 2323 shp->last_root = root; 2324 shp->last_table = 0; 2325 if(nv_isvtree(np)) 2326 { 2327 int len = strlen(np->nvname); 2328 while((nq=npnext) && memcmp(np->nvname,nq->nvname,len)==0 && nq->nvname[len]=='.') 2329 2330 { 2331 npnext = (Namval_t*)dtnext(root,nq); 2332 _nv_unset(nq,flags); 2333 nv_delete(nq,root,0); 2334 } 2335 } 2336 _nv_unset(np,flags); 2337 nv_delete(np,root,0); 2338 } 2339} 2340 2341/* 2342 * 2343 * Set the value of <np> to 0, and nullify any attributes 2344 * that <np> may have had. Free any freeable space occupied 2345 * by the value of <np>. If <np> denotes an array member, it 2346 * will retain its attributes. 2347 * <flags> can contain NV_RDONLY to override the readonly attribute 2348 * being cleared. 2349 * <flags> can contain NV_EXPORT to override preserve nvenv 2350 */ 2351void _nv_unset(register Namval_t *np,int flags) 2352{ 2353 Shell_t *shp = sh_getinterp(); 2354 register union Value *up; 2355 if(!(flags&NV_RDONLY) && nv_isattr (np,NV_RDONLY)) 2356 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np)); 2357 if(is_afunction(np) && np->nvalue.ip) 2358 { 2359 register struct slnod *slp = (struct slnod*)(np->nvenv); 2360 if(slp && !nv_isattr(np,NV_NOFREE)) 2361 { 2362 struct Ufunction *rq,*rp = np->nvalue.rp; 2363 /* free function definition */ 2364 register char *name=nv_name(np),*cp= strrchr(name,'.'); 2365 if(cp) 2366 { 2367 Namval_t *npv; 2368 *cp = 0; 2369 npv = nv_open(name,shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOADD); 2370 *cp++ = '.'; 2371 if(npv && npv!=shp->namespace) 2372 nv_setdisc(npv,cp,NIL(Namval_t*),(Namfun_t*)npv); 2373 } 2374 if(rp->fname && shp->fpathdict && (rq = (struct Ufunction*)nv_search(rp->fname,shp->fpathdict,0))) 2375 { 2376 do 2377 { 2378 if(rq->np != np) 2379 continue; 2380 dtdelete(shp->fpathdict,rq); 2381 break; 2382 } 2383 while(rq = (struct Ufunction*)dtnext(shp->fpathdict,rq)); 2384 } 2385 if(rp->sdict) 2386 { 2387 Namval_t *mp, *nq; 2388 for(mp=(Namval_t*)dtfirst(rp->sdict);mp;mp=nq) 2389 { 2390 nq = dtnext(rp->sdict,mp); 2391 _nv_unset(mp,NV_RDONLY); 2392 nv_delete(mp,rp->sdict,0); 2393 } 2394 dtclose(rp->sdict); 2395 } 2396 stakdelete(slp->slptr); 2397 free((void*)np->nvalue.ip); 2398 np->nvalue.ip = 0; 2399 } 2400 goto done; 2401 } 2402 if(shp->subshell) 2403 np = sh_assignok(np,0); 2404 nv_offattr(np,NV_NODISC); 2405 if(np->nvfun && !nv_isref(np)) 2406 { 2407 /* This function contains disc */ 2408 if(!nv_local) 2409 { 2410 nv_local=1; 2411 nv_putv(np,NIL(char*),flags,np->nvfun); 2412 nv_local=0; 2413 return; 2414 } 2415 /* called from disc, assign the actual value */ 2416 nv_local=0; 2417 } 2418 if(nv_isattr(np,NV_INT16P) == NV_INT16) 2419 { 2420 np->nvalue.cp = nv_isarray(np)?Empty:0; 2421 goto done; 2422 } 2423 if(nv_isarray(np) && np->nvalue.cp!=Empty && np->nvfun) 2424 up = np->nvalue.up; 2425 else if(nv_isref(np) && !nv_isattr(np,NV_EXPORT|NV_MINIMAL) && np->nvalue.nrp) 2426 { 2427 2428 if(np->nvalue.nrp->root) 2429 dtdelete(Refdict,(void*)np->nvalue.nrp); 2430 if(np->nvalue.nrp->sub) 2431 free(np->nvalue.nrp->sub); 2432 free((void*)np->nvalue.nrp); 2433 np->nvalue.cp = 0; 2434 up = 0; 2435 } 2436 else 2437 up = &np->nvalue; 2438 if(up && up->cp) 2439 { 2440 if(up->cp!=Empty && up->cp!=Null && !nv_isattr(np, NV_NOFREE)) 2441 free((void*)up->cp); 2442 up->cp = 0; 2443 } 2444done: 2445 if(!nv_isarray(np) || !nv_arrayptr(np)) 2446 { 2447 nv_setsize(np,0); 2448 if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT)) 2449 { 2450 if(nv_isattr(np,NV_EXPORT) && !strchr(np->nvname,'[')) 2451 env_delete(shp->env,nv_name(np)); 2452 if(!(flags&NV_EXPORT) || nv_isattr(np,NV_IMPORT|NV_EXPORT)==(NV_IMPORT|NV_EXPORT)) 2453 np->nvenv = 0; 2454 nv_setattr(np,0); 2455 } 2456 else 2457 { 2458 nv_setattr(np,NV_MINIMAL); 2459 nv_delete(np,(Dt_t*)0,0); 2460 } 2461 } 2462} 2463 2464/* 2465 * return the node pointer in the highest level scope 2466 */ 2467Namval_t *sh_scoped(Shell_t *shp, register Namval_t *np) 2468{ 2469 if(!dtvnext(shp->var_tree)) 2470 return(np); 2471 return(dtsearch(shp->var_tree,np)); 2472} 2473 2474#if 1 2475/* 2476 * return space separated list of names of variables in given tree 2477 */ 2478static char *tableval(Dt_t *root) 2479{ 2480 static Sfio_t *out; 2481 register Namval_t *np; 2482 register int first=1; 2483 register Dt_t *base = dtview(root,0); 2484 if(out) 2485 sfseek(out,(Sfoff_t)0,SEEK_SET); 2486 else 2487 out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); 2488 for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np)) 2489 { 2490 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)) 2491 { 2492 if(!first) 2493 sfputc(out,' '); 2494 else 2495 first = 0; 2496 sfputr(out,np->nvname,-1); 2497 } 2498 } 2499 sfputc(out,0); 2500 if(base) 2501 dtview(root,base); 2502 return((char*)out->_data); 2503} 2504#endif 2505 2506#if SHOPT_OPTIMIZE 2507struct optimize 2508{ 2509 Namfun_t hdr; 2510 Shell_t *sh; 2511 char **ptr; 2512 struct optimize *next; 2513 Namval_t *np; 2514}; 2515 2516static struct optimize *opt_free; 2517 2518static void optimize_clear(Namval_t* np, Namfun_t *fp) 2519{ 2520 struct optimize *op = (struct optimize*)fp; 2521 nv_stack(np,fp); 2522 nv_stack(np,(Namfun_t*)0); 2523 for(;op && op->np==np; op=op->next) 2524 { 2525 if(op->ptr) 2526 { 2527 *op->ptr = 0; 2528 op->ptr = 0; 2529 } 2530 } 2531} 2532 2533static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp) 2534{ 2535 nv_putv(np,val,flags,fp); 2536 optimize_clear(np,fp); 2537} 2538 2539static Namfun_t *clone_optimize(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) 2540{ 2541 return((Namfun_t*)0); 2542} 2543 2544static const Namdisc_t optimize_disc = {sizeof(struct optimize),put_optimize,0,0,0,0,clone_optimize}; 2545 2546void nv_optimize(Namval_t *np) 2547{ 2548 Shell_t *shp = sh_getinterp(); 2549 register Namfun_t *fp; 2550 register struct optimize *op, *xp; 2551 if(shp->argaddr) 2552 { 2553 if(np==SH_LINENO) 2554 { 2555 shp->argaddr = 0; 2556 return; 2557 } 2558 for(fp=np->nvfun; fp; fp = fp->next) 2559 { 2560 if(fp->disc && (fp->disc->getnum || fp->disc->getval)) 2561 { 2562 shp->argaddr = 0; 2563 return; 2564 } 2565 if(fp->disc== &optimize_disc) 2566 break; 2567 } 2568 if((xp= (struct optimize*)fp) && xp->ptr==shp->argaddr) 2569 return; 2570 if(op = opt_free) 2571 opt_free = op->next; 2572 else 2573 op=(struct optimize*)calloc(1,sizeof(struct optimize)); 2574 op->ptr = shp->argaddr; 2575 op->np = np; 2576 if(xp) 2577 { 2578 op->hdr.disc = 0; 2579 op->next = xp->next; 2580 xp->next = op; 2581 } 2582 else 2583 { 2584 op->hdr.disc = &optimize_disc; 2585 op->next = (struct optimize*)shp->optlist; 2586 shp->optlist = (void*)op; 2587 nv_stack(np,&op->hdr); 2588 } 2589 } 2590} 2591 2592void sh_optclear(Shell_t *shp, void *old) 2593{ 2594 register struct optimize *op,*opnext; 2595 for(op=(struct optimize*)shp->optlist; op; op = opnext) 2596 { 2597 opnext = op->next; 2598 if(op->ptr && op->hdr.disc) 2599 { 2600 nv_stack(op->np,&op->hdr); 2601 nv_stack(op->np,(Namfun_t*)0); 2602 } 2603 op->next = opt_free; 2604 opt_free = op; 2605 } 2606 shp->optlist = old; 2607} 2608 2609#else 2610# define optimize_clear(np,fp) 2611#endif /* SHOPT_OPTIMIZE */ 2612 2613/* 2614 * Return a pointer to a character string that denotes the value 2615 * of <np>. If <np> refers to an array, return a pointer to 2616 * the value associated with the current index. 2617 * 2618 * If the value of <np> is an integer, the string returned will 2619 * be overwritten by the next call to nv_getval. 2620 * 2621 * If <np> has no value, 0 is returned. 2622 */ 2623 2624char *nv_getval(register Namval_t *np) 2625{ 2626 Shell_t *shp = sh_getinterp(); 2627 register union Value *up= &np->nvalue; 2628 register int numeric; 2629#if SHOPT_OPTIMIZE 2630 if(!nv_local && shp->argaddr) 2631 nv_optimize(np); 2632#endif /* SHOPT_OPTIMIZE */ 2633 if((!np->nvfun || !np->nvfun->disc) && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF)) 2634 goto done; 2635 if(nv_isref(np)) 2636 { 2637 if(!np->nvalue.cp) 2638 return(0); 2639 shp->last_table = nv_reftable(np); 2640 return(nv_name(nv_refnode(np))); 2641 } 2642 if(np->nvfun && np->nvfun->disc) 2643 { 2644 if(!nv_local) 2645 { 2646 nv_local=1; 2647 return(nv_getv(np, np->nvfun)); 2648 } 2649 nv_local=0; 2650 } 2651 numeric = ((nv_isattr (np, NV_INTEGER)) != 0); 2652 if(numeric) 2653 { 2654 Sflong_t ll; 2655 if(!up->cp) 2656 return("0"); 2657 if(nv_isattr (np,NV_DOUBLE)==NV_DOUBLE) 2658 { 2659 Sfdouble_t ld; 2660 double d; 2661 char *format; 2662 if(nv_isattr(np,NV_LONG)) 2663 { 2664 ld = *up->ldp; 2665 if(nv_isattr (np,NV_EXPNOTE)) 2666 format = "%.*Lg"; 2667 else if(nv_isattr (np,NV_HEXFLOAT)) 2668 format = "%.*La"; 2669 else 2670 format = "%.*Lf"; 2671 sfprintf(shp->strbuf,format,nv_size(np),ld); 2672 } 2673 else 2674 { 2675 d = *up->dp; 2676 if(nv_isattr (np,NV_EXPNOTE)) 2677 format = "%.*g"; 2678 else if(nv_isattr (np,NV_HEXFLOAT)) 2679 format = "%.*a"; 2680 else 2681 format = "%.*f"; 2682 sfprintf(shp->strbuf,format,nv_size(np),d); 2683 } 2684 return(sfstruse(shp->strbuf)); 2685 } 2686 else if(nv_isattr(np,NV_UNSIGN)) 2687 { 2688 if(nv_isattr (np,NV_LONG)) 2689 ll = *(Sfulong_t*)up->llp; 2690 else if(nv_isattr (np,NV_SHORT)) 2691 { 2692 if(nv_isattr(np,NV_INT16P)==NV_INT16P) 2693 ll = *(uint16_t*)(up->sp); 2694 else 2695 ll = (uint16_t)up->s; 2696 } 2697 else 2698 ll = *(uint32_t*)(up->lp); 2699 } 2700 else if(nv_isattr (np,NV_LONG)) 2701 ll = *up->llp; 2702 else if(nv_isattr (np,NV_SHORT)) 2703 { 2704 if(nv_isattr(np,NV_INT16P)==NV_INT16P) 2705 ll = *up->sp; 2706 else 2707 ll = up->s; 2708 } 2709 else 2710 ll = *(up->lp); 2711 if((numeric=nv_size(np))==10) 2712 { 2713 if(nv_isattr(np,NV_UNSIGN)) 2714 { 2715 sfprintf(shp->strbuf,"%I*u",sizeof(ll),ll); 2716 return(sfstruse(shp->strbuf)); 2717 } 2718 numeric = 0; 2719 } 2720 return(fmtbase(ll,numeric, numeric&&numeric!=10)); 2721 } 2722done: 2723#if (_AST_VERSION>=20030127L) 2724 /* 2725 * if NV_RAW flag is on, return pointer to binary data 2726 * otherwise, base64 encode the data and return this string 2727 */ 2728 if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW)) 2729 { 2730 char *cp; 2731 char *ep; 2732 int size= nv_size(np), insize=(4*size)/3+size/45+8; 2733 base64encode(up->cp, size, (void**)0, cp=getbuf(insize), insize, (void**)&ep); 2734 *ep = 0; 2735 return(cp); 2736 } 2737#endif 2738 if((numeric=nv_size(np)) && up->cp && up->cp[numeric]) 2739 { 2740 char *cp = getbuf(numeric+1); 2741 memcpy(cp,up->cp,numeric); 2742 cp[numeric]=0; 2743 return(cp); 2744 } 2745 return ((char*)up->cp); 2746} 2747 2748Sfdouble_t nv_getnum(register Namval_t *np) 2749{ 2750 Shell_t *shp = sh_getinterp(); 2751 register union Value *up; 2752 register Sfdouble_t r=0; 2753 register char *str; 2754#if SHOPT_OPTIMIZE 2755 if(!nv_local && shp->argaddr) 2756 nv_optimize(np); 2757#endif /* SHOPT_OPTIMIZE */ 2758 if(nv_istable(np)) 2759 errormsg(SH_DICT,ERROR_exit(1),e_number,nv_name(np)); 2760 if(np->nvfun && np->nvfun->disc) 2761 { 2762 if(!nv_local) 2763 { 2764 nv_local=1; 2765 return(nv_getn(np, np->nvfun)); 2766 } 2767 nv_local=0; 2768 } 2769 if(nv_isref(np)) 2770 { 2771 str = nv_refsub(np); 2772 np = nv_refnode(np); 2773 if(str) 2774 nv_putsub(np,str,0L); 2775 } 2776 if(nv_isattr (np, NV_INTEGER)) 2777 { 2778 up= &np->nvalue; 2779 if(!up->lp || up->cp==Empty) 2780 r = 0; 2781 else if(nv_isattr(np, NV_DOUBLE)==NV_DOUBLE) 2782 { 2783 if(nv_isattr(np, NV_LONG)) 2784 r = *up->ldp; 2785 else 2786 r = *up->dp; 2787 } 2788 else if(nv_isattr(np, NV_UNSIGN)) 2789 { 2790 if(nv_isattr(np, NV_LONG)) 2791 r = (Sflong_t)*((Sfulong_t*)up->llp); 2792 else if(nv_isattr(np, NV_SHORT)) 2793 { 2794 if(nv_isattr(np,NV_INT16P)==NV_INT16P) 2795 r = (Sflong_t)(*(uint16_t*)up->sp); 2796 else 2797 r = (Sflong_t)((uint16_t)up->s); 2798 } 2799 else 2800 r = *((uint32_t*)up->lp); 2801 } 2802 else 2803 { 2804 if(nv_isattr(np, NV_LONG)) 2805 r = *up->llp; 2806 else if(nv_isattr(np, NV_SHORT)) 2807 { 2808 if(nv_isattr(np,NV_INT16P)==NV_INT16P) 2809 r = *up->sp; 2810 else 2811 r = up->s; 2812 } 2813 else 2814 r = *up->lp; 2815 } 2816 } 2817 else if((str=nv_getval(np)) && *str!=0) 2818 { 2819 if(nv_isattr(np,NV_LJUST|NV_RJUST) || (*str=='0' && !(str[1]=='x'||str[1]=='X'))) 2820 { 2821 while(*str=='0') 2822 str++; 2823 } 2824 r = sh_arith(shp,str); 2825 } 2826 return(r); 2827} 2828 2829/* 2830 * Give <np> the attributes <newatts,> and change its current 2831 * value to conform to <newatts>. The <size> of left and right 2832 * justified fields may be given. 2833 */ 2834void nv_newattr (register Namval_t *np, unsigned newatts, int size) 2835{ 2836 Shell_t *shp = sh_getinterp(); 2837 register char *sp; 2838 register char *cp = 0; 2839 register unsigned int n; 2840 Namval_t *mp = 0; 2841 Namarr_t *ap = 0; 2842 int oldsize,oldatts,trans; 2843 Namfun_t *fp= (newatts&NV_NODISC)?np->nvfun:0; 2844 char *prefix = shp->prefix,*sub; 2845 newatts &= ~NV_NODISC; 2846 2847 /* check for restrictions */ 2848 if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) || sp==nv_name(FPATHNOD))) 2849 errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np)); 2850 /* handle attributes that do not change data separately */ 2851 n = np->nvflag; 2852 trans = !(n&NV_INTEGER) && (n&(NV_LTOU|NV_UTOL)); 2853 if(newatts&NV_EXPORT) 2854 nv_offattr(np,NV_IMPORT); 2855 if(((n^newatts)&NV_EXPORT)) 2856 { 2857 /* record changes to the environment */ 2858 if(n&NV_EXPORT) 2859 env_delete(shp->env,nv_name(np)); 2860 else 2861 sh_envput(shp->env,np); 2862 } 2863 oldsize = nv_size(np); 2864 if((size==oldsize|| (n&NV_INTEGER)) && !trans && ((n^newatts)&~NV_NOCHANGE)==0) 2865 { 2866 if(size) 2867 nv_setsize(np,size); 2868 nv_offattr(np, ~NV_NOFREE); 2869 nv_onattr(np, newatts); 2870 return; 2871 } 2872 /* for an array, change all the elements */ 2873 if((ap=nv_arrayptr(np)) && ap->nelem>0) 2874 nv_putsub(np,NIL(char*),ARRAY_SCAN); 2875 oldsize = nv_size(np); 2876 oldatts = np->nvflag; 2877 if(fp) 2878 np->nvfun = 0; 2879 if(ap) /* add element to prevent array deletion */ 2880 { 2881 ap->nelem++; 2882#if SHOPT_FIXEDARRAY 2883 if(ap->fixed) 2884 { 2885 nv_setsize(np,size); 2886 np->nvflag &= NV_ARRAY; 2887 np->nvflag |= newatts; 2888 goto skip; 2889 } 2890#endif /* SHOPT_TYPEDEF */ 2891 } 2892 do 2893 { 2894 nv_setsize(np,oldsize); 2895 np->nvflag = oldatts; 2896 if (sp = nv_getval(np)) 2897 { 2898 if(nv_isattr(np,NV_ZFILL)) 2899 while(*sp=='0') sp++; 2900 cp = (char*)malloc((n=strlen (sp)) + 1); 2901 strcpy(cp, sp); 2902 if(sp && (mp=nv_opensub(np))) 2903 { 2904 sub = nv_getsub(mp); 2905 if(trans) 2906 { 2907 nv_disc(np, &ap->hdr,NV_POP); 2908 nv_clone(np,mp,0); 2909 nv_disc(np, &ap->hdr,NV_FIRST); 2910 nv_offattr(mp,NV_ARRAY); 2911 } 2912 nv_newattr(mp,newatts&~NV_ARRAY,size); 2913 } 2914 if(!mp) 2915 { 2916 if(ap) 2917 ap->nelem &= ~ARRAY_SCAN; 2918 if(!trans) 2919 _nv_unset(np,NV_RDONLY|NV_EXPORT); 2920 if(ap) 2921 ap->nelem |= ARRAY_SCAN; 2922 } 2923 if(size==0 && (newatts&NV_HOST)!=NV_HOST && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL))) 2924 size = n; 2925 } 2926 else if(!trans) 2927 _nv_unset(np,NV_EXPORT); 2928 nv_setsize(np,size); 2929 np->nvflag &= NV_ARRAY; 2930 np->nvflag |= newatts; 2931 if (cp) 2932 { 2933 if(!mp) 2934 nv_putval (np, cp, NV_RDONLY); 2935 free(cp); 2936 } 2937 } 2938 while(ap && nv_nextsub(np)); 2939#if SHOPT_FIXEDARRAY 2940skip: 2941#endif /* SHOPT_TYPEDEF */ 2942 if(fp) 2943 np->nvfun = fp; 2944 if(ap) 2945 ap->nelem--; 2946 shp->prefix = prefix; 2947 return; 2948} 2949 2950static char *oldgetenv(const char *string) 2951{ 2952 register char c0,c1; 2953 register const char *cp, *sp; 2954 register char **av = environ; 2955 if(!string || (c0= *string)==0) 2956 return(0); 2957 if((c1=*++string)==0) 2958 c1= '='; 2959 while(cp = *av++) 2960 { 2961 if(cp[0]!=c0 || cp[1]!=c1) 2962 continue; 2963 sp = string; 2964 while(*sp && *sp++ == *++cp); 2965 if(*sp==0 && *++cp=='=') 2966 return((char*)(cp+1)); 2967 } 2968 return(0); 2969} 2970 2971/* 2972 * This version of getenv uses the hash storage to access environment values 2973 */ 2974char *sh_getenv(const char *name) 2975{ 2976 Shell_t *shp = sh_getinterp(); 2977 register Namval_t *np; 2978 if(!shp->var_tree) 2979 { 2980#if 0 2981 if(name[0] == 'P' && name[1] == 'A' && name[2] == 'T' && name[3] == 'H' && name[4] == 0 || name[0] == 'L' && ((name[1] == 'C' || name[1] == 'D') && name[2] == '_' || name[1] == 'A' && name[1] == 'N') || name[0] == 'V' && name[1] == 'P' && name[2] == 'A' && name[3] == 'T' && name[4] == 'H' && name[5] == 0 || name[0] == '_' && name[1] == 'R' && name[2] == 'L' && name[3] == 'D' || name[0] == '_' && name[1] == 'A' && name[2] == 'S' && name[3] == 'T' && name[4] == '_') 2982#endif 2983 return(oldgetenv(name)); 2984 } 2985 else if((np = nv_search(name,shp->var_tree,0)) && nv_isattr(np,NV_EXPORT)) 2986 return(nv_getval(np)); 2987 return(0); 2988} 2989 2990#ifndef _NEXT_SOURCE 2991/* 2992 * Some dynamic linkers will make this file see the libc getenv(), 2993 * so sh_getenv() is used for the astintercept() callback. Plain 2994 * getenv() is provided for static links. 2995 */ 2996char *getenv(const char *name) 2997{ 2998 return sh_getenv(name); 2999} 3000#endif /* _NEXT_SOURCE */ 3001 3002#undef putenv 3003/* 3004 * This version of putenv uses the hash storage to assign environment values 3005 */ 3006int putenv(const char *name) 3007{ 3008 Shell_t *shp = sh_getinterp(); 3009 register Namval_t *np; 3010 if(name) 3011 { 3012 np = nv_open(name,shp->var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN); 3013 if(!strchr(name,'=')) 3014 _nv_unset(np,0); 3015 } 3016 return(0); 3017} 3018 3019/* 3020 * Override libast setenviron(). 3021 */ 3022char* sh_setenviron(const char *name) 3023{ 3024 Shell_t *shp = sh_getinterp(); 3025 register Namval_t *np; 3026 if(name) 3027 { 3028 np = nv_open(name,shp->var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN); 3029 if(strchr(name,'=')) 3030 return(nv_getval(np)); 3031 _nv_unset(np,0); 3032 } 3033 return(""); 3034} 3035 3036/* 3037 * Same linker dance as with getenv() above. 3038 */ 3039char* setenviron(const char *name) 3040{ 3041 return sh_setenviron(name); 3042} 3043 3044/* 3045 * normalize <cp> and return pointer to subscript if any 3046 * if <eq> is specified, return pointer to first = not in a subscript 3047 */ 3048static char *lastdot(char *cp, int eq) 3049{ 3050 register char *ep=0; 3051 register int c; 3052 if(eq) 3053 cp++; 3054 while(c= mbchar(cp)) 3055 { 3056 if(c=='[') 3057 { 3058 if(*cp==']') 3059 cp++; 3060 else 3061 cp = nv_endsubscript((Namval_t*)0,ep=cp,0); 3062 } 3063 else if(c=='.') 3064 { 3065 if(*cp=='[') 3066 { 3067 cp = nv_endsubscript((Namval_t*)0,ep=cp,0); 3068 if((ep=sh_checkid(ep+1,cp)) < cp) 3069 cp=strcpy(ep,cp); 3070 } 3071 ep = 0; 3072 } 3073 else if(eq && c == '=') 3074 return(cp-1); 3075 } 3076 return(eq?0:ep); 3077} 3078 3079int nv_rename(register Namval_t *np, int flags) 3080{ 3081 Shell_t *shp = sh_getinterp(); 3082 register Namval_t *mp=0,*nr=0; 3083 register char *cp; 3084 int r=0,arraynp,arraynr,index= -1; 3085 Namval_t *last_table = shp->last_table; 3086 Dt_t *last_root = shp->last_root; 3087 Dt_t *hp = 0; 3088 char *nvenv=0,*prefix=shp->prefix; 3089 Namarr_t *ap,*aq=0; 3090 if(nv_isattr(np,NV_PARAM) && shp->st.prevst) 3091 { 3092 if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) 3093 hp = dtvnext(shp->var_tree); 3094 } 3095 if(cp = nv_name(np)) 3096 arraynp = cp[strlen(cp)-1] == ']'; 3097 if(!(cp=nv_getval(np))) 3098 { 3099 if(flags&NV_MOVE) 3100 errormsg(SH_DICT,ERROR_exit(1),e_varname,""); 3101 return(0); 3102 } 3103 if(lastdot(cp,0) && nv_isattr(np,NV_MINIMAL)) 3104 errormsg(SH_DICT,ERROR_exit(1),e_varname,nv_name(np)); 3105 arraynr = cp[strlen(cp)-1] == ']'; 3106 if(nv_isarray(np) && !(mp=nv_opensub(np))) 3107 index=nv_aindex(np); 3108 shp->prefix = 0; 3109 if(!hp) 3110 hp = shp->var_tree; 3111 if(!(nr = nv_open(cp, hp, flags|NV_ARRAY|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL))) 3112 { 3113#if SHOPT_NAMESPACE 3114 if(shp->namespace) 3115 hp = nv_dict(shp->namespace); 3116 else 3117#endif /* SHOPT_NAMESPACE */ 3118 hp = shp->var_base; 3119 } 3120 else if(shp->last_root) 3121 hp = shp->last_root; 3122 if(!nr) 3123 nr= nv_open(cp, hp, flags|NV_NOREF|((flags&NV_MOVE)?0:NV_NOFAIL)); 3124 shp->prefix = prefix; 3125 if(!nr) 3126 { 3127 if(!nv_isvtree(np)) 3128 _nv_unset(np,0); 3129 return(0); 3130 } 3131 if(!mp && index>=0 && nv_isvtree(nr)) 3132 { 3133 sfprintf(shp->strbuf,"%s[%d]%c",nv_name(np),index,0); 3134 /* create a virtual node */ 3135 if(mp = nv_open(sfstruse(shp->strbuf),shp->var_tree,NV_VARNAME|NV_ADD|NV_ARRAY)) 3136 { 3137 if(ap = nv_arrayptr(np)) 3138 ap->nelem++; 3139 mp->nvenv = nvenv = (void*)np; 3140 } 3141 } 3142 if(mp) 3143 np = mp; 3144 if(nr==np) 3145 { 3146 if(index<0) 3147 return(0); 3148 if(cp = nv_getval(np)) 3149 cp = strdup(cp); 3150 } 3151 _nv_unset(np,NV_EXPORT); 3152 if(nr==np) 3153 { 3154 nv_putsub(np,(char*)0, index); 3155 nv_putval(np,cp,0); 3156 free((void*)cp); 3157 return(1); 3158 } 3159 shp->prev_table = shp->last_table; 3160 shp->prev_root = shp->last_root; 3161 shp->last_table = last_table; 3162 shp->last_root = last_root; 3163 if(flags&NV_MOVE) 3164 { 3165 if(arraynr && !nv_isattr(nr,NV_MINIMAL) && (mp=(Namval_t*)nr->nvenv) && (ap=nv_arrayptr(mp))) 3166 ap->nelem--; 3167 if(arraynp && !nv_isattr(np,NV_MINIMAL) && (mp=(Namval_t*)np->nvenv) && (ap=nv_arrayptr(mp))) 3168 ap->nelem++; 3169 } 3170 if(((aq=nv_arrayptr(nr)) && !arraynr) || nv_isvtree(nr)) 3171 { 3172 if(ap=nv_arrayptr(np)) 3173 { 3174 if(!ap->table) 3175 ap->table = dtopen(&_Nvdisc,Dtoset); 3176 if(ap->table) 3177 mp = nv_search(nv_getsub(np),ap->table,NV_ADD); 3178 nv_arraychild(np,mp,0); 3179 nvenv = (void*)np; 3180 } 3181 else 3182 mp = np; 3183 nv_clone(nr,mp,(flags&NV_MOVE)|NV_COMVAR); 3184 mp->nvenv = nvenv; 3185 if(flags&NV_MOVE) 3186 nv_delete(nr,(Dt_t*)0,NV_NOFREE); 3187 } 3188 else 3189 { 3190 nv_putval(np,nv_getval(nr),0); 3191 if(flags&NV_MOVE) 3192 _nv_unset(nr,0); 3193 } 3194 return(1); 3195} 3196 3197/* 3198 * Create a reference node from <np> to $np in dictionary <hp> 3199 */ 3200void nv_setref(register Namval_t *np, Dt_t *hp, int flags) 3201{ 3202 Shell_t *shp = sh_getinterp(); 3203 register Namval_t *nq=0, *nr=0; 3204 register char *ep,*cp; 3205 Dt_t *root = shp->last_root, *hpnext=0; 3206 Namarr_t *ap=0; 3207 if(nv_isref(np)) 3208 return; 3209 if(nv_isarray(np)) 3210 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np)); 3211 if(!(cp=nv_getval(np))) 3212 { 3213 _nv_unset(np,0); 3214 nv_onattr(np,NV_REF); 3215 return; 3216 } 3217 if((ep = lastdot(cp,0)) && nv_isattr(np,NV_MINIMAL)) 3218 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np)); 3219 if(hp) 3220 hpnext = dtvnext(hp); 3221 if((nr=nv_open(cp, hp?hp:shp->var_tree, flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)) || 3222 (hpnext && dtvnext(hpnext)==shp->var_base && (nr=nv_open(cp,hpnext,flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))) 3223 { 3224 nq = nr; 3225 hp = shp->last_root; 3226 } 3227 else 3228 hp = hp?shp->var_base:shp->var_tree; 3229 if(nr==np) 3230 { 3231 if(shp->namespace && nv_dict(shp->namespace)==hp) 3232 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np)); 3233 /* bind to earlier scope, or add to global scope */ 3234 if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np) 3235 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np)); 3236 if(nv_isarray(nq)) 3237 nv_putsub(nq,(char*)0,ARRAY_UNDEF); 3238 } 3239#if SHOPT_FIXEDARRAY 3240 if(nq && ep && nv_isarray(nq) && !((ap=nv_arrayptr(nq)) && ap->fixed) && !nv_getsub(nq)) 3241#else 3242 if(nq && ep && nv_isarray(nq) && !nv_getsub(nq)) 3243#endif /* SHOPT_FIXEDARRAY */ 3244 { 3245 if(!nv_arrayptr(nq)) 3246 { 3247 nv_putsub(nq,"1",ARRAY_FILL); 3248 _nv_unset(nq,NV_RDONLY); 3249 } 3250 nv_endsubscript(nq,ep-1,NV_ARRAY); 3251 } 3252 if(!nr) 3253 { 3254 shp->last_root = 0; 3255 nr= nq = nv_open(cp, hp, flags); 3256 if(shp->last_root) 3257 hp = shp->last_root; 3258 } 3259 if(shp->last_root == shp->var_tree && root!=shp->var_tree) 3260 { 3261 _nv_unset(np,NV_RDONLY); 3262 nv_onattr(np,NV_REF); 3263 errormsg(SH_DICT,ERROR_exit(1),e_globalref,nv_name(np)); 3264 } 3265 shp->instance = 1; 3266 if(nq && !ep && (ap=nv_arrayptr(nq)) && !(ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN))) 3267 ep = nv_getsub(nq); 3268#if SHOPT_FIXEDARRAY 3269 if(ep && !(ap && ap->fixed)) 3270#else 3271 if(ep) 3272#endif /* SHOPT_FIXEDARRAY */ 3273 { 3274 /* cause subscript evaluation and return result */ 3275 if(nv_isarray(nq)) 3276 ep = nv_getsub(nq); 3277 else 3278 { 3279 int n; 3280 ep[n=strlen(ep)-1] = 0; 3281 nv_putsub(nr, ep, ARRAY_FILL); 3282 ep[n] = ']'; 3283 if(nq = nv_opensub(nr)) 3284 ep = 0; 3285 else 3286 ep = nv_getsub(nq=nr); 3287 } 3288 } 3289 shp->instance = 0; 3290 shp->last_root = root; 3291 _nv_unset(np,0); 3292 nv_delete(np,(Dt_t*)0,0); 3293 np->nvalue.nrp = newof(0,struct Namref,1,sizeof(Dtlink_t)); 3294 np->nvalue.nrp->np = nq; 3295 np->nvalue.nrp->root = hp; 3296 if(ep) 3297 { 3298#if SHOPT_FIXEDARRAY 3299 if(ap && ap->fixed) 3300 np->nvalue.nrp->curi = ARRAY_FIXED|nv_arrfixed(nq,(Sfio_t*)0,1,&np->nvalue.nrp->dim); 3301 else 3302#endif /* SHOPT_FIXEDARRAY */ 3303 np->nvalue.nrp->sub = strdup(ep); 3304 } 3305 np->nvalue.nrp->table = shp->last_table; 3306 nv_onattr(np,NV_REF|NV_NOFREE); 3307 if(!Refdict) 3308 { 3309 NullNode.nvname = ".deleted"; 3310 NullNode.nvflag = NV_RDONLY; 3311 Refdict = dtopen(&_Refdisc,Dtobag); 3312 } 3313 dtinsert(Refdict,np->nvalue.nrp); 3314} 3315 3316/* 3317 * get the scope corresponding to <index> 3318 * whence uses the same values as lseeek() 3319 */ 3320Shscope_t *sh_getscope(int index, int whence) 3321{ 3322 Shell_t *shp = sh_getinterp(); 3323 register struct sh_scoped *sp, *topmost; 3324 if(whence==SEEK_CUR) 3325 sp = &shp->st; 3326 else 3327 { 3328 if ((struct sh_scoped*)shp->topscope != shp->st.self) 3329 topmost = (struct sh_scoped*)shp->topscope; 3330 else 3331 topmost = &(shp->st); 3332 sp = topmost; 3333 if(whence==SEEK_SET) 3334 { 3335 int n =0; 3336 while(sp = sp->prevst) 3337 n++; 3338 index = n - index; 3339 sp = topmost; 3340 } 3341 } 3342 if(index < 0) 3343 return((Shscope_t*)0); 3344 while(index-- && (sp = sp->prevst)); 3345 return((Shscope_t*)sp); 3346} 3347 3348/* 3349 * make <scoped> the top scope and return previous scope 3350 */ 3351Shscope_t *sh_setscope(Shscope_t *scope) 3352{ 3353 Shell_t *shp = sh_getinterp(); 3354 Shscope_t *old = (Shscope_t*)shp->st.self; 3355 *shp->st.self = shp->st; 3356 shp->st = *((struct sh_scoped*)scope); 3357 shp->var_tree = scope->var_tree; 3358 SH_PATHNAMENOD->nvalue.cp = shp->st.filename; 3359 SH_FUNNAMENOD->nvalue.cp = shp->st.funname; 3360 return(old); 3361} 3362 3363void sh_unscope(Shell_t *shp) 3364{ 3365 register Dt_t *root = shp->var_tree; 3366 register Dt_t *dp = dtview(root,(Dt_t*)0); 3367 table_unset(shp,root,NV_RDONLY|NV_NOSCOPE,dp); 3368 if(shp->st.real_fun && dp==shp->st.real_fun->sdict) 3369 { 3370 dp = dtview(dp,(Dt_t*)0); 3371 shp->st.real_fun->sdict->view = dp; 3372 } 3373 shp->var_tree=dp; 3374 dtclose(root); 3375} 3376 3377/* 3378 * The inverse of creating a reference node 3379 */ 3380void nv_unref(register Namval_t *np) 3381{ 3382 Namval_t *nq; 3383 if(!nv_isref(np)) 3384 return; 3385 nv_offattr(np,NV_NOFREE|NV_REF); 3386 if(!np->nvalue.nrp) 3387 return; 3388 nq = nv_refnode(np); 3389 if(Refdict) 3390 { 3391 if(np->nvalue.nrp->sub) 3392 free(np->nvalue.nrp->sub); 3393 dtdelete(Refdict,(void*)np->nvalue.nrp); 3394 } 3395 free((void*)np->nvalue.nrp); 3396 np->nvalue.cp = strdup(nv_name(nq)); 3397#if SHOPT_OPTIMIZE 3398 { 3399 Namfun_t *fp; 3400 for(fp=nq->nvfun; fp; fp = fp->next) 3401 { 3402 if(fp->disc== &optimize_disc) 3403 { 3404 optimize_clear(nq,fp); 3405 return; 3406 } 3407 } 3408 } 3409#endif 3410} 3411 3412/* 3413 * These following are for binary compatibility with the old hash library 3414 * They will be removed someday 3415 */ 3416 3417#if defined(__IMPORT__) && defined(__EXPORT__) 3418# define extern __EXPORT__ 3419#endif 3420 3421#undef hashscope 3422 3423extern Dt_t *hashscope(Dt_t *root) 3424{ 3425 return(dtvnext(root)); 3426} 3427 3428#undef hashfree 3429 3430extern Dt_t *hashfree(Dt_t *root) 3431{ 3432 Dt_t *dp = dtvnext(root); 3433 dtclose(root); 3434 return(dp); 3435} 3436 3437#undef hashname 3438 3439extern char *hashname(void *obj) 3440{ 3441 Namval_t *np = (Namval_t*)obj; 3442 return(np->nvname); 3443} 3444 3445#undef hashlook 3446 3447extern void *hashlook(Dt_t *root, const char *name, int mode,int size) 3448{ 3449 NOT_USED(size); 3450 return((void*)nv_search(name,root,mode)); 3451} 3452 3453char *nv_name(register Namval_t *np) 3454{ 3455 Shell_t *shp = sh_getinterp(); 3456 register Namval_t *table; 3457 register Namfun_t *fp; 3458#if SHOPT_FIXEDARRAY 3459 Namarr_t *ap; 3460#endif /* SHOPT_FIXEDARRAY */ 3461 char *cp; 3462 if(is_abuiltin(np) || is_afunction(np)) 3463 { 3464#if SHOPT_NAMESPACE 3465 if(shp->namespace && is_afunction(np)) 3466 { 3467 char *name = nv_name(shp->namespace); 3468 int n = strlen(name); 3469 if(memcmp(np->nvname,name,n)==0 && np->nvname[n]=='.') 3470 return(np->nvname+n+1); 3471 } 3472#endif /* SHOPT_NAMESPACE */ 3473 return(np->nvname); 3474 } 3475#if SHOPT_FIXEDARRAY 3476 ap = nv_arrayptr(np); 3477#endif /* SHOPT_FIXEDARRAY */ 3478 if(!nv_isattr(np,NV_MINIMAL|NV_EXPORT) && np->nvenv) 3479 { 3480 Namval_t *nq= shp->last_table, *mp= (Namval_t*)np->nvenv; 3481 if(np==shp->last_table) 3482 shp->last_table = 0; 3483 if(nv_isarray(mp)) 3484 sfprintf(shp->strbuf,"%s[%s]",nv_name(mp),np->nvname); 3485 else 3486 sfprintf(shp->strbuf,"%s.%s",nv_name(mp),np->nvname); 3487 shp->last_table = nq; 3488 return(sfstruse(shp->strbuf)); 3489 } 3490 if(nv_istable(np)) 3491#if 1 3492 shp->last_table = nv_parent(np); 3493#else 3494 shp->last_table = nv_create(np,0, NV_LAST,(Namfun_t*)0); 3495#endif 3496 else if(!nv_isref(np)) 3497 { 3498 for(fp= np->nvfun ; fp; fp=fp->next) 3499 if(fp->disc && fp->disc->namef) 3500 { 3501 if(np==shp->last_table) 3502 shp->last_table = 0; 3503 return((*fp->disc->namef)(np,fp)); 3504 } 3505 } 3506 if(!(table=shp->last_table) || *np->nvname=='.' || table==shp->namespace || np==table) 3507 { 3508#if SHOPT_FIXEDARRAY 3509 if(!ap || !ap->fixed || (ap->nelem&ARRAY_UNDEF)) 3510 return(np->nvname); 3511 table = 0; 3512#else 3513 return(np->nvname); 3514#endif /* SHOPT_FIXEDARRAY */ 3515 } 3516 if(table) 3517 { 3518 cp = nv_name(table); 3519 sfprintf(shp->strbuf,"%s.%s",cp,np->nvname); 3520 } 3521 else 3522 sfprintf(shp->strbuf,"%s",np->nvname); 3523#if SHOPT_FIXEDARRAY 3524 if(ap && ap->fixed) 3525 nv_arrfixed(np,shp->strbuf,1,(char*)0); 3526#endif /* SHOPT_FIXEDARRAY */ 3527 return(sfstruse(shp->strbuf)); 3528} 3529 3530Namval_t *nv_lastdict(void) 3531{ 3532 Shell_t *shp = sh_getinterp(); 3533 return(shp->last_table); 3534} 3535 3536#undef nv_context 3537/* 3538 * returns the data context for a builtin 3539 */ 3540void *nv_context(Namval_t *np) 3541{ 3542 return((void*)np->nvfun); 3543} 3544 3545#define DISABLE /* proto workaround */ 3546 3547int nv_isnull DISABLE (register Namval_t *np) 3548{ 3549 return(nv_isnull(np)); 3550} 3551 3552#undef nv_setsize 3553int nv_setsize(register Namval_t *np, int size) 3554{ 3555 int oldsize = nv_size(np); 3556 if(size>=0) 3557 np->nvsize = size; 3558 return(oldsize); 3559} 3560 3561Shell_t *nv_shell(Namval_t *np) 3562{ 3563 Namfun_t *fp; 3564 for(fp=np->nvfun;fp;fp=fp->next) 3565 { 3566 if(!fp->disc) 3567 return((Shell_t*)fp->last); 3568 } 3569 return(0); 3570} 3571 3572#undef nv_unset 3573 3574void nv_unset(register Namval_t *np) 3575{ 3576 _nv_unset(np,0); 3577 return; 3578} 3579