1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 static char *savesub = 0; 38 39 #if !_lib_pathnative && _lib_uwin_path 40 41 #define _lib_pathnative 1 42 43 extern int uwin_path(const char*, char*, int); 44 45 size_t 46 pathnative(const char* path, char* buf, size_t siz) 47 { 48 return uwin_path(path, buf, siz); 49 } 50 51 #endif /* _lib_pathnative */ 52 53 static void attstore(Namval_t*,void*); 54 #ifndef _ENV_H 55 static void pushnam(Namval_t*,void*); 56 static char *staknam(Namval_t*, char*); 57 #endif 58 static void ltou(const char*,char*); 59 static void rightjust(char*, int, int); 60 61 struct adata 62 { 63 char **argnam; 64 int attsize; 65 char *attval; 66 }; 67 68 char nv_local = 0; 69 #ifndef _ENV_H 70 static void(*nullscan)(Namval_t*,void*); 71 #endif 72 73 #if ( SFIO_VERSION <= 20010201L ) 74 # define _data data 75 #endif 76 77 #if !SHOPT_MULTIBYTE 78 # define mbchar(p) (*(unsigned char*)p++) 79 #endif /* SHOPT_MULTIBYTE */ 80 81 /* ======== name value pair routines ======== */ 82 83 #include "shnodes.h" 84 #include "builtins.h" 85 86 static char *getbuf(size_t len) 87 { 88 static char *buf; 89 static size_t buflen; 90 if(buflen < len) 91 { 92 if(buflen==0) 93 buf = (char*)malloc(len); 94 else 95 buf = (char*)realloc(buf,len); 96 buflen = len; 97 } 98 return(buf); 99 } 100 101 #ifdef _ENV_H 102 void sh_envput(Env_t* ep,Namval_t *np) 103 { 104 int offset = staktell(); 105 Namarr_t *ap = nv_arrayptr(np); 106 char *val; 107 if(ap) 108 { 109 if(ap->nelem&ARRAY_UNDEF) 110 nv_putsub(np,"0",0L); 111 else if(!(val=nv_getsub(np)) || strcmp(val,"0")) 112 return; 113 } 114 if(!(val = nv_getval(np))) 115 return; 116 stakputs(nv_name(np)); 117 stakputc('='); 118 stakputs(val); 119 stakseek(offset); 120 env_add(ep,stakptr(offset),ENV_STRDUP); 121 } 122 #endif 123 124 /* 125 * output variable name in format for re-input 126 */ 127 void nv_outname(Sfio_t *out, char *name, int len) 128 { 129 const char *cp=name, *sp; 130 int c, offset = staktell(); 131 while(sp= strchr(cp,'[')) 132 { 133 if(len>0 && cp+len <= sp) 134 break; 135 sfwrite(out,cp,++sp-cp); 136 stakseek(offset); 137 for(; c= *sp; sp++) 138 { 139 if(c==']') 140 break; 141 else if(c=='\\') 142 { 143 if(*sp=='[' || *sp==']' || *sp=='\\') 144 c = *sp++; 145 } 146 stakputc(c); 147 } 148 stakputc(0); 149 sfputr(out,sh_fmtq(stakptr(offset)),-1); 150 if(len>0) 151 { 152 sfputc(out,']'); 153 return; 154 } 155 cp = sp; 156 } 157 if(*cp) 158 { 159 if(len>0) 160 sfwrite(out,cp,len); 161 else 162 sfputr(out,cp,-1); 163 } 164 stakseek(offset); 165 } 166 167 /* 168 * Perform parameter assignment for a linked list of parameters 169 * <flags> contains attributes for the parameters 170 */ 171 void nv_setlist(register struct argnod *arg,register int flags) 172 { 173 register char *cp; 174 register Namval_t *np; 175 char *trap=sh.st.trap[SH_DEBUGTRAP]; 176 int traceon = (sh_isoption(SH_XTRACE)!=0); 177 int array = (flags&(NV_ARRAY|NV_IARRAY)); 178 flags &= ~(NV_TYPE|NV_ARRAY); 179 if(sh_isoption(SH_ALLEXPORT)) 180 flags |= NV_EXPORT; 181 if(sh.prefix) 182 { 183 flags &= ~(NV_IDENT|NV_EXPORT); 184 flags |= NV_VARNAME; 185 } 186 for(;arg; arg=arg->argnxt.ap) 187 { 188 sh.used_pos = 0; 189 if(arg->argflag&ARG_MAC) 190 cp = sh_mactrim(arg->argval,-1); 191 else 192 { 193 Namval_t *mp; 194 stakseek(0); 195 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED))) 196 { 197 int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN); 198 struct fornod *fp=(struct fornod*)arg->argchn.ap; 199 register Shnode_t *tp=fp->fortre; 200 char *prefix = sh.prefix; 201 flag |= (flags&NV_NOSCOPE); 202 if(arg->argflag&ARG_QUOTED) 203 cp = sh_mactrim(fp->fornam,-1); 204 else 205 cp = fp->fornam; 206 error_info.line = fp->fortyp-sh.st.firstline; 207 if(sh.fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET) 208 flag |= NV_NOSCOPE; 209 if(prefix && tp->com.comset && *cp=='[') 210 { 211 sh.prefix = 0; 212 np = nv_open(prefix,sh.var_tree,flag); 213 sh.prefix = prefix; 214 if(np) 215 { 216 if(!nv_isarray(np)) 217 { 218 stakputc('.'); 219 stakputs(cp); 220 cp = stakfreeze(1); 221 } 222 nv_close(np); 223 } 224 } 225 np = nv_open(cp,sh.var_tree,flag); 226 if(array) 227 { 228 if(!(flags&NV_APPEND)) 229 nv_unset(np); 230 if(array&NV_ARRAY) 231 { 232 nv_setarray(np,nv_associative); 233 } 234 else 235 { 236 nv_onattr(np,NV_ARRAY); 237 } 238 } 239 /* check for array assignment */ 240 if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL))) 241 { 242 int argc; 243 char **argv = sh_argbuild(&argc,&tp->com,0); 244 if(!(arg->argflag&ARG_APPEND)) 245 { 246 nv_unset(np); 247 } 248 nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv); 249 if(traceon || trap) 250 { 251 int n = -1; 252 char *name = nv_name(np); 253 if(arg->argflag&ARG_APPEND) 254 n = '+'; 255 if(trap) 256 sh_debug(trap,name,(char*)0,argv,(arg->argflag&ARG_APPEND)|ARG_ASSIGN); 257 if(traceon) 258 { 259 sh_trace(NIL(char**),0); 260 sfputr(sfstderr,name,n); 261 sfwrite(sfstderr,"=( ",3); 262 while(cp= *argv++) 263 sfputr(sfstderr,sh_fmtq(cp),' '); 264 sfwrite(sfstderr,")\n",2); 265 } 266 } 267 continue; 268 } 269 if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[') 270 { 271 if(*cp!='.' && *cp!='[' && strchr(cp,'[')) 272 { 273 nv_close(np); 274 np = nv_open(cp,sh.var_tree,flag); 275 } 276 if((arg->argflag&ARG_APPEND) && !nv_isarray(np)) 277 nv_unset(np); 278 } 279 else 280 { 281 if(sh_isoption(SH_BASH) || (array&NV_IARRAY)) 282 { 283 if(!(arg->argflag&ARG_APPEND)) 284 nv_unset(np); 285 } 286 else if((arg->argflag&ARG_APPEND) && (!nv_isarray(np) || (nv_aindex(np)>=0))) 287 { 288 nv_unset(np); 289 nv_setarray(np,nv_associative); 290 } 291 else 292 nv_setarray(np,nv_associative); 293 } 294 if(prefix) 295 cp = stakcopy(nv_name(np)); 296 sh.prefix = cp; 297 sh_exec(tp,sh_isstate(SH_ERREXIT)); 298 sh.prefix = prefix; 299 if(nv_isarray(np) && (mp=nv_opensub(np))) 300 np = mp; 301 nv_setvtree(np); 302 continue; 303 } 304 cp = arg->argval; 305 } 306 if(sh.prefix && *cp=='.' && cp[1]=='=') 307 cp++; 308 np = nv_open(cp,sh.var_tree,flags); 309 if(!np->nvfun) 310 { 311 if(sh.used_pos) 312 nv_onattr(np,NV_PARAM); 313 else 314 nv_offattr(np,NV_PARAM); 315 } 316 if(traceon || trap) 317 { 318 register char *sp=cp; 319 char *name=nv_name(np); 320 char *sub=0; 321 int append = 0; 322 if(nv_isarray(np)) 323 sub = savesub; 324 if(cp=strchr(sp,'=')) 325 { 326 if(cp[-1]=='+') 327 append = ARG_APPEND; 328 cp++; 329 } 330 if(traceon) 331 { 332 sh_trace(NIL(char**),0); 333 nv_outname(sfstderr,name,-1); 334 if(sub) 335 sfprintf(sfstderr,"[%s]",sh_fmtq(sub)); 336 if(cp) 337 { 338 if(append) 339 sfputc(sfstderr,'+'); 340 sfprintf(sfstderr,"=%s\n",sh_fmtq(cp)); 341 } 342 } 343 if(trap) 344 { 345 char *av[2]; 346 av[0] = cp; 347 av[1] = 0; 348 sh_debug(trap,name,sub,av,append); 349 } 350 } 351 } 352 } 353 354 /* 355 * copy the subscript onto the stack 356 */ 357 static void stak_subscript(const char *sub, int last) 358 { 359 register int c; 360 stakputc('['); 361 while(c= *sub++) 362 { 363 if(c=='[' || c==']' || c=='\\') 364 stakputc('\\'); 365 stakputc(c); 366 } 367 stakputc(last); 368 } 369 370 /* 371 * construct a new name from a prefix and base name on the stack 372 */ 373 static char *copystack(const char *prefix, register const char *name, const char *sub) 374 { 375 register int last=0,offset = staktell(); 376 if(prefix) 377 { 378 stakputs(prefix); 379 if(*stakptr(staktell()-1)=='.') 380 stakseek(staktell()-1); 381 if(*name=='.' && name[1]=='[') 382 last = staktell()+2; 383 if(*name!='[' && *name!='.' && *name!='=' && *name!='+') 384 stakputc('.'); 385 } 386 if(last) 387 { 388 stakputs(name); 389 if(sh_checkid(stakptr(last),(char*)0)) 390 stakseek(staktell()-2); 391 } 392 if(sub) 393 stak_subscript(sub,']'); 394 if(!last) 395 stakputs(name); 396 stakputc(0); 397 return(stakptr(offset)); 398 } 399 400 /* 401 * grow this stack string <name> by <n> bytes and move from cp-1 to end 402 * right by <n>. Returns beginning of string on the stack 403 */ 404 static char *stack_extend(const char *cname, char *cp, int n) 405 { 406 register char *name = (char*)cname; 407 int offset = name - stakptr(0); 408 int m = cp-name; 409 stakseek(strlen(name)+n+1); 410 name = stakptr(offset); 411 cp = name + m; 412 m = strlen(cp)+1; 413 while(m-->0) 414 cp[n+m]=cp[m]; 415 return((char*)name); 416 } 417 418 Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) 419 { 420 char *cp=(char*)name, *sp, *xp; 421 register int c; 422 register Namval_t *np=0, *nq=0; 423 Namfun_t *fp=0; 424 long mode, add=0; 425 int copy=1,isref,top=0,noscope=(flags&NV_NOSCOPE); 426 if(root==sh.var_tree) 427 { 428 if(dtvnext(root)) 429 top = 1; 430 else 431 flags &= ~NV_NOSCOPE; 432 } 433 if(!dp->disc) 434 copy = dp->nofree; 435 if(*cp=='.') 436 cp++; 437 while(1) 438 { 439 switch(c = *(unsigned char*)(sp = cp)) 440 { 441 case '[': 442 if(flags&NV_NOARRAY) 443 { 444 dp->last = cp; 445 return(np); 446 } 447 cp = nv_endsubscript((Namval_t*)0,sp,0); 448 if(sp==name || sp[-1]=='.') 449 c = *(sp = cp); 450 goto skip; 451 case '.': 452 if(flags&NV_IDENT) 453 return(0); 454 if(root==sh.var_tree) 455 flags &= ~NV_EXPORT; 456 if(!copy && !(flags&NV_NOREF)) 457 { 458 c = sp-name; 459 copy = cp-name; 460 dp->nofree = 1; 461 name = copystack((const char*)0, name,(const char*)0); 462 cp = (char*)name+copy; 463 sp = (char*)name+c; 464 c = '.'; 465 } 466 skip: 467 case '+': 468 case '=': 469 *sp = 0; 470 case 0: 471 isref = 0; 472 dp->last = cp; 473 mode = (c=='.' || (flags&NV_NOADD))?add:NV_ADD; 474 if(flags&NV_NOSCOPE) 475 mode |= HASH_NOSCOPE; 476 if(top) 477 nq = nv_search(name,sh.var_base,0); 478 if(np = nv_search(name,root,mode)) 479 { 480 isref = nv_isref(np); 481 if(top) 482 { 483 if(nq==np) 484 flags &= ~NV_NOSCOPE; 485 else if(nq) 486 { 487 if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq))) 488 np->nvname = nq->nvname; 489 flags |= NV_NOSCOPE; 490 } 491 } 492 else if(add && nv_isnull(np) && c=='.') 493 nv_setvtree(np); 494 } 495 if(c) 496 *sp = c; 497 top = 0; 498 if(isref) 499 { 500 char *sub=0; 501 if(c=='.') /* don't optimize */ 502 sh.argaddr = 0; 503 else if(flags&NV_NOREF) 504 { 505 if(c) 506 nv_unref(np); 507 return(np); 508 } 509 while(nv_isref(np)) 510 { 511 root = nv_reftree(np); 512 sh.last_table = nv_reftable(np); 513 sub = nv_refsub(np); 514 np = nv_refnode(np); 515 if(sub && c!='.') 516 nv_putsub(np,sub,0L); 517 flags |= NV_NOSCOPE; 518 } 519 if(sub && c==0) 520 return(np); 521 if(np==nq) 522 flags &= ~(noscope?0:NV_NOSCOPE); 523 else if(c) 524 { 525 c = (cp-sp); 526 copy = strlen(cp=nv_name(np)); 527 dp->nofree = 1; 528 name = copystack(cp,sp,sub); 529 sp = (char*)name + copy; 530 cp = sp+c; 531 c = *sp; 532 if(!noscope) 533 flags &= ~NV_NOSCOPE; 534 } 535 flags |= NV_NOREF; 536 } 537 sh.last_root = root; 538 do 539 { 540 if(!np) 541 { 542 if(*sp=='[' && *cp==0 && cp[-1]==']') 543 { 544 /* 545 * for backward compatibility 546 * evaluate subscript for 547 * possible side effects 548 */ 549 cp[-1] = 0; 550 sh_arith(sp+1); 551 cp[-1] = ']'; 552 } 553 return(np); 554 } 555 if(c=='[' || (c=='.' && nv_isarray(np))) 556 { 557 int n = 0; 558 if(c=='[') 559 { 560 n = mode|nv_isarray(np); 561 if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']') 562 { 563 /* not implemented yet */ 564 dp->last = cp; 565 return(np); 566 } 567 if(n&&(flags&NV_ARRAY)) 568 n |= ARRAY_FILL; 569 cp = nv_endsubscript(np,sp,n); 570 } 571 else 572 cp = sp; 573 if((c = *cp)=='.' || c=='[' || (n&ARRAY_FILL)) 574 575 { 576 int m = cp-sp; 577 char *sub = m?nv_getsub(np):0; 578 if(!sub) 579 sub = "0"; 580 n = strlen(sub)+2; 581 if(!copy) 582 { 583 copy = cp-name; 584 dp->nofree = 1; 585 name = copystack((const char*)0, name,(const char*)0); 586 cp = (char*)name+copy; 587 sp = cp-m; 588 } 589 if(n <= m) 590 { 591 if(n) 592 { 593 memcpy(sp+1,sub,n-2); 594 sp[n-1] = ']'; 595 } 596 if(n < m) 597 cp=strcpy(sp+n,cp); 598 } 599 else 600 { 601 int r = n-m; 602 m = sp-name; 603 name = stack_extend(name, cp-1, r); 604 sp = (char*)name + m; 605 *sp = '['; 606 memcpy(sp+1,sub,n-2); 607 sp[n-1] = ']'; 608 cp = sp+n; 609 610 } 611 } 612 else if(c==0 && mode && (n=nv_aindex(np))>0) 613 nv_putsub(np,(char*)0,n|ARRAY_FILL); 614 else if(n==0 && c==0) 615 { 616 /* subscript must be 0*/ 617 cp[-1] = 0; 618 c = sh_arith(sp+1); 619 cp[-1] = ']'; 620 if(c) 621 return(0); 622 } 623 dp->last = cp; 624 if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY))) 625 { 626 *(sp=cp) = 0; 627 nq = nv_search(name,root,mode); 628 *sp = c; 629 if(nq && nv_isnull(nq)) 630 nq = nv_arraychild(np,nq,c); 631 if(!(np=nq)) 632 return(np); 633 } 634 } 635 else if(nv_isarray(np)) 636 nv_putsub(np,NIL(char*),ARRAY_UNDEF); 637 if(c=='.' && (fp=np->nvfun)) 638 { 639 for(; fp; fp=fp->next) 640 { 641 if(fp->disc && fp->disc->createf) 642 break; 643 } 644 if(fp) 645 { 646 if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np) 647 { 648 add = NV_ADD; 649 break; 650 } 651 else if((np=nq) && (c = *(cp=dp->last=fp->last))==0) 652 return(np); 653 } 654 } 655 } 656 while(c=='['); 657 if(c!='.') 658 return(np); 659 cp++; 660 break; 661 default: 662 dp->last = cp; 663 if((c = mbchar(cp)) && !isaletter(c)) 664 return(np); 665 while(xp=cp, c=mbchar(cp), isaname(c)); 666 cp = xp; 667 } 668 } 669 return(np); 670 } 671 672 /* 673 * Put <arg> into associative memory. 674 * If <flags> & NV_ARRAY then follow array to next subscript 675 * If <flags> & NV_NOARRAY then subscript is not allowed 676 * If <flags> & NV_NOSCOPE then use the current scope only 677 * If <flags> & NV_ASSIGN then assignment is allowed 678 * If <flags> & NV_IDENT then name must be an identifier 679 * If <flags> & NV_VARNAME then name must be a valid variable name 680 * If <flags> & NV_NOADD then node will not be added if not found 681 * If <flags> & NV_NOREF then don't follow reference 682 * If <flags> & NV_NOFAIL then don't generate an error message on failure 683 * SH_INIT is only set while initializing the environment 684 */ 685 Namval_t *nv_open(const char *name, Dt_t *root, int flags) 686 { 687 register char *cp=(char*)name; 688 register int c; 689 register Namval_t *np; 690 Namfun_t fun; 691 int append=0; 692 const char *msg = e_varname; 693 char *fname = 0; 694 int offset = staktell(); 695 Dt_t *funroot; 696 697 memset(&fun,0,sizeof(fun)); 698 sh.last_table = sh.namespace; 699 if(!root) 700 root = sh.var_tree; 701 sh.last_root = root; 702 if(root==sh_subfuntree(1)) 703 { 704 flags |= NV_NOREF; 705 msg = e_badfun; 706 if((np=sh.namespace) || strchr(name,'.')) 707 { 708 name = cp = copystack(np?nv_name(np):0,name,(const char*)0); 709 fname = strrchr(cp,'.'); 710 *fname = 0; 711 fun.nofree = 1; 712 flags &= ~NV_IDENT; 713 funroot = root; 714 root = sh.var_tree; 715 } 716 } 717 else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN))) 718 { 719 long mode = ((flags&NV_NOADD)?0:NV_ADD); 720 if(flags&NV_NOSCOPE) 721 mode |= HASH_SCOPE|HASH_NOSCOPE; 722 np = nv_search(name,root,mode); 723 if(np && !(flags&NV_REF)) 724 { 725 while(nv_isref(np)) 726 { 727 sh.last_table = nv_reftable(np); 728 np = nv_refnode(np); 729 } 730 } 731 return(np); 732 } 733 else if(sh.prefix && /**name!='.' &&*/ (flags&NV_ASSIGN)) 734 { 735 name = cp = copystack(sh.prefix,name,(const char*)0); 736 fun.nofree = 1; 737 } 738 c = *(unsigned char*)cp; 739 if(root==sh.alias_tree) 740 { 741 msg = e_aliname; 742 while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') && 743 (c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT)); 744 if(sh.subshell && c=='=') 745 root = sh_subaliastree(1); 746 if(c= *--cp) 747 *cp = 0; 748 np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD); 749 if(c) 750 *cp = c; 751 goto skip; 752 } 753 else if(flags&NV_IDENT) 754 msg = e_ident; 755 else if(c=='.') 756 { 757 c = *++cp; 758 flags |= NV_NOREF; 759 if(root==sh.var_tree) 760 root = sh.var_base; 761 sh.last_table = 0; 762 } 763 if(c= !isaletter(c)) 764 goto skip; 765 np = nv_create(name, root, flags, &fun); 766 cp = fun.last; 767 if(fname) 768 { 769 c = ((flags&NV_NOSCOPE)?HASH_NOSCOPE:0)|((flags&NV_NOADD)?0:NV_ADD); 770 *fname = '.'; 771 np = nv_search(name, funroot, c); 772 *fname = 0; 773 } 774 else if(*cp=='+' && cp[1]=='=') 775 { 776 append=NV_APPEND; 777 cp++; 778 } 779 c = *cp; 780 skip: 781 if(c=='=' && np && (flags&NV_ASSIGN)) 782 { 783 cp++; 784 if(sh_isstate(SH_INIT)) 785 { 786 nv_putval(np, cp, NV_RDONLY); 787 if(np==PWDNOD) 788 nv_onattr(np,NV_TAGGED); 789 } 790 else 791 { 792 char *sub=0; 793 if(sh_isoption(SH_XTRACE) && nv_isarray(np)) 794 sub = nv_getsub(np); 795 c = msg==e_aliname? 0: (append | (flags&NV_EXPORT)); 796 nv_putval(np, cp, c); 797 savesub = sub; 798 } 799 nv_onattr(np, flags&NV_ATTRIBUTES); 800 } 801 else if(c) 802 { 803 if(flags&NV_NOFAIL) 804 return(0); 805 if(c=='.') 806 msg = e_noparent; 807 else if(c=='[') 808 msg = e_noarray; 809 errormsg(SH_DICT,ERROR_exit(1),msg,name); 810 } 811 if(fun.nofree) 812 stakseek(offset); 813 return(np); 814 } 815 816 #if SHOPT_MULTIBYTE 817 static int ja_size(char*, int, int); 818 static void ja_restore(void); 819 static char *savep; 820 static char savechars[8+1]; 821 #endif /* SHOPT_MULTIBYTE */ 822 823 /* 824 * put value <string> into name-value node <np>. 825 * If <np> is an array, then the element given by the 826 * current index is assigned to. 827 * If <flags> contains NV_RDONLY, readonly attribute is ignored 828 * If <flags> contains NV_INTEGER, string is a pointer to a number 829 * If <flags> contains NV_NOFREE, previous value is freed, and <string> 830 * becomes value of node and <flags> becomes attributes 831 */ 832 void nv_putval(register Namval_t *np, const char *string, int flags) 833 { 834 register const char *sp=string; 835 register union Value *up; 836 register char *cp; 837 register int size = 0; 838 register int dot; 839 int was_local = nv_local; 840 if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY)) 841 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np)); 842 /* The following could cause the shell to fork if assignment 843 * would cause a side effect 844 */ 845 sh.argaddr = 0; 846 if(sh.subshell && !nv_local) 847 np = sh_assignok(np,1); 848 if(np->nvfun && !nv_isattr(np,NV_REF)) 849 { 850 /* This function contains disc */ 851 if(!nv_local) 852 { 853 nv_local=1; 854 nv_putv(np,sp,flags,np->nvfun); 855 if(sp && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT))) 856 sh_envput(sh.env,np); 857 return; 858 } 859 /* called from disc, assign the actual value */ 860 } 861 flags &= ~NV_NODISC; 862 if(flags&(NV_NOREF|NV_NOFREE)) 863 { 864 if(!nv_isnull(np) && np->nvalue.cp!=sp) 865 nv_unset(np); 866 nv_local=0; 867 np->nvalue.cp = (char*)sp; 868 nv_setattr(np,(flags&~NV_RDONLY)|NV_NOFREE); 869 return; 870 } 871 nv_local=0; 872 up= &np->nvalue; 873 #if !SHOPT_BSH 874 if(nv_isattr(np,NV_EXPORT)) 875 nv_offattr(np,NV_IMPORT); 876 else if(!nv_isattr(np,NV_MINIMAL)) 877 np->nvenv = 0; 878 #endif /* SHOPT_BSH */ 879 if(nv_isattr (np, NV_INTEGER)) 880 { 881 if(nv_isattr(np, NV_DOUBLE)) 882 { 883 if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t)) 884 { 885 Sfdouble_t ld, old=0; 886 if(flags&NV_INTEGER) 887 { 888 if(flags&NV_LONG) 889 ld = *((Sfdouble_t*)sp); 890 else if(flags&NV_SHORT) 891 ld = *((float*)sp); 892 else 893 ld = *((double*)sp); 894 } 895 else 896 ld = sh_arith(sp); 897 if(!up->ldp) 898 up->ldp = new_of(Sfdouble_t,0); 899 else if(flags&NV_APPEND) 900 old = *(up->ldp); 901 *(up->ldp) = ld+old; 902 } 903 else 904 { 905 double d,od=0; 906 if(flags&NV_INTEGER) 907 { 908 if(flags&NV_LONG) 909 d = (double)(*(Sfdouble_t*)sp); 910 else if(flags&NV_SHORT) 911 d = (double)(*(float*)sp); 912 else 913 d = *(double*)sp; 914 } 915 else 916 d = sh_arith(sp); 917 if(!up->dp) 918 up->dp = new_of(double,0); 919 else if(flags&NV_APPEND) 920 od = *(up->dp); 921 *(up->dp) = d+od; 922 } 923 } 924 else 925 { 926 if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t)) 927 { 928 Sflong_t ll=0,oll=0; 929 if(flags&NV_INTEGER) 930 { 931 if(flags&NV_DOUBLE) 932 { 933 if(flags&NV_LONG) 934 ll = *((Sfdouble_t*)sp); 935 else if(flags&NV_SHORT) 936 ll = *((float*)sp); 937 else 938 ll = *((double*)sp); 939 } 940 else if(nv_isattr(np,NV_UNSIGN)) 941 { 942 if(flags&NV_LONG) 943 ll = *((Sfulong_t*)sp); 944 else if(flags&NV_SHORT) 945 ll = *((uint16_t*)sp); 946 else 947 ll = *((uint32_t*)sp); 948 } 949 else 950 { 951 if(flags&NV_LONG) 952 ll = *((Sflong_t*)sp); 953 else if(flags&NV_SHORT) 954 ll = *((uint16_t*)sp); 955 else 956 ll = *((uint32_t*)sp); 957 } 958 } 959 else if(sp) 960 ll = (Sflong_t)sh_arith(sp); 961 if(!up->llp) 962 up->llp = new_of(Sflong_t,0); 963 else if(flags&NV_APPEND) 964 oll = *(up->llp); 965 *(up->llp) = ll+oll; 966 } 967 else 968 { 969 int32_t l=0,ol=0; 970 if(flags&NV_INTEGER) 971 { 972 if(flags&NV_DOUBLE) 973 { 974 Sflong_t ll; 975 if(flags&NV_LONG) 976 ll = *((Sfdouble_t*)sp); 977 else if(flags&NV_SHORT) 978 ll = *((float*)sp); 979 else 980 ll = *((double*)sp); 981 l = (int32_t)ll; 982 } 983 else if(nv_isattr(np,NV_UNSIGN)) 984 { 985 if(flags&NV_LONG) 986 l = *((Sfulong_t*)sp); 987 else if(flags&NV_SHORT) 988 l = *((uint16_t*)sp); 989 else 990 l = *(uint32_t*)sp; 991 } 992 else 993 { 994 if(flags&NV_LONG) 995 l = *((Sflong_t*)sp); 996 else if(flags&NV_SHORT) 997 l = *((int16_t*)sp); 998 else 999 l = *(int32_t*)sp; 1000 } 1001 } 1002 else if(sp) 1003 { 1004 Sfdouble_t ld = sh_arith(sp); 1005 if(ld<0) 1006 l = (int32_t)ld; 1007 else 1008 l = (uint32_t)ld; 1009 } 1010 if(nv_size(np) <= 1) 1011 nv_setsize(np,10); 1012 if(nv_isattr (np, NV_SHORT)) 1013 { 1014 int16_t s=0; 1015 if(flags&NV_APPEND) 1016 s = up->s; 1017 up->s = s+(int16_t)l; 1018 nv_onattr(np,NV_NOFREE); 1019 } 1020 else 1021 { 1022 if(!up->lp) 1023 up->lp = new_of(int32_t,0); 1024 else if(flags&NV_APPEND) 1025 ol = *(up->lp); 1026 *(up->lp) = l+ol; 1027 } 1028 } 1029 } 1030 } 1031 else 1032 { 1033 const char *tofree=0; 1034 int offset; 1035 #if _lib_pathnative 1036 char buff[PATH_MAX]; 1037 #endif /* _lib_pathnative */ 1038 if(flags&NV_INTEGER) 1039 { 1040 if(flags&NV_DOUBLE) 1041 { 1042 if(flags&NV_LONG) 1043 sfprintf(sh.strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp)); 1044 else 1045 sfprintf(sh.strbuf,"%.*g",DBL_DIG,*((double*)sp)); 1046 } 1047 else if(flags&NV_LONG) 1048 sfprintf(sh.strbuf,"%lld\0",*((Sflong_t*)sp)); 1049 else 1050 sfprintf(sh.strbuf,"%ld\0",*((int32_t*)sp)); 1051 sp = sfstruse(sh.strbuf); 1052 } 1053 if(nv_isattr(np, NV_HOST)==NV_HOST && sp) 1054 { 1055 #ifdef _lib_pathnative 1056 /* 1057 * return the host file name given the UNIX name 1058 */ 1059 pathnative(sp,buff,sizeof(buff)); 1060 if(buff[1]==':' && buff[2]=='/') 1061 { 1062 buff[2] = '\\'; 1063 if(*buff>='A' && *buff<='Z') 1064 *buff += 'a'-'A'; 1065 } 1066 sp = buff; 1067 #else 1068 ; 1069 #endif /* _lib_pathnative */ 1070 } 1071 else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp) 1072 { 1073 for(;*sp == ' '|| *sp=='\t';sp++); 1074 if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST))) 1075 for(;*sp=='0';sp++); 1076 size = nv_size(np); 1077 #if SHOPT_MULTIBYTE 1078 if(size) 1079 size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL)); 1080 #endif /* SHOPT_MULTIBYTE */ 1081 } 1082 if(!up->cp) 1083 flags &= ~NV_APPEND; 1084 if((flags&NV_APPEND) && !nv_isattr(np,NV_BINARY)) 1085 { 1086 offset = staktell(); 1087 stakputs(up->cp); 1088 stakputs(sp); 1089 stakputc(0); 1090 sp = stakptr(offset); 1091 } 1092 if(!nv_isattr(np, NV_NOFREE)) 1093 { 1094 /* delay free in case <sp> points into free region */ 1095 tofree = up->cp; 1096 } 1097 nv_offattr(np,NV_NOFREE); 1098 if (sp) 1099 { 1100 dot = strlen(sp); 1101 #if (_AST_VERSION>=20030127L) 1102 if(nv_isattr(np,NV_BINARY)) 1103 { 1104 int oldsize = (flags&NV_APPEND)?nv_size(np):0; 1105 if(flags&NV_RAW) 1106 { 1107 if(tofree) 1108 free((void*)tofree); 1109 up->cp = sp; 1110 return; 1111 } 1112 size = 0; 1113 if(nv_isattr(np,NV_ZFILL)) 1114 size = nv_size(np); 1115 if(size==0) 1116 size = oldsize + (3*dot/4); 1117 cp = (char*)malloc(size+1); 1118 if(oldsize) 1119 memcpy((void*)cp,(void*)up->cp,oldsize); 1120 up->cp = cp; 1121 if(size <= oldsize) 1122 return; 1123 dot = base64decode(sp,dot, (void**)0, cp+oldsize, size-oldsize,(void**)0); 1124 dot += oldsize; 1125 if(!nv_isattr(np,NV_ZFILL) || nv_size(np)==0) 1126 nv_setsize(np,dot); 1127 else if(nv_isattr(np,NV_ZFILL) && (size>dot)) 1128 memset((void*)&cp[dot],0,size-dot); 1129 return; 1130 } 1131 else 1132 #endif 1133 if(size==0 && nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL)) 1134 nv_setsize(np,size=dot); 1135 else if(size > dot) 1136 dot = size; 1137 cp = (char*)malloc(((unsigned)dot+1)); 1138 } 1139 else 1140 cp = 0; 1141 up->cp = cp; 1142 if(sp) 1143 { 1144 if(nv_isattr(np, NV_LTOU)) 1145 ltou(sp,cp); 1146 else if(nv_isattr (np, NV_UTOL)) 1147 sh_utol(sp,cp); 1148 else 1149 strcpy(cp, sp); 1150 if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL)) 1151 rightjust(cp,size,'0'); 1152 else if(nv_isattr(np, NV_RJUST)) 1153 rightjust(cp,size,' '); 1154 else if(nv_isattr(np, NV_LJUST)) 1155 { 1156 register char *dp; 1157 dp = strlen (cp) + cp; 1158 *(cp = (cp + size)) = 0; 1159 for (; dp < cp; *dp++ = ' '); 1160 } 1161 #if SHOPT_MULTIBYTE 1162 /* restore original string */ 1163 if(savep) 1164 ja_restore(); 1165 #endif /* SHOPT_MULTIBYTE */ 1166 } 1167 if(flags&NV_APPEND) 1168 stakseek(offset); 1169 if(tofree) 1170 free((void*)tofree); 1171 } 1172 if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT))) 1173 sh_envput(sh.env,np); 1174 return; 1175 } 1176 1177 /* 1178 * 1179 * Right-justify <str> so that it contains no more than 1180 * <size> characters. If <str> contains fewer than <size> 1181 * characters, left-pad with <fill>. Trailing blanks 1182 * in <str> will be ignored. 1183 * 1184 * If the leftmost digit in <str> is not a digit, <fill> 1185 * will default to a blank. 1186 */ 1187 static void rightjust(char *str, int size, int fill) 1188 { 1189 register int n; 1190 register char *cp,*sp; 1191 n = strlen(str); 1192 1193 /* ignore trailing blanks */ 1194 for(cp=str+n;n && *--cp == ' ';n--); 1195 if (n == size) 1196 return; 1197 if(n > size) 1198 { 1199 *(str+n) = 0; 1200 for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++); 1201 return; 1202 } 1203 else *(sp = str+size) = 0; 1204 if (n == 0) 1205 { 1206 while (sp > str) 1207 *--sp = ' '; 1208 return; 1209 } 1210 while(n--) 1211 { 1212 sp--; 1213 *sp = *cp--; 1214 } 1215 if(!isdigit(*str)) 1216 fill = ' '; 1217 while(sp>str) 1218 *--sp = fill; 1219 return; 1220 } 1221 1222 #if SHOPT_MULTIBYTE 1223 /* 1224 * handle left and right justified fields for multi-byte chars 1225 * given physical size, return a logical size which reflects the 1226 * screen width of multi-byte characters 1227 * Multi-width characters replaced by spaces if they cross the boundary 1228 * <type> is non-zero for right justified fields 1229 */ 1230 1231 static int ja_size(char *str,int size,int type) 1232 { 1233 register char *cp = str; 1234 register int c, n=size; 1235 register int outsize; 1236 register char *oldcp=cp; 1237 int oldn; 1238 wchar_t w; 1239 while(*cp) 1240 { 1241 oldn = n; 1242 w = mbchar(cp); 1243 outsize = mbwidth(w); 1244 size -= outsize; 1245 c = cp-oldcp; 1246 n += (c-outsize); 1247 oldcp = cp; 1248 if(size<=0 && type==0) 1249 break; 1250 } 1251 /* check for right justified fields that need truncating */ 1252 if(size <0) 1253 { 1254 if(type==0) 1255 { 1256 /* left justified and character crosses field boundary */ 1257 n = oldn; 1258 /* save boundary char and replace with spaces */ 1259 size = c; 1260 savechars[size] = 0; 1261 while(size--) 1262 { 1263 savechars[size] = cp[size]; 1264 cp[size] = ' '; 1265 } 1266 savep = cp; 1267 } 1268 size = -size; 1269 if(type) 1270 n -= (ja_size(str,size,0)-size); 1271 } 1272 return(n); 1273 } 1274 1275 static void ja_restore(void) 1276 { 1277 register char *cp = savechars; 1278 while(*cp) 1279 *savep++ = *cp++; 1280 savep = 0; 1281 } 1282 #endif /* SHOPT_MULTIBYTE */ 1283 1284 #ifndef _ENV_H 1285 static char *staknam(register Namval_t *np, char *value) 1286 { 1287 register char *p,*q; 1288 q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2); 1289 p=strcopy(q,nv_name(np)); 1290 if(value) 1291 { 1292 *p++ = '='; 1293 strcpy(p,value); 1294 } 1295 return(q); 1296 } 1297 #endif 1298 1299 /* 1300 * put the name and attribute into value of attributes variable 1301 */ 1302 #ifdef _ENV_H 1303 static void attstore(register Namval_t *np, void *data) 1304 { 1305 register int flag, c = ' '; 1306 NOT_USED(data); 1307 if(!(nv_isattr(np,NV_EXPORT))) 1308 return; 1309 flag = nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER); 1310 stakputc('='); 1311 if((flag&NV_DOUBLE) && (flag&NV_INTEGER)) 1312 { 1313 /* export doubles as integers for ksh88 compatibility */ 1314 stakputc(c+(flag&~(NV_DOUBLE|NV_EXPNOTE))); 1315 } 1316 else 1317 { 1318 stakputc(c+flag); 1319 if(flag&NV_INTEGER) 1320 c += nv_size(np); 1321 } 1322 stakputc(c); 1323 stakputs(nv_name(np)); 1324 } 1325 #else 1326 static void attstore(register Namval_t *np, void *data) 1327 { 1328 register int flag = np->nvflag; 1329 register struct adata *ap = (struct adata*)data; 1330 if(!(flag&NV_EXPORT) || (flag&NV_FUNCT)) 1331 return; 1332 flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER); 1333 *ap->attval++ = '='; 1334 if((flag&NV_DOUBLE) && (flag&NV_INTEGER)) 1335 { 1336 /* export doubles as integers for ksh88 compatibility */ 1337 *ap->attval++ = ' '+(flag&~(NV_DOUBLE|NV_EXPNOTE)); 1338 *ap->attval = ' '; 1339 } 1340 else 1341 { 1342 *ap->attval++ = ' '+flag; 1343 if(flag&NV_INTEGER) 1344 *ap->attval = ' ' + nv_size(np); 1345 else 1346 *ap->attval = ' '; 1347 } 1348 ap->attval = strcopy(++ap->attval,nv_name(np)); 1349 } 1350 #endif 1351 1352 #ifndef _ENV_H 1353 static void pushnam(Namval_t *np, void *data) 1354 { 1355 register char *value; 1356 register struct adata *ap = (struct adata*)data; 1357 if(nv_isattr(np,NV_IMPORT)) 1358 { 1359 if(np->nvenv) 1360 *ap->argnam++ = np->nvenv; 1361 } 1362 else if(value=nv_getval(np)) 1363 *ap->argnam++ = staknam(np,value); 1364 if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER)) 1365 ap->attsize += (strlen(nv_name(np))+4); 1366 } 1367 #endif 1368 1369 /* 1370 * Generate the environment list for the child. 1371 */ 1372 1373 #ifdef _ENV_H 1374 char **sh_envgen(void) 1375 { 1376 int offset,tell; 1377 register char **er; 1378 env_delete(sh.env,"_"); 1379 er = env_get(sh.env); 1380 offset = staktell(); 1381 stakputs(e_envmarker); 1382 tell = staktell(); 1383 nv_scan(sh.var_tree, attstore,(void*)0,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER)); 1384 if(tell ==staktell()) 1385 stakseek(offset); 1386 else 1387 *--er = stakfreeze(1)+offset; 1388 return(er); 1389 } 1390 #else 1391 char **sh_envgen(void) 1392 { 1393 register char **er; 1394 register int namec; 1395 register char *cp; 1396 struct adata data; 1397 /* L_ARGNOD gets generated automatically as full path name of command */ 1398 nv_offattr(L_ARGNOD,NV_EXPORT); 1399 data.attsize = 6; 1400 namec = nv_scan(sh.var_tree,nullscan,(void*)0,NV_EXPORT,NV_EXPORT); 1401 er = (char**)stakalloc((namec+4)*sizeof(char*)); 1402 data.argnam = (er+=2); 1403 nv_scan(sh.var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT); 1404 *data.argnam = (char*)stakalloc(data.attsize); 1405 cp = data.attval = strcopy(*data.argnam,e_envmarker); 1406 nv_scan(sh.var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER)); 1407 *data.attval = 0; 1408 if(cp!=data.attval) 1409 data.argnam++; 1410 *data.argnam = 0; 1411 return(er); 1412 } 1413 #endif 1414 1415 struct scan 1416 { 1417 void (*scanfn)(Namval_t*, void*); 1418 int scanmask; 1419 int scanflags; 1420 int scancount; 1421 void *scandata; 1422 }; 1423 1424 1425 static int scanfilter(Dt_t *dict, void *arg, void *data) 1426 { 1427 register Namval_t *np = (Namval_t*)arg; 1428 register int k=np->nvflag; 1429 register struct scan *sp = (struct scan*)data; 1430 NOT_USED(dict); 1431 if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags))) 1432 { 1433 if(!np->nvalue.cp && !nv_isattr(np,~NV_DEFAULT)) 1434 return(0); 1435 if(sp->scanfn) 1436 { 1437 if(nv_isarray(np)) 1438 nv_putsub(np,NIL(char*),0L); 1439 (*sp->scanfn)(np,sp->scandata); 1440 } 1441 sp->scancount++; 1442 } 1443 return(0); 1444 } 1445 1446 /* 1447 * Walk through the name-value pairs 1448 * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags 1449 * are visited 1450 * If <mask> is zero, and <flags> non-zero, then nodes with one or 1451 * more of <flags> is visited 1452 * If <mask> and <flags> are zero, then all nodes are visted 1453 */ 1454 int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags) 1455 { 1456 Dt_t *base=0; 1457 struct scan sdata; 1458 int (*hashfn)(Dt_t*, void*, void*); 1459 sdata.scanmask = mask; 1460 sdata.scanflags = flags&~NV_NOSCOPE; 1461 sdata.scanfn = fn; 1462 sdata.scancount = 0; 1463 sdata.scandata = data; 1464 hashfn = scanfilter; 1465 if(flags&NV_NOSCOPE) 1466 base = dtview((Dt_t*)root,0); 1467 dtwalk(root, hashfn,&sdata); 1468 if(base) 1469 dtview((Dt_t*)root,base); 1470 return(sdata.scancount); 1471 } 1472 1473 /* 1474 * create a new environment scope 1475 */ 1476 void nv_scope(struct argnod *envlist) 1477 { 1478 register Dt_t *newscope; 1479 newscope = dtopen(&_Nvdisc,Dtoset); 1480 dtview(newscope,(Dt_t*)sh.var_tree); 1481 sh.var_tree = (Dt_t*)newscope; 1482 if(envlist) 1483 nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN); 1484 } 1485 1486 /* 1487 * Remove freeable local space associated with the nvalue field 1488 * of nnod. This includes any strings representing the value(s) of the 1489 * node, as well as its dope vector, if it is an array. 1490 */ 1491 1492 void sh_envnolocal (register Namval_t *np, void *data) 1493 { 1494 char *cp=0; 1495 NOT_USED(data); 1496 if(nv_isattr(np,NV_EXPORT) && nv_isarray(np)) 1497 { 1498 nv_putsub(np,NIL(char*),0); 1499 if(cp = nv_getval(np)) 1500 cp = strdup(cp); 1501 } 1502 if(nv_isattr(np,NV_EXPORT|NV_NOFREE)) 1503 { 1504 if(nv_isref(np)) 1505 { 1506 nv_offattr(np,NV_NOFREE|NV_REF); 1507 free((void*)np->nvalue.nrp); 1508 np->nvalue.cp = 0; 1509 } 1510 if(!cp) 1511 return; 1512 } 1513 if(nv_isarray(np)) 1514 nv_putsub(np,NIL(char*),ARRAY_UNDEF); 1515 _nv_unset(np,NV_RDONLY); 1516 nv_setattr(np,0); 1517 if(cp) 1518 { 1519 nv_putval(np,cp,0); 1520 free((void*)cp); 1521 } 1522 } 1523 1524 /* 1525 * Currently this is a dummy, but someday will be needed 1526 * for reference counting 1527 */ 1528 void nv_close(Namval_t *np) 1529 { 1530 NOT_USED(np); 1531 } 1532 1533 static void table_unset(register Dt_t *root, int flags, Dt_t *oroot) 1534 { 1535 register Namval_t *np,*nq; 1536 for(np=(Namval_t*)dtfirst(root);np;np=nq) 1537 { 1538 _nv_unset(np,flags); 1539 if(oroot && (nq=nv_search(nv_name(np),oroot,0)) && nv_isattr(nq,NV_EXPORT)) 1540 sh_envput(sh.env,nq); 1541 nq = (Namval_t*)dtnext(root,np); 1542 dtdelete(root,np); 1543 free((void*)np); 1544 } 1545 } 1546 1547 /* 1548 * 1549 * Set the value of <np> to 0, and nullify any attributes 1550 * that <np> may have had. Free any freeable space occupied 1551 * by the value of <np>. If <np> denotes an array member, it 1552 * will retain its attributes. 1553 * <flags> can contain NV_RDONLY to override the readonly attribute 1554 * being cleared. 1555 */ 1556 void _nv_unset(register Namval_t *np,int flags) 1557 { 1558 register union Value *up; 1559 if(!(flags&NV_RDONLY) && nv_isattr (np,NV_RDONLY)) 1560 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np)); 1561 if(is_afunction(np) && np->nvalue.ip) 1562 { 1563 register struct slnod *slp = (struct slnod*)(np->nvenv); 1564 if(slp && !nv_isattr(np,NV_NOFREE)) 1565 { 1566 /* free function definition */ 1567 register char *name=nv_name(np),*cp= strrchr(name,'.'); 1568 if(cp) 1569 { 1570 Namval_t *npv; 1571 *cp = 0; 1572 npv = nv_open(name,sh.var_tree,NV_NOARRAY|NV_VARNAME|NV_NOADD); 1573 *cp++ = '.'; 1574 if(npv) 1575 nv_setdisc(npv,cp,NIL(Namval_t*),(Namfun_t*)npv); 1576 } 1577 stakdelete(slp->slptr); 1578 free((void*)np->nvalue.ip); 1579 np->nvalue.ip = 0; 1580 } 1581 goto done; 1582 } 1583 if(sh.subshell && !nv_isnull(np)) 1584 np = sh_assignok(np,0); 1585 nv_offattr(np,NV_NODISC); 1586 if(np->nvfun && !nv_isref(np)) 1587 { 1588 /* This function contains disc */ 1589 if(!nv_local) 1590 { 1591 nv_local=1; 1592 nv_putv(np,NIL(char*),flags,np->nvfun); 1593 return; 1594 } 1595 /* called from disc, assign the actual value */ 1596 nv_local=0; 1597 } 1598 up = &np->nvalue; 1599 if(up->cp) 1600 { 1601 if(!nv_isattr (np, NV_NOFREE)) 1602 free((void*)up->cp); 1603 up->cp = 0; 1604 } 1605 done: 1606 if(!nv_isarray(np) || !nv_arrayptr(np)) 1607 { 1608 if(nv_isref(np)) 1609 free((void*)np->nvalue.nrp); 1610 nv_setsize(np,0); 1611 if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT)) 1612 { 1613 if(nv_isattr(np,NV_EXPORT) && !strchr(np->nvname,'[')) 1614 env_delete(sh.env,nv_name(np)); 1615 np->nvenv = 0; 1616 nv_setattr(np,0); 1617 } 1618 else 1619 nv_setattr(np,NV_MINIMAL); 1620 } 1621 } 1622 1623 void nv_unset(register Namval_t *np) 1624 { 1625 _nv_unset(np,0); 1626 } 1627 1628 /* 1629 * return the node pointer in the highest level scope 1630 */ 1631 Namval_t *nv_scoped(register Namval_t *np) 1632 { 1633 if(!dtvnext(sh.var_tree)) 1634 return(np); 1635 return(dtsearch(sh.var_tree,np)); 1636 } 1637 1638 #if 1 1639 /* 1640 * return space separated list of names of variables in given tree 1641 */ 1642 static char *tableval(Dt_t *root) 1643 { 1644 static Sfio_t *out; 1645 register Namval_t *np; 1646 register int first=1; 1647 register Dt_t *base = dtview(root,0); 1648 if(out) 1649 sfseek(out,(Sfoff_t)0,SEEK_SET); 1650 else 1651 out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); 1652 for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np)) 1653 { 1654 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)) 1655 { 1656 if(!first) 1657 sfputc(out,' '); 1658 else 1659 first = 0; 1660 sfputr(out,np->nvname,-1); 1661 } 1662 } 1663 sfputc(out,0); 1664 if(base) 1665 dtview(root,base); 1666 return((char*)out->_data); 1667 } 1668 #endif 1669 1670 #if SHOPT_OPTIMIZE 1671 struct optimize 1672 { 1673 Namfun_t hdr; 1674 char **ptr; 1675 struct optimize *next; 1676 Namval_t *np; 1677 }; 1678 1679 static struct optimize *opt_free; 1680 1681 static void optimize_clear(Namval_t* np, Namfun_t *fp) 1682 { 1683 struct optimize *op = (struct optimize*)fp; 1684 nv_stack(np,fp); 1685 nv_stack(np,(Namfun_t*)0); 1686 for(;op && op->np==np; op=op->next) 1687 { 1688 if(op->ptr) 1689 { 1690 *op->ptr = 0; 1691 op->ptr = 0; 1692 } 1693 } 1694 } 1695 1696 static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp) 1697 { 1698 nv_putv(np,val,flags,fp); 1699 optimize_clear(np,fp); 1700 } 1701 1702 static const Namdisc_t optimize_disc = {sizeof(struct optimize),put_optimize}; 1703 1704 void nv_optimize(Namval_t *np) 1705 { 1706 register Namfun_t *fp; 1707 register struct optimize *op, *xp; 1708 if(sh.argaddr) 1709 { 1710 for(fp=np->nvfun; fp; fp = fp->next) 1711 { 1712 if(fp->disc->getnum || fp->disc->getval) 1713 { 1714 sh.argaddr = 0; 1715 return; 1716 } 1717 if(fp->disc== &optimize_disc) 1718 break; 1719 } 1720 if((xp= (struct optimize*)fp) && xp->ptr==sh.argaddr) 1721 return; 1722 if(op = opt_free) 1723 opt_free = op->next; 1724 else 1725 op=(struct optimize*)calloc(1,sizeof(struct optimize)); 1726 op->ptr = sh.argaddr; 1727 op->np = np; 1728 if(xp) 1729 { 1730 op->hdr.disc = 0; 1731 op->next = xp->next; 1732 xp->next = op; 1733 } 1734 else 1735 { 1736 op->hdr.disc = &optimize_disc; 1737 op->next = (struct optimize*)sh.optlist; 1738 sh.optlist = (void*)op; 1739 nv_stack(np,&op->hdr); 1740 } 1741 } 1742 } 1743 1744 void sh_optclear(Shell_t *shp, void *old) 1745 { 1746 register struct optimize *op,*opnext; 1747 for(op=(struct optimize*)shp->optlist; op; op = opnext) 1748 { 1749 opnext = op->next; 1750 if(op->ptr && op->hdr.disc) 1751 { 1752 nv_stack(op->np,&op->hdr); 1753 nv_stack(op->np,(Namfun_t*)0); 1754 } 1755 op->next = opt_free; 1756 opt_free = op; 1757 } 1758 shp->optlist = old; 1759 } 1760 1761 #else 1762 # define optimize_clear(np,fp) 1763 #endif /* SHOPT_OPTIMIZE */ 1764 1765 /* 1766 * Return a pointer to a character string that denotes the value 1767 * of <np>. If <np> refers to an array, return a pointer to 1768 * the value associated with the current index. 1769 * 1770 * If the value of <np> is an integer, the string returned will 1771 * be overwritten by the next call to nv_getval. 1772 * 1773 * If <np> has no value, 0 is returned. 1774 */ 1775 1776 char *nv_getval(register Namval_t *np) 1777 { 1778 register union Value *up= &np->nvalue; 1779 register int numeric; 1780 #if SHOPT_OPTIMIZE 1781 if(!nv_local && sh.argaddr) 1782 nv_optimize(np); 1783 #endif /* SHOPT_OPTIMIZE */ 1784 if(!np->nvfun && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF|NV_TABLE)) 1785 goto done; 1786 if(nv_isref(np)) 1787 { 1788 sh.last_table = nv_reftable(np); 1789 return(nv_name(nv_refnode(np))); 1790 } 1791 if(np->nvfun) 1792 { 1793 if(!nv_local) 1794 { 1795 nv_local=1; 1796 return(nv_getv(np, np->nvfun)); 1797 } 1798 nv_local=0; 1799 } 1800 numeric = ((nv_isattr (np, NV_INTEGER)) != 0); 1801 if(numeric) 1802 { 1803 Sflong_t ll; 1804 if(!up->cp) 1805 return("0"); 1806 if(nv_isattr (np,NV_DOUBLE)) 1807 { 1808 Sfdouble_t ld; 1809 double d; 1810 char *format; 1811 if(nv_isattr(np,NV_LONG)) 1812 { 1813 ld = *up->ldp; 1814 if(nv_isattr (np,NV_EXPNOTE)) 1815 format = "%.*Lg"; 1816 else 1817 format = "%.*Lf"; 1818 sfprintf(sh.strbuf,format,nv_size(np),ld); 1819 } 1820 else 1821 { 1822 d = *up->dp; 1823 if(nv_isattr (np,NV_EXPNOTE)) 1824 format = "%.*g"; 1825 else 1826 format = "%.*f"; 1827 sfprintf(sh.strbuf,format,nv_size(np),d); 1828 } 1829 return(sfstruse(sh.strbuf)); 1830 } 1831 else if(nv_isattr(np,NV_UNSIGN)) 1832 { 1833 if(nv_isattr (np,NV_LONG)) 1834 ll = *(Sfulong_t*)up->llp; 1835 else if(nv_isattr (np,NV_SHORT)) 1836 ll = (uint16_t)up->s; 1837 else 1838 ll = *(uint32_t*)(up->lp); 1839 } 1840 else if(nv_isattr (np,NV_LONG)) 1841 ll = *up->llp; 1842 else if(nv_isattr (np,NV_SHORT)) 1843 ll = up->s; 1844 else 1845 ll = *(up->lp); 1846 if((numeric=nv_size(np))==10) 1847 { 1848 if(nv_isattr(np,NV_UNSIGN)) 1849 { 1850 sfprintf(sh.strbuf,"%I*u",sizeof(ll),ll); 1851 return(sfstruse(sh.strbuf)); 1852 } 1853 numeric = 0; 1854 } 1855 return(fmtbasell(ll,numeric, numeric&&numeric!=10)); 1856 } 1857 done: 1858 #if (_AST_VERSION>=20030127L) 1859 /* 1860 * if NV_RAW flag is on, return pointer to binary data 1861 * otherwise, base64 encode the data and return this string 1862 */ 1863 if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW)) 1864 { 1865 char *cp; 1866 int size= nv_size(np), insize=(4*size)/3+size/45+8; 1867 base64encode(up->cp, size, (void**)0, cp=getbuf(insize), insize, (void**)0); 1868 return(cp); 1869 } 1870 #endif 1871 if((numeric=nv_size(np)) && up->cp && up->cp[numeric]) 1872 { 1873 char *cp = getbuf(numeric+1); 1874 memcpy(cp,up->cp,numeric); 1875 cp[numeric]=0; 1876 return(cp); 1877 } 1878 return ((char*)up->cp); 1879 } 1880 1881 Sfdouble_t nv_getnum(register Namval_t *np) 1882 { 1883 register union Value *up; 1884 register Sfdouble_t r=0; 1885 register char *str; 1886 #if SHOPT_OPTIMIZE 1887 if(!nv_local && sh.argaddr) 1888 nv_optimize(np); 1889 #endif /* SHOPT_OPTIMIZE */ 1890 if(nv_istable(np)) 1891 errormsg(SH_DICT,ERROR_exit(1),e_number,nv_name(np)); 1892 if(np->nvfun) 1893 { 1894 if(!nv_local) 1895 { 1896 nv_local=1; 1897 return(nv_getn(np, np->nvfun)); 1898 } 1899 nv_local=0; 1900 } 1901 if(nv_isattr (np, NV_INTEGER)) 1902 { 1903 up= &np->nvalue; 1904 if(!up->lp) 1905 r = 0; 1906 else if(nv_isattr(np, NV_DOUBLE)) 1907 { 1908 if(nv_isattr(np, NV_LONG)) 1909 r = *up->ldp; 1910 else 1911 r = *up->dp; 1912 } 1913 else if(nv_isattr(np, NV_UNSIGN)) 1914 { 1915 if(nv_isattr(np, NV_LONG)) 1916 r = (Sflong_t)*((Sfulong_t*)up->llp); 1917 else if(nv_isattr(np, NV_SHORT)) 1918 r = (Sflong_t)((uint16_t)up->s); 1919 else 1920 r = *((uint32_t*)up->lp); 1921 } 1922 else 1923 { 1924 if(nv_isattr(np, NV_LONG)) 1925 r = *up->llp; 1926 else if(nv_isattr(np, NV_SHORT)) 1927 r = up->s; 1928 else 1929 r = *up->lp; 1930 } 1931 } 1932 else if((str=nv_getval(np)) && *str!=0) 1933 { 1934 if(np->nvfun || nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL)) 1935 { 1936 while(*str=='0') 1937 str++; 1938 } 1939 r = sh_arith(str); 1940 } 1941 return(r); 1942 } 1943 /* 1944 * Give <np> the attributes <newatts,> and change its current 1945 * value to conform to <newatts>. The <size> of left and right 1946 * justified fields may be given. 1947 */ 1948 void nv_newattr (register Namval_t *np, unsigned newatts, int size) 1949 { 1950 register char *sp; 1951 register char *cp = 0; 1952 register unsigned int n; 1953 Namarr_t *ap = 0; 1954 int oldsize,oldatts; 1955 1956 /* check for restrictions */ 1957 if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) || sp==nv_name(FPATHNOD))) 1958 errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np)); 1959 /* handle attributes that do not change data separately */ 1960 n = np->nvflag; 1961 #if SHOPT_BSH 1962 if(newatts&NV_EXPORT) 1963 nv_offattr(np,NV_IMPORT); 1964 #endif /* SHOPT_BSH */ 1965 if(((n^newatts)&NV_EXPORT)) 1966 { 1967 /* record changes to the environment */ 1968 if(n&NV_EXPORT) 1969 env_delete(sh.env,nv_name(np)); 1970 else 1971 sh_envput(sh.env,np); 1972 } 1973 if((size==0||(n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0) 1974 { 1975 if(size) 1976 nv_setsize(np,size); 1977 nv_offattr(np, ~NV_NOFREE); 1978 nv_onattr(np, newatts); 1979 return; 1980 } 1981 /* for an array, change all the elements */ 1982 if((ap=nv_arrayptr(np)) && ap->nelem>0) 1983 nv_putsub(np,NIL(char*),ARRAY_SCAN); 1984 oldsize = nv_size(np); 1985 oldatts = np->nvflag; 1986 if(ap) /* add element to prevent array deletion */ 1987 ap->nelem++; 1988 do 1989 { 1990 nv_setsize(np,oldsize); 1991 np->nvflag = oldatts; 1992 if (sp = nv_getval(np)) 1993 { 1994 if(nv_isattr(np,NV_ZFILL)) 1995 while(*sp=='0') sp++; 1996 cp = (char*)malloc((n=strlen (sp)) + 1); 1997 strcpy(cp, sp); 1998 if(ap) 1999 { 2000 Namval_t *mp; 2001 ap->nelem &= ~ARRAY_SCAN; 2002 if(mp=nv_opensub(np)) 2003 nv_onattr(mp,NV_NOFREE); 2004 } 2005 nv_unset(np); 2006 if(ap) 2007 ap->nelem |= ARRAY_SCAN; 2008 if(size==0 && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL))) 2009 size = n; 2010 } 2011 else 2012 nv_unset(np); 2013 nv_setsize(np,size); 2014 np->nvflag &= NV_ARRAY; 2015 np->nvflag |= newatts; 2016 if (cp) 2017 { 2018 nv_putval (np, cp, NV_RDONLY); 2019 free(cp); 2020 } 2021 } 2022 while(ap && nv_nextsub(np)); 2023 if(ap) 2024 ap->nelem--; 2025 return; 2026 } 2027 2028 #ifndef _NEXT_SOURCE 2029 static char *oldgetenv(const char *string) 2030 { 2031 register char c0,c1; 2032 register const char *cp, *sp; 2033 register char **av = environ; 2034 if(!string || (c0= *string)==0) 2035 return(0); 2036 if((c1=*++string)==0) 2037 c1= '='; 2038 while(cp = *av++) 2039 { 2040 if(cp[0]!=c0 || cp[1]!=c1) 2041 continue; 2042 sp = string; 2043 while(*sp && *sp++ == *++cp); 2044 if(*sp==0 && *++cp=='=') 2045 return((char*)(cp+1)); 2046 } 2047 return(0); 2048 } 2049 2050 /* 2051 * This version of getenv uses the hash storage to access environment values 2052 */ 2053 char *getenv(const char *name) 2054 /*@ 2055 assume name!=0; 2056 @*/ 2057 { 2058 register Namval_t *np; 2059 if(!sh.var_tree) 2060 return(oldgetenv(name)); 2061 if((np = nv_search(name,sh.var_tree,0)) && nv_isattr(np,NV_EXPORT)) 2062 return(nv_getval(np)); 2063 if(name[0] == 'P' && name[1] == 'A' && name[2] == 'T' && name[3] == 'H' && name[4] == 0) 2064 return(oldgetenv(name)); 2065 return(0); 2066 } 2067 #endif /* _NEXT_SOURCE */ 2068 2069 #undef putenv 2070 /* 2071 * This version of putenv uses the hash storage to assign environment values 2072 */ 2073 int putenv(const char *name) 2074 { 2075 register Namval_t *np; 2076 if(name) 2077 { 2078 np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN); 2079 if(!strchr(name,'=')) 2080 nv_unset(np); 2081 } 2082 return(0); 2083 } 2084 2085 2086 /* 2087 * Override libast setenv() 2088 */ 2089 char* setenviron(const char *name) 2090 { 2091 register Namval_t *np; 2092 if(name) 2093 { 2094 np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN); 2095 if(strchr(name,'=')) 2096 return(nv_getval(np)); 2097 nv_unset(np); 2098 } 2099 return(""); 2100 } 2101 2102 /* 2103 * copy <str1> to <str2> changing lower case to upper case 2104 * <str2> must be big enough to hold <str1> 2105 * <str1> and <str2> may point to the same place. 2106 */ 2107 2108 static void ltou(register char const *str1,register char *str2) 2109 /*@ 2110 assume str1!=0 && str2!=0; 2111 return x satisfying strlen(in str1)==strlen(in str2); 2112 @*/ 2113 { 2114 register int c; 2115 for(; c= *((unsigned char*)str1); str1++,str2++) 2116 { 2117 if(islower(c)) 2118 *str2 = toupper(c); 2119 else 2120 *str2 = c; 2121 } 2122 *str2 = 0; 2123 } 2124 2125 /* 2126 * normalize <cp> and return pointer to subscript if any 2127 */ 2128 static char *lastdot(register char *cp) 2129 { 2130 register char *dp=cp, *ep=0; 2131 register int c; 2132 while(c= *cp++) 2133 { 2134 *dp++ = c; 2135 if(c=='[') 2136 ep = cp; 2137 else if(c=='.') 2138 { 2139 if(*cp=='[') 2140 { 2141 ep = nv_endsubscript((Namval_t*)0,cp,0); 2142 c = ep-cp; 2143 memcpy(dp,cp,c); 2144 dp = sh_checkid(dp+1,dp+c); 2145 cp = ep; 2146 } 2147 ep = 0; 2148 } 2149 } 2150 *dp = 0; 2151 return(ep); 2152 } 2153 2154 /* 2155 * Create a reference node from <np> to $np in dictionary <hp> 2156 */ 2157 void nv_setref(register Namval_t *np, Dt_t *hp, int flags) 2158 { 2159 register Namval_t *nq, *nr; 2160 register char *ep,*cp; 2161 if(nv_isref(np)) 2162 return; 2163 if(nv_isarray(np)) 2164 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np)); 2165 if(!(cp=nv_getval(np))) 2166 errormsg(SH_DICT,ERROR_exit(1),e_noref,nv_name(np)); 2167 if((ep = lastdot(cp)) && nv_isattr(np,NV_MINIMAL)) 2168 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np)); 2169 if(!hp) 2170 hp = sh.var_tree; 2171 nr= nq = nv_open(cp, hp, flags|NV_NOREF); 2172 while(nv_isref(nr)) 2173 { 2174 sh.last_table = nv_reftable(nr); 2175 hp = nv_reftree(nr); 2176 nr = nv_refnode(nr); 2177 } 2178 if(nr==np) 2179 { 2180 if(sh.namespace && nv_dict(sh.namespace)==hp) 2181 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np)); 2182 /* bind to earlier scope, or add to global scope */ 2183 if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np) 2184 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np)); 2185 } 2186 if(ep) 2187 { 2188 /* cause subscript evaluation and return result */ 2189 #if 0 2190 nv_endsubscript(nq,ep,NV_ADD); 2191 #endif 2192 ep = nv_getsub(nq); 2193 } 2194 nv_unset(np); 2195 np->nvalue.nrp = newof(0,struct Namref,1,0); 2196 np->nvalue.nrp->np = nq; 2197 np->nvalue.nrp->root = hp; 2198 if(ep) 2199 np->nvalue.nrp->sub = strdup(ep); 2200 np->nvalue.nrp->table = sh.last_table; 2201 nv_onattr(np,NV_REF|NV_NOFREE); 2202 } 2203 2204 /* 2205 * get the scope corresponding to <index> 2206 * whence uses the same values as lseeek() 2207 */ 2208 Shscope_t *sh_getscope(int index, int whence) 2209 { 2210 register struct sh_scoped *sp, *topmost; 2211 if(whence==SEEK_CUR) 2212 sp = &sh.st; 2213 else 2214 { 2215 if ((struct sh_scoped*)sh.topscope != sh.st.self) 2216 topmost = (struct sh_scoped*)sh.topscope; 2217 else 2218 topmost = &(sh.st); 2219 sp = topmost; 2220 if(whence==SEEK_SET) 2221 { 2222 int n =0; 2223 while(sp = sp->prevst) 2224 n++; 2225 index = n - index; 2226 sp = topmost; 2227 } 2228 } 2229 if(index < 0) 2230 return((Shscope_t*)0); 2231 while(index-- && (sp = sp->prevst)); 2232 return((Shscope_t*)sp); 2233 } 2234 2235 /* 2236 * make <scoped> the top scope and return previous scope 2237 */ 2238 Shscope_t *sh_setscope(Shscope_t *scope) 2239 { 2240 Shscope_t *old = (Shscope_t*)sh.st.self; 2241 *sh.st.self = sh.st; 2242 sh.st = *((struct sh_scoped*)scope); 2243 sh.var_tree = scope->var_tree; 2244 return(old); 2245 } 2246 2247 void nv_unscope(void) 2248 { 2249 register Dt_t *root = sh.var_tree; 2250 register Dt_t *dp = dtview(root,(Dt_t*)0); 2251 table_unset(root,NV_RDONLY|NV_NOSCOPE,dp); 2252 sh.var_tree=dp; 2253 dtclose(root); 2254 } 2255 2256 /* 2257 * The inverse of creating a reference node 2258 */ 2259 void nv_unref(register Namval_t *np) 2260 { 2261 Namval_t *nq; 2262 if(!nv_isref(np)) 2263 return; 2264 nq = nv_refnode(np); 2265 nv_offattr(np,NV_NOFREE|NV_REF); 2266 free((void*)np->nvalue.nrp); 2267 np->nvalue.cp = strdup(nv_name(nq)); 2268 #if SHOPT_OPTIMIZE 2269 { 2270 Namfun_t *fp; 2271 for(fp=nq->nvfun; fp; fp = fp->next) 2272 { 2273 if(fp->disc== &optimize_disc) 2274 { 2275 optimize_clear(nq,fp); 2276 return; 2277 } 2278 } 2279 } 2280 #endif 2281 } 2282 2283 /* 2284 * These following are for binary compatibility with the old hash library 2285 * They will be removed someday 2286 */ 2287 2288 #if defined(__IMPORT__) && defined(__EXPORT__) 2289 # define extern __EXPORT__ 2290 #endif 2291 2292 #undef hashscope 2293 2294 extern Dt_t *hashscope(Dt_t *root) 2295 { 2296 return(dtvnext(root)); 2297 } 2298 2299 #undef hashfree 2300 2301 extern Dt_t *hashfree(Dt_t *root) 2302 { 2303 Dt_t *dp = dtvnext(root); 2304 dtclose(root); 2305 return(dp); 2306 } 2307 2308 #undef hashname 2309 2310 extern char *hashname(void *obj) 2311 { 2312 Namval_t *np = (Namval_t*)obj; 2313 return(np->nvname); 2314 } 2315 2316 #undef hashlook 2317 2318 extern void *hashlook(Dt_t *root, const char *name, int mode,int size) 2319 { 2320 NOT_USED(size); 2321 return((void*)nv_search(name,root,mode)); 2322 } 2323 2324 char *nv_name(register Namval_t *np) 2325 { 2326 register Namval_t *table; 2327 register Namfun_t *fp; 2328 char *cp; 2329 if(is_abuiltin(np) || is_afunction(np)) 2330 return(np->nvname); 2331 if(nv_istable(np)) 2332 #if 1 2333 sh.last_table = nv_parent(np); 2334 #else 2335 sh.last_table = nv_create(np,0, NV_LAST,(Namfun_t*)0); 2336 #endif 2337 else if(!nv_isref(np)) 2338 { 2339 for(fp= np->nvfun ; fp; fp=fp->next) 2340 if(fp->disc && fp->disc->namef) 2341 { 2342 if(np==sh.last_table) 2343 sh.last_table = 0; 2344 return((*fp->disc->namef)(np,fp)); 2345 } 2346 } 2347 if(!(table=sh.last_table) || *np->nvname=='.' || table==sh.namespace || np==table) 2348 return(np->nvname); 2349 cp = nv_name(table); 2350 sfprintf(sh.strbuf,"%s.%s",cp,np->nvname); 2351 return(sfstruse(sh.strbuf)); 2352 } 2353 2354 Namval_t *nv_lastdict(void) 2355 { 2356 return(sh.last_table); 2357 } 2358 2359 #undef nv_context 2360 /* 2361 * returns the data context for a builtin 2362 */ 2363 void *nv_context(Namval_t *np) 2364 { 2365 return((void*)np->nvfun); 2366 } 2367 2368 #define DISABLE /* proto workaround */ 2369 2370 int nv_isnull DISABLE (register Namval_t *np) 2371 { 2372 return(nv_isnull(np)); 2373 } 2374 2375 #undef nv_setsize 2376 int nv_setsize(register Namval_t *np, int size) 2377 { 2378 int oldsize = nv_size(np); 2379 if(size>=0) 2380 np->nvsize = size; 2381 return(oldsize); 2382 } 2383