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