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