1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 34 struct nvdir 35 { 36 Dt_t *root; 37 Namval_t *hp; 38 Namval_t *table; 39 Namval_t *(*nextnode)(Namval_t*,Dt_t*,Namfun_t*); 40 Namfun_t *fun; 41 struct nvdir *prev; 42 int len; 43 int offset; 44 char data[1]; 45 }; 46 47 char *nv_getvtree(Namval_t*, Namfun_t *); 48 static void put_tree(Namval_t*, const char*, int,Namfun_t*); 49 50 static Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp) 51 { 52 register Namfun_t *fp=dp; 53 while(fp=fp->next) 54 { 55 if(fp->disc && fp->disc->createf) 56 { 57 if(np=(*fp->disc->createf)(np,name,flag,fp)) 58 dp->last = fp->last; 59 return(np); 60 } 61 } 62 return((flag&NV_NOADD)?0:np); 63 } 64 65 static const Namdisc_t treedisc = 66 { 67 0, 68 put_tree, 69 nv_getvtree, 70 0, 71 0, 72 create_tree 73 }; 74 75 static char *nextdot(const char *str) 76 { 77 register char *cp; 78 if(*str=='.') 79 str++; 80 if(*str =='[') 81 { 82 cp = nv_endsubscript((Namval_t*)0,(char*)str,0); 83 return(*cp=='.'?cp:0); 84 } 85 else 86 return(strchr(str,'.')); 87 } 88 89 static Namfun_t *nextdisc(Namval_t *np) 90 { 91 register Namfun_t *fp; 92 if(nv_isref(np)) 93 return(0); 94 for(fp=np->nvfun;fp;fp=fp->next) 95 { 96 if(fp && fp->disc && fp->disc->nextf) 97 return(fp); 98 } 99 return(0); 100 } 101 102 void *nv_diropen(const char *name) 103 { 104 char *next,*last; 105 int c,len=strlen(name); 106 struct nvdir *save, *dp = new_of(struct nvdir,len); 107 Namval_t *np, fake; 108 Namfun_t *nfp; 109 if(!dp) 110 return(0); 111 memset((void*)dp, 0, sizeof(*dp)); 112 last=dp->data; 113 if(name[len-1]=='*' || name[len-1]=='@') 114 len -= 1; 115 name = memcpy(last,name,len); 116 last[len] = 0; 117 dp->len = len; 118 dp->root = sh.var_tree; 119 dp->table = sh.last_table; 120 if(*name) 121 { 122 fake.nvname = (char*)name; 123 dp->hp = (Namval_t*)dtprev(dp->root,&fake); 124 dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); 125 } 126 else 127 dp->hp = (Namval_t*)dtfirst(dp->root); 128 while(next= nextdot(last)) 129 { 130 c = *next; 131 *next = 0; 132 np = nv_search(last,dp->root,0); 133 *next = c; 134 if(np && ((nfp=nextdisc(np)) || nv_istable(np))) 135 { 136 if(!(save = new_of(struct nvdir,0))) 137 return(0); 138 *save = *dp; 139 dp->prev = save; 140 if(nv_istable(np)) 141 dp->root = nv_dict(np); 142 else 143 dp->root = (Dt_t*)dp; 144 dp->offset = last-(char*)name; 145 if(dp->offset<len) 146 dp->len = len-dp->offset; 147 else 148 dp->len = 0; 149 if(nfp) 150 { 151 dp->nextnode = nfp->disc->nextf; 152 dp->table = np; 153 dp->fun = nfp; 154 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); 155 } 156 else 157 dp->nextnode = 0; 158 } 159 else 160 break; 161 last = next+1; 162 } 163 return((void*)dp); 164 } 165 166 167 static Namval_t *nextnode(struct nvdir *dp) 168 { 169 if(dp->nextnode) 170 return((*dp->nextnode)(dp->hp,dp->root,dp->fun)); 171 if(dp->len && memcmp(dp->data, dp->hp->nvname, dp->len)) 172 return(0); 173 return((Namval_t*)dtnext(dp->root,dp->hp)); 174 } 175 176 char *nv_dirnext(void *dir) 177 { 178 register struct nvdir *save, *dp = (struct nvdir*)dir; 179 register Namval_t *np, *last_table; 180 register char *cp; 181 Namfun_t *nfp; 182 while(1) 183 { 184 while(np=dp->hp) 185 { 186 dp->hp = nextnode(dp); 187 if(nv_isnull(np)) 188 continue; 189 last_table = sh.last_table; 190 sh.last_table = dp->table; 191 cp = nv_name(np); 192 sh.last_table = last_table; 193 if(!dp->len || memcmp(cp+dp->offset,dp->data,dp->len)==0) 194 { 195 if((nfp=nextdisc(np)) || nv_istable(np)) 196 { 197 Dt_t *root; 198 if(nv_istable(np)) 199 root = nv_dict(np); 200 else 201 root = (Dt_t*)dp; 202 /* check for recursive walk */ 203 for(save=dp; save; save=save->prev) 204 { 205 if(save->root==root) 206 break; 207 } 208 if(save) 209 continue; 210 if(!(save = new_of(struct nvdir,0))) 211 return(0); 212 *save = *dp; 213 dp->prev = save; 214 dp->root = root; 215 dp->len = 0; 216 if(nfp && np->nvfun) 217 { 218 dp->nextnode = nfp->disc->nextf; 219 dp->table = np; 220 dp->fun = nfp; 221 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); 222 } 223 else 224 dp->nextnode = 0; 225 } 226 return(cp); 227 } 228 } 229 if(!(save=dp->prev)) 230 break; 231 #if 0 232 sh.last_table = dp->table; 233 #endif 234 *dp = *save; 235 free((void*)save); 236 } 237 return(0); 238 } 239 240 void nv_dirclose(void *dir) 241 { 242 struct nvdir *dp = (struct nvdir*)dir; 243 if(dp->prev) 244 nv_dirclose((void*)dp->prev); 245 free(dir); 246 } 247 248 static void outtype(Namval_t *np, Namfun_t *fp, Sfio_t* out, const char *prefix) 249 { 250 char *type=0; 251 Namval_t *tp = fp->type; 252 if(!tp && fp->disc && fp->disc->typef) 253 tp = (*fp->disc->typef)(np,fp); 254 for(fp=fp->next;fp;fp=fp->next) 255 { 256 if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp))) 257 { 258 outtype(np,fp,out,prefix); 259 break; 260 } 261 } 262 if(prefix && *prefix=='t') 263 type = "-T"; 264 else if(!prefix) 265 type = "type"; 266 if(type) 267 sfprintf(out,"%s %s ",type,tp->nvname); 268 } 269 270 /* 271 * print the attributes of name value pair give by <np> 272 */ 273 void nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname) 274 { 275 register const Shtable_t *tp; 276 register char *cp; 277 register unsigned val; 278 register unsigned mask; 279 register unsigned attr; 280 Namfun_t *fp=0; 281 for(fp=np->nvfun;fp;fp=fp->next) 282 { 283 if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp))) 284 break; 285 } 286 #if 0 287 if(!fp && !nv_isattr(np,~NV_ARRAY)) 288 { 289 if(!nv_isattr(np,NV_ARRAY) || nv_aindex(np)>=0) 290 return; 291 } 292 #else 293 if(!fp && !nv_isattr(np,~NV_MINIMAL)) 294 return; 295 #endif 296 297 if ((attr=nv_isattr(np,~NV_NOFREE)) || fp) 298 { 299 if((attr&NV_NOPRINT)==NV_NOPRINT) 300 attr &= ~NV_NOPRINT; 301 if(!attr && !fp) 302 return; 303 if(prefix) 304 sfputr(out,prefix,' '); 305 for(tp = shtab_attributes; *tp->sh_name;tp++) 306 { 307 val = tp->sh_number; 308 mask = val; 309 if(fp && (val&NV_INTEGER)) 310 break; 311 /* 312 * the following test is needed to prevent variables 313 * with E attribute from being given the F 314 * attribute as well 315 */ 316 if(val==(NV_INTEGER|NV_DOUBLE) && (attr&NV_EXPNOTE)) 317 continue; 318 if(val&NV_INTEGER) 319 mask |= NV_DOUBLE; 320 else if(val&NV_HOST) 321 mask = NV_HOST; 322 if((attr&mask)==val) 323 { 324 if(val==NV_ARRAY) 325 { 326 Namarr_t *ap = nv_arrayptr(np); 327 if(array_assoc(ap)) 328 { 329 if(tp->sh_name[1]!='A') 330 continue; 331 } 332 else if(tp->sh_name[1]=='A') 333 continue; 334 #if 0 335 cp = "associative"; 336 else 337 cp = "indexed"; 338 if(!prefix) 339 sfputr(out,cp,' '); 340 else if(*cp=='i') 341 tp++; 342 #endif 343 } 344 if(prefix) 345 { 346 if(*tp->sh_name=='-') 347 sfprintf(out,"%.2s ",tp->sh_name); 348 } 349 else 350 sfputr(out,tp->sh_name+2,' '); 351 if ((val&(NV_LJUST|NV_RJUST|NV_ZFILL)) && !(val&NV_INTEGER) && val!=NV_HOST) 352 sfprintf(out,"%d ",nv_size(np)); 353 } 354 if(val==NV_INTEGER && nv_isattr(np,NV_INTEGER)) 355 { 356 if(nv_size(np) != 10) 357 { 358 if(nv_isattr(np, NV_DOUBLE)) 359 cp = "precision"; 360 else 361 cp = "base"; 362 if(!prefix) 363 sfputr(out,cp,' '); 364 sfprintf(out,"%d ",nv_size(np)); 365 } 366 break; 367 } 368 } 369 if(fp) 370 outtype(np,fp,out,prefix); 371 if(noname) 372 return; 373 sfputr(out,nv_name(np),'\n'); 374 } 375 } 376 377 struct Walk 378 { 379 Sfio_t *out; 380 Dt_t *root; 381 int noscope; 382 int indent; 383 }; 384 385 static void outval(char *name, const char *vname, struct Walk *wp) 386 { 387 register Namval_t *np, *nq; 388 register Namfun_t *fp; 389 int isarray=0, associative=0, special=0; 390 if(!(np=nv_open(vname,wp->root,NV_ARRAY|NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope))) 391 return; 392 if(nv_isarray(np) && *name=='.') 393 special = 1; 394 if(!special && (fp=nv_hasdisc(np,&treedisc))) 395 { 396 if(!wp->out) 397 { 398 fp = nv_stack(np,fp); 399 if(fp = nv_stack(np,NIL(Namfun_t*))) 400 free((void*)fp); 401 np->nvfun = 0; 402 } 403 return; 404 } 405 if(nv_isnull(np)) 406 return; 407 if(special || nv_isarray(np)) 408 { 409 isarray=1; 410 associative= nv_aindex(np)<0; 411 if(array_elem(nv_arrayptr(np))==0) 412 isarray=2; 413 else 414 nq = nv_putsub(np,NIL(char*),ARRAY_SCAN|(wp->out?ARRAY_NOCHILD:0)); 415 } 416 if(!wp->out) 417 { 418 _nv_unset(np,NV_RDONLY); 419 nv_close(np); 420 return; 421 } 422 if(isarray==1 && !nq) 423 return; 424 if(special) 425 { 426 associative = 1; 427 sfnputc(wp->out,'\t',wp->indent); 428 } 429 else 430 { 431 sfnputc(wp->out,'\t',wp->indent); 432 nv_attribute(np,wp->out,"typeset",'='); 433 nv_outname(wp->out,name,-1); 434 sfputc(wp->out,(isarray==2?'\n':'=')); 435 if(isarray) 436 { 437 if(isarray==2) 438 return; 439 sfwrite(wp->out,"(\n",2); 440 sfnputc(wp->out,'\t',++wp->indent); 441 } 442 } 443 while(1) 444 { 445 char *fmtq,*ep; 446 if(isarray && associative) 447 { 448 if(!(fmtq = nv_getsub(np))) 449 break; 450 sfprintf(wp->out,"[%s]",sh_fmtq(fmtq)); 451 sfputc(wp->out,'='); 452 } 453 if(!(fmtq = sh_fmtq(nv_getval(np)))) 454 fmtq = ""; 455 else if(!associative && (ep=strchr(fmtq,'='))) 456 { 457 char *qp = strchr(fmtq,'\''); 458 if(!qp || qp>ep) 459 { 460 sfwrite(wp->out,fmtq,ep-fmtq); 461 sfputc(wp->out,'\\'); 462 fmtq = ep; 463 } 464 } 465 if(*name=='[' && !isarray) 466 sfprintf(wp->out,"(%s)\n",fmtq); 467 else 468 sfputr(wp->out,fmtq,'\n'); 469 if(!nv_nextsub(np)) 470 break; 471 sfnputc(wp->out,'\t',wp->indent); 472 } 473 if(isarray && !special) 474 { 475 sfnputc(wp->out,'\t',--wp->indent); 476 sfwrite(wp->out,")\n",2); 477 } 478 } 479 480 /* 481 * format initialization list given a list of assignments <argp> 482 */ 483 static char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp) 484 { 485 register char *cp,*nextcp,*arg; 486 register int m,r; 487 register Sfio_t *outfile = wp->out; 488 if(n==0) 489 m = strlen(prefix); 490 else if(cp=nextdot(prefix)) 491 m = cp-prefix; 492 else 493 m = strlen(prefix)-1; 494 m++; 495 if(outfile) 496 { 497 sfwrite(outfile,"(\n",2); 498 wp->indent++; 499 } 500 for(; arg= *argv; argv++) 501 { 502 cp = arg + n; 503 if(n==0 && cp[m-1]!='.') 504 continue; 505 if(n && cp[m-1]==0) 506 break; 507 if(n==0 || strncmp(arg,prefix-n,m+n)==0) 508 { 509 cp +=m; 510 r = 0; 511 if(*cp=='.') 512 cp++,r++; 513 if(nextcp=nextdot(cp)) 514 { 515 if(outfile) 516 { 517 sfnputc(outfile,'\t',wp->indent); 518 nv_outname(outfile,cp,nextcp-cp); 519 sfputc(outfile,'='); 520 } 521 argv = genvalue(argv,cp,n+m+r,wp); 522 if(outfile) 523 sfputc(outfile,'\n'); 524 if(*argv) 525 continue; 526 break; 527 } 528 else if(outfile && argv[1] && memcmp(arg,argv[1],r=strlen(arg))==0 && argv[1][r]=='[') 529 { 530 Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope); 531 if(!np) 532 continue; 533 sfnputc(outfile,'\t',wp->indent); 534 nv_attribute(np,outfile,"typeset",1); 535 nv_close(np); 536 sfputr(outfile,arg+m+(n?n+1:0),'='); 537 argv = genvalue(++argv,cp,cp-arg ,wp); 538 sfputc(outfile,'\n'); 539 } 540 else if(outfile && *cp=='[') 541 { 542 sfnputc(outfile,'\t',wp->indent); 543 sfputr(outfile,cp,'='); 544 argv = genvalue(++argv,cp,cp-arg ,wp); 545 sfputc(outfile,'\n'); 546 } 547 else 548 outval(cp,arg,wp); 549 } 550 else 551 break; 552 } 553 if(outfile) 554 { 555 int c = prefix[m-1]; 556 cp = (char*)prefix; 557 if(c=='.') 558 cp[m-1] = 0; 559 outval(".",prefix-n,wp); 560 if(c=='.') 561 cp[m-1] = c; 562 sfnputc(outfile,'\t',wp->indent-1); 563 sfputc(outfile,')'); 564 } 565 return(--argv); 566 } 567 568 /* 569 * walk the virtual tree and print or delete name-value pairs 570 */ 571 static char *walk_tree(register Namval_t *np, int dlete) 572 { 573 static Sfio_t *out; 574 struct Walk walk; 575 Sfio_t *outfile; 576 int savtop = staktell(); 577 char *savptr = stakfreeze(0); 578 register struct argnod *ap=0; 579 struct argnod *arglist=0; 580 char *name,*cp, **argv; 581 char *subscript=0; 582 void *dir; 583 int n=0, noscope=(dlete&NV_NOSCOPE); 584 stakputs(nv_name(np)); 585 if(subscript = nv_getsub(np)) 586 { 587 stakputc('['); 588 stakputs(subscript); 589 stakputc(']'); 590 stakputc('.'); 591 } 592 name = stakfreeze(1); 593 dir = nv_diropen(name); 594 if(subscript) 595 name[strlen(name)-1] = 0; 596 while(cp = nv_dirnext(dir)) 597 { 598 stakseek(ARGVAL); 599 stakputs(cp); 600 ap = (struct argnod*)stakfreeze(1); 601 ap->argflag = ARG_RAW; 602 ap->argchn.ap = arglist; 603 n++; 604 arglist = ap; 605 } 606 argv = (char**)stakalloc((n+1)*sizeof(char*)); 607 argv += n; 608 *argv = 0; 609 for(; ap; ap=ap->argchn.ap) 610 *--argv = ap->argval; 611 nv_dirclose(dir); 612 if(dlete&1) 613 outfile = 0; 614 else if(!(outfile=out)) 615 outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); 616 else 617 sfseek(outfile,0L,SEEK_SET); 618 walk.out = outfile; 619 walk.root = sh.last_root; 620 walk.indent = 0; 621 walk.noscope = noscope; 622 genvalue(argv,name,0,&walk); 623 stakset(savptr,savtop); 624 if(!outfile) 625 return((char*)0); 626 sfputc(out,0); 627 return((char*)out->_data); 628 } 629 630 /* 631 * get discipline for compound initializations 632 */ 633 char *nv_getvtree(register Namval_t *np, Namfun_t *fp) 634 { 635 NOT_USED(fp); 636 if(nv_isattr(np,NV_BINARY) && nv_isattr(np,NV_RAW)) 637 return(nv_getv(np,fp)); 638 if(nv_isattr(np,NV_ARRAY) && nv_arraychild(np,(Namval_t*)0,0)==np) 639 return(nv_getv(np,fp)); 640 return(walk_tree(np,0)); 641 } 642 643 /* 644 * put discipline for compound initializations 645 */ 646 static void put_tree(register Namval_t *np, const char *val, int flags,Namfun_t *fp) 647 { 648 struct Namarray *ap; 649 int nleft = 0; 650 if(!nv_isattr(np,NV_INTEGER)) 651 walk_tree(np,(flags&NV_NOSCOPE)|1); 652 nv_putv(np, val, flags,fp); 653 if(nv_isattr(np,NV_INTEGER)) 654 return; 655 if(ap= nv_arrayptr(np)) 656 nleft = array_elem(ap); 657 if(nleft==0) 658 { 659 fp = nv_stack(np,fp); 660 if(fp = nv_stack(np,NIL(Namfun_t*))) 661 { 662 free((void*)fp); 663 } 664 } 665 } 666 667 /* 668 * Insert discipline to cause $x to print current tree 669 */ 670 void nv_setvtree(register Namval_t *np) 671 { 672 register Namfun_t *nfp; 673 if(nv_hasdisc(np, &treedisc)) 674 return; 675 nfp = newof(NIL(void*),Namfun_t,1,0); 676 nfp->disc = &treedisc; 677 nv_stack(np, nfp); 678 } 679 680