1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2014 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 <dgkorn@gmail.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 <ast_float.h>
32 #include "name.h"
33 #include "argnod.h"
34 #include "lexstates.h"
35 #include "variables.h"
36
37 struct nvdir
38 {
39 Dt_t *root;
40 Namval_t *hp;
41 Namval_t *table;
42 Namval_t *otable;
43 Namval_t *(*nextnode)(Namval_t*,Dt_t*,Namfun_t*);
44 Namfun_t *fun;
45 struct nvdir *prev;
46 size_t len;
47 char *data;
48 };
49
50 static int Indent;
51 char *nv_getvtree(Namval_t*, Namfun_t *);
52 static void put_tree(Namval_t*, const char*, int,Namfun_t*);
53 static char *walk_tree(Namval_t*, Namval_t*, int);
54
read_tree(Namval_t * np,Sfio_t * in,int n,Namfun_t * dp)55 static int read_tree(Namval_t* np, Sfio_t *in, int n, Namfun_t *dp)
56 {
57 Shell_t *shp = sh_ptr(np);
58 Sfio_t *sp, *iop;
59 char *cp;
60 int c;
61 typedef int (*Shread_t)(Shell_t*, Sfio_t*, Sfio_t*);
62 Shread_t fun;
63 fun = *(void**)(dp+1);
64 if(n>=0)
65 return(-1);
66 if(fun)
67 {
68 iop = sftmp(SF_BUFSIZE*sizeof(char*));
69 sfputr(iop,nv_name(np),'=');
70 c = (*fun)(shp,in,iop);
71 sfseek(iop, (Sfoff_t)0, SEEK_SET);
72 goto done;
73 }
74 iop = in;
75 while((c = sfgetc(iop)) && isblank(c));
76 sfungetc(iop,c);
77 sfprintf(shp->strbuf,"%s=%c",nv_name(np),0);
78 cp = sfstruse(shp->strbuf);
79 sp = sfopen((Sfio_t*)0,cp,"s");
80 sfstack(iop,sp);
81 done:
82 c=sh_eval(shp,iop,SH_READEVAL);
83 if(iop != in)
84 sfclose(in);
85 return(c);
86 }
87
create_tree(Namval_t * np,const char * name,int flag,Namfun_t * dp)88 static Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp)
89 {
90 register Namfun_t *fp=dp;
91 fp->dsize = 0;
92 while(fp=fp->next)
93 {
94 if(fp->disc && fp->disc->createf)
95 {
96 if(np=(*fp->disc->createf)(np,name,flag,fp))
97 dp->last = fp->last;
98 return(np);
99 }
100 }
101 return((flag&NV_NOADD)?0:np);
102 }
103
clone_tree(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)104 static Namfun_t *clone_tree(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp){
105 Namfun_t *dp;
106 if ((flags&NV_MOVE) && nv_type(np))
107 return(fp);
108 dp = nv_clone_disc(fp,flags);
109 if((flags&NV_COMVAR) && !(flags&NV_RAW))
110 {
111 walk_tree(np,mp,flags);
112 if((flags&NV_MOVE) && !(fp->nofree&1))
113 free((void*)fp);
114 }
115 return(dp);
116 }
117
118 static const Namdisc_t treedisc =
119 {
120 0,
121 put_tree,
122 nv_getvtree,
123 0,
124 0,
125 create_tree,
126 clone_tree
127 ,0,0,0,
128 read_tree
129 };
130
nextdot(const char * str,void * context)131 static char *nextdot(const char *str, void* context)
132 {
133 register char *cp;
134 register int c;
135 if(*str=='.')
136 str++;
137 for(cp=(char*)str;c= *cp; cp++)
138 {
139 if(c=='[')
140 {
141 cp = nv_endsubscript((Namval_t*)0,(char*)cp,0,context);
142 return(*cp=='.'?cp:0);
143 }
144 if(c=='.')
145 return(cp);
146 }
147 return(0);
148 }
149
nextdisc(Namval_t * np)150 static Namfun_t *nextdisc(Namval_t *np)
151 {
152 register Namfun_t *fp;
153 if(nv_isref(np))
154 return(0);
155 for(fp=np->nvfun;fp;fp=fp->next)
156 {
157 if(fp && fp->disc && fp->disc->nextf)
158 return(fp);
159 }
160 return(0);
161 }
162
nv_diropen(Namval_t * np,const char * name,void * context)163 void *nv_diropen(Namval_t *np,const char *name, void *context)
164 {
165 Shell_t *shp = (Shell_t*)context;
166 const char *last;
167 char *next;
168 size_t c,len=strlen(name);
169 struct nvdir *save, *dp = new_of(struct nvdir,len+1);
170 Namval_t *nq=0,fake;
171 Namfun_t *nfp=0;
172 if(!dp)
173 return(0);
174 memset((void*)dp, 0, sizeof(*dp));
175 dp->data = (char*)(dp+1);
176 if(name[len-1]=='*' || name[len-1]=='@')
177 len -= 1;
178 name = memcpy(dp->data,name,len);
179 dp->data[len] = 0;
180 dp->len = len;
181 dp->root = shp->last_root?shp->last_root:shp->var_tree;
182
183 #if 1
184 last = &name[len];
185 if(!np)
186 np = nv_search(name,dp->root,0);
187 if(!np || !nv_isvtree(np)) while(1)
188 {
189 dp->table = shp->last_table;
190 shp->last_table = 0;
191 if(*(last=(char*)name)==0)
192 break;
193 if(!(next=nextdot(last,(void*)shp)))
194 break;
195 *next = 0;
196 np = nv_open(name, dp->root, NV_NOFAIL);
197 *next = '.';
198 if(!np || !nv_istable(np))
199 break;
200 dp->root = nv_dict(np);
201 name = next+1;
202 }
203 #else
204 dp->table = shp->last_table;
205 shp->last_table = 0;
206 last = dp->data;
207 #endif
208 if(*name)
209 {
210 fake.nvname = (char*)name;
211 if(dp->hp = (Namval_t*)dtprev(dp->root,&fake))
212 {
213 char *cp = nv_name(dp->hp);
214 c = strlen(cp);
215 if(strncmp(name,cp,c) || name[c]!='[')
216 dp->hp = (Namval_t*)dtnext(dp->root,dp->hp);
217 else
218 {
219 np = dp->hp;
220 last = 0;
221 }
222 }
223 else
224 dp->hp = (Namval_t*)dtfirst(dp->root);
225 }
226 else
227 dp->hp = (Namval_t*)dtfirst(dp->root);
228 while(1)
229 {
230 if(!last)
231 next = 0;
232 else if(next= nextdot(last,(void*)shp))
233 {
234 c = *next;
235 *next = 0;
236 }
237 if(!np)
238 {
239 if(nfp && nfp->disc && nfp->disc->createf)
240 {
241 np = (*nfp->disc->createf)(nq,last,0,nfp);
242 if(*nfp->last == '[')
243 {
244 nv_endsubscript(np,nfp->last,NV_NOADD,np->nvshell);
245 if(nq = nv_opensub(np))
246 np = nq;
247 }
248 }
249 else
250 np = nv_search(last,dp->root,0);
251 }
252 if(next)
253 *next = c;
254 if(np==dp->hp && !next)
255 dp->hp = (Namval_t*)dtnext(dp->root,dp->hp);
256 if(np && ((nfp=nextdisc(np)) || nv_istable(np)))
257 {
258 if(!(save = new_of(struct nvdir,0)))
259 return(0);
260 *save = *dp;
261 dp->prev = save;
262 if(nv_istable(np))
263 dp->root = nv_dict(np);
264 else
265 {
266 Namarr_t *ap;
267 Namval_t *mp = nv_open(name,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOFAIL);
268 int sub;
269 if(mp && (ap=nv_arrayptr(mp)) && !ap->fun && !ap->flags && (sub=nv_aindex(mp))>=0)
270 nv_putsub(np,NULL,sub,0);
271 dp->root = (Dt_t*)np;
272 }
273 if(nfp)
274 {
275 dp->nextnode = nfp->disc->nextf;
276 dp->table = np;
277 dp->otable = shp->last_table;
278 dp->fun = nfp;
279 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
280 }
281 else
282 dp->nextnode = 0;
283 }
284 else
285 break;
286 if(!next || next[1]==0)
287 break;
288 last = next+1;
289 nq = np;
290 np = 0;
291 }
292 return((void*)dp);
293 }
294
295
nextnode(struct nvdir * dp)296 static Namval_t *nextnode(struct nvdir *dp)
297 {
298 if(dp->nextnode)
299 return((*dp->nextnode)(dp->hp,dp->root,dp->fun));
300 if(dp->len && strncmp(dp->data, dp->hp->nvname, dp->len))
301 return(0);
302 return((Namval_t*)dtnext(dp->root,dp->hp));
303 }
304
nv_dirnext(void * dir)305 char *nv_dirnext(void *dir)
306 {
307 Shell_t *shp = 0;
308 register struct nvdir *save, *dp = (struct nvdir*)dir;
309 register Namval_t *np, *last_table;
310 register char *cp;
311 Namfun_t *nfp;
312 Namval_t *nq;
313 Namarr_t *ap = dp->table?nv_arrayptr(dp->table):0;
314 int dot=-1,xdot,flags;
315 if(ap && !ap->fun && nv_type(dp->table) && (ap->flags&ARRAY_SCAN))
316 {
317 dot = nv_aindex(dp->table);
318 flags = ap->flags;
319 }
320 while(1)
321 {
322 if(!shp && dp->hp)
323 shp = sh_ptr(dp->hp);
324 while(np=dp->hp)
325 {
326 #if 0
327 char *sptr;
328 #endif
329 if(ap=nv_arrayptr(np))
330 nv_putsub(np,(char*)0, 0,ARRAY_UNDEF);
331 dp->hp = nextnode(dp);
332 if(nv_isnull(np) && !nv_isarray(np) && !nv_isattr(np,NV_INTEGER))
333 continue;
334 last_table = shp->last_table;
335 #if 0
336 if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL))
337 {
338 sptr = dp->table->nvenv;
339 dp->table->nvenv = (char*)dp->otable;
340 }
341 #endif
342 shp->last_table = dp->table;
343 if(!dp->table)
344 dot = -1;
345 if(dot>=0)
346 {
347 xdot = nv_aindex(dp->table);
348 nv_putsub(dp->table,(char*)0,dot,flags);
349 }
350 cp = nv_name(np);
351 if(dot>=0)
352 nv_putsub(dp->table,(char*)0,xdot,xdot<dot?0:flags);
353
354 #if 0
355 if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL))
356 dp->table->nvenv = sptr;
357 #endif
358 if(dp->nextnode && !dp->hp && (nq = (Namval_t*)dp->table))
359 {
360 Namarr_t *aq = nv_arrayptr(nq);
361 if(aq && (aq->flags&ARRAY_SCAN) && nv_nextsub(nq))
362 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,dp->fun);
363 }
364 shp->last_table = last_table;
365 if(!dp->len || strncmp(cp,dp->data,dp->len)==0)
366 {
367 if((nfp=nextdisc(np)) && (nfp->disc->getval||nfp->disc->getnum) && nv_isvtree(np) && strcmp(cp,dp->data))
368 nfp = 0;
369 if(nfp || nv_istable(np))
370 {
371 Dt_t *root;
372 size_t len;
373 if(nv_istable(np))
374 root = nv_dict(np);
375 else
376 root = (Dt_t*)np;
377 /* check for recursive walk */
378 for(save=dp; save; save=save->prev)
379 {
380 if(save->root==root)
381 break;
382 }
383 if(save)
384 return(cp);
385 len = strlen(cp);
386 if(!(save = new_of(struct nvdir,len+1)))
387 return(0);
388 *save = *dp;
389 dp->prev = save;
390 dp->root = root;
391 dp->len = len-1;
392 dp->data = (char*)(save+1);
393 memcpy(dp->data,cp,len+1);
394 if(nfp && np->nvfun)
395 {
396 #if 0
397 Namarr_t *ap = nv_arrayptr(np);
398 if(ap && (ap->flags&ARRAY_UNDEF))
399 nv_putsub(np,(char*)0,0,ARRAY_SCAN);
400 #endif
401 dp->nextnode = nfp->disc->nextf;
402 dp->otable = dp->table;
403 dp->table = np;
404 dp->fun = nfp;
405 dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
406 }
407 else
408 dp->nextnode = 0;
409 }
410 return(cp);
411 }
412 }
413 if(!(save=dp->prev))
414 break;
415 *dp = *save;
416 free((void*)save);
417 }
418 return(0);
419 }
420
nv_dirclose(void * dir)421 void nv_dirclose(void *dir)
422 {
423 struct nvdir *dp = (struct nvdir*)dir;
424 if(dp->prev)
425 nv_dirclose((void*)dp->prev);
426 free(dir);
427 }
428
outtype(Namval_t * np,Namfun_t * fp,Sfio_t * out,const char * prefix)429 static void outtype(Namval_t *np, Namfun_t *fp, Sfio_t* out, const char *prefix)
430 {
431 char *type=0;
432 Namval_t *tp = fp->type;
433 if(!tp && fp->disc && fp->disc->typef)
434 tp = (*fp->disc->typef)(np,fp);
435 for(fp=fp->next;fp;fp=fp->next)
436 {
437 if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp)))
438 {
439 outtype(np,fp,out,prefix);
440 break;
441 }
442 }
443 if(prefix && *prefix=='t')
444 type = "-T";
445 else if(!prefix)
446 type = "type";
447 if(type)
448 {
449 char *cp=tp->nvname;
450 if(cp=strrchr(cp,'.'))
451 cp++;
452 else
453 cp = tp->nvname;
454 sfprintf(out,"%s %s ",type,cp);
455 }
456 }
457
458 /*
459 * print the attributes of name value pair give by <np>
460 */
nv_attribute(register Namval_t * np,Sfio_t * out,char * prefix,int noname)461 void nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname)
462 {
463 register const Shtable_t *tp;
464 register char *cp;
465 register unsigned val,mask,attr;
466 char *ip=0;
467 Namfun_t *fp=0;
468 Namval_t *typep=0;
469 #if SHOPT_FIXEDARRAY
470 int fixed=0;
471 #endif /* SHOPT_FIXEDARRAY */
472 for(fp=np->nvfun;fp;fp=fp->next)
473 {
474 if((typep=fp->type) || (fp->disc && fp->disc->typef && (typep=(*fp->disc->typef)(np,fp))))
475 break;
476 }
477 if(np==typep)
478 {
479 fp = 0;
480 typep = 0;
481 }
482 if(!fp && !nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)))
483 {
484 if(prefix && *prefix)
485 {
486 if(nv_isvtree(np))
487 sfprintf(out,"%s -C ",prefix);
488 else if((!np->nvalue.cp||np->nvalue.cp==Empty) && nv_isattr(np,~NV_NOFREE)==NV_MINIMAL && strcmp(np->nvname,"_"))
489 sfputr(out,prefix,' ');
490 }
491 return;
492 }
493
494 if ((attr=nv_isattr(np,~NV_NOFREE)) || fp)
495 {
496 if((attr&(NV_NOPRINT|NV_INTEGER))==NV_NOPRINT)
497 attr &= ~NV_NOPRINT;
498 if(!attr && !fp)
499 return;
500 if(fp)
501 {
502 prefix = Empty;
503 attr &= NV_RDONLY|NV_ARRAY;
504 if(nv_isattr(np,NV_REF|NV_TAGGED)==(NV_REF|NV_TAGGED))
505 attr |= (NV_REF|NV_TAGGED);
506 if(typep)
507 {
508 cp = typep->nvname;
509 if(cp = strrchr(cp,'.'))
510 cp++;
511 else
512 cp = typep->nvname;
513 sfputr(out,cp,' ');
514 fp = 0;
515 }
516 }
517 else if(prefix && *prefix)
518 sfputr(out,prefix,' ');
519 for(tp = shtab_attributes; *tp->sh_name;tp++)
520 {
521 val = tp->sh_number;
522 mask = val;
523 if(fp && (val&NV_INTEGER))
524 break;
525 /*
526 * the following test is needed to prevent variables
527 * with E attribute from being given the F
528 * attribute as well
529 */
530 if(val==NV_DOUBLE && (attr&(NV_EXPNOTE|NV_HEXFLOAT)))
531 continue;
532 if(val&NV_INTEGER)
533 mask |= NV_DOUBLE;
534 else if(val&NV_HOST)
535 mask = NV_HOST;
536 if((attr&mask)==val)
537 {
538 if(val==NV_ARRAY)
539 {
540 Namarr_t *ap = nv_arrayptr(np);
541 char **xp=0;
542 if(ap && array_assoc(ap))
543 {
544 if(tp->sh_name[1]!='A')
545 continue;
546 }
547 else if(tp->sh_name[1]=='A')
548 continue;
549 if((ap && (ap->flags&ARRAY_TREE)) || (!ap && nv_isattr(np,NV_NOFREE)))
550 {
551 if(prefix && *prefix)
552 sfwrite(out,"-C ",3);
553 }
554 #if SHOPT_FIXEDARRAY
555 if(ap && ap->fixed)
556 fixed++;
557 else
558 #endif /* SHOPT_FIXEDARRAY */
559 if(ap && !array_assoc(ap) && (xp=(char**)(ap+1)) && *xp)
560 ip = nv_namptr(*xp,0)->nvname;
561 }
562 if(val==NV_UTOL || val==NV_LTOU)
563 {
564 if((cp = (char*)nv_mapchar(np,0)) && strcmp(cp,tp->sh_name+2))
565 {
566 sfprintf(out,"-M %s ",cp);
567 continue;
568 }
569 }
570 if(prefix)
571 {
572 if(*tp->sh_name=='-')
573 sfprintf(out,"%.2s ",tp->sh_name);
574 if(ip)
575 {
576 sfprintf(out,"[%s] ",ip);
577 ip = 0;
578 }
579 }
580 else
581 sfputr(out,tp->sh_name+2,' ');
582 if ((val&(NV_LJUST|NV_RJUST|NV_ZFILL)) && !(val&NV_INTEGER) && val!=NV_HOST)
583 sfprintf(out,"%d ",nv_size(np));
584 if(val==(NV_REF|NV_TAGGED))
585 attr &= ~(NV_REF|NV_TAGGED);
586 }
587 if(val==NV_INTEGER && nv_isattr(np,NV_INTEGER))
588 {
589 int size=10;
590 if(nv_isattr(np,NV_DOUBLE|NV_EXPNOTE)==(NV_DOUBLE|NV_EXPNOTE))
591 {
592 size = DBL_DIG;
593 if(nv_isattr(np,NV_LONG))
594 size = LDBL_DIG;
595 else if(nv_isattr(np,NV_SHORT))
596 size = FLT_DIG;
597 size -= 2;
598 }
599 if(nv_size(np) != size)
600 {
601 if(nv_isattr(np, NV_DOUBLE)== NV_DOUBLE)
602 cp = "precision";
603 else
604 cp = "base";
605 if(!prefix)
606 sfputr(out,cp,' ');
607 sfprintf(out,"%d ",nv_size(np));
608 }
609 break;
610 }
611 }
612 if(fp)
613 outtype(np,fp,out,prefix);
614 if(noname)
615 return;
616 #if xSHOPT_FIXEDARRAY
617 if(fixed)
618 {
619 sfprintf(out,"%s",nv_name(np));
620 nv_arrfixed(np,out,0,(char*)0);
621 sfputc(out,';');
622 }
623 #endif /* SHOPT_FIXEDARRAY */
624 sfputr(out,nv_name(np),'\n');
625 }
626 }
627
628 struct Walk
629 {
630 Shell_t *shp;
631 Sfio_t *out;
632 Dt_t *root;
633 int noscope;
634 int indent;
635 int nofollow;
636 int array;
637 int flags;
638 };
639
nv_outnode(Namval_t * np,Sfio_t * out,int indent,int special)640 void nv_outnode(Namval_t *np, Sfio_t* out, int indent, int special)
641 {
642 char *fmtq,*ep,*xp;
643 Namval_t *mp;
644 Namarr_t *ap = nv_arrayptr(np);
645 int scan,tabs=0,c,more,associative = 0;
646 int saveI = Indent, dot=-1;
647 bool json = (special&NV_JSON);
648 bool json_last = (special&NV_JSON_LAST);
649 Shell_t *shp = (Shell_t*)np->nvshell;
650 special &= ~(NV_JSON|NV_JSON_LAST);
651 Indent = indent;
652 if(ap)
653 {
654 sfputc(out,json?'[':'(');
655 if(array_elem(ap)==0)
656 return;
657 if(!(ap->flags&ARRAY_SCAN))
658 nv_putsub(np,NIL(char*),0,ARRAY_SCAN);
659 if(indent>=0)
660 {
661 sfputc(out,'\n');
662 tabs=1;
663 }
664 if(!(associative =(array_assoc(ap)!=0)))
665 {
666 if(array_elem(ap) < nv_aimax(np)+1)
667 associative=1;
668 }
669 }
670 mp = nv_opensub(np);
671 while(1)
672 {
673 if(mp && mp->nvalue.cp==Empty && !mp->nvfun)
674 {
675 more = nv_nextsub(np);
676 goto skip;
677 }
678 if(mp && special && nv_isvtree(mp) && !nv_isarray(mp))
679 {
680 if(!nv_nextsub(np))
681 break;
682 mp = nv_opensub(np);
683 continue;
684 }
685 if(tabs)
686 sfnputc(out,'\t',Indent = ++indent);
687 tabs=0;
688 if(associative||special)
689 {
690 Namarr_t *aq;
691 if(mp && (aq=nv_arrayptr(mp)) && !aq->fun && array_elem(aq) < nv_aimax(mp)+1)
692 sfwrite(out,"typeset -a ",11);
693 if(!(fmtq = nv_getsub(np)))
694 break;
695 if(!json)
696 sfprintf(out,"[%s]=",sh_fmtstr(fmtq,'['));
697 else if(associative)
698 sfprintf(out,"%s: ",sh_fmtj(fmtq));
699 }
700 if(ap && !array_assoc(ap))
701 scan = ap->flags&ARRAY_SCAN;
702 if(mp && nv_isarray(mp))
703 {
704 nv_outnode(mp, out, indent,0);
705 if(indent>0)
706 sfnputc(out,'\t',indent);
707 if(nv_arrayptr(mp))
708 sfputc(out,json?']':')');
709 sfputc(out,indent>=0?'\n':' ');
710 if(ap && !array_assoc(ap))
711 ap->flags |= scan;
712 more = nv_nextsub(np);
713 goto skip;
714 }
715 if(mp && nv_isvtree(mp))
716 {
717 if(indent<0)
718 nv_onattr(mp,NV_EXPORT);
719 nv_onattr(mp,NV_TABLE);
720 }
721 if(ap)
722 dot = nv_aindex(np);
723 ep = nv_getval(mp?mp:np);
724 if(dot>=0)
725 nv_putsub(np,NULL,dot,0);
726 else if(mp && associative)
727 nv_putsub(np,mp->nvname,0,ARRAY_SCAN);
728 if(ep==Empty && !(ap && ap->fixed))
729 ep = 0;
730 xp = 0;
731 if(!ap && nv_isattr(np,NV_INTEGER|NV_LJUST)==NV_LJUST)
732 {
733 xp = ep+nv_size(np);
734 while(--xp>ep && *xp==' ');
735 if(xp>ep || *xp!=' ')
736 xp++;
737 if(xp < (ep+nv_size(np)))
738 *xp = 0;
739 else
740 xp = 0;
741 }
742 if(mp && nv_isvtree(mp))
743 fmtq = ep;
744 else if(json)
745 {
746 if(nv_isattr(np,NV_INTEGER))
747 {
748 Namval_t *tp;
749 if((tp=nv_type(np)) && strcmp(tp->nvname,"_Bool")==0)
750 fmtq = nv_getval(np);
751 else
752 {
753 Sfdouble_t d = nv_getnum(np);
754 sfprintf(shp->strbuf,"%.*Lg",sizeof(d),d);
755 fmtq = sfstruse(shp->strbuf);
756 }
757 }
758 else if(!(fmtq = sh_fmtj(ep)))
759 fmtq = "\"\"";
760 }
761 else if(!ep && !mp && nv_isarray(np))
762 fmtq = " ()";
763 else if(!(fmtq = sh_fmtq(ep)))
764 fmtq = "";
765 else if(!associative && (ep=strchr(fmtq,'=')))
766 {
767 char *qp = strchr(fmtq,'\'');
768 if(!qp || qp>ep)
769 {
770 sfwrite(out,fmtq,ep-fmtq);
771 sfputc(out,'\\');
772 fmtq = ep;
773 }
774 }
775 if(ap && !array_assoc(ap))
776 ap->flags |= scan;
777 more = nv_nextsub(np);
778 if(json_last || (ap && !more))
779 json = 0;
780 c = json?',':'\n';
781 if(indent<0)
782 {
783 c = indent < -1?-1:';';
784 if(ap || nv_isarray(np))
785 c = more?' ':-1;
786 }
787 sfputr(out,fmtq,c);
788 if(json)
789 sfputc(out,'\n');
790 if(xp)
791 *xp = ' ';
792 skip:
793 if(!more)
794 break;
795 mp = nv_opensub(np);
796 if(indent>0 && !(mp && special && nv_isvtree(mp)))
797 sfnputc(out,'\t',indent);
798 }
799 Indent = saveI;
800 }
801
outname(Shell_t * shp,Sfio_t * out,char * name,int len,bool json)802 static void outname(Shell_t *shp, Sfio_t *out, char *name, int len, bool json)
803 {
804 if(json)
805 {
806 if(len < 0)
807 len = strlen(name);
808 sfputc(out,'"');
809 if(*name=='[')
810 {
811 len-=2;
812 if(*++name == '\'')
813 len--;
814 }
815 }
816 else if(*name=='[' && name[-1]=='.')
817 name--;
818 sh_outname(shp,out,name, len);
819 if(json)
820 sfwrite(out,"\": ",3);
821 }
822
outval(char * name,const char * vname,struct Walk * wp)823 static void outval(char *name, const char *vname, struct Walk *wp)
824 {
825 register Namval_t *tp=0, *np, *nq, *last_table=wp->shp->last_table;
826 register Namfun_t *fp;
827 int isarray=0, special=0,mode=0;
828 bool json = (wp->flags&NV_JSON);
829 Dt_t *root = wp->root?wp->root:wp->shp->var_base;
830 if(*name!='.' || vname[strlen(vname)-1]==']')
831 mode = NV_ARRAY;
832 if(!(np=nv_open(vname,root,mode|NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope)))
833 {
834 wp->shp->last_table = last_table;
835 wp->flags &= ~NV_COMVAR;
836 return;
837 }
838 if(!wp->out)
839 wp->shp->last_table = last_table;
840 if(wp->shp->last_table)
841 tp = nv_type(wp->shp->last_table);
842 last_table = wp->shp->last_table;
843 fp = nv_hasdisc(np,&treedisc);
844 if(*name=='.')
845 {
846 if(nv_isattr(np,NV_BINARY) || nv_type(np))
847 return;
848 if(fp && np->nvalue.cp && np->nvalue.cp!=Empty)
849 {
850 nv_local = 1;
851 fp = 0;
852 }
853 if(fp)
854 return;
855 if(nv_isarray(np))
856 return;
857 }
858 if(!special && fp && !nv_isarray(np))
859 {
860 Namfun_t *xp;
861 if(!wp->out)
862 {
863 fp = nv_stack(np,fp);
864 if(fp = nv_stack(np,NIL(Namfun_t*)))
865 free((void*)fp);
866 np->nvfun = 0;
867 if(!nv_isattr(np,NV_MINIMAL))
868 np->nvenv = 0;
869 return;
870 }
871 for(xp=fp->next; xp; xp = xp->next)
872 {
873 if(xp->disc && (xp->disc->getval || xp->disc->getnum))
874 break;
875 }
876 if(!xp)
877 {
878 if(nv_type(np) || !(wp->flags&NV_COMVAR))
879 {
880 wp->flags &= ~NV_COMVAR;
881 return;
882 }
883 if(wp->indent>0)
884 sfnputc(wp->out,'\t',wp->indent);
885 nv_attribute(np,wp->out,"typeset",' ');
886 sfputr(wp->out,name,wp->indent>0?'\n':-1);
887 return;
888 }
889 }
890 wp->flags &= ~NV_COMVAR;
891 #if 0
892 if(nv_isnull(np) && !nv_isarray(np) && !nv_isattr(np,NV_INTEGER))
893 return;
894 #else
895 if(!nv_isarray(np) && !nv_isattr(np,NV_INTEGER))
896 {
897 if(nv_isnull(np))
898 return;
899 if(np->nvalue.cp==Empty && tp && (last_table->nvname[0]!='_' || last_table->nvname[1]))
900 {
901 for(fp=np->nvfun;fp;fp=fp->next)
902 {
903 if(fp->disc && (fp->disc->getval || fp->disc->getnum))
904 break;
905 }
906 if(!fp)
907 return;
908 }
909 }
910 #endif
911 if(special || (nv_isarray(np) && nv_arrayptr(np)))
912 {
913 isarray=1;
914 if(array_elem(nv_arrayptr(np))==0)
915 {
916 Namval_t *mp;
917 isarray=2;
918 if(tp && (last_table->nvname[0]!='_' || last_table->nvname[1]))
919 return;
920 }
921 else
922 nq = nv_putsub(np,NIL(char*),0,ARRAY_SCAN|(wp->out&&!nv_type(np)?ARRAY_NOCHILD:0));
923 }
924 if(!wp->out)
925 {
926 _nv_unset(np,NV_RDONLY);
927 if(wp->shp->subshell || (wp->flags!=NV_RDONLY) || nv_isattr(np,NV_MINIMAL|NV_NOFREE))
928 wp->root = 0;
929 nv_delete(np,wp->root,nv_isattr(np,NV_MINIMAL)?NV_NOFREE:0);
930 return;
931 }
932 if(isarray==1 && !nq)
933 {
934 int c = json?':':'=';
935 if(wp->out->_next[-1]!=c)
936 return;
937 if(json)
938 sfputc(wp->out,' ');
939 sfputc(wp->out,json?'[':'(');
940 if(wp->indent>=0)
941 sfputc(wp->out,'\n');
942 return;
943 }
944 if(isarray==0 && nv_isarray(np) && (nv_isnull(np)||np->nvalue.cp==Empty)) /* empty array */
945 isarray = 2;
946 special |= wp->nofollow;
947 if(!wp->array && wp->indent>0)
948 sfnputc(wp->out,'\t',wp->indent);
949 if(!special)
950 {
951 if(*name!='.')
952 {
953 Namarr_t *ap;
954 if(!json)
955 nv_attribute(np,wp->out,"typeset",'=');
956 #if xSHOPT_FIXEDARRAY
957 if((ap=nv_arrayptr(np)) && ap->fixed)
958 {
959 sfprintf(wp->out,"%s",name);
960 nv_arrfixed(np,wp->out,0,(char*)0);
961 sfputc(wp->out,';');
962 }
963 #endif /* SHOPT_FIXEDARRAY */
964 }
965 outname(wp->shp,wp->out,name,-1, json);
966 if((np->nvalue.cp && np->nvalue.cp!=Empty) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)) || nv_isvtree(np))
967 if(!json)
968 sfputc(wp->out,(isarray==2?(wp->indent>=0?'\n':';'):'='));
969 if(isarray==2)
970 return;
971 }
972 fp = np->nvfun;
973 if(*name=='.' && !isarray)
974 np->nvfun = 0;
975 nv_outnode(np, wp->out, wp->indent, special|(wp->flags&(NV_JSON|NV_JSON_LAST)));
976 if(*name=='.' && !isarray)
977 np->nvfun = fp;
978 if(isarray && !special)
979 {
980 if(wp->indent>0)
981 {
982 sfnputc(wp->out,'\t',wp->indent);
983 if(json && !(wp->flags&NV_JSON_LAST))
984 sfwrite(wp->out,"],\n",3);
985 else
986 sfwrite(wp->out,json?"]\n":")\n",2);
987 }
988 else
989 sfwrite(wp->out,");",2);
990 }
991 }
992
993 /*
994 * format initialization list given a list of assignments <argp>
995 */
genvalue(char ** argv,const char * prefix,int n,struct Walk * wp)996 static char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp)
997 {
998 register char *cp,*nextcp,*arg;
999 register Sfio_t *outfile = wp->out;
1000 register int r;
1001 Shell_t *shp = wp->shp;
1002 Namarr_t *ap;
1003 Namval_t *np,*tp;
1004 size_t m,l;
1005 bool json = (wp->flags&NV_JSON);
1006 bool array_parent = (wp->flags&NV_ARRAY);
1007 char endchar = json?'}':')';
1008 char **names;
1009 wp->flags &= ~NV_ARRAY;
1010 if(n==0)
1011 m = strlen(prefix);
1012 else if(cp=nextdot(prefix,(void*)shp))
1013 m = cp-prefix;
1014 else
1015 m = strlen(prefix)-1;
1016 m++;
1017 wp->flags &= ~NV_COMVAR;
1018 if(outfile && !wp->array)
1019 {
1020 sfputc(outfile,json?'{':'(');
1021 if(wp->indent>=0)
1022 {
1023 wp->indent++;
1024 sfputc(outfile,'\n');
1025 }
1026 }
1027 for(; arg= *argv; argv++)
1028 {
1029 cp = arg + n;
1030 if(n==0 && cp[m-1]!='.')
1031 continue;
1032 if(n && cp[m-1]==0)
1033 break;
1034 if(n==0 || strncmp(arg,prefix-n,m+n)==0)
1035 {
1036 cp +=m;
1037 r = 0;
1038 if(*cp=='.')
1039 cp++,r++;
1040 if(wp->indent < 0 && argv[1]==0)
1041 wp->indent--;
1042 if(nextcp=nextdot(cp,(void*)shp))
1043 {
1044 if(outfile)
1045 {
1046 *nextcp = 0;
1047 np=nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope);
1048 if(!np || (nv_isarray(np) && (!(tp=nv_opensub(np)) || !nv_isvtree(tp))))
1049 {
1050 *nextcp = '.';
1051 continue;
1052 }
1053 if(*cp!='[' && (tp = nv_type(np)) && (ap=nv_arrayptr(np)) && !ap->fun)
1054 continue;
1055 if(wp->indent>=0)
1056 sfnputc(outfile,'\t',wp->indent);
1057 if(!json && *cp!='[' && tp)
1058 {
1059 char *sp;
1060 if(sp = strrchr(tp->nvname,'.'))
1061 sp++;
1062 else
1063 sp = tp->nvname;
1064 sfputr(outfile,sp,' ');
1065 }
1066 else if(*cp!='[' && wp->indent>=0 && nv_isvtree(np))
1067 {
1068 if(!json)
1069 nv_attribute(np,outfile,"typeset",' ');;
1070 }
1071 if(!array_parent)
1072 {
1073 outname(shp,outfile,cp,nextcp-cp, json);
1074 if(!json)
1075 sfputc(outfile,'=');
1076 }
1077 *nextcp = '.';
1078 }
1079 else
1080 {
1081 outval(cp,arg,wp);
1082 continue;
1083 }
1084 argv = genvalue(argv,cp,n+m+r,wp);
1085 if(wp->indent>=0)
1086 sfputc(outfile,'\n');
1087 if(*argv)
1088 continue;
1089 break;
1090 }
1091 else if(outfile && !wp->nofollow && argv[1] && memcmp(arg,argv[1],l=strlen(arg))==0 && argv[1][l]=='[')
1092 {
1093 int k=1;
1094 Namarr_t *aq=0;
1095 np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope);
1096 if(!np)
1097 continue;
1098 if((wp->array = nv_isarray(np)) && (aq=nv_arrayptr(np)))
1099 k = array_elem(aq);
1100
1101 if(wp->indent>0)
1102 sfnputc(outfile,'\t',wp->indent);
1103 if(json)
1104 sfputc(outfile,'"');
1105 else
1106 nv_attribute(np,outfile,"typeset",1);
1107 nv_close(np);
1108 sfputr(outfile,arg+m+r+(n?n:0),(k?(json?'"':'='):'\n'));
1109 if(json)
1110 sfputc(outfile,':');
1111 if(!k)
1112 {
1113 wp->array=0;
1114 continue;
1115 }
1116 wp->nofollow=1;
1117 if(json && aq && !aq->fun)
1118 wp->flags |= NV_ARRAY;
1119 argv = genvalue(argv,cp,cp-arg ,wp);
1120 if(wp->indent>0)
1121 sfputc(outfile,'\n');
1122 }
1123 else if(outfile && *cp=='[' && cp[-1]!='.')
1124 {
1125 /* skip multi-dimensional arrays */
1126 if(*nv_endsubscript((Namval_t*)0,cp,0,(void*)shp)=='[')
1127 continue;
1128 if(wp->indent>0)
1129 sfnputc(outfile,'\t',wp->indent);
1130 if(cp[-1]=='.')
1131 cp--;
1132 sfputr(outfile,cp,'=');
1133 if(*cp=='.')
1134 cp++;
1135 argv = genvalue(++argv,cp,cp-arg ,wp);
1136 sfputc(outfile,wp->indent>0?'\n':';');
1137 }
1138 else
1139 {
1140 if(n && *cp && cp[-1]!='.' && cp[-1]!='[')
1141 break;
1142 if(outfile && wp->indent<0 && (wp->flags&NV_COMVAR))
1143 sfputc(outfile,';');
1144 wp->flags |= NV_COMVAR;
1145 if(argv[1])
1146 {
1147 ssize_t r = (cp-argv[0]) + strlen(cp);
1148 if(argv[1][r]=='.' && strncmp(argv[0],argv[1],r)==0)
1149 wp->flags &= ~NV_COMVAR;
1150 }
1151 if((wp->flags& NV_JSON) && (!argv[1] || strlen(argv[1])<m+n || memcmp(argv[1],arg,m+n-1)))
1152 wp->flags |= NV_JSON_LAST;
1153 outval(cp,arg,wp);
1154 if(wp->array)
1155 {
1156 if(wp->indent>=0)
1157 {
1158 wp->indent++;
1159 if(json)
1160 endchar = ']';
1161 }
1162 else
1163 sfputc(outfile,' ');
1164 wp->array = 0;
1165 }
1166 }
1167 }
1168 else
1169 break;
1170 wp->nofollow = 0;
1171 }
1172 wp->array = 0;
1173 wp->flags &= ~NV_COMVAR;
1174 if(outfile)
1175 {
1176 int c = prefix[m-1];
1177 cp = (char*)prefix;
1178 if(c=='.')
1179 cp[m-1] = 0;
1180 outval(".",prefix-n,wp);
1181 if(c=='.')
1182 cp[m-1] = c;
1183 if(wp->indent>0)
1184 sfnputc(outfile,'\t',--wp->indent);
1185 sfputc(outfile,endchar);
1186 if(json && wp->indent>0 && *argv && memcmp(arg,argv[-1],n)==0)
1187 sfputc(outfile,',');
1188 if(*argv && n && wp->indent<0)
1189 sfputc(outfile,';');
1190 }
1191 wp->flags &= ~NV_JSON_LAST;
1192 return(--argv);
1193 }
1194
1195 /*
1196 * walk the virtual tree and print or delete name-value pairs
1197 */
walk_tree(register Namval_t * np,Namval_t * xp,int flags)1198 static char *walk_tree(register Namval_t *np, Namval_t *xp, int flags)
1199 {
1200 Shell_t *shp = sh_ptr(np);
1201 static Sfio_t *out;
1202 struct Walk walk;
1203 Sfio_t *outfile;
1204 Sfoff_t off = 0;
1205 int len, savtop = stktell(shp->stk);
1206 char *savptr = stkfreeze(shp->stk,0);
1207 register struct argnod *ap=0;
1208 struct argnod *arglist=0;
1209 char *name,*cp, **argv;
1210 char *subscript=0;
1211 void *dir;
1212 int n=0, noscope=(flags&NV_NOSCOPE);
1213 Namarr_t *arp = nv_arrayptr(np);
1214 Dt_t *save_tree = shp->var_tree, *last_root;
1215 Namval_t *mp=0, *table;
1216 char *xpname = xp?stkcopy(shp->stk,nv_name(xp)):0;
1217 walk.shp = shp;
1218 if(xp)
1219 {
1220 if(!(last_root = shp->last_root))
1221 last_root = shp->var_tree;
1222 shp->last_root = shp->prev_root;
1223 shp->last_table = shp->prev_table;
1224 }
1225 if(shp->last_table)
1226 shp->last_root = nv_dict(shp->last_table);
1227 if(shp->last_root)
1228 shp->var_tree = shp->last_root;
1229 table = shp->last_table;
1230 sfputr(shp->stk,nv_name(np),-1);
1231 shp->last_table = table;
1232 if(arp && !(arp->flags&ARRAY_SCAN) && (subscript = nv_getsub(np)))
1233 {
1234 mp = nv_opensub(np);
1235 sfputc(shp->stk,'[');
1236 sfputr(shp->stk,subscript,']');
1237 sfputc(shp->stk,'.');
1238 }
1239 else if(*stkptr(shp->stk,stktell(shp->stk)-1) == ']')
1240 mp = np;
1241 name = stkfreeze(shp->stk,1);
1242 shp->last_root = 0;
1243 if(shp->last_table && !nv_type(shp->last_table) && (cp=nv_name(shp->last_table)) && strcmp(cp,".sh") && (len=strlen(cp)) && strncmp(name,cp,len)==0 && name[len]=='.')
1244 name += len+1;
1245 len = strlen(name);
1246 dir = nv_diropen(mp,name,(void*)shp);
1247 walk.root = shp->last_root?shp->last_root:shp->var_tree;
1248 if(subscript)
1249 name[strlen(name)-1] = 0;
1250 while(cp = nv_dirnext(dir))
1251 {
1252 if(cp[len]!='.')
1253 continue;
1254 if(xp)
1255 {
1256 Dt_t *dp = shp->var_tree;
1257 Namval_t *nq, *mq;
1258 if(strlen(cp)<=len)
1259 continue;
1260 nq = nv_open(cp,walk.root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL);
1261 if(!nq && (flags&NV_MOVE))
1262 nq = nv_search(cp,walk.root,NV_NOADD);
1263 stkseek(shp->stk,0);
1264 sfputr(shp->stk,xpname,-1);
1265 sfputr(shp->stk,cp+len,0);
1266 shp->var_tree = save_tree;
1267 mq = nv_open(stkptr(shp->stk,0),last_root,NV_VARNAME|NV_NOASSIGN|NV_NOFAIL);
1268 shp->var_tree = dp;
1269 if(nq && mq)
1270 {
1271 register struct nvdir *odir=0,*dp = (struct nvdir*)dir;
1272 char *nvenv = mq->nvenv;
1273 if(dp->table==nq)
1274 {
1275 dp = dp->prev;
1276 odir = dir;
1277 dir = dp;
1278 }
1279 nv_clone(nq,mq,flags|NV_RAW);
1280 mq->nvenv = nvenv;
1281 if(flags&NV_MOVE)
1282 nv_delete(nq,walk.root,0);
1283 if(odir)
1284 free(odir);
1285 }
1286 continue;
1287 }
1288 stkseek(shp->stk,ARGVAL);
1289 sfputr(shp->stk,cp,-1);
1290 ap = (struct argnod*)stkfreeze(shp->stk,1);
1291 ap->argflag = ARG_RAW;
1292 ap->argchn.ap = arglist;
1293 n++;
1294 arglist = ap;
1295 }
1296 nv_dirclose(dir);
1297 if(xp)
1298 {
1299 shp->var_tree = save_tree;
1300 return((char*)0);
1301 }
1302 argv = (char**)stkalloc(shp->stk,(n+1)*sizeof(char*));
1303 argv += n;
1304 *argv = 0;
1305 for(; ap; ap=ap->argchn.ap)
1306 *--argv = ap->argval;
1307 if(flags&1)
1308 outfile = 0;
1309 else if(!(outfile=out))
1310 outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
1311 else if(flags&NV_TABLE)
1312 off = sftell(outfile);
1313 else
1314 sfseek(outfile,0L,SEEK_SET);
1315 walk.out = outfile;
1316 walk.indent = (flags&NV_EXPORT)?-1:Indent;
1317 walk.nofollow = 0;
1318 walk.noscope = noscope;
1319 walk.array = 0;
1320 walk.flags = flags;
1321 genvalue(argv,name,0,&walk);
1322 stkset(shp->stk,savptr,savtop);
1323 shp->var_tree = save_tree;
1324 if(!outfile)
1325 return((char*)0);
1326 sfputc(out,0);
1327 sfseek(out,off,SEEK_SET);
1328 return((char*)out->_data+off);
1329 }
1330
nv_isvtree(Namval_t * np)1331 Namfun_t *nv_isvtree(Namval_t *np)
1332 {
1333 if(np==SH_STATS || np==SH_SIG)
1334 return((Namfun_t*)1);
1335 if(np)
1336 return(nv_hasdisc(np,&treedisc));
1337 return(0);
1338 }
1339
1340 /*
1341 * get discipline for compound initializations
1342 */
nv_getvtree(register Namval_t * np,Namfun_t * fp)1343 char *nv_getvtree(register Namval_t *np, Namfun_t *fp)
1344 {
1345 #if 1
1346 int flags=0, dsize=0;
1347 #else
1348 int flags=0, dsize=fp?fp->dsize:0;
1349 #endif
1350 for(; fp && fp->next; fp=fp->next)
1351 {
1352 if(fp->next->disc && (fp->next->disc->getnum || fp->next->disc->getval))
1353 return(nv_getv(np,fp));
1354 }
1355 if(nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
1356 return(nv_getv(np,fp));
1357 if(nv_isattr(np,NV_ARRAY) && !nv_type(np) && nv_arraychild(np,(Namval_t*)0,0)==np)
1358 return(nv_getv(np,fp));
1359 if(flags = nv_isattr(np,NV_EXPORT|NV_TAGGED))
1360 nv_offattr(np,NV_EXPORT|NV_TAGGED);
1361 if(flags |= nv_isattr(np,NV_TABLE))
1362 nv_offattr(np,NV_TABLE);
1363 if(dsize && (flags&NV_EXPORT))
1364 return("()");
1365 return(walk_tree(np,(Namval_t*)0,flags));
1366 }
1367
1368 /*
1369 * put discipline for compound initializations
1370 */
put_tree(register Namval_t * np,const char * val,int flags,Namfun_t * fp)1371 static void put_tree(register Namval_t *np, const char *val, int flags,Namfun_t *fp)
1372 {
1373 struct Namarray *ap;
1374 int nleft = 0;
1375 if(!val && !fp->next && nv_isattr(np,NV_NOFREE))
1376 return;
1377 if(!nv_isattr(np,(NV_INTEGER|NV_BINARY)))
1378 {
1379 Shell_t *shp = sh_ptr(np);
1380 Namval_t *last_table = shp->last_table;
1381 Dt_t *last_root = shp->last_root;
1382 Namval_t *mp = val?nv_open(val,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_ARRAY|NV_NOFAIL):0;
1383 if(mp && nv_isvtree(mp))
1384 {
1385 shp->prev_table = shp->last_table;
1386 shp->prev_root = shp->last_root;
1387 shp->last_table = last_table;
1388 shp->last_root = last_root;
1389 if(!(flags&NV_APPEND))
1390 walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1);
1391 nv_clone(mp,np,NV_COMVAR);
1392 return;
1393 }
1394 walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1);
1395 }
1396 nv_putv(np, val, flags,fp);
1397 if(val && nv_isattr(np,(NV_INTEGER|NV_BINARY)))
1398 return;
1399 if(ap= nv_arrayptr(np))
1400 nleft = array_elem(ap);
1401 if(nleft==0)
1402 {
1403 fp = nv_stack(np,fp);
1404 if(fp = nv_stack(np,NIL(Namfun_t*)))
1405 free((void*)fp);
1406 }
1407 }
1408
1409 /*
1410 * Insert discipline to cause $x to print current tree
1411 */
nv_setvtree(register Namval_t * np)1412 void nv_setvtree(register Namval_t *np)
1413 {
1414 Shell_t *shp = sh_ptr(np);
1415 register Namfun_t *nfp;
1416 if(shp->subshell)
1417 sh_assignok(np,1);
1418 if(nv_hasdisc(np, &treedisc))
1419 return;
1420 nfp = newof(NIL(void*),Namfun_t,1,sizeof(void*));
1421 *(void**)(nfp+1)= 0;
1422 nfp->disc = &treedisc;
1423 nfp->dsize = sizeof(Namfun_t);
1424 nv_stack(np, nfp);
1425 }
1426
1427