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