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
read_tree(Namval_t * np,Sfio_t * iop,int n,Namfun_t * dp)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
create_tree(Namval_t * np,const char * name,int flag,Namfun_t * dp)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
clone_tree(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)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
nextdot(const char * str)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
nextdisc(Namval_t * np)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
nv_diropen(Namval_t * np,const char * name)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
nextnode(struct nvdir * dp)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
nv_dirnext(void * dir)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
nv_dirclose(void * dir)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
outtype(Namval_t * np,Namfun_t * fp,Sfio_t * out,const char * prefix)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 */
nv_attribute(register Namval_t * np,Sfio_t * out,char * prefix,int noname)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
nv_outnode(Namval_t * np,Sfio_t * out,int indent,int special)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
outval(char * name,const char * vname,struct Walk * wp)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 */
genvalue(char ** argv,const char * prefix,int n,struct Walk * wp)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 */
walk_tree(register Namval_t * np,Namval_t * xp,int flags)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
nv_isvtree(Namval_t * np)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 */
nv_getvtree(register Namval_t * np,Namfun_t * fp)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 */
put_tree(register Namval_t * np,const char * val,int flags,Namfun_t * fp)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 */
nv_setvtree(register Namval_t * np)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