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