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