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