Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/nvtree.c
1810 views
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 <[email protected]> *
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
1172