1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * David Korn
23 * AT&T Labs
24 *
25 */
26
27 #include "defs.h"
28
29 static const char sh_opttype[] =
30 "[-1c?\n@(#)$Id: type (AT&T Labs Research) 2008-07-01 $\n]"
31 USAGE_LICENSE
32 "[+NAME?\f?\f - set the type of variables to \b\f?\f\b]"
33 "[+DESCRIPTION?\b\f?\f\b sets the type on each of the variables specified "
34 "by \aname\a to \b\f?\f\b. If \b=\b\avalue\a is specified, "
35 "the variable \aname\a is set to \avalue\a before the variable "
36 "is converted to \b\f?\f\b.]"
37 "[+?If no \aname\as are specified then the names and values of all "
38 "variables of this type are written to standard output.]"
39 "[+?\b\f?\f\b is built-in to the shell as a declaration command so that "
40 "field splitting and pathname expansion are not performed on "
41 "the arguments. Tilde expansion occurs on \avalue\a.]"
42 "[r?Enables readonly. Once enabled, the value cannot be changed or unset.]"
43 "[a]:?[type?Indexed array. Each \aname\a will converted to an index "
44 "array of type \b\f?\f\b. If a variable already exists, the current "
45 "value will become index \b0\b. If \b[\b\atype\a\b]]\b is "
46 "specified, each subscript is interpreted as a value of enumeration "
47 "type \atype\a.]"
48 "[A?Associative array. Each \aname\a will converted to an associate "
49 "array of type \b\f?\f\b. If a variable already exists, the current "
50 "value will become subscript \b0\b.]"
51 "[h]:[string?Used within a type definition to provide a help string "
52 "for variable \aname\a. Otherwise, it is ignored.]"
53 "[S?Used with a type definition to indicate that the variable is shared by "
54 "each instance of the type. When used inside a function defined "
55 "with the \bfunction\b reserved word, the specified variables "
56 "will have function static scope. Otherwise, the variable is "
57 "unset prior to processing the assignment list.]"
58 "[+DETAILS]\ftypes\f"
59 "\n"
60 "\n[name[=value]...]\n"
61 "\n"
62 "[+EXIT STATUS?]{"
63 "[+0?Successful completion.]"
64 "[+>0?An error occurred.]"
65 "}"
66
67 "[+SEE ALSO?\fother\f \breadonly\b(1), \btypeset\b(1)]"
68 ;
69
70 typedef struct Namtype Namtype_t;
71 typedef struct Namchld
72 {
73 Namfun_t fun;
74 Namtype_t *ptype;
75 Namtype_t *ttype;
76 } Namchld_t;
77
78 struct Namtype
79 {
80 Namfun_t fun;
81 Shell_t *sh;
82 Namval_t *np;
83 Namval_t *parent;
84 Namval_t *bp;
85 Namval_t *cp;
86 char *nodes;
87 char *data;
88 Namchld_t childfun;
89 int numnodes;
90 char **names;
91 size_t dsize;
92 short strsize;
93 unsigned short ndisc;
94 unsigned short current;
95 unsigned short nref;
96 };
97
98 #if 0
99 struct type
100 {
101 Namtype_t hdr;
102 unsigned short ndisc;
103 unsigned short current;
104 unsigned short nref;
105 };
106 #endif
107
108 typedef struct
109 {
110 char _cSfdouble_t;
111 Sfdouble_t _dSfdouble_t;
112 char _cdouble;
113 double _ddouble;
114 char _cfloat;
115 float _dfloat;
116 char _cSflong_t;
117 Sflong_t _dSflong_t;
118 char _clong;
119 long _dlong;
120 char _cshort;
121 short _dshort;
122 char _cpointer;
123 char *_dpointer;
124 } _Align_;
125
126 #define alignof(t) ((char*)&((_Align_*)0)->_d##t-(char*)&((_Align_*)0)->_c##t)
127
128 static void put_type(Namval_t*, const char*, int, Namfun_t*);
129 static Namval_t* create_type(Namval_t*, const char*, int, Namfun_t*);
130 static Namfun_t* clone_type(Namval_t*, Namval_t*, int, Namfun_t*);
131 static Namval_t* next_type(Namval_t*, Dt_t*, Namfun_t*);
132
133 static const Namdisc_t type_disc =
134 {
135 sizeof(Namtype_t),
136 put_type,
137 0,
138 0,
139 0,
140 create_type,
141 clone_type,
142 0,
143 next_type,
144 0,
145 #if 0
146 read_type
147 #endif
148 };
149
datasize(Namval_t * np,size_t * offset)150 static size_t datasize(Namval_t *np, size_t *offset)
151 {
152 size_t s=0, a=0;
153 Namarr_t *ap;
154 if(nv_isattr(np,NV_INTEGER))
155 {
156 if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
157 {
158 if(nv_isattr(np, NV_LONG))
159 {
160 a = alignof(Sfdouble_t);
161 s = sizeof(Sfdouble_t);
162 }
163 else if(nv_isattr(np, NV_SHORT))
164 {
165 a = alignof(float);
166 s = sizeof(float);
167 }
168 else
169 {
170 a = alignof(double);
171 s = sizeof(double);
172 }
173 }
174 else
175 {
176 if(nv_isattr(np, NV_LONG))
177 {
178 a = alignof(Sflong_t);
179 s = sizeof(Sflong_t);
180 }
181 else if(nv_isattr(np, NV_SHORT))
182 {
183 a = alignof(short);
184 s = sizeof(short);
185 }
186 else
187 {
188 a = alignof(long);
189 s = sizeof(long);
190 }
191 }
192 }
193 else if(nv_isattr(np, NV_BINARY) || nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
194 s = nv_size(np);
195 else
196 {
197 a = alignof(pointer);
198 s = nv_size(np);
199 }
200 if(a>1 && offset)
201 *offset = a*((*offset +a-1)/a);
202 if(nv_isarray(np) && (ap = nv_arrayptr(np)))
203 s *= array_elem(ap);
204 return(s);
205 }
206
name_chtype(Namval_t * np,Namfun_t * fp)207 static char *name_chtype(Namval_t *np, Namfun_t *fp)
208 {
209 Namchld_t *pp = (Namchld_t*)fp;
210 char *cp, *sub;
211 Namval_t *tp = sh.last_table;
212 Namval_t *nq = pp->ptype->np;
213 Namarr_t *ap;
214 if(nv_isattr(np,NV_REF|NV_TAGGED)==(NV_REF|NV_TAGGED))
215 sh.last_table = 0;
216 cp = nv_name(nq);
217 if((ap = nv_arrayptr(nq)) && !(ap->nelem&ARRAY_UNDEF) && (sub= nv_getsub(nq)))
218 sfprintf(sh.strbuf,"%s[%s].%s",cp,sub,np->nvname);
219 else
220 sfprintf(sh.strbuf,"%s.%s",cp,np->nvname);
221 sh.last_table = tp;
222 return(sfstruse(sh.strbuf));
223 }
224
put_chtype(Namval_t * np,const char * val,int flag,Namfun_t * fp)225 static void put_chtype(Namval_t* np, const char* val, int flag, Namfun_t* fp)
226 {
227 if(!val && nv_isattr(np,NV_REF))
228 return;
229 nv_putv(np,val,flag,fp);
230 if(!val)
231 {
232 Namchld_t *pp = (Namchld_t*)fp;
233 size_t dsize=0,offset = (char*)np-(char*)pp->ptype;
234 Namval_t *mp = (Namval_t*)((char*)pp->ttype+offset);
235 dsize = datasize(mp,&dsize);
236 if(mp->nvalue.cp >= pp->ttype->data && mp->nvalue.cp < (char*)pp+pp->ttype->fun.dsize)
237 {
238 np->nvalue.cp = pp->ptype->data + (mp->nvalue.cp-pp->ptype->data);
239 memcpy((char*)np->nvalue.cp,mp->nvalue.cp,dsize);
240 }
241 else if(!nv_isarray(mp) && mp->nvalue.cp)
242 {
243 np->nvalue.cp = mp->nvalue.cp;
244 nv_onattr(np,NV_NOFREE);
245 }
246 np->nvsize = mp->nvsize;
247 np->nvflag = mp->nvflag&~NV_RDONLY;
248 }
249 }
250
clone_chtype(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)251 static Namfun_t *clone_chtype(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
252 {
253 if(flags&NV_NODISC)
254 return(0);
255 return(nv_clone_disc(fp,flags));
256 }
257
258 static const Namdisc_t chtype_disc =
259 {
260 sizeof(Namchld_t),
261 put_chtype,
262 0,
263 0,
264 0,
265 0,
266 clone_chtype,
267 name_chtype
268 };
269
findref(void * nodes,int n)270 static Namval_t *findref(void *nodes, int n)
271 {
272 Namval_t *tp,*np = nv_namptr(nodes,n);
273 char *name = np->nvname;
274 int i=n, len= strrchr(name,'.')-name;
275 Namtype_t *pp;
276 while(--i>0)
277 {
278 np = nv_namptr(nodes,i);
279 if(np->nvname[len]==0)
280 {
281 tp = nv_type(np);
282 pp = (Namtype_t*)nv_hasdisc(tp,&type_disc);
283 return(nv_namptr(pp->nodes,n-i-1));
284 }
285 }
286 return(0);
287 }
288
fixnode(Namtype_t * dp,Namtype_t * pp,int i,struct Namref * nrp,int flag)289 static int fixnode(Namtype_t *dp, Namtype_t *pp, int i, struct Namref *nrp,int flag)
290 {
291 Namval_t *nq = nv_namptr(dp->nodes,i);
292 Namfun_t *fp;
293 if(fp=nv_hasdisc(nq,&chtype_disc))
294 nv_disc(nq, fp, NV_POP);
295 if(nv_isattr(nq,NV_REF))
296 {
297 nq->nvalue.nrp = nrp++;
298 nv_setsize(nq,0);
299 if(strchr(nq->nvname,'.'))
300 nq->nvalue.nrp->np = findref(dp->nodes,i);
301 else
302 nq->nvalue.nrp->np = nv_namptr(pp->childfun.ttype->nodes,i);
303 nq->nvalue.nrp->root = sh.last_root;
304 nq->nvalue.nrp->table = pp->np;
305 nq ->nvflag = NV_REF|NV_NOFREE|NV_MINIMAL;
306 return(1);
307 }
308 if(nq->nvalue.cp || nq->nvfun)
309 {
310 const char *data = nq->nvalue.cp;
311 if(nq->nvfun)
312 {
313 Namval_t *np = nv_namptr(pp->nodes,i);
314 if(nv_isarray(nq))
315 nq->nvalue.cp = 0;
316 nq->nvfun = 0;
317 if(nv_isarray(nq) && nv_type(np))
318 clone_all_disc(np,nq,flag&~NV_TYPE);
319 else
320 clone_all_disc(np,nq,flag);
321 if(fp)
322 nv_disc(np, fp, NV_LAST);
323 }
324 #if 0
325 if(nq->nvalue.cp >= pp->data && nq->nvalue.cp < (char*)pp +pp->fun.dsize)
326 nq->nvalue.cp = dp->data + (nq->nvalue.cp-pp->data);
327 #else
328 if(data >= pp->data && data < (char*)pp +pp->fun.dsize)
329 nq->nvalue.cp = dp->data + (data-pp->data);
330 #endif
331 else if(!nq->nvfun && pp->childfun.ttype!=pp->childfun.ptype)
332 {
333 Namval_t *nr = nv_namptr( pp->childfun.ttype->nodes,i);
334 if(nr->nvalue.cp!=nq->nvalue.cp)
335 {
336 if(i=nv_size(nq))
337 {
338 const char *cp = nq->nvalue.cp;
339 nq->nvalue.cp = (char*)malloc(i);
340 memcpy((char*)nq->nvalue.cp,cp,i);
341 }
342 else
343 nq->nvalue.cp = strdup(nq->nvalue.cp);
344 nv_offattr(nq,NV_NOFREE);
345 }
346 }
347
348 }
349 if(fp)
350 nv_disc(nq, &dp->childfun.fun, NV_LAST);
351 return(0);
352 }
353
clone_type(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)354 static Namfun_t *clone_type(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
355 {
356 Namtype_t *dp, *pp=(Namtype_t*)fp;
357 register int i;
358 register Namval_t *nq, *nr;
359 size_t size = fp->dsize;
360 int save, offset=staktell();
361 char *cp;
362 Dt_t *root = sh.last_root;
363 Namval_t *last_table = sh.last_table;
364 struct Namref *nrp = 0;
365 Namarr_t *ap;
366 if(flags&NV_MOVE)
367 {
368 pp->np = mp;
369 pp->childfun.ptype = pp;
370 return(fp);
371 }
372 if(flags&NV_TYPE)
373 return(nv_clone_disc(fp,flags));
374 if(size==0 && (!fp->disc || (size=fp->disc->dsize)==0))
375 size = sizeof(Namfun_t);
376 dp = (Namtype_t*)malloc(size+pp->nref*sizeof(struct Namref));
377 if(pp->nref)
378 {
379 nrp = (struct Namref*)((char*)dp + size);
380 memset((void*)nrp,0,pp->nref*sizeof(struct Namref));
381 }
382 memcpy((void*)dp,(void*)pp,size);
383 #if 0
384 dp->parent = nv_lastdict();
385 #else
386 dp->parent = mp;
387 #endif
388 dp->fun.nofree = (flags&NV_RDONLY?1:0);
389 dp->np = mp;
390 dp->childfun.ptype = dp;
391 #if 0
392 dp->childfun.ttype = (Namtype_t*)nv_hasdisc(dp->fun.type,&type_disc);
393 #endif
394 dp->nodes = (char*)(dp+1);
395 dp->data = (char*)dp + (pp->data - (char*)pp);
396 for(i=dp->numnodes; --i >= 0; )
397 {
398 nq = nv_namptr(dp->nodes,i);
399 if(fixnode(dp,pp,i,nrp,NV_TYPE))
400 {
401 nrp++;
402 nq = nq->nvalue.nrp->np;
403 }
404 if(nq->nvalue.cp || !nv_isvtree(nq) || nv_isattr(nq,NV_RDONLY))
405 {
406 /* see if default value has been overwritten */
407 if(!mp->nvname)
408 continue;
409 sh.last_table = last_table;
410 if(pp->strsize<0)
411 cp = nv_name(np);
412 else
413 cp = nv_name(mp);
414 stakputs(cp);
415 stakputc('.');
416 stakputs(nq->nvname);
417 stakputc(0);
418 root = nv_dict(mp);
419 save = fp->nofree;
420 fp->nofree = 1;
421 nr = nv_create(stakptr(offset),root,NV_VARNAME|NV_NOADD,fp);
422 fp->nofree = save;
423 stakseek(offset);
424 if(nr)
425 {
426 if(nv_isattr(nq,NV_RDONLY) && (nq->nvalue.cp || nv_isattr(nq,NV_INTEGER)))
427 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nq->nvname);
428 if(nv_isref(nq))
429 nq = nv_refnode(nq);
430 if((size = datasize(nr,(size_t*)0)) && size==datasize(nq,(size_t*)0))
431 memcpy((char*)nq->nvalue.cp,nr->nvalue.cp,size);
432 else if(ap=nv_arrayptr(nr))
433 {
434 nv_putsub(nr,NIL(char*),ARRAY_SCAN|ARRAY_NOSCOPE);
435 do
436 {
437 if(array_assoc(ap))
438 cp = (char*)((*ap->fun)(nr,NIL(char*),NV_ANAME));
439 else
440 cp = nv_getsub(nr);
441 nv_putsub(nq,cp,ARRAY_ADD|ARRAY_NOSCOPE);
442 if(array_assoc(ap))
443 {
444 Namval_t *mp = (Namval_t*)((*ap->fun)(nr,NIL(char*),NV_ACURRENT));
445 Namval_t *mq = (Namval_t*)((*ap->fun)(nq,NIL(char*),NV_ACURRENT));
446 nv_clone(mp,mq,NV_MOVE);
447 ap->nelem--;
448 nv_delete(mp,ap->table,0);
449 }
450 else
451 {
452 cp = nv_getval(nr);
453 nv_putval(nq,cp,0);
454 }
455 }
456 while(nv_nextsub(nr));
457 }
458 else
459 nv_putval(nq,nv_getval(nr),NV_RDONLY);
460 #if SHOPT_TYPEDEF
461 if(sh.mktype)
462 nv_addnode(nr,1);
463 #endif /* SHOPT_TYPEDEF */
464 if(pp->strsize<0)
465 continue;
466 _nv_unset(nr,0);
467 if(!nv_isattr(nr,NV_MINIMAL))
468 nv_delete(nr,sh.last_root,0);
469 }
470 else if(nv_isattr(nq,NV_RDONLY) && !nq->nvalue.cp && !nv_isattr(nq,NV_INTEGER))
471 errormsg(SH_DICT,ERROR_exit(1),e_required,nq->nvname,nv_name(mp));
472 }
473 }
474 if(nv_isattr(mp,NV_BINARY))
475 mp->nvalue.cp = dp->data;
476 if(pp->strsize<0)
477 dp->strsize = -pp->strsize;
478 return(&dp->fun);
479 }
480
481
482 /*
483 * return Namval_t* corresponding to child <name> in <np>
484 */
create_type(Namval_t * np,const char * name,int flag,Namfun_t * fp)485 static Namval_t *create_type(Namval_t *np,const char *name,int flag,Namfun_t *fp)
486 {
487 Namtype_t *dp = (Namtype_t*)fp;
488 register const char *cp=name;
489 register int i=0,n;
490 Namval_t *nq=0;
491 if(!name)
492 return(dp->parent);
493 while((n=*cp++) && n != '=' && n != '+' && n!='[');
494 n = (cp-1) -name;
495 if(dp->numnodes && dp->strsize<0)
496 {
497 char *base = (char*)np-sizeof(Dtlink_t);
498 int m=strlen(np->nvname);
499 while((nq=nv_namptr(base,++i)) && memcmp(nq->nvname,np->nvname,m)==0)
500 {
501 if(nq->nvname[m]=='.' && memcmp(name,&nq->nvname[m+1],n)==0 && nq->nvname[m+n+1]==0)
502 goto found;
503 }
504 nq = 0;
505 }
506 else for(i=0; i < dp->numnodes; i++)
507 {
508 nq = nv_namptr(dp->nodes,i);
509 if((n==0||memcmp(name,nq->nvname,n)==0) && nq->nvname[n]==0)
510 {
511 while(nv_isref(nq))
512 nq = nq->nvalue.nrp->np;
513 goto found;
514 }
515 }
516 nq = 0;
517 found:
518 if(nq)
519 {
520 fp->last = (char*)&name[n];
521 sh.last_table = dp->parent;
522 }
523 else
524 {
525 if(name[n]!='=') for(i=0; i < dp->ndisc; i++)
526 {
527 if((memcmp(name,dp->names[i],n)==0) && dp->names[i][n]==0)
528 return(nq);
529 }
530 errormsg(SH_DICT,ERROR_exit(1),e_notelem,n,name,nv_name(np));
531 }
532 return(nq);
533 }
534
put_type(Namval_t * np,const char * val,int flag,Namfun_t * fp)535 static void put_type(Namval_t* np, const char* val, int flag, Namfun_t* fp)
536 {
537 Namval_t *nq;
538 if(val && (nq=nv_open(val,sh.var_tree,NV_VARNAME|NV_ARRAY|NV_NOADD|NV_NOFAIL)))
539 {
540 Namfun_t *pp;
541 if((pp=nv_hasdisc(nq,fp->disc)) && pp->type==fp->type)
542
543 {
544 _nv_unset(np, flag);
545 nv_clone(nq,np,0);
546 return;
547 }
548 }
549 nv_putv(np,val,flag,fp);
550 if(!val)
551 {
552 Namtype_t *dp = (Namtype_t*)fp;
553 Namval_t *nq;
554 Namarr_t *ap;
555 int i;
556 if(nv_isarray(np) && (ap=nv_arrayptr(np)) && ap->nelem>0)
557 return;
558 for(i=0; i < dp->numnodes; i++)
559 {
560 nq = nv_namptr(dp->nodes,i);
561 if(ap=nv_arrayptr(nq))
562 ap->nelem |= ARRAY_UNDEF;
563 if(!nv_hasdisc(nq,&type_disc))
564 _nv_unset(nq,flag|NV_TYPE|nv_isattr(nq,NV_RDONLY));
565 }
566 nv_disc(np,fp,NV_POP);
567 if(!(fp->nofree&1))
568 free((void*)fp);
569 }
570 }
571
next_type(register Namval_t * np,Dt_t * root,Namfun_t * fp)572 static Namval_t *next_type(register Namval_t* np, Dt_t *root,Namfun_t *fp)
573 {
574 Namtype_t *dp = (Namtype_t*)fp;
575 if(!root)
576 {
577 Namarr_t *ap = nv_arrayptr(np);
578 if(ap && (ap->nelem&ARRAY_UNDEF))
579 nv_putsub(np,(char*)0,ARRAY_SCAN);
580 dp->current = 0;
581 }
582 else if(++dp->current>=dp->numnodes)
583 return(0);
584 return(nv_namptr(dp->nodes,dp->current));
585 }
586
clone_inttype(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)587 static Namfun_t *clone_inttype(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
588 {
589 Namfun_t *pp= (Namfun_t*)malloc(fp->dsize);
590 memcpy((void*)pp, (void*)fp, fp->dsize);
591 fp->nofree &= ~1;
592 if(nv_isattr(mp,NV_NOFREE) && mp->nvalue.cp)
593 memcpy((void*)mp->nvalue.cp,np->nvalue.cp, fp->dsize-sizeof(*fp));
594 else
595 mp->nvalue.cp = (char*)(fp+1);
596 if(!nv_isattr(mp,NV_MINIMAL))
597 mp->nvenv = 0;
598 nv_offattr(mp,NV_RDONLY);
599 return(pp);
600 }
601
typeinfo(Opt_t * op,Sfio_t * out,const char * str,Optdisc_t * fp)602 static int typeinfo(Opt_t* op, Sfio_t *out, const char *str, Optdisc_t *fp)
603 {
604 char *cp,**help,buffer[256];
605 Namtype_t *dp;
606 Namval_t *np,*nq,*tp;
607 int n, i, offset=staktell();
608 Sfio_t *sp;
609
610 np = *(Namval_t**)(fp+1);
611 stakputs(NV_CLASS);
612 stakputc('.');
613 stakputs(np->nvname);
614 stakputc(0);
615 np = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
616 stakseek(offset);
617 if(!np)
618 {
619 sfprintf(sfstderr,"%s: no such variable\n",np->nvname);
620 return(-1);
621 }
622 if(!(dp=(Namtype_t*)nv_hasdisc(np,&type_disc)))
623 {
624 Namfun_t *fp;
625 for(fp=np->nvfun;fp;fp=fp->next)
626 {
627 if(fp->disc && fp->disc->clonef==clone_inttype)
628 break;
629 }
630 if(!fp)
631 {
632 sfprintf(sfstderr,"%s: not a type\n",np->nvname);
633 return(-1);
634 }
635 if(strcmp(str,"other")==0)
636 return(0);
637 tp = fp->type;
638 nv_offattr(np,NV_RDONLY);
639 fp->type = 0;
640 if(np->nvenv)
641 sfprintf(out,"[+?\b%s\b is a %s.]\n", tp->nvname, np->nvenv);
642 cp = (char*)out->_next;
643 sfprintf(out,"[+?\b%s\b is a %n ", tp->nvname, &i);
644 nv_attribute(np,out,(char*)0, 1);
645 if(cp[i+1]=='i')
646 cp[i-1]='n';
647 fp->type = tp;
648 nv_onattr(np,NV_RDONLY);
649 sfprintf(out," with default value \b%s\b.]",nv_getval(np));
650 return(0);
651 }
652 if(strcmp(str,"other")==0)
653 {
654 Nambfun_t *bp;
655 if(bp=(Nambfun_t*)nv_hasdisc(np,nv_discfun(NV_DCADD)))
656 {
657 for(i=0; i < bp->num; i++)
658 {
659 if(nv_isattr(bp->bltins[i],NV_OPTGET))
660 sfprintf(out,"\b%s.%s\b(3), ",np->nvname,bp->bnames[i]);
661 }
662 }
663 return(0);
664 }
665 help = &dp->names[dp->ndisc];
666 sp = sfnew((Sfio_t*)0,buffer,sizeof(buffer),-1,SF_STRING|SF_WRITE);
667 sfprintf(out,"[+?\b%s\b defines the following fields:]{\n",np->nvname);
668 for(i=0; i < dp->numnodes; i++)
669 {
670 nq = nv_namptr(dp->nodes,i);
671 if(tp=nv_type(nq))
672 {
673 Namfun_t *pp = nv_hasdisc(nq,&type_disc);
674 sfprintf(out,"\t[+%s?%s.\n",nq->nvname,tp->nvname);
675 n = strlen(nq->nvname);
676 while((cp=nv_namptr(dp->nodes,i+1)->nvname) && memcmp(cp,nq->nvname,n)==0 && cp[n]=='.')
677 i++;
678 }
679 else
680 {
681 sfseek(sp,(Sfoff_t)0, SEEK_SET);
682 nv_attribute(nq,sp,(char*)0,1);
683 cp = 0;
684 if(!nv_isattr(nq,NV_REF))
685 cp = sh_fmtq(nv_getval(nq));
686 sfputc(sp,0);
687 for(n=strlen(buffer); n>0 && buffer[n-1]==' '; n--);
688 buffer[n] = 0;
689 if(cp)
690 sfprintf(out,"\t[+%s?%s, default value is %s.\n",nq->nvname,*buffer?buffer:"string",cp);
691 else
692 sfprintf(out,"\t[+%s?%s.\n",nq->nvname,*buffer?buffer:"string");
693 }
694 if(help[i])
695 sfprintf(out," %s.",help[i]);
696 sfputc(out,']');
697 }
698 sfprintf(out,"}\n");
699 if(dp->ndisc>0)
700 {
701 stakseek(offset);
702 stakputs(NV_CLASS);
703 stakputc('.');
704 stakputs(np->nvname);
705 stakputc('.');
706 n = staktell();
707 sfprintf(out,"[+?\b%s\b defines the following discipline functions:]{\n",np->nvname);
708 for(i=0; i < dp->ndisc; i++)
709 {
710 stakputs(dp->names[i]);
711 stakputc(0);
712 cp = 0;
713 if((nq = nv_search(stakptr(offset),sh.fun_tree,0)) && nq->nvalue.cp)
714 cp = nq->nvalue.rp->help;
715 sfprintf(out,"\t[+%s?%s]\n",dp->names[i],cp?cp:Empty);
716 if(cp)
717 sfputc(out,'.');
718 stakseek(n);
719 }
720 sfprintf(out,"}\n");
721 }
722 stakseek(offset);
723 sfclose(sp);
724 return(0);
725 }
726
std_disc(Namval_t * mp,Namtype_t * pp)727 static int std_disc(Namval_t *mp, Namtype_t *pp)
728 {
729 register const char *sp, *cp = strrchr(mp->nvname,'.');
730 register const char **argv;
731 register int i;
732 Namval_t *np=0,*nq;
733 if(cp)
734 cp++;
735 else
736 cp = mp->nvname;
737 if(strcmp(cp,"create")==0)
738 {
739 if(pp)
740 pp->cp = mp;
741 return(0);
742 }
743 for(argv=nv_discnames; sp=*argv; argv++)
744 {
745 if(strcmp(cp,sp)==0)
746 {
747 if(!pp)
748 return(1);
749 goto found;
750 }
751 }
752 return(0);
753 found:
754 if(memcmp(sp=mp->nvname,NV_CLASS,sizeof(NV_CLASS)-1)==0)
755 sp += sizeof(NV_CLASS);
756 sp += strlen(pp->fun.type->nvname)+1;
757 if(sp == cp)
758 np = pp->fun.type;
759 else for(i=1; i < pp->numnodes; i++)
760 {
761 nq = nv_namptr(pp->nodes,i);
762 if(memcmp(nq->nvname, sp, cp-sp-1)==0)
763 {
764 np = nq;
765 break;
766 }
767 }
768 if(np)
769 {
770 nv_onattr(mp,NV_NOFREE);
771 if(!nv_setdisc(np,cp, mp, (Namfun_t*)np))
772 sfprintf(sfstderr," nvsetdisc failed name=%s sp=%s cp=%s\n",np->nvname,sp,cp);
773 }
774 else
775 sfprintf(sfstderr,"can't set discipline %s cp=%s \n",sp,cp);
776 return(1);
777 }
778
779
nv_addtype(Namval_t * np,const char * optstr,Optdisc_t * op,size_t optsz)780 void nv_addtype(Namval_t *np, const char *optstr, Optdisc_t *op, size_t optsz)
781 {
782 Namdecl_t *cp = newof((Namdecl_t*)0,Namdecl_t,1,optsz);
783 Optdisc_t *dp = (Optdisc_t*)(cp+1);
784 Shell_t *shp = sh_getinterp();
785 Namval_t *mp,*bp;
786 char *name;
787 if(optstr)
788 cp->optstring = optstr;
789 else
790 cp->optstring = sh_opttype;
791 memcpy((void*)dp,(void*)op, optsz);
792 cp->optinfof = (void*)dp;
793 cp->tp = np;
794 mp = nv_search("typeset",shp->bltin_tree,0);
795 if(name=strrchr(np->nvname,'.'))
796 name++;
797 else
798 name = np->nvname;
799 if((bp=nv_search(name,shp->fun_tree,NV_NOSCOPE)) && !bp->nvalue.ip)
800 nv_delete(bp,shp->fun_tree,0);
801 bp = sh_addbuiltin(name, mp->nvalue.bfp, (void*)cp);
802 nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
803 nv_onattr(np, NV_RDONLY);
804 }
805
nv_newtype(Namval_t * mp)806 void nv_newtype(Namval_t *mp)
807 {
808 struct {
809 Optdisc_t opt;
810 Namval_t *np;
811 } optdisc;
812 memset(&optdisc,0,sizeof(optdisc));
813 optdisc.opt.infof = typeinfo;
814 optdisc.np = mp;
815 nv_addtype(mp,sh_opttype, &optdisc.opt, sizeof(optdisc));
816 }
817
818 /*
819 * This function creates a type out of the <numnodes> nodes in the
820 * array <nodes>. The first node is the name for the type
821 */
nv_mktype(Namval_t ** nodes,int numnodes)822 Namval_t *nv_mktype(Namval_t **nodes, int numnodes)
823 {
824 Namval_t *mp=nodes[0], *bp=0, *np, *nq, **mnodes=nodes;
825 int i,j,k,m,n,nd=0,nref=0,iref=0,inherit=0;
826 int size=sizeof(NV_DATA), dsize=0, nnodes;
827 size_t offset=0;
828 char *name=0, *cp, *sp, **help;
829 Namtype_t *pp,*qp=0,*dp,*tp;
830 Dt_t *root = nv_dict(mp);
831 struct Namref *nrp = 0;
832 Namfun_t *fp;
833 m = strlen(mp->nvname)+1;
834 for(nnodes=1,i=1; i <numnodes; i++)
835 {
836 np=nodes[i];
837 if(is_afunction(np))
838 {
839 if(!std_disc(np, (Namtype_t*)0))
840 {
841 size += strlen(np->nvname+m)+1;
842 if(memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1)==0)
843 size -= sizeof(NV_CLASS);
844 nd++;
845 }
846 continue;
847 }
848 if(nv_isattr(np,NV_REF))
849 iref++;
850 if(np->nvenv)
851 size += strlen((char*)np->nvenv)+1;
852 if(strcmp(&np->nvname[m],NV_DATA)==0 && !nv_type(np))
853 continue;
854 if(qp)
855 { /* delete duplicates */
856 for(j=0; j < qp->numnodes;j++)
857 {
858 nq = nv_namptr(qp->nodes,j);
859 if(strcmp(nq->nvname,&np->nvname[m])==0)
860 break;
861 }
862 if(j < qp->numnodes)
863 continue;
864 }
865 nnodes++;
866 if(name && memcmp(&name[m],&np->nvname[m],n)==0 && np->nvname[m+n]=='.')
867 offset -= sizeof(char*);
868 dsize = datasize(np,&offset);
869 if(!nv_isarray(np) && (dp=(Namtype_t*)nv_hasdisc(np, &type_disc)))
870 {
871 nnodes += dp->numnodes;
872 if((n=dp->strsize)<0)
873 n = -n;
874 iref = nref += dp->nref;
875 if(np->nvname[m]=='_' && np->nvname[m+1]==0 && (bp=nv_type(np)))
876 {
877 qp = dp;
878 nd = dp->ndisc;
879 nnodes = dp->numnodes;
880 offset = 0;
881 dsize = nv_size(np);
882 size += n;
883 }
884 else
885 size += n + dp->numnodes*(strlen(&np->nvname[m])+1);
886 n = strlen(np->nvname);
887 while((i+1) < numnodes && (cp=nodes[i+1]->nvname) && memcmp(cp,np->nvname,n)==0 && cp[n]=='.')
888 i++;
889 }
890 else if(nv_isattr(np,NV_REF))
891 nref++;
892 offset += (dsize?dsize:4);
893 size += (n=strlen(name=np->nvname)-m+1);
894 }
895 offset = roundof(offset,sizeof(char*));
896 nv_setsize(mp,offset);
897 if(nd)
898 nd++;
899 k = roundof(sizeof(Namtype_t),sizeof(Sfdouble_t)) - sizeof(Namtype_t);
900 pp = newof(NiL, Namtype_t, 1, nnodes*NV_MINSZ + offset + size + (nnodes+nd)*sizeof(char*) + iref*sizeof(struct Namref)+k);
901 pp->fun.dsize = sizeof(Namtype_t)+nnodes*NV_MINSZ +offset+k;
902 pp->fun.type = mp;
903 pp->parent = nv_lastdict();
904 pp->np = mp;
905 pp->bp = bp;
906 pp->childfun.fun.disc = &chtype_disc;
907 pp->childfun.fun.nofree = 1;
908 pp->childfun.ttype = pp;
909 pp->childfun.ptype = pp;
910 pp->fun.disc = &type_disc;
911 pp->nodes = (char*)(pp+1);
912 pp->numnodes = nnodes;
913 pp->data = pp->nodes + nnodes*NV_MINSZ +k;
914 pp->dsize = offset;
915 nrp = (struct Namref*)(pp->data+offset);
916 pp->names = (char**)(nrp+iref);
917 help = &pp->names[nd];
918 pp->strsize = size;
919 cp = (char*)&pp->names[nd+nnodes];
920 if(qp)
921 mnodes = newof(NiL, Namval_t*, nd+1, 0);
922 nd = 0;
923 nq = nv_namptr(pp->nodes,0);
924 nq->nvname = cp;
925 nv_onattr(nq,NV_MINIMAL);
926 cp = strcopy(cp,NV_DATA);
927 *cp++ = 0;
928 for(name=0, offset=0, k=i=1; i < numnodes; i++)
929 {
930 np=nodes[i];
931 if(is_afunction(np))
932 {
933 sp = np->nvname+m;
934 if(memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1)==0)
935 sp += sizeof(NV_CLASS);
936 if(!std_disc(np, pp))
937 {
938 /* see if discipline already defined */
939 for(j=0; j< nd; j++)
940 {
941 if(strcmp(sp,pp->names[j])==0)
942 {
943 mnodes[j] = nodes[i];
944 break;
945 }
946 }
947 if(j>=nd)
948 {
949 pp->names[nd] = cp;
950 mnodes[nd++] = nodes[i];
951 cp = strcopy(cp,sp);
952 *cp++ = 0;
953 }
954 nv_onattr(mnodes[j],NV_NOFREE);
955 }
956 continue;
957 }
958 if(inherit)
959 {
960 for(j=0; j < k ; j++)
961 {
962 nq = nv_namptr(pp->nodes,j);
963 if(strcmp(nq->nvname,&np->nvname[m])==0)
964 break;
965 }
966 if(j < k)
967 {
968 sp = nv_getval(np);
969 if(nv_isvtree(np))
970 sfprintf(sfstderr,"initialization not implemented\n");
971 else if(sp)
972 nv_putval(nq,sp,0);
973 goto skip;
974 }
975 }
976 if(strcmp(&np->nvname[m],NV_DATA)==0 && !nv_type(np))
977 {
978 char *val=nv_getval(np);
979 nq = nv_namptr(pp->nodes,0);
980 nq->nvfun = 0;
981 nv_putval(nq,(val?val:0),nv_isattr(np,~(NV_IMPORT|NV_EXPORT|NV_ARRAY)));
982 nq->nvflag = np->nvflag|NV_NOFREE|NV_MINIMAL;
983 goto skip;
984 }
985 if(qp)
986 {
987 Nambfun_t *bp;
988 dp = (Namtype_t*)nv_hasdisc(nv_type(np), &type_disc);
989 memcpy(pp->nodes,dp->nodes,dp->numnodes*NV_MINSZ);
990 offset = nv_size(np);
991 memcpy(pp->data,dp->data,offset);
992 for(k=0;k < dp->numnodes; k++)
993 {
994 Namval_t *nr = nv_namptr(qp->nodes,k);
995 nq = nv_namptr(pp->nodes,k);
996 if(fixnode(pp,dp,k,nrp,0))
997 {
998 nrp++;
999 nq = nq->nvalue.nrp->np;
1000 }
1001 if(!nv_isattr(nr,NV_REF) && !nv_hasdisc(nr,&type_disc))
1002 {
1003 if(nr->nvsize)
1004 memcpy((char*)nq->nvalue.cp,nr->nvalue.cp,size=datasize(nr,(size_t*)0));
1005 else
1006 {
1007 nq->nvalue.cp = nr->nvalue.cp;
1008 nv_onattr(nq,NV_NOFREE);
1009 }
1010 }
1011 }
1012 if(bp=(Nambfun_t*)nv_hasdisc(np,nv_discfun(NV_DCADD)))
1013 {
1014 for(j=0; j < bp->num; j++)
1015 {
1016 pp->names[nd++] = (char*)bp->bnames[j];
1017 mnodes[j] = bp->bltins[j];
1018 }
1019 }
1020 qp = 0;
1021 inherit=1;
1022 goto skip;
1023 }
1024 nq = nv_namptr(pp->nodes,k);
1025 if(np->nvenv)
1026 {
1027 /* need to save the string pointer */
1028 nv_offattr(np,NV_EXPORT);
1029 help[k] = cp;
1030 cp = strcopy(cp,np->nvenv);
1031 j = *help[k];
1032 if(islower(j))
1033 *help[k] = toupper(j);
1034 *cp++ = 0;
1035 np->nvenv = 0;
1036 }
1037 nq->nvname = cp;
1038 if(name && memcmp(name,&np->nvname[m],n)==0 && np->nvname[m+n]=='.')
1039 offset -= sizeof(char*);
1040 dsize = datasize(np,&offset);
1041 cp = strcopy(name=cp, &np->nvname[m]);
1042 n = cp-name;
1043 *cp++ = 0;
1044 nq->nvsize = np->nvsize;
1045 nq->nvflag = (np->nvflag&~(NV_IMPORT|NV_EXPORT))|NV_NOFREE|NV_MINIMAL;
1046 if(dp = (Namtype_t*)nv_hasdisc(np, &type_disc))
1047 {
1048 int r,kfirst=k;
1049 char *cname = &np->nvname[m];
1050 /*
1051 * If field is a type, mark the type by setting
1052 * strsize<0. This changes create_type()
1053 */
1054 clone_all_disc(np,nq,NV_RDONLY);
1055 if(nv_isarray(np))
1056 {
1057 nv_disc(nq, &pp->childfun.fun, NV_LAST);
1058 k++;
1059 goto skip;
1060 }
1061 if(fp=nv_hasdisc(nq,&chtype_disc))
1062 nv_disc(nq, &pp->childfun.fun, NV_LAST);
1063 if(tp = (Namtype_t*)nv_hasdisc(nq, &type_disc))
1064 tp->strsize = -tp->strsize;
1065 else sfprintf(sfstderr,"tp==NULL\n");
1066 for(r=0; r < dp->numnodes; r++)
1067 {
1068 Namval_t *nr = nv_namptr(dp->nodes,r);
1069 nq = nv_namptr(pp->nodes,++k);
1070 nq->nvname = cp;
1071 dsize = datasize(nr,&offset);
1072 nq->nvflag = nr->nvflag;
1073 if(nr->nvalue.cp)
1074 {
1075 Namchld_t *xp = (Namchld_t*)nv_hasdisc(nr,&chtype_disc);
1076 if(xp && nr->nvalue.cp >= xp->ptype->data && nr->nvalue.cp < xp->ptype->data+xp->ptype->fun.dsize)
1077 {
1078 nq->nvalue.cp = pp->data+offset;
1079 memcpy((char*)nq->nvalue.cp,nr->nvalue.cp,dsize);
1080 nv_onattr(nq,NV_NOFREE);
1081 }
1082 else
1083 nq->nvalue.cp = strdup(nr->nvalue.cp);
1084 nv_disc(nq, &pp->childfun.fun, NV_LAST);
1085 }
1086 nq->nvsize = nr->nvsize;
1087 offset += dsize;
1088 if(*cname!='_' || cname[1])
1089 {
1090 cp = strcopy(cp,cname);
1091 *cp++ = '.';
1092 }
1093 cp = strcopy(cp,nr->nvname);
1094 *cp++ = 0;
1095 }
1096 while((i+1) < numnodes && (cname=&nodes[i+1]->nvname[m]) && memcmp(cname,&np->nvname[m],n)==0 && cname[n]=='.')
1097 {
1098 int j=kfirst;
1099 nv_unset(np);
1100 nv_delete(np,root,0);
1101 np = nodes[++i];
1102 while(j < k)
1103 {
1104 nq = nv_namptr(pp->nodes,++j);
1105 if(strcmp(nq->nvname,cname)==0)
1106 {
1107 sfprintf(sfstderr,"%s found at k=%d\n",nq->nvname,k);
1108 if(nq->nvalue.cp>=pp->data && nq->nvalue.cp< (char*)pp->names)
1109 memcpy((char*)nq->nvalue.cp,np->nvalue.cp,datasize(np,0));
1110 break;
1111 }
1112 }
1113 }
1114 }
1115 else
1116 {
1117 j = nv_isattr(np,NV_NOFREE);
1118 nq->nvfun = np->nvfun;
1119 np->nvfun = 0;
1120 if(nv_isarray(nq) && !nq->nvfun)
1121 {
1122 nv_putsub(nq, (char*)0, ARRAY_FILL);
1123 if(nv_isattr(nq,NV_INTEGER))
1124 nv_putval(nq, "0",0);
1125 else
1126 ((Namarr_t*)nq->nvfun)->nelem--;
1127 }
1128 nv_disc(nq, &pp->childfun.fun, NV_LAST);
1129 if(nq->nvfun)
1130 {
1131 for(fp=nq->nvfun; fp; fp = fp->next)
1132 fp->nofree |= 1;
1133 }
1134 nq->nvalue.cp = np->nvalue.cp;
1135 if(dsize)
1136 {
1137 nq->nvalue.cp = pp->data+offset;
1138 sp = (char*)np->nvalue.cp;
1139 if(nv_isattr(np,NV_INT16P) ==NV_INT16)
1140 {
1141 sp= (char*)&np->nvalue;
1142 nv_onattr(nq,NV_INT16P);
1143 j = 1;
1144 }
1145 if(sp)
1146 memcpy((char*)nq->nvalue.cp,sp,dsize);
1147 else if(nv_isattr(np,NV_LJUST|NV_RJUST))
1148 memset((char*)nq->nvalue.cp,' ',dsize);
1149 if(!j)
1150 free((void*)np->nvalue.cp);
1151 }
1152 if(!nq->nvalue.cp && nq->nvfun== &pp->childfun.fun)
1153 nq->nvalue.cp = Empty;
1154 np->nvalue.cp = 0;
1155 #if 0
1156 offset += dsize;
1157 #else
1158 offset += (dsize?dsize:4);
1159 #endif
1160 }
1161 k++;
1162 skip:
1163 if(!nv_isnull(np))
1164 _nv_unset(np,0);
1165 nv_delete(np,root,0);
1166 }
1167 pp->ndisc = nd;
1168 pp->nref = nref;
1169 if(k>1)
1170 {
1171 nv_setsize(mp,offset);
1172 mp->nvalue.cp = pp->data;
1173 nv_onattr(mp,NV_NOFREE|NV_BINARY|NV_RAW);
1174 }
1175 else if(!mp->nvalue.cp)
1176 mp->nvalue.cp = Empty;
1177 nv_disc(mp, &pp->fun, NV_LAST);
1178 if(nd>0)
1179 {
1180 pp->names[nd] = 0;
1181 nv_adddisc(mp, (const char**)pp->names, mnodes);
1182 }
1183 if(mnodes!=nodes)
1184 free((void*)mnodes);
1185 nv_newtype(mp);
1186 return(mp);
1187 }
1188
nv_mkinttype(char * name,size_t size,int sign,const char * help,Namdisc_t * ep)1189 Namval_t *nv_mkinttype(char *name, size_t size, int sign, const char *help, Namdisc_t *ep)
1190 {
1191 Namval_t *mp;
1192 Namfun_t *fp;
1193 Namdisc_t *dp;
1194 int offset=staktell();
1195 stakputs(NV_CLASS);
1196 stakputc('.');
1197 stakputs(name);
1198 stakputc(0);
1199 mp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME);
1200 stakseek(offset);
1201 offset = size + sizeof(Namdisc_t);
1202 fp = newof(NiL, Namfun_t, 1, offset);
1203 fp->type = mp;
1204 fp->nofree |= 1;
1205 fp->dsize = sizeof(Namfun_t)+size;
1206 dp = (Namdisc_t*)(fp+1);
1207 if(ep)
1208 *dp = *ep;
1209 dp->clonef = clone_inttype;
1210 fp->disc = dp;
1211 mp->nvalue.cp = (char*)(fp+1) + sizeof(Namdisc_t);
1212 nv_setsize(mp,10);
1213 mp->nvenv = (char*)help;
1214 nv_onattr(mp,NV_NOFREE|NV_RDONLY|NV_INTEGER|NV_EXPORT);
1215 if(size==16)
1216 nv_onattr(mp,NV_INT16P);
1217 else if(size==64)
1218 nv_onattr(mp,NV_INT64);
1219 if(!sign)
1220 nv_onattr(mp,NV_UNSIGN);
1221 nv_disc(mp, fp, NV_LAST);
1222 nv_newtype(mp);
1223 return(mp);
1224 }
1225
nv_typename(Namval_t * tp,Sfio_t * out)1226 void nv_typename(Namval_t *tp, Sfio_t *out)
1227 {
1228 char *v,*cp;
1229 Namtype_t *dp;
1230 cp = nv_name(tp);
1231 if(v=strrchr(cp,'.'))
1232 cp = v+1;
1233 if((dp = (Namtype_t*)nv_hasdisc(tp,&type_disc)) && dp->bp)
1234 {
1235 nv_typename(dp->bp,out);
1236 sfprintf(out,"%s.%s",sfstruse(out),cp);
1237 }
1238 else
1239 sfputr(out,cp,-1);
1240 }
1241
nv_type(Namval_t * np)1242 Namval_t *nv_type(Namval_t *np)
1243 {
1244 Namfun_t *fp;
1245 if(nv_isattr(np,NV_BLTIN|BLT_DCL)==(NV_BLTIN|BLT_DCL))
1246 {
1247 Namdecl_t *ntp = (Namdecl_t*)nv_context(np);
1248 return(ntp?ntp->tp:0);
1249 }
1250 for(fp=np->nvfun; fp; fp=fp->next)
1251 {
1252 if(fp->type)
1253 return(fp->type);
1254 if(fp->disc && fp->disc->typef && (np= (*fp->disc->typef)(np,fp)))
1255 return(np);
1256 }
1257 return(0);
1258 }
1259
1260 /*
1261 * call any and all create functions
1262 */
type_init(Namval_t * np)1263 static void type_init(Namval_t *np)
1264 {
1265 int i;
1266 Namtype_t *dp, *pp=(Namtype_t*)nv_hasdisc(np,&type_disc);
1267 Namval_t *nq;
1268 if(!pp)
1269 return;
1270 for(i=0; i < pp->numnodes; i++)
1271 {
1272 nq = nv_namptr(pp->nodes,i);
1273 if((dp=(Namtype_t*)nv_hasdisc(nq,&type_disc)) && dp->cp)
1274 sh_fun(dp->cp,nq, (char**)0);
1275 }
1276 if(pp->cp)
1277 sh_fun(pp->cp, np, (char**)0);
1278 }
1279
1280 /*
1281 * This function turns variable <np> to the type <tp>
1282 */
nv_settype(Namval_t * np,Namval_t * tp,int flags)1283 int nv_settype(Namval_t* np, Namval_t *tp, int flags)
1284 {
1285 int isnull = nv_isnull(np);
1286 int rdonly = nv_isattr(np,NV_RDONLY);
1287 char *val=0;
1288 Namarr_t *ap=0;
1289 int nelem=0;
1290 #if SHOPT_TYPEDEF
1291 Namval_t *tq;
1292 if(nv_type(np)==tp)
1293 return(0);
1294 if(nv_isarray(np) && (tq=nv_type(np)))
1295 {
1296 if(tp==tq)
1297 return(0);
1298 errormsg(SH_DICT,ERROR_exit(1),e_redef,nv_name(np));
1299 }
1300 if((ap=nv_arrayptr(np)) && ap->nelem>0)
1301 {
1302 nv_putsub(np,NIL(char*),ARRAY_SCAN);
1303 ap->hdr.type = tp;
1304 do
1305 {
1306 nv_arraysettype(np, tp, nv_getsub(np),flags);
1307 }
1308 while(nv_nextsub(np));
1309 }
1310 else if(ap || nv_isarray(np))
1311 {
1312 flags &= ~NV_APPEND;
1313 if(!ap)
1314 {
1315 nv_putsub(np,"0",ARRAY_FILL);
1316 ap = nv_arrayptr(np);
1317 nelem = 1;
1318
1319 }
1320 }
1321 else
1322 #endif /*SHOPT_TYPEDEF */
1323 {
1324 if(isnull)
1325 flags &= ~NV_APPEND;
1326 else if(!nv_isvtree(np))
1327 {
1328 val = strdup(nv_getval(np));
1329 if(!(flags&NV_APPEND))
1330 _nv_unset(np, NV_RDONLY);
1331 }
1332 if(!nv_clone(tp,np,flags|NV_NOFREE))
1333 return(0);
1334 }
1335 if(ap)
1336 {
1337 int nofree;
1338 nv_disc(np,&ap->hdr,NV_POP);
1339 np->nvalue.up = 0;
1340 nv_clone(tp,np,flags|NV_NOFREE);
1341 if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE))
1342 free((void*)np->nvalue.cp);
1343 np->nvalue.up = 0;
1344 nofree = ap->hdr.nofree;
1345 ap->hdr.nofree = 0;
1346 ap->hdr.type = tp;
1347 nv_disc(np, &ap->hdr, NV_FIRST);
1348 ap->hdr.nofree = nofree;
1349 nv_onattr(np,NV_ARRAY);
1350 if(nelem)
1351 {
1352 ap->nelem++;
1353 nv_putsub(np,"0",0);
1354 _nv_unset(np,NV_RDONLY);
1355 ap->nelem--;
1356 }
1357 }
1358 type_init(np);
1359 if(!rdonly)
1360 nv_offattr(np,NV_RDONLY);
1361 if(val)
1362 {
1363 nv_putval(np,val,NV_RDONLY);
1364 free((void*)val);
1365 }
1366 return(0);
1367 }
1368
1369 #define S(x) #x
1370 #define FIELD(x,y) { S(y##x), S(x##_t), offsetof(struct stat,st_##y##x) }
1371 typedef struct _field_
1372 {
1373 char *name;
1374 char *type;
1375 int offset;
1376 } Fields_t;
1377
1378 Fields_t foo[]=
1379 {
1380 FIELD(dev,),
1381 FIELD(ino,),
1382 FIELD(nlink,),
1383 FIELD(mode,),
1384 FIELD(uid,),
1385 FIELD(gid,),
1386 FIELD(size,),
1387 FIELD(time,a),
1388 FIELD(time,m),
1389 FIELD(time,c),
1390 #if 0
1391 FIELD(blksize,),
1392 FIELD(blocks,),
1393 #endif
1394 0
1395 };
1396
1397
nv_mkstruct(const char * name,int rsize,Fields_t * fields)1398 Namval_t *nv_mkstruct(const char *name, int rsize, Fields_t *fields)
1399 {
1400 Namval_t *mp, *nq, *nr, *tp;
1401 Fields_t *fp;
1402 Namtype_t *dp, *pp;
1403 char *cp, *sp;
1404 int nnodes=0, offset=staktell(), n, r, i, j;
1405 size_t m, size=0;
1406 stakputs(NV_CLASS);
1407 stakputc('.');
1408 r = staktell();
1409 stakputs(name);
1410 stakputc(0);
1411 mp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME);
1412 stakseek(r);
1413
1414 for(fp=fields; fp->name; fp++)
1415 {
1416 m = strlen(fp->name)+1;
1417 size += m;
1418 nnodes++;
1419 if(memcmp(fp->type,"typeset",7))
1420 {
1421 stakputs(fp->type);
1422 stakputc(0);
1423 tp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME|NV_NOADD|NV_NOFAIL);
1424 stakseek(r);
1425 if(!tp)
1426 errormsg(SH_DICT,ERROR_exit(1),e_unknowntype,strlen(fp->type),fp->type);
1427 if(dp = (Namtype_t*)nv_hasdisc(tp,&type_disc))
1428 {
1429 nnodes += dp->numnodes;
1430 if((i=dp->strsize) < 0)
1431 i = -i;
1432 size += i + dp->numnodes*m;
1433 }
1434 }
1435 }
1436 pp = newof(NiL,Namtype_t, 1, nnodes*NV_MINSZ + rsize + size);
1437 pp->fun.dsize = sizeof(Namtype_t)+nnodes*NV_MINSZ +rsize;
1438 pp->fun.type = mp;
1439 pp->np = mp;
1440 pp->childfun.fun.disc = &chtype_disc;
1441 pp->childfun.fun.nofree = 1;
1442 pp->childfun.ttype = pp;
1443 pp->childfun.ptype = pp;
1444 pp->fun.disc = &type_disc;
1445 pp->nodes = (char*)(pp+1);
1446 pp->numnodes = nnodes;
1447 pp->strsize = size;
1448 pp->data = pp->nodes + nnodes*NV_MINSZ;
1449 cp = pp->data + rsize;
1450 for(i=0,fp=fields; fp->name; fp++)
1451 {
1452 nq = nv_namptr(pp->nodes,i++);
1453 nq->nvname = cp;
1454 nq->nvalue.cp = pp->data + fp->offset;
1455 nv_onattr(nq,NV_MINIMAL|NV_NOFREE);
1456 m = strlen(fp->name)+1;
1457 memcpy(cp, fp->name, m);
1458 cp += m;
1459 if(memcmp(fp->type,"typeset",7))
1460 {
1461 stakputs(fp->type);
1462 stakputc(0);
1463 tp = nv_open(stakptr(offset), sh.var_tree, NV_VARNAME);
1464 stakseek(r);
1465 clone_all_disc(tp,nq,NV_RDONLY);
1466 nq->nvflag = tp->nvflag|NV_MINIMAL|NV_NOFREE;
1467 nq->nvsize = tp->nvsize;
1468 if(dp = (Namtype_t*)nv_hasdisc(nq,&type_disc))
1469 dp->strsize = -dp->strsize;
1470 if(dp = (Namtype_t*)nv_hasdisc(tp,&type_disc))
1471 {
1472 if(nv_hasdisc(nq,&chtype_disc))
1473 nv_disc(nq, &pp->childfun.fun, NV_LAST);
1474 sp = (char*)nq->nvalue.cp;
1475 memcpy(sp, dp->data, nv_size(tp));
1476 for(j=0; j < dp->numnodes; j++)
1477 {
1478 nr = nv_namptr(dp->nodes,j);
1479 nq = nv_namptr(pp->nodes,i++);
1480 nq->nvname = cp;
1481 memcpy(cp,fp->name,m);
1482 cp[m-1] = '.';
1483 cp += m;
1484 n = strlen(nr->nvname)+1;
1485 memcpy(cp,nr->nvname,n);
1486 cp += n;
1487 if(nr->nvalue.cp>=dp->data && nr->nvalue.cp < (char*)pp + pp->fun.dsize)
1488 {
1489 nq->nvalue.cp = sp + (nr->nvalue.cp-dp->data);
1490 }
1491 nq->nvflag = nr->nvflag;
1492 nq->nvsize = nr->nvsize;
1493 }
1494 }
1495 }
1496 else if(strmatch(fp->type+7,"*-*i*")==0)
1497 {
1498 nv_onattr(nq,NV_NOFREE|NV_RDONLY|NV_INTEGER);
1499 if(strmatch(fp->type+7,"*-*s*")==0)
1500 nv_onattr(nq,NV_INT16P);
1501 else if(strmatch(fp->type+7,"*-*l*")==0)
1502 nv_onattr(nq,NV_INT64);
1503 if(strmatch(fp->type+7,"*-*u*")==0)
1504 nv_onattr(nq,NV_UNSIGN);
1505 }
1506
1507 }
1508 stakseek(offset);
1509 nv_onattr(mp,NV_RDONLY|NV_NOFREE|NV_BINARY);
1510 nv_setsize(mp,rsize);
1511 nv_disc(mp, &pp->fun, NV_LAST);
1512 mp->nvalue.cp = pp->data;
1513 nv_newtype(mp);
1514 return(mp);
1515 }
1516
put_stat(Namval_t * np,const char * val,int flag,Namfun_t * nfp)1517 static void put_stat(Namval_t* np, const char* val, int flag, Namfun_t* nfp)
1518 {
1519 if(val)
1520 {
1521 if(stat(val,(struct stat*)np->nvalue.cp)<0)
1522 sfprintf(sfstderr,"stat of %s failed\n",val);
1523 return;
1524 }
1525 nv_putv(np,val,flag,nfp);
1526 nv_disc(np,nfp,NV_POP);
1527 if(!(nfp->nofree&1))
1528 free((void*)nfp);
1529 }
1530
1531 static const Namdisc_t stat_disc =
1532 {
1533 0,
1534 put_stat
1535 };
1536
1537
nv_mkstat(void)1538 void nv_mkstat(void)
1539 {
1540 Namval_t *tp;
1541 Namfun_t *fp;
1542 tp = nv_mkstruct("stat_t", sizeof(struct stat), foo);
1543 nv_offattr(tp,NV_RDONLY);
1544 nv_setvtree(tp);
1545 fp = newof(NiL,Namfun_t,1,0);
1546 fp->type = tp;
1547 fp->disc = &stat_disc;
1548 nv_disc(tp,fp,NV_FIRST);
1549 nv_putval(tp,"/dev/null",0);
1550 nv_onattr(tp,NV_RDONLY);
1551 }
1552