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