xref: /titanic_51/usr/src/lib/libshell/common/bltins/enum.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
17c2fbfb3SApril Chin /***********************************************************************
27c2fbfb3SApril Chin *                                                                      *
37c2fbfb3SApril Chin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
57c2fbfb3SApril Chin *                      and is licensed under the                       *
67c2fbfb3SApril Chin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
87c2fbfb3SApril Chin *                                                                      *
97c2fbfb3SApril Chin *                A copy of the License is available at                 *
107c2fbfb3SApril Chin *            http://www.opensource.org/licenses/cpl1.0.txt             *
117c2fbfb3SApril Chin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
127c2fbfb3SApril Chin *                                                                      *
137c2fbfb3SApril Chin *              Information and Software Systems Research               *
147c2fbfb3SApril Chin *                            AT&T Research                             *
157c2fbfb3SApril Chin *                           Florham Park NJ                            *
167c2fbfb3SApril Chin *                                                                      *
177c2fbfb3SApril Chin *                  David Korn <dgk@research.att.com>                   *
187c2fbfb3SApril Chin *                                                                      *
197c2fbfb3SApril Chin ***********************************************************************/
207c2fbfb3SApril Chin #pragma prototyped
217c2fbfb3SApril Chin #include	<shell.h>
227c2fbfb3SApril Chin 
237c2fbfb3SApril Chin static const char enum_usage[] =
247c2fbfb3SApril Chin "[-?@(#)$Id: enum (AT&T Research) 2008-01-08 $\n]"
257c2fbfb3SApril Chin USAGE_LICENSE
267c2fbfb3SApril Chin "[+NAME?enum - create an enumeration type]"
277c2fbfb3SApril Chin "[+DESCRIPTION?\benum\b is a declaration command that creates an enumeration "
287c2fbfb3SApril Chin     "type \atypename\a that can only store any one of the values in the indexed "
297c2fbfb3SApril Chin     "array variable \atypename\a.]"
30*3e14f97fSRoger A. Faulkner "[+?If the list of \avalue\as is omitted, then \atypename\a must name an "
317c2fbfb3SApril Chin     "indexed array variable with at least two elements.]"
327c2fbfb3SApril Chin "[i:ignorecase?The values are case insensitive.]"
337c2fbfb3SApril Chin "\n"
347c2fbfb3SApril Chin "\n\atypename\a[\b=(\b \avalue\a ... \b)\b]\n"
357c2fbfb3SApril Chin "\n"
367c2fbfb3SApril Chin "[+EXIT STATUS]"
377c2fbfb3SApril Chin     "{"
387c2fbfb3SApril Chin         "[+0?Successful completion.]"
397c2fbfb3SApril Chin         "[+>0?An error occurred.]"
407c2fbfb3SApril Chin     "}"
417c2fbfb3SApril Chin "[+SEE ALSO?\bksh\b(1), \btypeset\b(1).]"
427c2fbfb3SApril Chin ;
437c2fbfb3SApril Chin 
447c2fbfb3SApril Chin static const char enum_type[] =
457c2fbfb3SApril Chin "[-1c?\n@(#)$Id: type (AT&T Labs Research) 2008-01-08 $\n]"
467c2fbfb3SApril Chin USAGE_LICENSE
477c2fbfb3SApril Chin "[+NAME?\f?\f - create an instance of type \b\f?\f\b]"
487c2fbfb3SApril Chin "[+DESCRIPTION?\b\f?\f\b creates a variable for each \aname\a with "
497c2fbfb3SApril Chin     "enumeration type \b\f?\f\b where \b\f?\f\b is a type that has been "
507c2fbfb3SApril Chin     "created with the \benum\b(1) command.]"
517c2fbfb3SApril Chin "[+?The variable can have one of the following values\fvalues\f.  "
527c2fbfb3SApril Chin     "The the values are \fcase\fcase sensitive.]"
537c2fbfb3SApril Chin "[+?If \b=\b\avalue\a is omitted, the default is \fdefault\f.]"
547c2fbfb3SApril Chin "[+?If no \aname\as are specified then the names and values of all "
557c2fbfb3SApril Chin         "variables of this type are written to standard output.]"
567c2fbfb3SApril Chin "[+?\b\f?\f\b is built-in to the shell as a declaration command so that "
577c2fbfb3SApril Chin         "field splitting and pathname expansion are not performed on "
587c2fbfb3SApril Chin         "the arguments.  Tilde expansion occurs on \avalue\a.]"
597c2fbfb3SApril Chin "[r?Enables readonly.  Once enabled, the value cannot be changed or unset.]"
607c2fbfb3SApril Chin "[a?index array.  Each \aname\a will converted to an index "
617c2fbfb3SApril Chin         "array of type \b\f?\f\b.  If a variable already exists, the current "
627c2fbfb3SApril Chin         "value will become index \b0\b.]"
637c2fbfb3SApril Chin "[A?Associative array.  Each \aname\a will converted to an associate "
647c2fbfb3SApril Chin         "array of type \b\f?\f\b.  If a variable already exists, the current "
657c2fbfb3SApril Chin         "value will become subscript \b0\b.]"
667c2fbfb3SApril Chin "[h]:[string?Used within a type definition to provide a help string  "
677c2fbfb3SApril Chin         "for variable \aname\a.  Otherwise, it is ignored.]"
687c2fbfb3SApril Chin "[S?Used with a type definition to indicate that the variable is shared by "
697c2fbfb3SApril Chin         "each instance of the type.  When used inside a function defined "
707c2fbfb3SApril Chin         "with the \bfunction\b reserved word, the specified variables "
717c2fbfb3SApril Chin         "will have function static scope.  Otherwise, the variable is "
727c2fbfb3SApril Chin         "unset prior to processing the assignment list.]"
737c2fbfb3SApril Chin #if 0
747c2fbfb3SApril Chin "[p?Causes the output to be in a form of \b\f?\f\b commands that can be "
757c2fbfb3SApril Chin         "used as input to the shell to recreate the current type of "
767c2fbfb3SApril Chin         "these variables.]"
777c2fbfb3SApril Chin #endif
787c2fbfb3SApril Chin "\n"
797c2fbfb3SApril Chin "\n[name[=value]...]\n"
807c2fbfb3SApril Chin "\n"
817c2fbfb3SApril Chin "[+EXIT STATUS?]{"
827c2fbfb3SApril Chin         "[+0?Successful completion.]"
837c2fbfb3SApril Chin         "[+>0?An error occurred.]"
847c2fbfb3SApril Chin "}"
857c2fbfb3SApril Chin 
867c2fbfb3SApril Chin "[+SEE ALSO?\benum\b(1), \btypeset\b(1)]"
877c2fbfb3SApril Chin ;
887c2fbfb3SApril Chin 
897c2fbfb3SApril Chin struct Enum
907c2fbfb3SApril Chin {
917c2fbfb3SApril Chin 	Namfun_t	hdr;
927c2fbfb3SApril Chin 	short		nelem;
937c2fbfb3SApril Chin 	short		iflag;
947c2fbfb3SApril Chin 	const char	*values[1];
957c2fbfb3SApril Chin };
967c2fbfb3SApril Chin 
enuminfo(Opt_t * op,Sfio_t * out,const char * str,Optdisc_t * fp)977c2fbfb3SApril Chin static int enuminfo(Opt_t* op, Sfio_t *out, const char *str, Optdisc_t *fp)
987c2fbfb3SApril Chin {
997c2fbfb3SApril Chin 	Namval_t	*np;
1007c2fbfb3SApril Chin 	struct Enum	*ep;
1017c2fbfb3SApril Chin 	int		n=0;
1027c2fbfb3SApril Chin 	const char	*v;
1037c2fbfb3SApril Chin 	np = *(Namval_t**)(fp+1);
1047c2fbfb3SApril Chin 	ep = (struct Enum*)np->nvfun;
1057c2fbfb3SApril Chin 	if(strcmp(str,"default")==0)
1067c2fbfb3SApril Chin #if 0
1077c2fbfb3SApril Chin 		sfprintf(out,"\b%s\b%c",ep->values[0],0);
1087c2fbfb3SApril Chin #else
1097c2fbfb3SApril Chin 		sfprintf(out,"\b%s\b",ep->values[0]);
1107c2fbfb3SApril Chin #endif
1117c2fbfb3SApril Chin 	else if(strcmp(str,"case")==0)
1127c2fbfb3SApril Chin 	{
1137c2fbfb3SApril Chin 		if(ep->iflag)
1147c2fbfb3SApril Chin 			sfprintf(out,"not ");
1157c2fbfb3SApril Chin 	}
1167c2fbfb3SApril Chin 	else while(v=ep->values[n++])
1177c2fbfb3SApril Chin 	{
1187c2fbfb3SApril Chin 		sfprintf(out,", \b%s\b",v);
1197c2fbfb3SApril Chin 	}
1207c2fbfb3SApril Chin 	return(0);
1217c2fbfb3SApril Chin }
1227c2fbfb3SApril Chin 
clone_enum(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)1237c2fbfb3SApril Chin static Namfun_t *clone_enum(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
1247c2fbfb3SApril Chin {
1257c2fbfb3SApril Chin 	struct Enum	*ep, *pp=(struct Enum*)fp;
1267c2fbfb3SApril Chin 	ep = newof(0,struct Enum,1,pp->nelem*sizeof(char*));
1277c2fbfb3SApril Chin 	memcpy((void*)ep,(void*)pp,sizeof(struct Enum)+pp->nelem*sizeof(char*));
1287c2fbfb3SApril Chin 	return(&ep->hdr);
1297c2fbfb3SApril Chin }
1307c2fbfb3SApril Chin 
put_enum(Namval_t * np,const char * val,int flags,Namfun_t * fp)1317c2fbfb3SApril Chin static void put_enum(Namval_t* np,const char *val,int flags,Namfun_t *fp)
1327c2fbfb3SApril Chin {
1337c2fbfb3SApril Chin 	struct Enum 		*ep = (struct Enum*)fp;
1347c2fbfb3SApril Chin 	register const char	*v;
1357c2fbfb3SApril Chin 	unsigned short		i=0, n;
1367c2fbfb3SApril Chin 	if(!val)
1377c2fbfb3SApril Chin 	{
1387c2fbfb3SApril Chin 		nv_disc(np,&ep->hdr,NV_POP);
1397c2fbfb3SApril Chin 		if(!ep->hdr.nofree)
1407c2fbfb3SApril Chin 			free((void*)ep);
1417c2fbfb3SApril Chin 		nv_putv(np, val, flags,fp);
1427c2fbfb3SApril Chin 		return;
1437c2fbfb3SApril Chin 	}
1447c2fbfb3SApril Chin 	if(flags&NV_INTEGER)
1457c2fbfb3SApril Chin 	{
1467c2fbfb3SApril Chin 		nv_putv(np,val,flags,fp);
1477c2fbfb3SApril Chin 		return;
1487c2fbfb3SApril Chin 	}
1497c2fbfb3SApril Chin 	while(v=ep->values[i])
1507c2fbfb3SApril Chin 	{
1517c2fbfb3SApril Chin 		if(ep->iflag)
1527c2fbfb3SApril Chin 			n = strcasecmp(v,val);
1537c2fbfb3SApril Chin 		else
1547c2fbfb3SApril Chin 			n = strcmp(v,val);
1557c2fbfb3SApril Chin 		if(n==0)
1567c2fbfb3SApril Chin 		{
1577c2fbfb3SApril Chin 			nv_putv(np, (char*)&i, NV_UINT16, fp);
1587c2fbfb3SApril Chin 			return;
1597c2fbfb3SApril Chin 		}
1607c2fbfb3SApril Chin 		i++;
1617c2fbfb3SApril Chin 	}
1627c2fbfb3SApril Chin 	error(ERROR_exit(1), "%s:  invalid value %s",nv_name(np),val);
1637c2fbfb3SApril Chin }
1647c2fbfb3SApril Chin 
get_enum(register Namval_t * np,Namfun_t * fp)1657c2fbfb3SApril Chin static char* get_enum(register Namval_t* np, Namfun_t *fp)
1667c2fbfb3SApril Chin {
1677c2fbfb3SApril Chin 	static char buff[6];
1687c2fbfb3SApril Chin 	struct Enum *ep = (struct Enum*)fp;
1697c2fbfb3SApril Chin 	long n = nv_getn(np,fp);
1707c2fbfb3SApril Chin 	if(n < ep->nelem)
1717c2fbfb3SApril Chin 		return((char*)ep->values[n]);
1727c2fbfb3SApril Chin 	sfsprintf(buff,sizeof(buff),"%u%c",n,0);
1737c2fbfb3SApril Chin 	return(buff);
1747c2fbfb3SApril Chin }
1757c2fbfb3SApril Chin 
get_nenum(register Namval_t * np,Namfun_t * fp)1767c2fbfb3SApril Chin static Sfdouble_t get_nenum(register Namval_t* np, Namfun_t *fp)
1777c2fbfb3SApril Chin {
1787c2fbfb3SApril Chin 	return(nv_getn(np,fp));
1797c2fbfb3SApril Chin }
1807c2fbfb3SApril Chin 
1817c2fbfb3SApril Chin const Namdisc_t ENUM_disc        = {  0, put_enum, get_enum, get_nenum, 0,0,clone_enum };
1827c2fbfb3SApril Chin 
1837c2fbfb3SApril Chin #ifdef STANDALONE
enum_create(int argc,char ** argv,void * context)1847c2fbfb3SApril Chin static int enum_create(int argc, char** argv, void* context)
1857c2fbfb3SApril Chin #else
1867c2fbfb3SApril Chin int b_enum(int argc, char** argv, void* context)
1877c2fbfb3SApril Chin #endif
1887c2fbfb3SApril Chin {
1897c2fbfb3SApril Chin 	int			sz,i,n,iflag = 0;
1907c2fbfb3SApril Chin 	Namval_t		*np, *tp;
1917c2fbfb3SApril Chin 	Namarr_t		*ap;
1927c2fbfb3SApril Chin 	char			*cp,*sp;
1937c2fbfb3SApril Chin 	struct Enum		*ep;
1947c2fbfb3SApril Chin 	Shell_t			*shp = ((Shbltin_t*)context)->shp;
1957c2fbfb3SApril Chin 	struct {
1967c2fbfb3SApril Chin 	    Optdisc_t	opt;
1977c2fbfb3SApril Chin 	    Namval_t	*np;
1987c2fbfb3SApril Chin 	}			optdisc;
1997c2fbfb3SApril Chin 
2007c2fbfb3SApril Chin 	cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY);
2017c2fbfb3SApril Chin 	for (;;)
2027c2fbfb3SApril Chin 	{
2037c2fbfb3SApril Chin 		switch (optget(argv, enum_usage))
2047c2fbfb3SApril Chin 		{
2057c2fbfb3SApril Chin 		case 'i':
2067c2fbfb3SApril Chin 			iflag = 'i';
2077c2fbfb3SApril Chin 			continue;
2087c2fbfb3SApril Chin 		case '?':
2097c2fbfb3SApril Chin 			error(ERROR_USAGE|4, "%s", opt_info.arg);
2107c2fbfb3SApril Chin 			break;
2117c2fbfb3SApril Chin 		case ':':
2127c2fbfb3SApril Chin 			error(2, "%s", opt_info.arg);
2137c2fbfb3SApril Chin 			break;
2147c2fbfb3SApril Chin 		}
2157c2fbfb3SApril Chin 		break;
2167c2fbfb3SApril Chin 	}
2177c2fbfb3SApril Chin 	argv += opt_info.index;
2187c2fbfb3SApril Chin 	if (error_info.errors || !*argv || *(argv + 1))
2197c2fbfb3SApril Chin 	{
2207c2fbfb3SApril Chin 		error(ERROR_USAGE|2, "%s", optusage(NiL));
2217c2fbfb3SApril Chin 		return 1;
2227c2fbfb3SApril Chin 	}
2237c2fbfb3SApril Chin 	while(cp = *argv++)
2247c2fbfb3SApril Chin 	{
2257c2fbfb3SApril Chin 		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)
2267c2fbfb3SApril Chin 			error(ERROR_exit(1), "%s must name an array  containing at least two elements",cp);
2277c2fbfb3SApril Chin 		n = staktell();
2287c2fbfb3SApril Chin 		sfprintf(stkstd,"%s.%s%c",NV_CLASS,np->nvname,0);
2297c2fbfb3SApril Chin 		tp = nv_open(stakptr(n), shp->var_tree, NV_VARNAME);
2307c2fbfb3SApril Chin 		stakseek(n);
2317c2fbfb3SApril Chin 		n = sz;
2327c2fbfb3SApril Chin 		i = 0;
2337c2fbfb3SApril Chin 		nv_onattr(tp, NV_UINT16);
2347c2fbfb3SApril Chin 		nv_putval(tp, (char*)&i, NV_INTEGER);
2357c2fbfb3SApril Chin 		nv_putsub(np, (char*)0, ARRAY_SCAN);
2367c2fbfb3SApril Chin 		do
2377c2fbfb3SApril Chin 		{
2387c2fbfb3SApril Chin 			sz += strlen(nv_getval(np));
2397c2fbfb3SApril Chin 		}
2407c2fbfb3SApril Chin 		while(nv_nextsub(np));
2417c2fbfb3SApril Chin 		sz += n*sizeof(char*);
2427c2fbfb3SApril Chin 		if(!(ep = newof(0,struct Enum,1,sz)))
2437c2fbfb3SApril Chin 			error(ERROR_system(1), "out of space");
2447c2fbfb3SApril Chin 		ep->iflag = iflag;
2457c2fbfb3SApril Chin 		ep->nelem = n;
2467c2fbfb3SApril Chin 		cp = (char*)&ep->values[n+1];
2477c2fbfb3SApril Chin 		nv_putsub(np, (char*)0, ARRAY_SCAN);
2487c2fbfb3SApril Chin 		ep->values[n] = 0;
2497c2fbfb3SApril Chin 		i = 0;
2507c2fbfb3SApril Chin 		do
2517c2fbfb3SApril Chin 		{
2527c2fbfb3SApril Chin 			ep->values[i++] = cp;
2537c2fbfb3SApril Chin 			sp =  nv_getval(np);
2547c2fbfb3SApril Chin 			n = strlen(sp);
2557c2fbfb3SApril Chin 			memcpy(cp,sp,n+1);
2567c2fbfb3SApril Chin 			cp += n+1;
2577c2fbfb3SApril Chin 		}
2587c2fbfb3SApril Chin 		while(nv_nextsub(np));
2597c2fbfb3SApril Chin 		ep->hdr.dsize = sizeof(struct Enum)+sz;
2607c2fbfb3SApril Chin 		ep->hdr.disc = &ENUM_disc;
2617c2fbfb3SApril Chin 		ep->hdr.type = tp;
2627c2fbfb3SApril Chin 		nv_onattr(tp, NV_RDONLY);
2637c2fbfb3SApril Chin 		nv_disc(tp, &ep->hdr,NV_FIRST);
2647c2fbfb3SApril Chin 		memset(&optdisc,0,sizeof(optdisc));
2657c2fbfb3SApril Chin 		optdisc.opt.infof = enuminfo;
2667c2fbfb3SApril Chin 		optdisc.np = tp;
2677c2fbfb3SApril Chin 		nv_addtype(tp, enum_type, &optdisc.opt, sizeof(optdisc));
2687c2fbfb3SApril Chin 	}
2697c2fbfb3SApril Chin 	return error_info.errors != 0;
2707c2fbfb3SApril Chin }
2717c2fbfb3SApril Chin 
2727c2fbfb3SApril Chin #ifdef STANDALONE
lib_init(int flag,void * context)2737c2fbfb3SApril Chin void lib_init(int flag, void* context)
2747c2fbfb3SApril Chin {
2757c2fbfb3SApril Chin 	Shell_t		*shp = ((Shbltin_t*)context)->shp;
2767c2fbfb3SApril Chin 	Namval_t	*mp,*bp;
2777c2fbfb3SApril Chin 	if(flag)
2787c2fbfb3SApril Chin 		return;
2797c2fbfb3SApril Chin 	bp = sh_addbuiltin("Enum", enum_create, (void*)0);
2807c2fbfb3SApril Chin 	mp = nv_search("typeset",shp->bltin_tree,0);
2817c2fbfb3SApril Chin 	nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
2827c2fbfb3SApril Chin }
2837c2fbfb3SApril Chin #endif
284