xref: /titanic_50/usr/src/lib/libshell/common/sh/nvtype.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
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