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