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