Blame src/cmd/ksh93/bltins/enum.c

Packit Service a8c26c
/***********************************************************************
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*               This software is part of the ast package               *
Packit Service a8c26c
*          Copyright (c) 1982-2012 AT&T Intellectual Property          *
Packit Service a8c26c
*                      and is licensed under the                       *
Packit Service a8c26c
*                 Eclipse Public License, Version 1.0                  *
Packit Service a8c26c
*                    by AT&T Intellectual Property                     *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                A copy of the License is available at                 *
Packit Service a8c26c
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit Service a8c26c
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*              Information and Software Systems Research               *
Packit Service a8c26c
*                            AT&T Research                             *
Packit Service a8c26c
*                           Florham Park NJ                            *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                  David Korn <dgk@research.att.com>                   *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
***********************************************************************/
Packit Service a8c26c
#pragma prototyped
Packit Service a8c26c
#include	<shell.h>
Packit Service a8c26c
Packit Service a8c26c
static const char enum_usage[] =
Packit Service a8c26c
"[-?@(#)$Id: enum (AT&T Research) 2008-01-08 $\n]"
Packit Service a8c26c
USAGE_LICENSE
Packit Service a8c26c
"[+NAME?enum - create an enumeration type]"
Packit Service a8c26c
"[+DESCRIPTION?\benum\b is a declaration command that creates an enumeration "
Packit Service a8c26c
    "type \atypename\a that can only store any one of the values in the indexed "
Packit Service a8c26c
    "array variable \atypename\a.]"
Packit Service a8c26c
"[+?If the list of \avalue\as is omitted, then \atypename\a must name an "
Packit Service a8c26c
    "indexed array variable with at least two elements.]" 
Packit Service a8c26c
"[i:ignorecase?The values are case insensitive.]"
Packit Service a8c26c
"\n"
Packit Service a8c26c
"\n\atypename\a[\b=(\b \avalue\a ... \b)\b]\n"
Packit Service a8c26c
"\n"
Packit Service a8c26c
"[+EXIT STATUS]"
Packit Service a8c26c
    "{"
Packit Service a8c26c
        "[+0?Successful completion.]"
Packit Service a8c26c
        "[+>0?An error occurred.]"
Packit Service a8c26c
    "}"
Packit Service a8c26c
"[+SEE ALSO?\bksh\b(1), \btypeset\b(1).]"
Packit Service a8c26c
;
Packit Service a8c26c
Packit Service a8c26c
static const char enum_type[] =
Packit Service a8c26c
"[-1c?\n@(#)$Id: type (AT&T Labs Research) 2008-01-08 $\n]"
Packit Service a8c26c
USAGE_LICENSE
Packit Service a8c26c
"[+NAME?\f?\f - create an instance of type \b\f?\f\b]"
Packit Service a8c26c
"[+DESCRIPTION?\b\f?\f\b creates a variable for each \aname\a with "
Packit Service a8c26c
    "enumeration type \b\f?\f\b where \b\f?\f\b is a type that has been "
Packit Service a8c26c
    "created with the \benum\b(1) command.]"
Packit Service a8c26c
"[+?The variable can have one of the following values\fvalues\f.  "
Packit Service a8c26c
    "The the values are \fcase\fcase sensitive.]"
Packit Service a8c26c
"[+?If \b=\b\avalue\a is omitted, the default is \fdefault\f.]"
Packit Service a8c26c
"[+?If no \aname\as are specified then the names and values of all "
Packit Service a8c26c
        "variables of this type are written to standard output.]"
Packit Service a8c26c
"[+?\b\f?\f\b is built-in to the shell as a declaration command so that "
Packit Service a8c26c
        "field splitting and pathname expansion are not performed on "
Packit Service a8c26c
        "the arguments.  Tilde expansion occurs on \avalue\a.]"
Packit Service a8c26c
"[r?Enables readonly.  Once enabled, the value cannot be changed or unset.]"
Packit Service a8c26c
"[a?index array.  Each \aname\a will converted to an index "
Packit Service a8c26c
        "array of type \b\f?\f\b.  If a variable already exists, the current "
Packit Service a8c26c
        "value will become index \b0\b.]"
Packit Service a8c26c
"[A?Associative array.  Each \aname\a will converted to an associate "
Packit Service a8c26c
        "array of type \b\f?\f\b.  If a variable already exists, the current "
