Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/nvdisc.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
* AT&T Labs
23
*
24
*/
25
26
#include "defs.h"
27
#include "variables.h"
28
#include "builtins.h"
29
#include "path.h"
30
31
static void assign(Namval_t*,const char*,int,Namfun_t*);
32
33
int nv_compare(Dt_t* dict, Void_t *sp, Void_t *dp, Dtdisc_t *disc)
34
{
35
if(sp==dp)
36
return(0);
37
return(strcmp((char*)sp,(char*)dp));
38
}
39
40
/*
41
* call the next getval function in the chain
42
*/
43
char *nv_getv(Namval_t *np, register Namfun_t *nfp)
44
{
45
register Namfun_t *fp;
46
register char *cp;
47
if((fp = nfp) != NIL(Namfun_t*) && !nv_local)
48
fp = nfp = nfp->next;
49
nv_local=0;
50
for(; fp; fp=fp->next)
51
{
52
if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
53
continue;
54
if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
55
break;
56
}
57
if(fp && fp->disc->getval)
58
cp = (*fp->disc->getval)(np,fp);
59
else if(fp && fp->disc->getnum)
60
{
61
sfprintf(sh.strbuf,"%.*Lg",12,(*fp->disc->getnum)(np,fp));
62
cp = sfstruse(sh.strbuf);
63
}
64
else
65
{
66
nv_local=1;
67
cp = nv_getval(np);
68
}
69
return(cp);
70
}
71
72
/*
73
* call the next getnum function in the chain
74
*/
75
Sfdouble_t nv_getn(Namval_t *np, register Namfun_t *nfp)
76
{
77
register Namfun_t *fp;
78
register Sfdouble_t d=0;
79
Shell_t *shp = sh_getinterp();
80
char *str;
81
if((fp = nfp) != NIL(Namfun_t*) && !nv_local)
82
fp = nfp = nfp->next;
83
nv_local=0;
84
for(; fp; fp=fp->next)
85
{
86
if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
87
continue;
88
if(!fp->disc->getnum && nv_isattr(np,NV_INTEGER))
89
continue;
90
if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
91
break;
92
}
93
if(fp && fp->disc && fp->disc->getnum)
94
d = (*fp->disc->getnum)(np,fp);
95
else if(nv_isattr(np,NV_INTEGER))
96
{
97
nv_local = 1;
98
d = nv_getnum(np);
99
}
100
else
101
{
102
if(fp && fp->disc && fp->disc->getval)
103
str = (*fp->disc->getval)(np,fp);
104
else
105
str = nv_getv(np,fp?fp:nfp);
106
if(str && *str)
107
{
108
if(nv_isattr(np,NV_LJUST|NV_RJUST) || (*str=='0' && !(str[1]=='x'||str[1]=='X')))
109
{
110
while(*str=='0')
111
str++;
112
}
113
d = sh_arith(shp,str);
114
}
115
}
116
return(d);
117
}
118
119
/*
120
* call the next assign function in the chain
121
*/
122
void nv_putv(Namval_t *np, const char *value, int flags, register Namfun_t *nfp)
123
{
124
register Namfun_t *fp, *fpnext;
125
Namarr_t *ap;
126
if((fp=nfp) != NIL(Namfun_t*) && !nv_local)
127
fp = nfp = nfp->next;
128
nv_local=0;
129
if(flags&NV_NODISC)
130
fp = 0;
131
for(; fp; fp=fpnext)
132
{
133
fpnext = fp->next;
134
if(!fp->disc || !fp->disc->putval)
135
{
136
if(!value && (!(ap=nv_arrayptr(np)) || ap->nelem==0))
137
{
138
if(fp->disc || !(fp->nofree&1))
139
nv_disc(np,fp,NV_POP);
140
if(!(fp->nofree&1))
141
free((void*)fp);
142
}
143
continue;
144
}
145
if(!nv_isattr(np,NV_NODISC) || fp==(Namfun_t*)nv_arrayptr(np))
146
break;
147
}
148
if(!value && (flags&NV_TYPE) && fp && fp->disc->putval==assign)
149
fp = 0;
150
if(fp && fp->disc->putval)
151
(*fp->disc->putval)(np,value, flags, fp);
152
else
153
{
154
nv_local=1;
155
if(value)
156
nv_putval(np, value, flags);
157
else
158
_nv_unset(np, flags&(NV_RDONLY|NV_EXPORT));
159
}
160
}
161
162
#define LOOKUPS 0
163
#define ASSIGN 1
164
#define APPEND 2
165
#define UNASSIGN 3
166
#define LOOKUPN 4
167
#define BLOCKED ((Namval_t*)&nv_local)
168
169
struct vardisc
170
{
171
Namfun_t fun;
172
Namval_t *disc[5];
173
};
174
175
struct blocked
176
{
177
struct blocked *next;
178
Namval_t *np;
179
int flags;
180
void *sub;
181
int isub;
182
};
183
184
static struct blocked *blist;
185
186
#define isblocked(bp,type) ((bp)->flags & (1<<(type)))
187
#define block(bp,type) ((bp)->flags |= (1<<(type)))
188
#define unblock(bp,type) ((bp)->flags &= ~(1<<(type)))
189
190
/*
191
* returns pointer to blocking structure
192
*/
193
static struct blocked *block_info(Namval_t *np, struct blocked *pp)
194
{
195
register struct blocked *bp;
196
void *sub=0;
197
int isub=0;
198
if(nv_isarray(np) && (isub=nv_aindex(np)) < 0)
199
sub = nv_associative(np,(const char*)0,NV_ACURRENT);
200
for(bp=blist ; bp; bp=bp->next)
201
{
202
if(bp->np==np && bp->sub==sub && bp->isub==isub)
203
return(bp);
204
}
205
if(pp)
206
{
207
pp->np = np;
208
pp->flags = 0;
209
pp->isub = isub;
210
pp->sub = sub;
211
pp->next = blist;
212
blist = pp;
213
}
214
return(pp);
215
}
216
217
static void block_done(struct blocked *bp)
218
{
219
blist = bp = bp->next;
220
if(bp && (bp->isub>=0 || bp->sub))
221
nv_putsub(bp->np, bp->sub,(bp->isub<0?0:bp->isub)|ARRAY_SETSUB);
222
}
223
224
/*
225
* free discipline if no more discipline functions
226
*/
227
static void chktfree(register Namval_t *np, register struct vardisc *vp)
228
{
229
register int n;
230
for(n=0; n< sizeof(vp->disc)/sizeof(*vp->disc); n++)
231
{
232
if(vp->disc[n])
233
break;
234
}
235
if(n>=sizeof(vp->disc)/sizeof(*vp->disc))
236
{
237
/* no disc left so pop */
238
Namfun_t *fp;
239
if((fp=nv_stack(np, NIL(Namfun_t*))) && !(fp->nofree&1))
240
free((void*)fp);
241
}
242
}
243
244
/*
245
* This function performs an assignment disc on the given node <np>
246
*/
247
static void assign(Namval_t *np,const char* val,int flags,Namfun_t *handle)
248
{
249
int type = (flags&NV_APPEND)?APPEND:ASSIGN;
250
register struct vardisc *vp = (struct vardisc*)handle;
251
register Namval_t *nq = vp->disc[type];
252
struct blocked block, *bp = block_info(np, &block);
253
Namval_t node;
254
union Value *up = np->nvalue.up;
255
#if SHOPT_TYPEDEF
256
Namval_t *tp, *nr;
257
if(val && (tp=nv_type(np)) && (nr=nv_open(val,sh.var_tree,NV_VARNAME|NV_ARRAY|NV_NOADD|NV_NOFAIL)) && tp==nv_type(nr))
258
{
259
char *sub = nv_getsub(np);
260
_nv_unset(np,0);
261
if(sub)
262
{
263
nv_putsub(np, sub, ARRAY_ADD);
264
nv_putval(np,nv_getval(nr), 0);
265
}
266
else
267
nv_clone(nr,np,0);
268
goto done;
269
}
270
#endif /* SHOPT_TYPEDEF */
271
if(val || isblocked(bp,type))
272
{
273
if(!nq || isblocked(bp,type))
274
{
275
nv_putv(np,val,flags,handle);
276
goto done;
277
}
278
node = *SH_VALNOD;
279
if(!nv_isnull(SH_VALNOD))
280
{
281
nv_onattr(SH_VALNOD,NV_NOFREE);
282
_nv_unset(SH_VALNOD,0);
283
}
284
if(flags&NV_INTEGER)
285
nv_onattr(SH_VALNOD,(flags&(NV_LONG|NV_DOUBLE|NV_EXPNOTE|NV_HEXFLOAT|NV_SHORT)));
286
nv_putval(SH_VALNOD, val, (flags&NV_INTEGER)?flags:NV_NOFREE);
287
}
288
else
289
nq = vp->disc[type=UNASSIGN];
290
if(nq && !isblocked(bp,type))
291
{
292
int bflag=0;
293
block(bp,type);
294
if (type==APPEND && (bflag= !isblocked(bp,LOOKUPS)))
295
block(bp,LOOKUPS);
296
sh_fun(nq,np,(char**)0);
297
unblock(bp,type);
298
if(bflag)
299
unblock(bp,LOOKUPS);
300
if(!vp->disc[type])
301
chktfree(np,vp);
302
}
303
if(nv_isarray(np))
304
np->nvalue.up = up;
305
if(val)
306
{
307
register char *cp;
308
Sfdouble_t d;
309
if(nv_isnull(SH_VALNOD))
310
cp=0;
311
else if(flags&NV_INTEGER)
312
{
313
d = nv_getnum(SH_VALNOD);
314
cp = (char*)(&d);
315
flags |= (NV_LONG|NV_DOUBLE);
316
flags &= ~NV_SHORT;
317
}
318
else
319
cp = nv_getval(SH_VALNOD);
320
if(cp)
321
nv_putv(np,cp,flags|NV_RDONLY,handle);
322
_nv_unset(SH_VALNOD,0);
323
/* restore everything but the nvlink field */
324
memcpy(&SH_VALNOD->nvname, &node.nvname, sizeof(node)-sizeof(node.nvlink));
325
}
326
else if(sh_isstate(SH_INIT) || np==SH_FUNNAMENOD)
327
{
328
/* don't free functions during reinitialization */
329
nv_putv(np,val,flags,handle);
330
}
331
else if(!nq || !isblocked(bp,type))
332
{
333
Dt_t *root = sh_subfuntree(1);
334
int n;
335
Namarr_t *ap;
336
block(bp,type);
337
nv_disc(np,handle,NV_POP);
338
nv_putv(np, val, flags, handle);
339
if(sh.subshell)
340
goto done;
341
if(nv_isarray(np) && (ap=nv_arrayptr(np)) && ap->nelem>0)
342
goto done;
343
for(n=0; n < sizeof(vp->disc)/sizeof(*vp->disc); n++)
344
{
345
if((nq=vp->disc[n]) && !nv_isattr(nq,NV_NOFREE))
346
{
347
_nv_unset(nq,0);
348
dtdelete(root,nq);
349
}
350
}
351
unblock(bp,type);
352
if(!(handle->nofree&1))
353
free(handle);
354
}
355
done:
356
if(bp== &block)
357
block_done(bp);
358
if(nq && nq->nvalue.rp->running==1)
359
{
360
nq->nvalue.rp->running=0;
361
_nv_unset(nq,0);
362
}
363
}
364
365
/*
366
* This function executes a lookup disc and then performs
367
* the lookup on the given node <np>
368
*/
369
static char* lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
370
{
371
register struct vardisc *vp = (struct vardisc*)handle;
372
struct blocked block, *bp = block_info(np, &block);
373
register Namval_t *nq = vp->disc[type];
374
register char *cp=0;
375
Namval_t node;
376
union Value *up = np->nvalue.up;
377
if(nq && !isblocked(bp,type))
378
{
379
node = *SH_VALNOD;
380
if(!nv_isnull(SH_VALNOD))
381
{
382
nv_onattr(SH_VALNOD,NV_NOFREE);
383
_nv_unset(SH_VALNOD,0);
384
}
385
if(type==LOOKUPN)
386
{
387
nv_onattr(SH_VALNOD,NV_DOUBLE|NV_INTEGER);
388
nv_setsize(SH_VALNOD,10);
389
}
390
block(bp,type);
391
sh_fun(nq,np,(char**)0);
392
unblock(bp,type);
393
if(!vp->disc[type])
394
chktfree(np,vp);
395
if(type==LOOKUPN)
396
{
397
cp = (char*)(SH_VALNOD->nvalue.cp);
398
*dp = nv_getnum(SH_VALNOD);
399
}
400
else if(cp = nv_getval(SH_VALNOD))
401
cp = stkcopy(stkstd,cp);
402
_nv_unset(SH_VALNOD,NV_RDONLY);
403
if(!nv_isnull(&node))
404
{
405
/* restore everything but the nvlink field */
406
memcpy(&SH_VALNOD->nvname, &node.nvname, sizeof(node)-sizeof(node.nvlink));
407
}
408
}
409
if(nv_isarray(np))
410
np->nvalue.up = up;
411
if(!cp)
412
{
413
if(type==LOOKUPS)
414
cp = nv_getv(np,handle);
415
else
416
*dp = nv_getn(np,handle);
417
}
418
if(bp== &block)
419
block_done(bp);
420
if(nq && nq->nvalue.rp->running==1)
421
{
422
nq->nvalue.rp->running=0;
423
_nv_unset(nq,0);
424
}
425
return(cp);
426
}
427
428
static char* lookups(Namval_t *np, Namfun_t *handle)
429
{
430
return(lookup(np,LOOKUPS,(Sfdouble_t*)0,handle));
431
}
432
433
static Sfdouble_t lookupn(Namval_t *np, Namfun_t *handle)
434
{
435
Sfdouble_t d;
436
lookup(np,LOOKUPN, &d ,handle);
437
return(d);
438
}
439
440
441
/*
442
* Set disc on given <event> to <action>
443
* If action==np, the current disc is returned
444
* A null return value indicates that no <event> is known for <np>
445
* If <event> is NULL, then return the event name after <action>
446
* If <event> is NULL, and <action> is NULL, return the first event
447
*/
448
char *nv_setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp)
449
{
450
register struct vardisc *vp = (struct vardisc*)np->nvfun;
451
register int type;
452
char *empty = "";
453
while(vp)
454
{
455
if(vp->fun.disc && (vp->fun.disc->setdisc || vp->fun.disc->putval == assign))
456
break;
457
vp = (struct vardisc*)vp->fun.next;
458
}
459
if(vp && !vp->fun.disc)
460
vp = 0;
461
if(np == (Namval_t*)fp)
462
{
463
register const char *name;
464
register int getname=0;
465
/* top level call, check for get/set */
466
if(!event)
467
{
468
if(!action)
469
return((char*)nv_discnames[0]);
470
getname=1;
471
event = (char*)action;
472
}
473
for(type=0; name=nv_discnames[type]; type++)
474
{
475
if(strcmp(event,name)==0)
476
break;
477
}
478
if(getname)
479
{
480
event = 0;
481
if(name && !(name = nv_discnames[++type]))
482
action = 0;
483
}
484
if(!name)
485
{
486
for(fp=(Namfun_t*)vp; fp; fp=fp->next)
487
{
488
if(fp->disc && fp->disc->setdisc)
489
return((*fp->disc->setdisc)(np,event,action,fp));
490
}
491
}
492
else if(getname)
493
return((char*)name);
494
}
495
if(!fp)
496
return(NIL(char*));
497
if(np != (Namval_t*)fp)
498
{
499
/* not the top level */
500
while(fp = fp->next)
501
{
502
if(fp->disc && fp->disc->setdisc)
503
return((*fp->disc->setdisc)(np,event,action,fp));
504
}
505
return(NIL(char*));
506
}
507
/* Handle GET/SET/APPEND/UNSET disc */
508
if(vp && vp->fun.disc->putval!=assign)
509
vp = 0;
510
if(!vp)
511
{
512
Namdisc_t *dp;
513
if(action==np)
514
return((char*)action);
515
if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,sizeof(Namdisc_t))))
516
return(0);
517
dp = (Namdisc_t*)(vp+1);
518
vp->fun.disc = dp;
519
memset(dp,0,sizeof(*dp));
520
dp->dsize = sizeof(struct vardisc);
521
dp->putval = assign;
522
if(nv_isarray(np) && !nv_arrayptr(np))
523
nv_putsub(np,(char*)0, 1);
524
nv_stack(np, (Namfun_t*)vp);
525
}
526
if(action==np)
527
{
528
action = vp->disc[type];
529
empty = 0;
530
}
531
else if(action)
532
{
533
Namdisc_t *dp = (Namdisc_t*)vp->fun.disc;
534
if(type==LOOKUPS)
535
dp->getval = lookups;
536
else if(type==LOOKUPN)
537
dp->getnum = lookupn;
538
vp->disc[type] = action;
539
}
540
else
541
{
542
struct blocked *bp;
543
action = vp->disc[type];
544
vp->disc[type] = 0;
545
if(!(bp=block_info(np,(struct blocked*)0)) || !isblocked(bp,UNASSIGN))
546
chktfree(np,vp);
547
}
548
return(action?(char*)action:empty);
549
}
550
551
/*
552
* Set disc on given <event> to <action>
553
* If action==np, the current disc is returned
554
* A null return value indicates that no <event> is known for <np>
555
* If <event> is NULL, then return the event name after <action>
556
* If <event> is NULL, and <action> is NULL, return the first event
557
*/
558
static char *setdisc(register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp)
559
{
560
register Nambfun_t *vp = (Nambfun_t*)fp;
561
register int type,getname=0;
562
register const char *name;
563
const char **discnames = vp->bnames;
564
/* top level call, check for discipline match */
565
if(!event)
566
{
567
if(!action)
568
return((char*)discnames[0]);
569
getname=1;
570
event = (char*)action;
571
}
572
for(type=0; name=discnames[type]; type++)
573
{
574
if(strcmp(event,name)==0)
575
break;
576
}
577
if(getname)
578
{
579
event = 0;
580
if(name && !(name = discnames[++type]))
581
action = 0;
582
}
583
if(!name)
584
return(nv_setdisc(np,event,action,fp));
585
else if(getname)
586
return((char*)name);
587
/* Handle the disciplines */
588
if(action==np)
589
action = vp->bltins[type];
590
else if(action)
591
{
592
Namval_t *tp = nv_type(np);
593
if(tp && (np = (Namval_t*)vp->bltins[type]) && nv_isattr(np,NV_STATICF))
594
errormsg(SH_DICT,ERROR_exit(1),e_staticfun,name,tp->nvname);
595
vp->bltins[type] = action;
596
}
597
else
598
{
599
action = vp->bltins[type];
600
vp->bltins[type] = 0;
601
}
602
return(action?(char*)action:"");
603
}
604
605
static void putdisc(Namval_t* np, const char* val, int flag, Namfun_t* fp)
606
{
607
nv_putv(np,val,flag,fp);
608
if(!val && !(flag&NV_NOFREE))
609
{
610
register Nambfun_t *vp = (Nambfun_t*)fp;
611
register int i;
612
for(i=0; vp->bnames[i]; i++)
613
{
614
register Namval_t *mp;
615
if((mp=vp->bltins[i]) && !nv_isattr(mp,NV_NOFREE))
616
{
617
if(is_abuiltin(mp))
618
{
619
if(mp->nvfun && !nv_isattr(mp,NV_NOFREE))
620
free((void*)mp->nvfun);
621
dtdelete(sh.bltin_tree,mp);
622
free((void*)mp);
623
}
624
}
625
}
626
nv_disc(np,fp,NV_POP);
627
if(!(fp->nofree&1))
628
free((void*)fp);
629
630
}
631
}
632
633
static const Namdisc_t Nv_bdisc = { 0, putdisc, 0, 0, setdisc };
634
635
Namfun_t *nv_clone_disc(register Namfun_t *fp, int flags)
636
{
637
register Namfun_t *nfp;
638
register int size;
639
if(!fp->disc && !fp->next && (fp->nofree&1))
640
return(fp);
641
if(!(size=fp->dsize) && (!fp->disc || !(size=fp->disc->dsize)))
642
size = sizeof(Namfun_t);
643
if(!(nfp=newof(NIL(Namfun_t*),Namfun_t,1,size-sizeof(Namfun_t))))
644
return(0);
645
memcpy(nfp,fp,size);
646
nfp->nofree &= ~1;
647
nfp->nofree |= (flags&NV_RDONLY)?1:0;
648
return(nfp);
649
}
650
651
int nv_adddisc(Namval_t *np, const char **names, Namval_t **funs)
652
{
653
register Nambfun_t *vp;
654
register int n=0;
655
register const char **av=names;
656
if(av)
657
{
658
while(*av++)
659
n++;
660
}
661
if(!(vp = newof(NIL(Nambfun_t*),Nambfun_t,1,n*sizeof(Namval_t*))))
662
return(0);
663
vp->fun.dsize = sizeof(Nambfun_t)+n*sizeof(Namval_t*);
664
vp->fun.nofree |= 2;
665
vp->num = n;
666
if(funs)
667
memcpy((void*)vp->bltins, (void*)funs,n*sizeof(Namval_t*));
668
else while(n>=0)
669
vp->bltins[n--] = 0;
670
vp->fun.disc = &Nv_bdisc;
671
vp->bnames = names;
672
nv_stack(np,&vp->fun);
673
return(1);
674
}
675
676
/*
677
* push, pop, clne, or reorder disciplines onto node <np>
678
* mode can be one of
679
* NV_FIRST: Move or push <fp> to top of the stack or delete top
680
* NV_LAST: Move or push <fp> to bottom of stack or delete last
681
* NV_POP: Delete <fp> from top of the stack
682
* NV_CLONE: Replace fp with a copy created my malloc() and return it
683
*/
684
Namfun_t *nv_disc(register Namval_t *np, register Namfun_t* fp, int mode)
685
{
686
Namfun_t *lp, **lpp;
687
if(nv_isref(np))
688
return(0);
689
if(mode==NV_CLONE && !fp)
690
return(0);
691
if(fp)
692
{
693
fp->subshell = sh.subshell;
694
if((lp=np->nvfun)==fp)
695
{
696
if(mode==NV_CLONE)
697
{
698
lp = nv_clone_disc(fp,0);
699
return(np->nvfun=lp);
700
}
701
if(mode==NV_FIRST || mode==0)
702
return(fp);
703
np->nvfun = lp->next;
704
if(mode==NV_POP)
705
return(fp);
706
if(mode==NV_LAST && (lp->next==0 || lp->next->disc==0))
707
return(fp);
708
}
709
/* see if <fp> is on the list already */
710
lpp = &np->nvfun;
711
if(lp)
712
{
713
while(lp->next && lp->next->disc)
714
{
715
if(lp->next==fp)
716
{
717
if(mode==NV_LAST && fp->next==0)
718
return(fp);
719
if(mode==NV_CLONE)
720
{
721
fp = nv_clone_disc(fp,0);
722
lp->next = fp;
723
return(fp);
724
}
725
lp->next = fp->next;
726
if(mode==NV_POP)
727
return(fp);
728
if(mode!=NV_LAST)
729
break;
730
}
731
lp = lp->next;
732
}
733
if(mode==NV_LAST && lp->disc)
734
lpp = &lp->next;
735
}
736
if(mode==NV_POP)
737
return(0);
738
/* push */
739
nv_offattr(np,NV_NODISC);
740
if(mode==NV_LAST)
741
{
742
if(lp && !lp->disc)
743
fp->next = lp;
744
else
745
fp->next = 0;
746
}
747
else
748
{
749
if((fp->nofree&1) && *lpp)
750
fp = nv_clone_disc(fp,0);
751
fp->next = *lpp;
752
}
753
*lpp = fp;
754
}
755
else
756
{
757
if(mode==NV_FIRST)
758
return(np->nvfun);
759
else if(mode==NV_LAST)
760
for(lp=np->nvfun; lp; fp=lp,lp=lp->next);
761
else if(fp = np->nvfun)
762
np->nvfun = fp->next;
763
}
764
return(fp);
765
}
766
767
/*
768
* returns discipline pointer if discipline with specified functions
769
* is on the discipline stack
770
*/
771
Namfun_t *nv_hasdisc(Namval_t *np, const Namdisc_t *dp)
772
{
773
register Namfun_t *fp;
774
for(fp=np->nvfun; fp; fp = fp->next)
775
{
776
if(fp->disc== dp)
777
return(fp);
778
}
779
return(0);
780
}
781
782
struct notify
783
{
784
Namfun_t hdr;
785
char **ptr;
786
};
787
788
static void put_notify(Namval_t* np,const char *val,int flags,Namfun_t *fp)
789
{
790
struct notify *pp = (struct notify*)fp;
791
nv_putv(np,val,flags,fp);
792
nv_stack(np,fp);
793
nv_stack(np,(Namfun_t*)0);
794
*pp->ptr = 0;
795
if(!(fp->nofree&1))
796
free((void*)fp);
797
}
798
799
static const Namdisc_t notify_disc = { 0, put_notify };
800
801
int nv_unsetnotify(Namval_t *np, char **addr)
802
{
803
register Namfun_t *fp;
804
for(fp=np->nvfun;fp;fp=fp->next)
805
{
806
if(fp->disc->putval==put_notify && ((struct notify*)fp)->ptr==addr)
807
{
808
nv_stack(np,fp);
809
nv_stack(np,(Namfun_t*)0);
810
if(!(fp->nofree&1))
811
free((void*)fp);
812
return(1);
813
}
814
}
815
return(0);
816
}
817
818
int nv_setnotify(Namval_t *np, char **addr)
819
{
820
struct notify *pp = newof(0,struct notify, 1,0);
821
if(!pp)
822
return(0);
823
pp->ptr = addr;
824
pp->hdr.disc = &notify_disc;
825
nv_stack(np,&pp->hdr);
826
return(1);
827
}
828
829
static void *newnode(const char *name)
830
{
831
register int s;
832
register Namval_t *np = newof(0,Namval_t,1,s=strlen(name)+1);
833
if(np)
834
{
835
np->nvname = (char*)np+sizeof(Namval_t);
836
memcpy(np->nvname,name,s);
837
}
838
return((void*)np);
839
}
840
841
/*
842
* clone a numeric value
843
*/
844
static void *num_clone(register Namval_t *np, void *val)
845
{
846
register int size;
847
void *nval;
848
if(!val)
849
return(0);
850
if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
851
{
852
if(nv_isattr(np,NV_LONG))
853
size = sizeof(Sfdouble_t);
854
else if(nv_isattr(np,NV_SHORT))
855
size = sizeof(float);
856
else
857
size = sizeof(double);
858
}
859
else
860
{
861
if(nv_isattr(np,NV_LONG))
862
size = sizeof(Sflong_t);
863
else if(nv_isattr(np,NV_SHORT))
864
{
865
if(nv_isattr(np,NV_INT16P)==NV_INT16P)
866
size = sizeof(short);
867
else
868
return((void*)np->nvalue.ip);
869
}
870
else
871
size = sizeof(int32_t);
872
}
873
if(!(nval = malloc(size)))
874
return(0);
875
memcpy(nval,val,size);
876
return(nval);
877
}
878
879
void clone_all_disc( Namval_t *np, Namval_t *mp, int flags)
880
{
881
register Namfun_t *fp, **mfp = &mp->nvfun, *nfp, *fpnext;
882
for(fp=np->nvfun; fp;fp=fpnext)
883
{
884
fpnext = fp->next;
885
if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
886
return;
887
if((fp->nofree&2) && (flags&NV_NODISC))
888
nfp = 0;
889
if(fp->disc && fp->disc->clonef)
890
nfp = (*fp->disc->clonef)(np,mp,flags,fp);
891
else if(flags&NV_MOVE)
892
nfp = fp;
893
else
894
nfp = nv_clone_disc(fp,flags);
895
if(!nfp)
896
continue;
897
nfp->next = 0;
898
*mfp = nfp;
899
mfp = &nfp->next;
900
}
901
}
902
903
/*
904
* clone <mp> from <np> flags can be one of the following
905
* NV_APPEND - append <np> onto <mp>
906
* NV_MOVE - move <np> to <mp>
907
* NV_NOFREE - mark the new node as nofree
908
* NV_NODISC - discplines with funs non-zero will not be copied
909
* NV_COMVAR - cloning a compound variable
910
*/
911
int nv_clone(Namval_t *np, Namval_t *mp, int flags)
912
{
913
Namfun_t *fp, *fpnext;
914
const char *val = mp->nvalue.cp;
915
unsigned short flag = mp->nvflag;
916
unsigned short size = mp->nvsize;
917
for(fp=mp->nvfun; fp; fp=fpnext)
918
{
919
fpnext = fp->next;
920
if(!fpnext && (flags&NV_COMVAR) && fp->disc && fp->disc->namef)
921
break;
922
if(!(fp->nofree&1))
923
free((void*)fp);
924
}
925
mp->nvfun = fp;
926
if(fp=np->nvfun)
927
{
928
if(nv_isattr(mp,NV_EXPORT|NV_MINIMAL) == (NV_EXPORT|NV_MINIMAL))
929
{
930
mp->nvenv = 0;
931
nv_offattr(mp,NV_MINIMAL);
932
}
933
if(!(flags&NV_COMVAR) && !nv_isattr(np,NV_MINIMAL) && np->nvenv && !(nv_isattr(mp,NV_MINIMAL)))
934
mp->nvenv = np->nvenv;
935
mp->nvflag &= NV_MINIMAL;
936
mp->nvflag |= np->nvflag&~(NV_ARRAY|NV_MINIMAL|NV_NOFREE);
937
flag = mp->nvflag;
938
clone_all_disc(np, mp, flags);
939
}
940
if(flags&NV_APPEND)
941
return(1);
942
if(mp->nvsize == size)
943
nv_setsize(mp,nv_size(np));
944
if(mp->nvflag == flag)
945
mp->nvflag = (np->nvflag&~(NV_MINIMAL))|(mp->nvflag&NV_MINIMAL);
946
if(nv_isattr(np,NV_EXPORT))
947
mp->nvflag |= (np->nvflag&NV_MINIMAL);
948
if(mp->nvalue.cp==val && !nv_isattr(np,NV_INTEGER))
949
{
950
if(np->nvalue.cp && np->nvalue.cp!=Empty && (flags&NV_COMVAR) && !(flags&NV_MOVE))
951
{
952
if(size)
953
mp->nvalue.cp = (char*)memdup(np->nvalue.cp,size);
954
else
955
mp->nvalue.cp = strdup(np->nvalue.cp);
956
nv_offattr(mp,NV_NOFREE);
957
}
958
else if((np->nvfun || !nv_isattr(np,NV_ARRAY)) && !(mp->nvalue.cp = np->nvalue.cp))
959
nv_offattr(mp,NV_NOFREE);
960
}
961
if(flags&NV_MOVE)
962
{
963
if(nv_isattr(np,NV_INTEGER))
964
mp->nvalue.ip = np->nvalue.ip;
965
np->nvfun = 0;
966
np->nvalue.cp = 0;
967
if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(mp,NV_EXPORT))
968
{
969
mp->nvenv = np->nvenv;
970
if(nv_isattr(np,NV_MINIMAL))
971
{
972
np->nvenv = 0;
973
np->nvflag = NV_EXPORT;
974
}
975
else
976
np->nvflag = 0;
977
}
978
else
979
np->nvflag &= NV_MINIMAL;
980
nv_setsize(np,0);
981
return(1);
982
}
983
else if((flags&NV_ARRAY) && !nv_isattr(np,NV_MINIMAL))
984
mp->nvenv = np->nvenv;
985
if(nv_isattr(np,NV_INTEGER) && mp->nvalue.ip!=np->nvalue.ip && np->nvalue.cp!=Empty)
986
{
987
mp->nvalue.ip = (int*)num_clone(np,(void*)np->nvalue.ip);
988
nv_offattr(mp,NV_NOFREE);
989
}
990
else if((flags&NV_NOFREE) && !nv_arrayptr(np))
991
nv_onattr(np,NV_NOFREE);
992
return(1);
993
}
994
995
/*
996
* The following discipline is for copy-on-write semantics
997
*/
998
static char* clone_getv(Namval_t *np, Namfun_t *handle)
999
{
1000
return(np->nvalue.np?nv_getval(np->nvalue.np):0);
1001
}
1002
1003
static Sfdouble_t clone_getn(Namval_t *np, Namfun_t *handle)
1004
{
1005
return(np->nvalue.np?nv_getnum(np->nvalue.np):0);
1006
}
1007
1008
static void clone_putv(Namval_t *np,const char* val,int flags,Namfun_t *handle)
1009
{
1010
Namfun_t *dp = nv_stack(np,(Namfun_t*)0);
1011
Namval_t *mp = np->nvalue.np;
1012
if(!sh.subshell)
1013
free((void*)dp);
1014
if(val)
1015
nv_clone(mp,np,NV_NOFREE);
1016
np->nvalue.cp = 0;
1017
nv_putval(np,val,flags);
1018
}
1019
1020
static const Namdisc_t clone_disc =
1021
{
1022
0,
1023
clone_putv,
1024
clone_getv,
1025
clone_getn
1026
};
1027
1028
Namval_t *nv_mkclone(Namval_t *mp)
1029
{
1030
Namval_t *np;
1031
Namfun_t *dp;
1032
np = newof(0,Namval_t,1,0);
1033
np->nvflag = mp->nvflag;
1034
np->nvsize = mp->nvsize;
1035
np->nvname = mp->nvname;
1036
np->nvalue.np = mp;
1037
np->nvflag = mp->nvflag;
1038
dp = newof(0,Namfun_t,1,0);
1039
dp->disc = &clone_disc;
1040
nv_stack(np,dp);
1041
dtinsert(nv_dict(sh.namespace),np);
1042
return(np);
1043
}
1044
1045
Namval_t *nv_search(const char *name, Dt_t *root, int mode)
1046
{
1047
register Namval_t *np;
1048
register Dt_t *dp = 0;
1049
if(mode&HASH_NOSCOPE)
1050
dp = dtview(root,0);
1051
if(mode&HASH_BUCKET)
1052
{
1053
Namval_t *mp = (void*)name;
1054
if(!(np = dtsearch(root,mp)) && (mode&NV_ADD))
1055
name = nv_name(mp);
1056
}
1057
else
1058
{
1059
if(*name=='.' && root==sh.var_tree && !dp)
1060
root = sh.var_base;
1061
np = dtmatch(root,(void*)name);
1062
}
1063
#if SHOPT_COSHELL
1064
if(sh.inpool)
1065
mode |= HASH_NOSCOPE;
1066
#endif /* SHOPT_COSHELL */
1067
if(!np && (mode&NV_ADD))
1068
{
1069
if(sh.namespace && !(mode&HASH_NOSCOPE) && root==sh.var_tree)
1070
root = nv_dict(sh.namespace);
1071
else if(!dp && !(mode&HASH_NOSCOPE))
1072
{
1073
register Dt_t *next;
1074
while(next=dtvnext(root))
1075
root = next;
1076
}
1077
np = (Namval_t*)dtinsert(root,newnode(name));
1078
}
1079
if(dp)
1080
dtview(root,dp);
1081
return(np);
1082
}
1083
1084
/*
1085
* finds function or builtin for given name and the discipline variable
1086
* if var!=0 the variable pointer is returned and the built-in name
1087
* is put onto the stack at the current offset.
1088
* otherwise, a pointer to the builtin (variable or type) is returned
1089
* and var contains the poiner to the variable
1090
* if last==0 and first component of name is a reference, nv_bfsearch()
1091
will return 0.
1092
*/
1093
Namval_t *nv_bfsearch(const char *name, Dt_t *root, Namval_t **var, char **last)
1094
{
1095
Shell_t *shp = sh_getinterp();
1096
int c,offset = staktell();
1097
register char *sp, *cp=0;
1098
Namval_t *np, *nq;
1099
char *dname=0;
1100
if(var)
1101
*var = 0;
1102
/* check for . in the name before = */
1103
for(sp=(char*)name+1; *sp; sp++)
1104
{
1105
if(*sp=='=')
1106
return(0);
1107
if(*sp=='[')
1108
{
1109
while(*sp=='[')
1110
{
1111
sp = nv_endsubscript((Namval_t*)0,(char*)sp,0);
1112
if(sp[-1]!=']')
1113
return(0);
1114
}
1115
if(*sp==0)
1116
break;
1117
if(*sp!='.')
1118
return(0);
1119
cp = sp;
1120
}
1121
else if(*sp=='.')
1122
cp = sp;
1123
}
1124
if(!cp)
1125
return(var?nv_search(name,root,0):0);
1126
stakputs(name);
1127
stakputc(0);
1128
dname = cp+1;
1129
cp = stakptr(offset) + (cp-name);
1130
if(last)
1131
*last = cp;
1132
c = *cp;
1133
*cp = 0;
1134
nq=nv_open(stakptr(offset),0,NV_VARNAME|NV_NOASSIGN|NV_NOADD|NV_NOFAIL);
1135
*cp = c;
1136
if(!nq)
1137
{
1138
np = 0;
1139
goto done;
1140
}
1141
if(!var)
1142
{
1143
np = nq;
1144
goto done;
1145
}
1146
*var = nq;
1147
if(c=='[')
1148
nv_endsubscript(nq, cp,NV_NOADD);
1149
stakseek(offset);
1150
#if SHOPT_NAMESPACE
1151
if(nv_istable(nq))
1152
{
1153
Namval_t *nsp = shp->namespace;
1154
if(last==0)
1155
return(nv_search(name,root,0));
1156
shp->namespace = 0;
1157
stakputs(nv_name(nq));
1158
shp->namespace = nsp;
1159
stakputs(dname-1);
1160
stakputc(0);
1161
np = nv_search(stakptr(offset),root,0);
1162
stakseek(offset);
1163
return(np);
1164
}
1165
#endif /* SHOPT_NAMESPACE */
1166
while(nv_isarray(nq) && !nv_isattr(nq,NV_MINIMAL|NV_EXPORT) && nq->nvenv && nv_isarray((Namval_t*)nq->nvenv))
1167
nq = (Namval_t*)nq->nvenv;
1168
return((Namval_t*)nv_setdisc(nq,dname,nq,(Namfun_t*)nq));
1169
done:
1170
stakseek(offset);
1171
return(np);
1172
}
1173
1174
/*
1175
* add or replace built-in version of command corresponding to <path>
1176
* The <bltin> argument is a pointer to the built-in
1177
* if <extra>==1, the built-in will be deleted
1178
* Special builtins cannot be added or deleted return failure
1179
* The return value for adding builtins is a pointer to the node or NULL on
1180
* failure. For delete NULL means success and the node that cannot be
1181
* deleted is returned on failure.
1182
*/
1183
Namval_t *sh_addbuiltin(const char *path, Shbltin_f bltin, void *extra)
1184
{
1185
register const char *name;
1186
char *cp;
1187
register Namval_t *np, *nq=0;
1188
int offset=staktell();
1189
if(extra==(void*)1)
1190
name = path;
1191
else if((name = path_basename(path))==path && bltin!=(Shbltin_f)SYSTYPESET->nvalue.bfp && (nq=nv_bfsearch(name,sh.bltin_tree,(Namval_t**)0,&cp)))
1192
path = name = stakptr(offset);
1193
else if(sh.bltin_dir && extra!=(void*)1)
1194
{
1195
stakputs(sh.bltin_dir);
1196
stakputc('/');
1197
stakputs(name);
1198
path = stakptr(offset);
1199
}
1200
if(np = nv_search(name,sh.bltin_tree,0))
1201
{
1202
/* exists without a path */
1203
stakseek(offset);
1204
if(extra == (void*)1)
1205
{
1206
if(np->nvfun && !nv_isattr(np,NV_NOFREE))
1207
free((void*)np->nvfun);
1208
dtdelete(sh.bltin_tree,np);
1209
return(0);
1210
}
1211
if(!bltin)
1212
return(np);
1213
}
1214
else for(np=(Namval_t*)dtfirst(sh.bltin_tree);np;np=(Namval_t*)dtnext(sh.bltin_tree,np))
1215
{
1216
if(strcmp(name,path_basename(nv_name(np))))
1217
continue;
1218
/* exists probably with different path so delete it */
1219
if(strcmp(path,nv_name(np)))
1220
{
1221
if(nv_isattr(np,BLT_SPC))
1222
return(np);
1223
if(!bltin)
1224
bltin = (Shbltin_f)np->nvalue.bfp;
1225
if(np->nvenv)
1226
dtdelete(sh.bltin_tree,np);
1227
if(extra == (void*)1)
1228
return(0);
1229
np = 0;
1230
}
1231
break;
1232
}
1233
if(!np && !(np = nv_search(path,sh.bltin_tree,bltin?NV_ADD:0)))
1234
return(0);
1235
stakseek(offset);
1236
if(nv_isattr(np,BLT_SPC))
1237
{
1238
if(extra)
1239
np->nvfun = (Namfun_t*)extra;
1240
return(np);
1241
}
1242
np->nvenv = 0;
1243
np->nvfun = 0;
1244
if(bltin)
1245
{
1246
np->nvalue.bfp = (Nambfp_f)bltin;
1247
nv_onattr(np,NV_BLTIN|NV_NOFREE);
1248
np->nvfun = (Namfun_t*)extra;
1249
}
1250
if(nq)
1251
{
1252
cp=nv_setdisc(nq,cp+1,np,(Namfun_t*)nq);
1253
nv_close(nq);
1254
if(!cp)
1255
errormsg(SH_DICT,ERROR_exit(1),e_baddisc,name);
1256
}
1257
if(extra == (void*)1)
1258
return(0);
1259
return(np);
1260
}
1261
1262
#undef nv_stack
1263
extern Namfun_t *nv_stack(register Namval_t *np, register Namfun_t* fp)
1264
{
1265
return(nv_disc(np,fp,0));
1266
}
1267
1268
struct table
1269
{
1270
Namfun_t fun;
1271
Namval_t *parent;
1272
Shell_t *shp;
1273
Dt_t *dict;
1274
};
1275
1276
static Namval_t *next_table(register Namval_t* np, Dt_t *root,Namfun_t *fp)
1277
{
1278
struct table *tp = (struct table *)fp;
1279
if(root)
1280
return((Namval_t*)dtnext(root,np));
1281
else
1282
return((Namval_t*)dtfirst(tp->dict));
1283
}
1284
1285
static Namval_t *create_table(Namval_t *np,const char *name,int flags,Namfun_t *fp)
1286
{
1287
struct table *tp = (struct table *)fp;
1288
tp->shp->last_table = np;
1289
return(nv_create(name, tp->dict, flags, fp));
1290
}
1291
1292
static Namfun_t *clone_table(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
1293
{
1294
struct table *tp = (struct table*)fp;
1295
struct table *ntp = (struct table*)nv_clone_disc(fp,0);
1296
Dt_t *oroot=tp->dict,*nroot=dtopen(&_Nvdisc,Dtoset);
1297
if(!nroot)
1298
return(0);
1299
memcpy((void*)ntp,(void*)fp,sizeof(struct table));
1300
ntp->dict = nroot;
1301
ntp->parent = nv_lastdict();
1302
for(np=(Namval_t*)dtfirst(oroot);np;np=(Namval_t*)dtnext(oroot,np))
1303
{
1304
mp = (Namval_t*)dtinsert(nroot,newnode(np->nvname));
1305
nv_clone(np,mp,flags);
1306
}
1307
return(&ntp->fun);
1308
}
1309
1310
struct adata
1311
{
1312
Shell_t *sh;
1313
Namval_t *tp;
1314
char *mapname;
1315
char **argnam;
1316
int attsize;
1317
char *attval;
1318
};
1319
1320
static void delete_fun(Namval_t *np, void *data)
1321
{
1322
Shell_t *shp = ((struct adata*)data)->sh;
1323
nv_delete(np,shp->fun_tree,NV_NOFREE);
1324
}
1325
1326
static void put_table(register Namval_t* np, const char* val, int flags, Namfun_t* fp)
1327
{
1328
register Dt_t *root = ((struct table*)fp)->dict;
1329
register Namval_t *nq, *mp;
1330
Namarr_t *ap;
1331
struct adata data;
1332
if(val)
1333
{
1334
nv_putv(np,val,flags,fp);
1335
return;
1336
}
1337
if(nv_isarray(np) && (ap=nv_arrayptr(np)) && array_elem(ap))
1338
return;
1339
memset(&data,0,sizeof(data));
1340
data.mapname = nv_name(np);
1341
data.sh = ((struct table*)fp)->shp;
1342
nv_scan(data.sh->fun_tree,delete_fun,(void*)&data,NV_FUNCTION,NV_FUNCTION|NV_NOSCOPE);
1343
dtview(root,0);
1344
for(mp=(Namval_t*)dtfirst(root);mp;mp=nq)
1345
{
1346
_nv_unset(mp,flags);
1347
nq = (Namval_t*)dtnext(root,mp);
1348
dtdelete(root,mp);
1349
free((void*)mp);
1350
}
1351
dtclose(root);
1352
if(!(fp->nofree&1))
1353
free((void*)fp);
1354
np->nvfun = 0;
1355
}
1356
1357
/*
1358
* return space separated list of names of variables in given tree
1359
*/
1360
static char *get_table(Namval_t *np, Namfun_t *fp)
1361
{
1362
register Dt_t *root = ((struct table*)fp)->dict;
1363
static Sfio_t *out;
1364
register int first=1;
1365
register Dt_t *base = dtview(root,0);
1366
if(out)
1367
sfseek(out,(Sfoff_t)0,SEEK_SET);
1368
else
1369
out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
1370
for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
1371
{
1372
if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
1373
{
1374
if(!first)
1375
sfputc(out,' ');
1376
else
1377
first = 0;
1378
sfputr(out,np->nvname,-1);
1379
}
1380
}
1381
sfputc(out,0);
1382
if(base)
1383
dtview(root,base);
1384
return((char*)out->_data);
1385
}
1386
1387
static const Namdisc_t table_disc =
1388
{
1389
sizeof(struct table),
1390
put_table,
1391
get_table,
1392
0,
1393
0,
1394
create_table,
1395
clone_table,
1396
0,
1397
next_table,
1398
};
1399
1400
Namval_t *nv_parent(Namval_t *np)
1401
{
1402
struct table *tp = (struct table *)nv_hasdisc(np,&table_disc);
1403
if(tp)
1404
return(tp->parent);
1405
return(0);
1406
}
1407
1408
Dt_t *nv_dict(Namval_t* np)
1409
{
1410
Shell_t *shp=sh_getinterp();
1411
struct table *tp = (struct table*)nv_hasdisc(np,&table_disc);
1412
if(tp)
1413
return(tp->dict);
1414
np = shp->last_table;
1415
while(np)
1416
{
1417
if(tp = (struct table*)nv_hasdisc(np,&table_disc))
1418
return(tp->dict);
1419
#if 0
1420
np = nv_create(np,(const char*)0, NV_FIRST, (Namfun_t*)0);
1421
#else
1422
break;
1423
#endif
1424
}
1425
return(shp->var_tree);
1426
}
1427
1428
int nv_istable(Namval_t *np)
1429
{
1430
return(nv_hasdisc(np,&table_disc)!=0);
1431
}
1432
1433
/*
1434
* create a mountable name-value pair tree
1435
*/
1436
Namval_t *nv_mount(Namval_t *np, const char *name, Dt_t *dict)
1437
{
1438
Namval_t *mp, *pp;
1439
struct table *tp;
1440
if(nv_hasdisc(np,&table_disc))
1441
pp = np;
1442
else
1443
pp = nv_lastdict();
1444
if(!(tp = newof((struct table*)0, struct table,1,0)))
1445
return(0);
1446
if(name)
1447
{
1448
Namfun_t *fp = pp->nvfun;
1449
mp = (*fp->disc->createf)(pp,name,0,fp);
1450
}
1451
else
1452
mp = np;
1453
nv_offattr(mp,NV_TABLE);
1454
if(!nv_isnull(mp))
1455
_nv_unset(mp,NV_RDONLY);
1456
tp->shp = sh_getinterp();
1457
tp->dict = dict;
1458
tp->parent = pp;
1459
tp->fun.disc = &table_disc;
1460
nv_disc(mp, &tp->fun, NV_FIRST);
1461
return(mp);
1462
}
1463
1464
const Namdisc_t *nv_discfun(int which)
1465
{
1466
switch(which)
1467
{
1468
case NV_DCADD:
1469
return(&Nv_bdisc);
1470
case NV_DCRESTRICT:
1471
return(&RESTRICTED_disc);
1472
}
1473
return(0);
1474
}
1475
1476
int nv_hasget(Namval_t *np)
1477
{
1478
register Namfun_t *fp;
1479
for(fp=np->nvfun; fp; fp=fp->next)
1480
{
1481
if(!fp->disc || (!fp->disc->getnum && !fp->disc->getval))
1482
continue;
1483
return(1);
1484
}
1485
return(0);
1486
}
1487
1488
#if SHOPT_NAMESPACE
1489
Namval_t *sh_fsearch(Shell_t *shp, const char *fname, int add)
1490
{
1491
Stk_t *stkp = shp->stk;
1492
int offset = stktell(stkp);
1493
sfputr(stkp,nv_name(shp->namespace),'.');
1494
sfputr(stkp,fname,0);
1495
fname = stkptr(stkp,offset);
1496
return(nv_search(fname,sh_subfuntree(add&NV_ADD),add));
1497
}
1498
#endif /* SHOPT_NAMESPACE */
1499
1500