1*8462SApril.Chin@Sun.COM /***********************************************************************
2*8462SApril.Chin@Sun.COM *                                                                      *
3*8462SApril.Chin@Sun.COM *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
5*8462SApril.Chin@Sun.COM *                      and is licensed under the                       *
6*8462SApril.Chin@Sun.COM *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
8*8462SApril.Chin@Sun.COM *                                                                      *
9*8462SApril.Chin@Sun.COM *                A copy of the License is available at                 *
10*8462SApril.Chin@Sun.COM *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*8462SApril.Chin@Sun.COM *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*8462SApril.Chin@Sun.COM *                                                                      *
13*8462SApril.Chin@Sun.COM *              Information and Software Systems Research               *
14*8462SApril.Chin@Sun.COM *                            AT&T Research                             *
15*8462SApril.Chin@Sun.COM *                           Florham Park NJ                            *
16*8462SApril.Chin@Sun.COM *                                                                      *
17*8462SApril.Chin@Sun.COM *                  David Korn <dgk@research.att.com>                   *
18*8462SApril.Chin@Sun.COM *                                                                      *
19*8462SApril.Chin@Sun.COM ***********************************************************************/
20*8462SApril.Chin@Sun.COM #pragma prototyped
21*8462SApril.Chin@Sun.COM #include	<shell.h>
22*8462SApril.Chin@Sun.COM 
23*8462SApril.Chin@Sun.COM static const char enum_usage[] =
24*8462SApril.Chin@Sun.COM "[-?@(#)$Id: enum (AT&T Research) 2008-01-08 $\n]"
25*8462SApril.Chin@Sun.COM USAGE_LICENSE
26*8462SApril.Chin@Sun.COM "[+NAME?enum - create an enumeration type]"
27*8462SApril.Chin@Sun.COM "[+DESCRIPTION?\benum\b is a declaration command that creates an enumeration "
28*8462SApril.Chin@Sun.COM     "type \atypename\a that can only store any one of the values in the indexed "
29*8462SApril.Chin@Sun.COM     "array variable \atypename\a.]"
30*8462SApril.Chin@Sun.COM "[+?If the list of \avalue\as is ommitted, then \atypename\a must name an "
31*8462SApril.Chin@Sun.COM     "indexed array variable with at least two elements.]"
32*8462SApril.Chin@Sun.COM "[i:ignorecase?The values are case insensitive.]"
33*8462SApril.Chin@Sun.COM "\n"
34*8462SApril.Chin@Sun.COM "\n\atypename\a[\b=(\b \avalue\a ... \b)\b]\n"
35*8462SApril.Chin@Sun.COM "\n"
36*8462SApril.Chin@Sun.COM "[+EXIT STATUS]"
37*8462SApril.Chin@Sun.COM     "{"
38*8462SApril.Chin@Sun.COM         "[+0?Successful completion.]"
39*8462SApril.Chin@Sun.COM         "[+>0?An error occurred.]"
40*8462SApril.Chin@Sun.COM     "}"
41*8462SApril.Chin@Sun.COM "[+SEE ALSO?\bksh\b(1), \btypeset\b(1).]"
42*8462SApril.Chin@Sun.COM ;
43*8462SApril.Chin@Sun.COM 
44*8462SApril.Chin@Sun.COM static const char enum_type[] =
45*8462SApril.Chin@Sun.COM "[-1c?\n@(#)$Id: type (AT&T Labs Research) 2008-01-08 $\n]"
46*8462SApril.Chin@Sun.COM USAGE_LICENSE
47*8462SApril.Chin@Sun.COM "[+NAME?\f?\f - create an instance of type \b\f?\f\b]"
48*8462SApril.Chin@Sun.COM "[+DESCRIPTION?\b\f?\f\b creates a variable for each \aname\a with "
49*8462SApril.Chin@Sun.COM     "enumeration type \b\f?\f\b where \b\f?\f\b is a type that has been "
50*8462SApril.Chin@Sun.COM     "created with the \benum\b(1) command.]"
51*8462SApril.Chin@Sun.COM "[+?The variable can have one of the following values\fvalues\f.  "
52*8462SApril.Chin@Sun.COM     "The the values are \fcase\fcase sensitive.]"
53*8462SApril.Chin@Sun.COM "[+?If \b=\b\avalue\a is omitted, the default is \fdefault\f.]"
54*8462SApril.Chin@Sun.COM "[+?If no \aname\as are specified then the names and values of all "
55*8462SApril.Chin@Sun.COM         "variables of this type are written to standard output.]"
56*8462SApril.Chin@Sun.COM "[+?\b\f?\f\b is built-in to the shell as a declaration command so that "
57*8462SApril.Chin@Sun.COM         "field splitting and pathname expansion are not performed on "
58*8462SApril.Chin@Sun.COM         "the arguments.  Tilde expansion occurs on \avalue\a.]"
59*8462SApril.Chin@Sun.COM "[r?Enables readonly.  Once enabled, the value cannot be changed or unset.]"
60*8462SApril.Chin@Sun.COM "[a?index array.  Each \aname\a will converted to an index "
61*8462SApril.Chin@Sun.COM         "array of type \b\f?\f\b.  If a variable already exists, the current "
62*8462SApril.Chin@Sun.COM         "value will become index \b0\b.]"
63*8462SApril.Chin@Sun.COM "[A?Associative array.  Each \aname\a will converted to an associate "
64*8462SApril.Chin@Sun.COM         "array of type \b\f?\f\b.  If a variable already exists, the current "
65*8462SApril.Chin@Sun.COM         "value will become subscript \b0\b.]"
66*8462SApril.Chin@Sun.COM "[h]:[string?Used within a type definition to provide a help string  "
67*8462SApril.Chin@Sun.COM         "for variable \aname\a.  Otherwise, it is ignored.]"
68*8462SApril.Chin@Sun.COM "[S?Used with a type definition to indicate that the variable is shared by "
69*8462SApril.Chin@Sun.COM         "each instance of the type.  When used inside a function defined "
70*8462SApril.Chin@Sun.COM         "with the \bfunction\b reserved word, the specified variables "
71*8462SApril.Chin@Sun.COM         "will have function static scope.  Otherwise, the variable is "
72*8462SApril.Chin@Sun.COM         "unset prior to processing the assignment list.]"
73*8462SApril.Chin@Sun.COM #if 0
74*8462SApril.Chin@Sun.COM "[p?Causes the output to be in a form of \b\f?\f\b commands that can be "
75*8462SApril.Chin@Sun.COM         "used as input to the shell to recreate the current type of "
76*8462SApril.Chin@Sun.COM         "these variables.]"
77*8462SApril.Chin@Sun.COM #endif
78*8462SApril.Chin@Sun.COM "\n"
79*8462SApril.Chin@Sun.COM "\n[name[=value]...]\n"
80*8462SApril.Chin@Sun.COM "\n"
81*8462SApril.Chin@Sun.COM "[+EXIT STATUS?]{"
82*8462SApril.Chin@Sun.COM         "[+0?Successful completion.]"
83*8462SApril.Chin@Sun.COM         "[+>0?An error occurred.]"
84*8462SApril.Chin@Sun.COM "}"
85*8462SApril.Chin@Sun.COM 
86*8462SApril.Chin@Sun.COM "[+SEE ALSO?\benum\b(1), \btypeset\b(1)]"
87*8462SApril.Chin@Sun.COM ;
88*8462SApril.Chin@Sun.COM 
89*8462SApril.Chin@Sun.COM struct Enum
90*8462SApril.Chin@Sun.COM {
91*8462SApril.Chin@Sun.COM 	Namfun_t	hdr;
92*8462SApril.Chin@Sun.COM 	short		nelem;
93*8462SApril.Chin@Sun.COM 	short		iflag;
94*8462SApril.Chin@Sun.COM 	const char	*values[1];
95*8462SApril.Chin@Sun.COM };
96*8462SApril.Chin@Sun.COM 
97*8462SApril.Chin@Sun.COM static int enuminfo(Opt_t* op, Sfio_t *out, const char *str, Optdisc_t *fp)
98*8462SApril.Chin@Sun.COM {
99*8462SApril.Chin@Sun.COM 	Namval_t	*np;
100*8462SApril.Chin@Sun.COM 	struct Enum	*ep;
101*8462SApril.Chin@Sun.COM 	int		n=0;
102*8462SApril.Chin@Sun.COM 	const char	*v;
103*8462SApril.Chin@Sun.COM 	np = *(Namval_t**)(fp+1);
104*8462SApril.Chin@Sun.COM 	ep = (struct Enum*)np->nvfun;
105*8462SApril.Chin@Sun.COM 	if(strcmp(str,"default")==0)
106*8462SApril.Chin@Sun.COM #if 0
107*8462SApril.Chin@Sun.COM 		sfprintf(out,"\b%s\b%c",ep->values[0],0);
108*8462SApril.Chin@Sun.COM #else
109*8462SApril.Chin@Sun.COM 		sfprintf(out,"\b%s\b",ep->values[0]);
110*8462SApril.Chin@Sun.COM #endif
111*8462SApril.Chin@Sun.COM 	else if(strcmp(str,"case")==0)
112*8462SApril.Chin@Sun.COM 	{
113*8462SApril.Chin@Sun.COM 		if(ep->iflag)
114*8462SApril.Chin@Sun.COM 			sfprintf(out,"not ");
115*8462SApril.Chin@Sun.COM 	}
116*8462SApril.Chin@Sun.COM 	else while(v=ep->values[n++])
117*8462SApril.Chin@Sun.COM 	{
118*8462SApril.Chin@Sun.COM 		sfprintf(out,", \b%s\b",v);
119*8462SApril.Chin@Sun.COM 	}
120*8462SApril.Chin@Sun.COM 	return(0);
121*8462SApril.Chin@Sun.COM }
122*8462SApril.Chin@Sun.COM 
123*8462SApril.Chin@Sun.COM static Namfun_t *clone_enum(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
124*8462SApril.Chin@Sun.COM {
125*8462SApril.Chin@Sun.COM 	struct Enum	*ep, *pp=(struct Enum*)fp;
126*8462SApril.Chin@Sun.COM 	ep = newof(0,struct Enum,1,pp->nelem*sizeof(char*));
127*8462SApril.Chin@Sun.COM 	memcpy((void*)ep,(void*)pp,sizeof(struct Enum)+pp->nelem*sizeof(char*));
128*8462SApril.Chin@Sun.COM 	return(&ep->hdr);
129*8462SApril.Chin@Sun.COM }
130*8462SApril.Chin@Sun.COM 
131*8462SApril.Chin@Sun.COM static void put_enum(Namval_t* np,const char *val,int flags,Namfun_t *fp)
132*8462SApril.Chin@Sun.COM {
133*8462SApril.Chin@Sun.COM 	struct Enum 		*ep = (struct Enum*)fp;
134*8462SApril.Chin@Sun.COM 	register const char	*v;
135*8462SApril.Chin@Sun.COM 	unsigned short		i=0, n;
136*8462SApril.Chin@Sun.COM 	if(!val)
137*8462SApril.Chin@Sun.COM 	{
138*8462SApril.Chin@Sun.COM 		nv_disc(np,&ep->hdr,NV_POP);
139*8462SApril.Chin@Sun.COM 		if(!ep->hdr.nofree)
140*8462SApril.Chin@Sun.COM 			free((void*)ep);
141*8462SApril.Chin@Sun.COM 		nv_putv(np, val, flags,fp);
142*8462SApril.Chin@Sun.COM 		return;
143*8462SApril.Chin@Sun.COM 	}
144*8462SApril.Chin@Sun.COM 	if(flags&NV_INTEGER)
145*8462SApril.Chin@Sun.COM 	{
146*8462SApril.Chin@Sun.COM 		nv_putv(np,val,flags,fp);
147*8462SApril.Chin@Sun.COM 		return;
148*8462SApril.Chin@Sun.COM 	}
149*8462SApril.Chin@Sun.COM 	while(v=ep->values[i])
150*8462SApril.Chin@Sun.COM 	{
151*8462SApril.Chin@Sun.COM 		if(ep->iflag)
152*8462SApril.Chin@Sun.COM 			n = strcasecmp(v,val);
153*8462SApril.Chin@Sun.COM 		else
154*8462SApril.Chin@Sun.COM 			n = strcmp(v,val);
155*8462SApril.Chin@Sun.COM 		if(n==0)
156*8462SApril.Chin@Sun.COM 		{
157*8462SApril.Chin@Sun.COM 			nv_putv(np, (char*)&i, NV_UINT16, fp);
158*8462SApril.Chin@Sun.COM 			return;
159*8462SApril.Chin@Sun.COM 		}
160*8462SApril.Chin@Sun.COM 		i++;
161*8462SApril.Chin@Sun.COM 	}
162*8462SApril.Chin@Sun.COM 	error(ERROR_exit(1), "%s:  invalid value %s",nv_name(np),val);
163*8462SApril.Chin@Sun.COM }
164*8462SApril.Chin@Sun.COM 
165*8462SApril.Chin@Sun.COM static char* get_enum(register Namval_t* np, Namfun_t *fp)
166*8462SApril.Chin@Sun.COM {
167*8462SApril.Chin@Sun.COM 	static char buff[6];
168*8462SApril.Chin@Sun.COM 	struct Enum *ep = (struct Enum*)fp;
169*8462SApril.Chin@Sun.COM 	long n = nv_getn(np,fp);
170*8462SApril.Chin@Sun.COM 	if(n < ep->nelem)
171*8462SApril.Chin@Sun.COM 		return((char*)ep->values[n]);
172*8462SApril.Chin@Sun.COM 	sfsprintf(buff,sizeof(buff),"%u%c",n,0);
173*8462SApril.Chin@Sun.COM 	return(buff);
174*8462SApril.Chin@Sun.COM }
175*8462SApril.Chin@Sun.COM 
176*8462SApril.Chin@Sun.COM static Sfdouble_t get_nenum(register Namval_t* np, Namfun_t *fp)
177*8462SApril.Chin@Sun.COM {
178*8462SApril.Chin@Sun.COM 	return(nv_getn(np,fp));
179*8462SApril.Chin@Sun.COM }
180*8462SApril.Chin@Sun.COM 
181*8462SApril.Chin@Sun.COM const Namdisc_t ENUM_disc        = {  0, put_enum, get_enum, get_nenum, 0,0,clone_enum };
182*8462SApril.Chin@Sun.COM 
183*8462SApril.Chin@Sun.COM #ifdef STANDALONE
184*8462SApril.Chin@Sun.COM static int enum_create(int argc, char** argv, void* context)
185*8462SApril.Chin@Sun.COM #else
186*8462SApril.Chin@Sun.COM int b_enum(int argc, char** argv, void* context)
187*8462SApril.Chin@Sun.COM #endif
188*8462SApril.Chin@Sun.COM {
189*8462SApril.Chin@Sun.COM 	int			sz,i,n,iflag = 0;
190*8462SApril.Chin@Sun.COM 	Namval_t		*np, *tp;
191*8462SApril.Chin@Sun.COM 	Namarr_t		*ap;
192*8462SApril.Chin@Sun.COM 	char			*cp,*sp;
193*8462SApril.Chin@Sun.COM 	struct Enum		*ep;
194*8462SApril.Chin@Sun.COM 	Shell_t			*shp = ((Shbltin_t*)context)->shp;
195*8462SApril.Chin@Sun.COM 	struct {
196*8462SApril.Chin@Sun.COM 	    Optdisc_t	opt;
197*8462SApril.Chin@Sun.COM 	    Namval_t	*np;
198*8462SApril.Chin@Sun.COM 	}			optdisc;
199*8462SApril.Chin@Sun.COM 
200*8462SApril.Chin@Sun.COM 	cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY);
201*8462SApril.Chin@Sun.COM 	for (;;)
202*8462SApril.Chin@Sun.COM 	{
203*8462SApril.Chin@Sun.COM 		switch (optget(argv, enum_usage))
204*8462SApril.Chin@Sun.COM 		{
205*8462SApril.Chin@Sun.COM 		case 'i':
206*8462SApril.Chin@Sun.COM 			iflag = 'i';
207*8462SApril.Chin@Sun.COM 			continue;
208*8462SApril.Chin@Sun.COM 		case '?':
209*8462SApril.Chin@Sun.COM 			error(ERROR_USAGE|4, "%s", opt_info.arg);
210*8462SApril.Chin@Sun.COM 			break;
211*8462SApril.Chin@Sun.COM 		case ':':
212*8462SApril.Chin@Sun.COM 			error(2, "%s", opt_info.arg);
213*8462SApril.Chin@Sun.COM 			break;
214*8462SApril.Chin@Sun.COM 		}
215*8462SApril.Chin@Sun.COM 		break;
216*8462SApril.Chin@Sun.COM 	}
217*8462SApril.Chin@Sun.COM 	argv += opt_info.index;
218*8462SApril.Chin@Sun.COM 	if (error_info.errors || !*argv || *(argv + 1))
219*8462SApril.Chin@Sun.COM 	{
220*8462SApril.Chin@Sun.COM 		error(ERROR_USAGE|2, "%s", optusage(NiL));
221*8462SApril.Chin@Sun.COM 		return 1;
222*8462SApril.Chin@Sun.COM 	}
223*8462SApril.Chin@Sun.COM 	while(cp = *argv++)
224*8462SApril.Chin@Sun.COM 	{
225*8462SApril.Chin@Sun.COM 		if(!(np = nv_open(cp, (void*)0, NV_VARNAME|NV_NOADD))  || !(ap=nv_arrayptr(np)) || ap->fun || (sz=ap->nelem&(((1L<<ARRAY_BITS)-1))) < 2)
226*8462SApril.Chin@Sun.COM 			error(ERROR_exit(1), "%s must name an array  containing at least two elements",cp);
227*8462SApril.Chin@Sun.COM 		n = staktell();
228*8462SApril.Chin@Sun.COM 		sfprintf(stkstd,"%s.%s%c",NV_CLASS,np->nvname,0);
229*8462SApril.Chin@Sun.COM 		tp = nv_open(stakptr(n), shp->var_tree, NV_VARNAME);
230*8462SApril.Chin@Sun.COM 		stakseek(n);
231*8462SApril.Chin@Sun.COM 		n = sz;
232*8462SApril.Chin@Sun.COM 		i = 0;
233*8462SApril.Chin@Sun.COM 		nv_onattr(tp, NV_UINT16);
234*8462SApril.Chin@Sun.COM 		nv_putval(tp, (char*)&i, NV_INTEGER);
235*8462SApril.Chin@Sun.COM 		nv_putsub(np, (char*)0, ARRAY_SCAN);
236*8462SApril.Chin@Sun.COM 		do
237*8462SApril.Chin@Sun.COM 		{
238*8462SApril.Chin@Sun.COM 			sz += strlen(nv_getval(np));
239*8462SApril.Chin@Sun.COM 		}
240*8462SApril.Chin@Sun.COM 		while(nv_nextsub(np));
241*8462SApril.Chin@Sun.COM 		sz += n*sizeof(char*);
242*8462SApril.Chin@Sun.COM 		if(!(ep = newof(0,struct Enum,1,sz)))
243*8462SApril.Chin@Sun.COM 			error(ERROR_system(1), "out of space");
244*8462SApril.Chin@Sun.COM 		ep->iflag = iflag;
245*8462SApril.Chin@Sun.COM 		ep->nelem = n;
246*8462SApril.Chin@Sun.COM 		cp = (char*)&ep->values[n+1];
247*8462SApril.Chin@Sun.COM 		nv_putsub(np, (char*)0, ARRAY_SCAN);
248*8462SApril.Chin@Sun.COM 		ep->values[n] = 0;
249*8462SApril.Chin@Sun.COM 		i = 0;
250*8462SApril.Chin@Sun.COM 		do
251*8462SApril.Chin@Sun.COM 		{
252*8462SApril.Chin@Sun.COM 			ep->values[i++] = cp;
253*8462SApril.Chin@Sun.COM 			sp =  nv_getval(np);
254*8462SApril.Chin@Sun.COM 			n = strlen(sp);
255*8462SApril.Chin@Sun.COM 			memcpy(cp,sp,n+1);
256*8462SApril.Chin@Sun.COM 			cp += n+1;
257*8462SApril.Chin@Sun.COM 		}
258*8462SApril.Chin@Sun.COM 		while(nv_nextsub(np));
259*8462SApril.Chin@Sun.COM 		ep->hdr.dsize = sizeof(struct Enum)+sz;
260*8462SApril.Chin@Sun.COM 		ep->hdr.disc = &ENUM_disc;
261*8462SApril.Chin@Sun.COM 		ep->hdr.type = tp;
262*8462SApril.Chin@Sun.COM 		nv_onattr(tp, NV_RDONLY);
263*8462SApril.Chin@Sun.COM 		nv_disc(tp, &ep->hdr,NV_FIRST);
264*8462SApril.Chin@Sun.COM 		memset(&optdisc,0,sizeof(optdisc));
265*8462SApril.Chin@Sun.COM 		optdisc.opt.infof = enuminfo;
266*8462SApril.Chin@Sun.COM 		optdisc.np = tp;
267*8462SApril.Chin@Sun.COM 		nv_addtype(tp, enum_type, &optdisc.opt, sizeof(optdisc));
268*8462SApril.Chin@Sun.COM 	}
269*8462SApril.Chin@Sun.COM 	return error_info.errors != 0;
270*8462SApril.Chin@Sun.COM }
271*8462SApril.Chin@Sun.COM 
272*8462SApril.Chin@Sun.COM #ifdef STANDALONE
273*8462SApril.Chin@Sun.COM void lib_init(int flag, void* context)
274*8462SApril.Chin@Sun.COM {
275*8462SApril.Chin@Sun.COM 	Shell_t		*shp = ((Shbltin_t*)context)->shp;
276*8462SApril.Chin@Sun.COM 	Namval_t	*mp,*bp;
277*8462SApril.Chin@Sun.COM 	if(flag)
278*8462SApril.Chin@Sun.COM 		return;
279*8462SApril.Chin@Sun.COM 	bp = sh_addbuiltin("Enum", enum_create, (void*)0);
280*8462SApril.Chin@Sun.COM 	mp = nv_search("typeset",shp->bltin_tree,0);
281*8462SApril.Chin@Sun.COM 	nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
282*8462SApril.Chin@Sun.COM }
283*8462SApril.Chin@Sun.COM #endif
284