Packit Service a8c26c
        "value will become subscript \b0\b.]"
Packit Service a8c26c
"[h]:[string?Used within a type definition to provide a help string  "
Packit Service a8c26c
        "for variable \aname\a.  Otherwise, it is ignored.]"
Packit Service a8c26c
"[S?Used with a type definition to indicate that the variable is shared by "
Packit Service a8c26c
        "each instance of the type.  When used inside a function defined "
Packit Service a8c26c
        "with the \bfunction\b reserved word, the specified variables "
Packit Service a8c26c
        "will have function static scope.  Otherwise, the variable is "
Packit Service a8c26c
        "unset prior to processing the assignment list.]"
Packit Service a8c26c
#if 0
Packit Service a8c26c
"[p?Causes the output to be in a form of \b\f?\f\b commands that can be "
Packit Service a8c26c
        "used as input to the shell to recreate the current type of "
Packit Service a8c26c
        "these variables.]"
Packit Service a8c26c
#endif
Packit Service a8c26c
"\n"
Packit Service a8c26c
"\n[name[=value]...]\n"
Packit Service a8c26c
"\n"
Packit Service a8c26c
"[+EXIT STATUS?]{"
Packit Service a8c26c
        "[+0?Successful completion.]"
Packit Service a8c26c
        "[+>0?An error occurred.]"
