1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2008 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 22 /* 23 * code for tree nodes and name walking 24 * 25 * David Korn 26 * AT&T Labs 27 * 28 */ 29 30 #include "defs.h" 31 #include "name.h" 32 #include "argnod.h" 33 #include "lexstates.h" 34 35 struct nvdir 36 { 37 Dt_t *root; 38 Namval_t *hp; 39 Namval_t *table; 40 Namval_t *otable; 41 Namval_t *(*nextnode)(Namval_t*,Dt_t*,Namfun_t*); 42 Namfun_t *fun; 43 struct nvdir *prev; 44 int len; 45 char data[1]; 46 }; 47 48 char *nv_getvtree(Namval_t*, Namfun_t *); 49 static void put_tree(Namval_t*, const char*, int,Namfun_t*); 50 static char *walk_tree(Namval_t*, Namval_t*, int); 51 52 static int read_tree(Namval_t* np, Sfio_t *iop, int n, Namfun_t *dp) 53 { 54 Sfio_t *sp; 55 char *cp; 56 int c; 57 if(n>=0) 58 return(-1); 59 while((c = sfgetc(iop)) && isblank(c)); 60 sfungetc(iop,c); 61 sfprintf(sh.strbuf,"%s=%c",nv_name(np),0); 62 cp = sfstruse(sh.strbuf); 63 sp = sfopen((Sfio_t*)0,cp,"s"); 64 sfstack(iop,sp); 65 c=sh_eval(iop,SH_READEVAL); 66 return(c); 67 } 68 69 static Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp) 70 { 71 register Namfun_t *fp=dp; 72 while(fp=fp->next) 73 { 74 if(fp->disc && fp->disc->createf) 75 { 76 if(np=(*fp->disc->createf)(np,name,flag,fp)) 77 dp->last = fp->last; 78 return(np); 79 } 80 } 81 return((flag&NV_NOADD)?0:np); 82 } 83 84 static Namfun_t *clone_tree(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp){ 85 Namfun_t *dp; 86 if ((flags&NV_MOVE) && nv_type(np)) 87 return(fp); 88 dp = nv_clone_disc(fp,flags); 89 if((flags&NV_COMVAR) && !(flags&NV_RAW)) 90 { 91 walk_tree(np,mp,flags); 92 if((flags&NV_MOVE) && !(fp->nofree&1)) 93 free((void*)fp); 94 } 95 return(dp); 96 } 97 98 static const Namdisc_t treedisc = 99 { 100 0, 101 put_tree, 102 nv_getvtree, 103 0, 104 0, 105 create_tree, 106 clone_tree 107 ,0,0,0, 108 read_tree 109 }; 110 111 static char *nextdot(const char *str) 112 { 113 register char *cp; 114 register int c; 115 if(*str=='.') 116 str++; 117 for(cp=(char*)str;c= *cp; cp++) 118 { 119 if(c=='[') 120 { 121 cp = nv_endsubscript((Namval_t*)0,(char*)cp,0); 122 return(*cp=='.'?cp:0); 123 } 124 if(c=='.') 125 return(cp); 126 } 127 return(0); 128 } 129 130 static Namfun_t *nextdisc(Namval_t *np) 131 { 132 register Namfun_t *fp; 133 if(nv_isref(np)) 134 return(0); 135 for(fp=np->nvfun;fp;fp=fp->next) 136 { 137 if(fp && fp->disc && fp->disc->nextf) 138 return(fp); 139 } 140 return(0); 141 } 142 143 void *nv_diropen(Namval_t *np,const char *name) 144 { 145 char *next,*last; 146 int c,len=strlen(name); 147 struct nvdir *save, *dp = new_of(struct nvdir,len); 148 Namval_t *nq=0,fake; 149 Namfun_t *nfp=0; 150 if(!dp) 151 return(0); 152 memset((void*)dp, 0, sizeof(*dp)); 153 if(name[len-1]=='*' || name[len-1]=='@') 154 len -= 1; 155 name = memcpy(dp->data,name,len); 156 dp->data[len] = 0; 157 dp->len = len; 158 dp->root = sh.last_root?sh.last_root:sh.var_tree; 159 #if 1 160 while(1) 161 { 162 dp->table = sh.last_table; 163 sh.last_table = 0; 164 if(*(last=(char*)name)==0) 165 break; 166 if(!(next=nextdot(last))) 167 break; 168 *next = 0; 169 np = nv_open(name, dp->root, NV_NOFAIL); 170 *next = '.'; 171 if(!np || !nv_istable(np)) 172 break; 173 dp->root = nv_dict(np); 174 name = next+1; 175 } 176 #else 177 dp->table = sh.last_table; 178 sh.last_table = 0; 179 last = dp->data; 180 #endif 181 if(*name) 182 { 183 fake.nvname = (char*)name; 184 if(dp->hp = (Namval_t*)dtprev(dp->root,&fake)) 185 { 186 char *cp = nv_name(dp->hp); 187 c = strlen(cp); 188 if(memcmp(name,cp,c) || name[c]!='[') 189 dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); 190 else 191 { 192 np = dp->hp; 193 last = 0; 194 } 195 } 196 } 197 else 198 dp->hp = (Namval_t*)dtfirst(dp->root); 199 while(1) 200 { 201 if(!last) 202 next = 0; 203 else if(next= nextdot(last)) 204 { 205 c = *next; 206 *next = 0; 207 } 208 if(!np) 209 { 210 if(nfp && nfp->disc && nfp->disc->createf) 211 { 212 np = (*nfp->disc->createf)(nq,last,0,nfp); 213 if(*nfp->last == '[') 214 { 215 nv_endsubscript(np,nfp->last,NV_NOADD); 216 if(nq = nv_opensub(np)) 217 np = nq; 218 } 219 } 220 else 221 np = nv_search(last,dp->root,0); 222 } 223 if(next) 224 *next = c; 225 if(np==dp->hp && !next) 226 dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); 227 if(np && ((nfp=nextdisc(np)) || nv_istable(np))) 228 { 229 if(!(save = new_of(struct nvdir,0))) 230 return(0); 231 *save = *dp; 232 dp->prev = save; 233 if(nv_istable(np)) 234 dp->root = nv_dict(np); 235 else 236 dp->root = (Dt_t*)np; 237 if(nfp) 238 { 239 dp->nextnode = nfp->disc->nextf; 240 dp->table = np; 241 dp->otable = sh.last_table; 242 dp->fun = nfp; 243 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); 244 } 245 else 246 dp->nextnode = 0; 247 } 248 else 249 break; 250 if(!next || next[1]==0) 251 break; 252 last = next+1; 253 nq = np; 254 np = 0; 255 } 256 return((void*)dp); 257 } 258 259 260 static Namval_t *nextnode(struct nvdir *dp) 261 { 262 if(dp->nextnode) 263 return((*dp->nextnode)(dp->hp,dp->root,dp->fun)); 264 if(dp->len && memcmp(dp->data, dp->hp->nvname, dp->len)) 265 return(0); 266 return((Namval_t*)dtnext(dp->root,dp->hp)); 267 } 268 269 char *nv_dirnext(void *dir) 270 { 271 register struct nvdir *save, *dp = (struct nvdir*)dir; 272 register Namval_t *np, *last_table; 273 register char *cp; 274 Namfun_t *nfp; 275 Namval_t *nq; 276 while(1) 277 { 278 while(np=dp->hp) 279 { 280 #if 0 281 char *sptr; 282 #endif 283 if(nv_isarray(np)) 284 nv_putsub(np,(char*)0, ARRAY_UNDEF); 285 dp->hp = nextnode(dp); 286 if(nv_isnull(np) && !nv_isarray(np)) 287 continue; 288 last_table = sh.last_table; 289 #if 0 290 if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL)) 291 { 292 sptr = dp->table->nvenv; 293 dp->table->nvenv = (char*)dp->otable; 294 } 295 #endif 296 sh.last_table = dp->table; 297 cp = nv_name(np); 298 #if 0 299 if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL)) 300 dp->table->nvenv = sptr; 301 #endif 302 if(dp->nextnode && !dp->hp && (nq = (Namval_t*)dp->table)) 303 { 304 Namarr_t *ap = nv_arrayptr(nq); 305 if(ap && (ap->nelem&ARRAY_SCAN) && nv_nextsub(nq)) 306 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,dp->fun); 307 } 308 sh.last_table = last_table; 309 if(!dp->len || memcmp(cp,dp->data,dp->len)==0) 310 { 311 if((nfp=nextdisc(np)) && (nfp->disc->getval||nfp->disc->getnum) && nv_isvtree(np) && strcmp(cp,dp->data)) 312 nfp = 0; 313 if(nfp || nv_istable(np)) 314 { 315 Dt_t *root; 316 if(nv_istable(np)) 317 root = nv_dict(np); 318 else 319 root = (Dt_t*)np; 320 /* check for recursive walk */ 321 for(save=dp; save; save=save->prev) 322 { 323 if(save->root==root) 324 break; 325 } 326 if(save) 327 return(cp); 328 if(!(save = new_of(struct nvdir,0))) 329 return(0); 330 *save = *dp; 331 dp->prev = save; 332 dp->root = root; 333 dp->len = 0; 334 if(nfp && np->nvfun) 335 { 336 #if 0 337 Namarr_t *ap = nv_arrayptr(np); 338 if(ap && (ap->nelem&ARRAY_UNDEF)) 339 nv_putsub(np,(char*)0,ARRAY_SCAN); 340 #endif 341 dp->nextnode = nfp->disc->nextf; 342 dp->otable = dp->table; 343 dp->table = np; 344 dp->fun = nfp; 345 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); 346 } 347 else 348 dp->nextnode = 0; 349 } 350 return(cp); 351 } 352 } 353 if(!(save=dp->prev)) 354 break; 355 *dp = *save; 356 free((void*)save); 357 } 358 return(0); 359 } 360 361 void nv_dirclose(void *dir) 362 { 363 struct nvdir *dp = (struct nvdir*)dir; 364 if(dp->prev) 365 nv_dirclose((void*)dp->prev); 366 free(dir); 367 } 368 369 static void outtype(Namval_t *np, Namfun_t *fp, Sfio_t* out, const char *prefix) 370 { 371 char *type=0; 372 Namval_t *tp = fp->type; 373 if(!tp && fp->disc && fp->disc->typef) 374 tp = (*fp->disc->typef)(np,fp); 375 for(fp=fp->next;fp;fp=fp->next) 376 { 377 if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp))) 378 { 379 outtype(np,fp,out,prefix); 380 break; 381 } 382 } 383 if(prefix && *prefix=='t') 384 type = "-T"; 385 else if(!prefix) 386 type = "type"; 387 if(type) 388 { 389 char *cp=tp->nvname; 390 if(cp=strrchr(cp,'.')) 391 cp++; 392 else 393 cp = tp->nvname; 394 sfprintf(out,"%s %s ",type,cp); 395 } 396 } 397 398 /* 399 * print the attributes of name value pair give by <np> 400 */ 401 void nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname) 402 { 403 register const Shtable_t *tp; 404 register char *cp; 405 register unsigned val,mask,attr; 406 char *ip=0; 407 Namfun_t *fp=0; 408 Namval_t *typep=0; 409 for(fp=np->nvfun;fp;fp=fp->next) 410 { 411 if((typep=fp->type) || (fp->disc && fp->disc->typef && (typep=(*fp->disc->typef)(np,fp)))) 412 break; 413 } 414 if(!fp && !nv_isattr(np,~(NV_MINIMAL|NV_NOFREE))) 415 { 416 if(prefix && *prefix) 417 { 418 if(nv_isvtree(np)) 419 sfprintf(out,"%s -C ",prefix); 420 else if(!np->nvalue.cp && nv_isattr(np,~NV_NOFREE)==NV_MINIMAL && strcmp(np->nvname,"_")) 421 sfputr(out,prefix,' '); 422 } 423 return; 424 } 425 426 if ((attr=nv_isattr(np,~NV_NOFREE)) || fp) 427 { 428 if((attr&NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) 429 attr &= ~NV_NOPRINT; 430 if(!attr && !fp) 431 return; 432 if(fp) 433 { 434 prefix = Empty; 435 attr &= NV_RDONLY|NV_ARRAY; 436 if(nv_isattr(np,NV_REF|NV_TAGGED)==(NV_REF|NV_TAGGED)) 437 attr |= (NV_REF|NV_TAGGED); 438 if(typep) 439 { 440 char *cp = typep->nvname; 441 if(cp = strrchr(cp,'.')) 442 cp++; 443 else 444 cp = typep->nvname; 445 sfputr(out,cp,' '); 446 fp = 0; 447 } 448 } 449 else if(prefix && *prefix) 450 sfputr(out,prefix,' '); 451 for(tp = shtab_attributes; *tp->sh_name;tp++) 452 { 453 val = tp->sh_number; 454 mask = val; 455 if(fp && (val&NV_INTEGER)) 456 break; 457 /* 458 * the following test is needed to prevent variables 459 * with E attribute from being given the F 460 * attribute as well 461 */ 462 if(val==NV_DOUBLE && (attr&(NV_EXPNOTE|NV_HEXFLOAT))) 463 continue; 464 if(val&NV_INTEGER) 465 mask |= NV_DOUBLE; 466 else if(val&NV_HOST) 467 mask = NV_HOST; 468 if((attr&mask)==val) 469 { 470 if(val==NV_ARRAY) 471 { 472 Namarr_t *ap = nv_arrayptr(np); 473 char **xp=0; 474 if(ap && array_assoc(ap)) 475 { 476 if(tp->sh_name[1]!='A') 477 continue; 478 } 479 else if(tp->sh_name[1]=='A') 480 continue; 481 if(ap && (ap->nelem&ARRAY_TREE)) 482 { 483 if(prefix && *prefix) 484 sfwrite(out,"-C ",3); 485 } 486 if(ap && !array_assoc(ap) && (xp=(char**)(ap+1)) && *xp) 487 ip = nv_namptr(*xp,0)->nvname; 488 } 489 if(prefix) 490 { 491 if(*tp->sh_name=='-') 492 sfprintf(out,"%.2s ",tp->sh_name); 493 if(ip) 494 { 495 sfprintf(out,"[%s] ",ip); 496 ip = 0; 497 } 498 } 499 else 500 sfputr(out,tp->sh_name+2,' '); 501 if ((val&(NV_LJUST|NV_RJUST|NV_ZFILL)) && !(val&NV_INTEGER) && val!=NV_HOST) 502 sfprintf(out,"%d ",nv_size(np)); 503 if(val==(NV_REF|NV_TAGGED)) 504 attr &= ~(NV_REF|NV_TAGGED); 505 } 506 if(val==NV_INTEGER && nv_isattr(np,NV_INTEGER)) 507 { 508 if(nv_size(np) != 10) 509 { 510 if(nv_isattr(np, NV_DOUBLE)== NV_DOUBLE) 511 cp = "precision"; 512 else 513 cp = "base"; 514 if(!prefix) 515 sfputr(out,cp,' '); 516 sfprintf(out,"%d ",nv_size(np)); 517 } 518 break; 519 } 520 } 521 if(fp) 522 outtype(np,fp,out,prefix); 523 if(noname) 524 return; 525 sfputr(out,nv_name(np),'\n'); 526 } 527 } 528 529 struct Walk 530 { 531 Sfio_t *out; 532 Dt_t *root; 533 int noscope; 534 int indent; 535 int nofollow; 536 int array; 537 int flags; 538 }; 539 540 void nv_outnode(Namval_t *np, Sfio_t* out, int indent, int special) 541 { 542 char *fmtq,*ep,*xp; 543 Namval_t *mp; 544 Namarr_t *ap = nv_arrayptr(np); 545 int tabs=0,c,more,associative = 0; 546 if(ap) 547 { 548 if(!(ap->nelem&ARRAY_SCAN)) 549 nv_putsub(np,NIL(char*),ARRAY_SCAN); 550 sfputc(out,'('); 551 if(indent>=0) 552 { 553 sfputc(out,'\n'); 554 tabs=1; 555 } 556 if(!(associative =(array_assoc(ap)!=0))) 557 { 558 if(array_elem(ap) < nv_aimax(np)+1) 559 associative=1; 560 } 561 } 562 mp = nv_opensub(np); 563 while(1) 564 { 565 if(mp && special && nv_isvtree(mp)) 566 { 567 if(!nv_nextsub(np)) 568 break; 569 mp = nv_opensub(np); 570 continue; 571 } 572 if(tabs) 573 sfnputc(out,'\t',++indent); 574 tabs=0; 575 if(associative||special) 576 { 577 if(!(fmtq = nv_getsub(np))) 578 break; 579 sfprintf(out,"[%s]",sh_fmtq(fmtq)); 580 sfputc(out,'='); 581 } 582 if(mp && nv_isarray(mp)) 583 { 584 nv_outnode(mp, out, indent+(indent>=0),0); 585 if(indent>0) 586 sfnputc(out,'\t',indent); 587 sfputc(out,')'); 588 sfputc(out,indent>=0?'\n':' '); 589 more = nv_nextsub(np); 590 goto skip; 591 } 592 if(mp && nv_isvtree(mp)) 593 nv_onattr(mp,NV_EXPORT); 594 ep = nv_getval(mp?mp:np); 595 xp = 0; 596 if(!ap && nv_isattr(np,NV_INTEGER|NV_LJUST)==NV_LJUST) 597 { 598 xp = ep+nv_size(np); 599 while(--xp>ep && *xp==' '); 600 if(xp>ep || *xp!=' ') 601 xp++; 602 if(xp < (ep+nv_size(np))) 603 *xp = 0; 604 else 605 xp = 0; 606 } 607 if(mp && nv_isvtree(mp)) 608 fmtq = ep; 609 else if(!(fmtq = sh_fmtq(ep))) 610 fmtq = ""; 611 else if(!associative && (ep=strchr(fmtq,'='))) 612 { 613 char *qp = strchr(fmtq,'\''); 614 if(!qp || qp>ep) 615 { 616 sfwrite(out,fmtq,ep-fmtq); 617 sfputc(out,'\\'); 618 fmtq = ep; 619 } 620 } 621 more = nv_nextsub(np); 622 c = '\n'; 623 if(indent<0) 624 { 625 c = ';'; 626 if(ap) 627 c = more?' ':-1; 628 } 629 sfputr(out,fmtq,c); 630 if(xp) 631 *xp = ' '; 632 skip: 633 if(!more) 634 return; 635 mp = nv_opensub(np); 636 if(indent>0 && !(mp && special && nv_isvtree(mp))) 637 sfnputc(out,'\t',indent); 638 } 639 } 640 641 static void outval(char *name, const char *vname, struct Walk *wp) 642 { 643 register Namval_t *np, *nq; 644 register Namfun_t *fp; 645 int isarray=0, special=0,mode=0; 646 if(*name!='.' || vname[strlen(vname)-1]==']') 647 mode = NV_ARRAY; 648 if(!(np=nv_open(vname,wp->root,mode|NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope))) 649 return; 650 fp = nv_hasdisc(np,&treedisc); 651 if(*name=='.') 652 { 653 if(nv_isattr(np,NV_BINARY)) 654 return; 655 if(fp && np->nvalue.cp && np->nvalue.cp!=Empty) 656 { 657 nv_local = 1; 658 fp = 0; 659 } 660 if(fp) 661 return; 662 if(nv_isarray(np)) 663 return; 664 } 665 if(!special && fp && !nv_isarray(np)) 666 { 667 Namfun_t *xp; 668 if(!wp->out) 669 { 670 fp = nv_stack(np,fp); 671 if(fp = nv_stack(np,NIL(Namfun_t*))) 672 free((void*)fp); 673 np->nvfun = 0; 674 return; 675 } 676 for(xp=fp->next; xp; xp = xp->next) 677 { 678 if(xp->disc && (xp->disc->getval || xp->disc->getnum)) 679 break; 680 } 681 if(!xp) 682 return; 683 } 684 if((nv_isnull(np) || np->nvalue.cp==Empty) && !nv_isarray(np)) 685 return; 686 if(special || (nv_isarray(np) && nv_arrayptr(np))) 687 { 688 isarray=1; 689 if(array_elem(nv_arrayptr(np))==0) 690 isarray=2; 691 else 692 nq = nv_putsub(np,NIL(char*),ARRAY_SCAN|(wp->out?ARRAY_NOCHILD:0)); 693 } 694 if(!wp->out) 695 { 696 _nv_unset(np,NV_RDONLY); 697 nv_close(np); 698 #if 0 699 if(sh.subshell==0 && !(wp->flags&NV_RDONLY) && !nv_isattr(np,NV_MINIMAL|NV_NOFREE)) 700 nv_delete(np,wp->root,0); 701 #endif 702 return; 703 } 704 if(isarray==1 && !nq) 705 { 706 sfputc(wp->out,'('); 707 if(wp->indent>=0) 708 sfputc(wp->out,'\n'); 709 return; 710 } 711 if(isarray==0 && nv_isarray(np) && nv_isnull(np)) /* empty array */ 712 isarray = 2; 713 special |= wp->nofollow; 714 if(!wp->array && wp->indent>0) 715 sfnputc(wp->out,'\t',wp->indent); 716 if(!special) 717 { 718 if(*name!='.') 719 nv_attribute(np,wp->out,"typeset",'='); 720 nv_outname(wp->out,name,-1); 721 if(np->nvalue.cp || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)) || nv_isvtree(np)) 722 sfputc(wp->out,(isarray==2?'\n':'=')); 723 if(isarray==2) 724 return; 725 } 726 fp = np->nvfun; 727 if(*name=='.' && !isarray) 728 np->nvfun = 0; 729 nv_outnode(np, wp->out, wp->indent, special); 730 if(*name=='.' && !isarray) 731 np->nvfun = fp; 732 if(isarray && !special) 733 { 734 if(wp->indent>0) 735 { 736 sfnputc(wp->out,'\t',wp->indent); 737 sfwrite(wp->out,")\n",2); 738 } 739 else 740 sfwrite(wp->out,");",2); 741 } 742 } 743 744 /* 745 * format initialization list given a list of assignments <argp> 746 */ 747 static char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp) 748 { 749 register char *cp,*nextcp,*arg; 750 register Sfio_t *outfile = wp->out; 751 register int m,r,l; 752 if(n==0) 753 m = strlen(prefix); 754 else if(cp=nextdot(prefix)) 755 m = cp-prefix; 756 else 757 m = strlen(prefix)-1; 758 m++; 759 if(outfile && !wp->array) 760 { 761 sfputc(outfile,'('); 762 if(wp->indent>=0) 763 { 764 wp->indent++; 765 sfputc(outfile,'\n'); 766 } 767 } 768 for(; arg= *argv; argv++) 769 { 770 cp = arg + n; 771 if(n==0 && cp[m-1]!='.') 772 continue; 773 if(n && cp[m-1]==0) 774 break; 775 if(n==0 || strncmp(arg,prefix-n,m+n)==0) 776 { 777 cp +=m; 778 r = 0; 779 if(*cp=='.') 780 cp++,r++; 781 if(nextcp=nextdot(cp)) 782 { 783 if(outfile) 784 { 785 Namval_t *np,*tp; 786 *nextcp = 0; 787 np=nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope); 788 if(!np || (nv_isarray(np) && (!(tp=nv_opensub(np)) || !nv_isvtree(tp)))) 789 { 790 *nextcp = '.'; 791 continue; 792 } 793 if(wp->indent>=0) 794 sfnputc(outfile,'\t',wp->indent); 795 if(*cp!='[' && (tp = nv_type(np))) 796 { 797 char *sp; 798 if(sp = strrchr(tp->nvname,'.')) 799 sp++; 800 else 801 sp = tp->nvname; 802 sfputr(outfile,sp,' '); 803 } 804 nv_outname(outfile,cp,nextcp-cp); 805 sfputc(outfile,'='); 806 *nextcp = '.'; 807 } 808 else 809 { 810 outval(cp,arg,wp); 811 continue; 812 } 813 argv = genvalue(argv,cp,n+m+r,wp); 814 if(wp->indent>=0) 815 sfputc(outfile,'\n'); 816 if(*argv) 817 continue; 818 break; 819 } 820 else if(outfile && !wp->nofollow && argv[1] && memcmp(arg,argv[1],l=strlen(arg))==0 && argv[1][l]=='[') 821 { 822 Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope); 823 if(!np) 824 continue; 825 wp->array = nv_isarray(np); 826 if(wp->indent>0) 827 sfnputc(outfile,'\t',wp->indent); 828 nv_attribute(np,outfile,"typeset",1); 829 nv_close(np); 830 sfputr(outfile,arg+m+r+(n?n:0),'='); 831 wp->nofollow=1; 832 argv = genvalue(argv,cp,cp-arg ,wp); 833 sfputc(outfile,wp->indent<0?';':'\n'); 834 } 835 else if(outfile && *cp=='[') 836 { 837 if(wp->indent) 838 sfnputc(outfile,'\t',wp->indent); 839 sfputr(outfile,cp,'='); 840 argv = genvalue(++argv,cp,cp-arg ,wp); 841 sfputc(outfile,'\n'); 842 } 843 else 844 { 845 outval(cp,arg,wp); 846 if(wp->array) 847 { 848 if(wp->indent>=0) 849 wp->indent++; 850 else 851 sfputc(outfile,' '); 852 wp->array = 0; 853 } 854 } 855 } 856 else 857 break; 858 wp->nofollow = 0; 859 } 860 wp->array = 0; 861 if(outfile) 862 { 863 int c = prefix[m-1]; 864 cp = (char*)prefix; 865 if(c=='.') 866 cp[m-1] = 0; 867 outval(".",prefix-n,wp); 868 if(c=='.') 869 cp[m-1] = c; 870 if(wp->indent>0) 871 sfnputc(outfile,'\t',--wp->indent); 872 sfputc(outfile,')'); 873 } 874 return(--argv); 875 } 876 877 /* 878 * walk the virtual tree and print or delete name-value pairs 879 */ 880 static char *walk_tree(register Namval_t *np, Namval_t *xp, int flags) 881 { 882 static Sfio_t *out; 883 struct Walk walk; 884 Sfio_t *outfile; 885 int len, savtop = staktell(); 886 char *savptr = stakfreeze(0); 887 register struct argnod *ap=0; 888 struct argnod *arglist=0; 889 char *name,*cp, **argv; 890 char *subscript=0; 891 void *dir; 892 int n=0, noscope=(flags&NV_NOSCOPE); 893 Namarr_t *arp = nv_arrayptr(np); 894 Dt_t *save_tree = sh.var_tree; 895 Namval_t *mp=0; 896 Shell_t *shp = sh_getinterp(); 897 char *xpname = xp?stakcopy(nv_name(xp)):0; 898 if(xp) 899 { 900 shp->last_root = shp->prev_root; 901 shp->last_table = shp->prev_table; 902 } 903 if(shp->last_table) 904 shp->last_root = nv_dict(shp->last_table); 905 if(shp->last_root) 906 shp->var_tree = shp->last_root; 907 stakputs(nv_name(np)); 908 if(arp && !(arp->nelem&ARRAY_SCAN) && (subscript = nv_getsub(np))) 909 { 910 mp = nv_opensub(np); 911 stakputc('['); 912 stakputs(subscript); 913 stakputc(']'); 914 stakputc('.'); 915 } 916 else if(*stakptr(staktell()-1) == ']') 917 mp = np; 918 name = stakfreeze(1); 919 len = strlen(name); 920 shp->last_root = 0; 921 dir = nv_diropen(mp,name); 922 walk.root = shp->last_root?shp->last_root:shp->var_tree; 923 if(subscript) 924 name[strlen(name)-1] = 0; 925 while(cp = nv_dirnext(dir)) 926 { 927 if(cp[len]!='.') 928 continue; 929 if(xp) 930 { 931 Dt_t *dp = shp->var_tree; 932 Namval_t *nq, *mq; 933 if(strlen(cp)<=len) 934 continue; 935 nq = nv_open(cp,walk.root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL); 936 if(!nq && (flags&NV_MOVE)) 937 nq = nv_search(cp,walk.root,NV_NOADD); 938 stakseek(0); 939 stakputs(xpname); 940 stakputs(cp+len); 941 stakputc(0); 942 shp->var_tree = save_tree; 943 mq = nv_open(stakptr(0),save_tree,NV_VARNAME|NV_NOASSIGN|NV_NOFAIL); 944 shp->var_tree = dp; 945 if(nq && mq) 946 { 947 nv_clone(nq,mq,flags|NV_RAW); 948 if(flags&NV_MOVE) 949 nv_delete(nq,walk.root,0); 950 } 951 continue; 952 } 953 stakseek(ARGVAL); 954 stakputs(cp); 955 ap = (struct argnod*)stakfreeze(1); 956 ap->argflag = ARG_RAW; 957 ap->argchn.ap = arglist; 958 n++; 959 arglist = ap; 960 } 961 nv_dirclose(dir); 962 if(xp) 963 { 964 shp->var_tree = save_tree; 965 return((char*)0); 966 } 967 argv = (char**)stakalloc((n+1)*sizeof(char*)); 968 argv += n; 969 *argv = 0; 970 for(; ap; ap=ap->argchn.ap) 971 *--argv = ap->argval; 972 if(flags&1) 973 outfile = 0; 974 else if(!(outfile=out)) 975 outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); 976 else 977 sfseek(outfile,0L,SEEK_SET); 978 walk.out = outfile; 979 walk.indent = (flags&NV_EXPORT)?-1:0; 980 walk.nofollow = 0; 981 walk.noscope = noscope; 982 walk.array = 0; 983 walk.flags = flags; 984 genvalue(argv,name,0,&walk); 985 stakset(savptr,savtop); 986 shp->var_tree = save_tree; 987 if(!outfile) 988 return((char*)0); 989 sfputc(out,0); 990 return((char*)out->_data); 991 } 992 993 Namfun_t *nv_isvtree(Namval_t *np) 994 { 995 if(np) 996 return(nv_hasdisc(np,&treedisc)); 997 return(0); 998 } 999 1000 /* 1001 * get discipline for compound initializations 1002 */ 1003 char *nv_getvtree(register Namval_t *np, Namfun_t *fp) 1004 { 1005 int flags=0; 1006 for(; fp && fp->next; fp=fp->next) 1007 { 1008 if(fp->next->disc && (fp->next->disc->getnum || fp->next->disc->getval)) 1009 return(nv_getv(np,fp)); 1010 } 1011 if(nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW)) 1012 return(nv_getv(np,fp)); 1013 if(nv_isattr(np,NV_ARRAY) && !nv_type(np) && nv_arraychild(np,(Namval_t*)0,0)==np) 1014 return(nv_getv(np,fp)); 1015 if(flags = nv_isattr(np,NV_EXPORT)) 1016 nv_offattr(np,NV_EXPORT); 1017 return(walk_tree(np,(Namval_t*)0,flags)); 1018 } 1019 1020 /* 1021 * put discipline for compound initializations 1022 */ 1023 static void put_tree(register Namval_t *np, const char *val, int flags,Namfun_t *fp) 1024 { 1025 struct Namarray *ap; 1026 int nleft = 0; 1027 if(!val && !fp->next && nv_isattr(np,NV_NOFREE)) 1028 return; 1029 if(!nv_isattr(np,(NV_INTEGER|NV_BINARY))) 1030 { 1031 Shell_t *shp = sh_getinterp(); 1032 Namval_t *last_table = shp->last_table; 1033 Dt_t *last_root = shp->last_root; 1034 Namval_t *mp = val?nv_open(val,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL):0; 1035 if(mp && nv_isvtree(mp)) 1036 { 1037 shp->prev_table = shp->last_table; 1038 shp->prev_root = shp->last_root; 1039 shp->last_table = last_table; 1040 shp->last_root = last_root; 1041 if(!(flags&NV_APPEND)) 1042 walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1); 1043 nv_clone(mp,np,NV_COMVAR); 1044 return; 1045 } 1046 walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1); 1047 } 1048 nv_putv(np, val, flags,fp); 1049 if(val && nv_isattr(np,(NV_INTEGER|NV_BINARY))) 1050 return; 1051 if(ap= nv_arrayptr(np)) 1052 nleft = array_elem(ap); 1053 if(nleft==0) 1054 { 1055 fp = nv_stack(np,fp); 1056 if(fp = nv_stack(np,NIL(Namfun_t*))) 1057 free((void*)fp); 1058 } 1059 } 1060 1061 /* 1062 * Insert discipline to cause $x to print current tree 1063 */ 1064 void nv_setvtree(register Namval_t *np) 1065 { 1066 register Namfun_t *nfp; 1067 if(sh.subshell) 1068 sh_assignok(np,1); 1069 if(nv_hasdisc(np, &treedisc)) 1070 return; 1071 nfp = newof(NIL(void*),Namfun_t,1,0); 1072 nfp->disc = &treedisc; 1073 nv_stack(np, nfp); 1074 } 1075 1076