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