Packit Service a8c26c
"}"
Packit Service a8c26c
Packit Service a8c26c
"[+SEE ALSO?\benum\b(1), \btypeset\b(1)]"
Packit Service a8c26c
;
Packit Service a8c26c
Packit Service a8c26c
struct Enum
Packit Service a8c26c
{
Packit Service a8c26c
	Namfun_t	hdr;
Packit Service a8c26c
	short		nelem;
Packit Service a8c26c
	short		iflag;
Packit Service a8c26c
	const char	*values[1];
Packit Service a8c26c
};
Packit Service a8c26c
Packit Service a8c26c
static int enuminfo(Opt_t* op, Sfio_t *out, const char *str, Optdisc_t *fp)
Packit Service a8c26c
{
Packit Service a8c26c
	Namval_t	*np;
Packit Service a8c26c
	struct Enum	*ep;
Packit Service a8c26c
	int		n=0;
Packit Service a8c26c
	const char	*v;
Packit Service a8c26c
	np = *(Namval_t**)(fp+1);
Packit Service a8c26c
	ep = (struct Enum*)np->nvfun;
Packit Service a8c26c
	if(strcmp(str,"default")==0)
Packit Service a8c26c
#if 0
Packit Service a8c26c
		sfprintf(out,"\b%s\b%c",ep->values[0],0);
Packit Service a8c26c
#else
Packit Service a8c26c
		sfprintf(out,"\b%s\b",ep->values[0]);
Packit Service a8c26c
#endif
Packit Service a8c26c
	else if(strcmp(str,"case")==0)
Packit Service a8c26c
	{
Packit Service a8c26c
		if(ep->iflag)
Packit Service a8c26c
			sfprintf(out,"not ");
Packit Service a8c26c
	}
Packit Service a8c26c
	else while(v=ep->values[n++])
Packit Service a8c26c
	{
Packit Service a8c26c
		sfprintf(out,", \b%s\b",v);
Packit Service a8c26c
	}
Packit Service a8c26c
	return(0);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
static Namfun_t *clone_enum(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
Packit Service a8c26c
{
Packit Service a8c26c
	struct Enum	*ep, *pp=(struct Enum*)fp;
Packit Service a8c26c
	ep = newof(0,struct Enum,1,pp->nelem*sizeof(char*));
Packit Service a8c26c
	memcpy((void*)ep,(void*)pp,sizeof(struct Enum)+pp->nelem*sizeof(char*));
Packit Service a8c26c
	return(&ep->hdr);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
static void put_enum(Namval_t* np,const char *val,int flags,Namfun_t *fp)
Packit Service a8c26c
{
Packit Service a8c26c
	struct Enum 		*ep = (struct Enum*)fp;
Packit Service a8c26c
	register const char	*v;
Packit Service a8c26c
	unsigned short		i=0, n;
Packit Service a8c26c
	if(!val)
Packit Service a8c26c
	{
Packit Service a8c26c
		nv_putv(np, val, flags,fp);
Packit Service a8c26c
		nv_disc(np,&ep->hdr,NV_POP);
Packit Service a8c26c
		if(!ep->hdr.nofree)
Packit Service a8c26c
			free((void*)ep);
Packit Service a8c26c
		return;
Packit Service a8c26c
	}
Packit Service a8c26c
	if(flags&NV_INTEGER)
Packit Service a8c26c
	{
Packit Service a8c26c
		nv_putv(np,val,flags,fp);
Packit Service a8c26c
		return;
Packit Service a8c26c
	}
Packit Service a8c26c
	while(v=ep->values[i])
Packit Service a8c26c
	{
Packit Service a8c26c
		if(ep->iflag)
Packit Service a8c26c
			n = strcasecmp(v,val);
Packit Service a8c26c
		else
Packit Service a8c26c
			n = strcmp(v,val);
Packit Service a8c26c
		if(n==0)
Packit Service a8c26c
		{
Packit Service a8c26c
			nv_putv(np, (char*)&i, NV_UINT16, fp);
Packit Service a8c26c
			return;
Packit Service a8c26c
		}
Packit Service a8c26c
		i++;
Packit Service a8c26c
	}
Packit Service a8c26c
	if(nv_isattr(np,NV_NOFREE))
Packit Service a8c26c
		error(ERROR_exit(1), "%s:  invalid value %s",nv_name(np),val);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
static char* get_enum(register Namval_t* np, Namfun_t *fp)
Packit Service a8c26c
{
Packit Service a8c26c
	static char buff[6];
Packit Service a8c26c
	struct Enum *ep = (struct Enum*)fp;
Packit Service a8c26c
	long n = nv_getn(np,fp);
Packit Service a8c26c
	if(n < ep->nelem)
Packit Service a8c26c
		return((char*)ep->values[n]);
Packit Service a8c26c
	sfsprintf(buff,sizeof(buff),"%u%c",n,0);
Packit Service a8c26c
	return(buff);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
static Sfdouble_t get_nenum(register Namval_t* np, Namfun_t *fp)
Packit Service a8c26c
{
Packit Service a8c26c
	return(nv_getn(np,fp));
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
const Namdisc_t ENUM_disc        = {  0, put_enum, get_enum, get_nenum, 0,0,clone_enum };
Packit Service a8c26c
Packit Service a8c26c
#ifdef STANDALONE
Packit Service a8c26c
static int enum_create(int argc, char** argv, Shbltin_t *context)
Packit Service a8c26c
#else
Packit Service a8c26c
int b_enum(int argc, char** argv, Shbltin_t *context)
Packit Service a8c26c
#endif
Packit Service a8c26c
{
Packit Service a8c26c
	int			sz,i,n,iflag = 0;
Packit Service a8c26c
	Namval_t		*np, *tp;
Packit Service a8c26c
	Namarr_t		*ap;
Packit Service a8c26c
	char			*cp,*sp;
Packit Service a8c26c
	struct Enum		*ep;
Packit Service a8c26c
	Shell_t			*shp = context->shp;
Packit Service a8c26c
	struct {
Packit Service a8c26c
	    Optdisc_t	opt;
Packit Service a8c26c
	    Namval_t	*np;
Packit Service a8c26c
	}			optdisc;
Packit Service a8c26c
Packit Service a8c26c
	cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY);
Packit Service a8c26c
	for (;;)
Packit Service a8c26c
	{
Packit Service a8c26c
		switch (optget(argv, enum_usage))
Packit Service a8c26c
		{
Packit Service a8c26c
		case 'i':
Packit Service a8c26c
			iflag = 'i';
Packit Service a8c26c
			continue;
Packit Service a8c26c
		case '?':
Packit Service a8c26c
			error(ERROR_USAGE|4, "%s", opt_info.arg);
Packit Service a8c26c
			break;
Packit Service a8c26c
		case ':':
Packit Service a8c26c
			error(2, "%s", opt_info.arg);
Packit Service a8c26c
			break;
Packit Service a8c26c
		}
Packit Service a8c26c
		break;
Packit Service a8c26c
	}
Packit Service a8c26c
	argv += opt_info.index;
Packit Service a8c26c
	if (error_info.errors || !*argv || *(argv + 1))
Packit Service a8c26c
	{
Packit Service a8c26c
		error(ERROR_USAGE|2, "%s", optusage(NiL));
Packit Service a8c26c
		return 1;
Packit Service a8c26c
	}
Packit Service a8c26c
	while(cp = *argv++)
Packit Service a8c26c
	{
Packit Service a8c26c
		if(!(np = nv_open(cp, (void*)0, NV_VARNAME|NV_NOADD))  || !(ap=nv_arrayptr(np)) || ap->fun || (sz=ap->nelem&(((1L<
Packit Service a8c26c
			error(ERROR_exit(1), "%s must name an array  containing at least two elements",cp);
Packit Service a8c26c
		n = staktell();
Packit Service a8c26c
		sfprintf(stkstd,"%s.%s%c",NV_CLASS,np->nvname,0);
Packit Service a8c26c
		tp = nv_open(stakptr(n), shp->var_tree, NV_VARNAME);
Packit Service a8c26c
		stakseek(n);
Packit Service a8c26c
		n = sz;
Packit Service a8c26c
		i = 0;
Packit Service a8c26c
		nv_onattr(tp, NV_UINT16);
Packit Service a8c26c
		nv_putval(tp, (char*)&i, NV_INTEGER);
Packit Service a8c26c
		nv_putsub(np, (char*)0, ARRAY_SCAN);
Packit Service a8c26c
		do
Packit Service a8c26c
		{
Packit Service a8c26c
			sz += strlen(nv_getval(np));
Packit Service a8c26c
		}
Packit Service a8c26c
		while(nv_nextsub(np));
Packit Service a8c26c
		sz += n*sizeof(char*);
Packit Service a8c26c
		if(!(ep = newof(0,struct Enum,1,sz)))
Packit Service a8c26c
			error(ERROR_system(1), "out of space");
Packit Service a8c26c
		ep->iflag = iflag;
Packit Service a8c26c
		ep->nelem = n;
Packit Service a8c26c
		cp = (char*)&ep->values[n+1];
Packit Service a8c26c
		nv_putsub(np, (char*)0, ARRAY_SCAN);
Packit Service a8c26c
		ep->values[n] = 0;
Packit Service a8c26c
		i = 0;
Packit Service a8c26c
		do
Packit Service a8c26c
		{
Packit Service a8c26c
			ep->values[i++] = cp;
Packit Service a8c26c
			sp =  nv_getval(np);
Packit Service a8c26c
			n = strlen(sp);
Packit Service a8c26c
			memcpy(cp,sp,n+1);
Packit Service a8c26c
			cp += n+1;
Packit Service a8c26c
		}
Packit Service a8c26c
		while(nv_nextsub(np));
Packit Service a8c26c
		ep->hdr.dsize = sizeof(struct Enum)+sz;
Packit Service a8c26c
		ep->hdr.disc = &ENUM_disc;
Packit Service a8c26c
		ep->hdr.type = tp;
Packit Service a8c26c
		nv_onattr(tp, NV_RDONLY);
Packit Service a8c26c
		nv_disc(tp, &ep->hdr,NV_FIRST);
Packit Service a8c26c
		memset(&optdisc,0,sizeof(optdisc));
Packit Service a8c26c
		optdisc.opt.infof = enuminfo;
Packit Service a8c26c
		optdisc.np = tp;
Packit Service a8c26c
		nv_addtype(tp, enum_type, &optdisc.opt, sizeof(optdisc)); 
Packit Service a8c26c
	}
Packit Service a8c26c
	return error_info.errors != 0;
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
#ifdef STANDALONE
Packit Service a8c26c
void lib_init(int flag, void* context)
Packit Service a8c26c
{
Packit Service a8c26c
	Shell_t		*shp = ((Shbltin_t*)context)->shp;
Packit Service a8c26c
	Namval_t	*mp,*bp;
Packit Service a8c26c
	if(flag)
Packit Service a8c26c
		return;
Packit Service a8c26c
	bp = sh_addbuiltin("Enum", enum_create, (void*)0); 
Packit Service a8c26c
	mp = nv_search("typeset",shp->bltin_tree,0);
Packit Service a8c26c
	nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
Packit Service a8c26c
}
Packit Service a8c26c
#endif