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