1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@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 omitted, 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_putv(np, val, flags,fp); 139 nv_disc(np,&ep->hdr,NV_POP); 140 if(!ep->hdr.nofree) 141 free((void*)ep); 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 if(nv_isattr(np,NV_NOFREE)) 163 error(ERROR_exit(1), "%s: invalid value %s",nv_name(np),val); 164 } 165 166 static char* get_enum(register Namval_t* np, Namfun_t *fp) 167 { 168 static char buff[6]; 169 struct Enum *ep = (struct Enum*)fp; 170 long n = nv_getn(np,fp); 171 if(n < ep->nelem) 172 return((char*)ep->values[n]); 173 sfsprintf(buff,sizeof(buff),"%u%c",n,0); 174 return(buff); 175 } 176 177 static Sfdouble_t get_nenum(register Namval_t* np, Namfun_t *fp) 178 { 179 return(nv_getn(np,fp)); 180 } 181 182 const Namdisc_t ENUM_disc = { 0, put_enum, get_enum, get_nenum, 0,0,clone_enum }; 183 184 #ifdef STANDALONE 185 static int enum_create(int argc, char** argv, Shbltin_t *context) 186 #else 187 int b_enum(int argc, char** argv, Shbltin_t *context) 188 #endif 189 { 190 int sz,i,n,iflag = 0; 191 Namval_t *np, *tp; 192 Namarr_t *ap; 193 char *cp,*sp; 194 struct Enum *ep; 195 Shell_t *shp = context->shp; 196 struct { 197 Optdisc_t opt; 198 Namval_t *np; 199 } optdisc; 200 201 cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); 202 for (;;) 203 { 204 switch (optget(argv, enum_usage)) 205 { 206 case 'i': 207 iflag = 'i'; 208 continue; 209 case '?': 210 error(ERROR_USAGE|4, "%s", opt_info.arg); 211 break; 212 case ':': 213 error(2, "%s", opt_info.arg); 214 break; 215 } 216 break; 217 } 218 argv += opt_info.index; 219 if (error_info.errors || !*argv || *(argv + 1)) 220 { 221 error(ERROR_USAGE|2, "%s", optusage(NiL)); 222 return 1; 223 } 224 while(cp = *argv++) 225 { 226 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) 227 error(ERROR_exit(1), "%s must name an array containing at least two elements",cp); 228 n = staktell(); 229 sfprintf(stkstd,"%s.%s%c",NV_CLASS,np->nvname,0); 230 tp = nv_open(stakptr(n), shp->var_tree, NV_VARNAME); 231 stakseek(n); 232 n = sz; 233 i = 0; 234 nv_onattr(tp, NV_UINT16); 235 nv_putval(tp, (char*)&i, NV_INTEGER); 236 nv_putsub(np, (char*)0, ARRAY_SCAN); 237 do 238 { 239 sz += strlen(nv_getval(np)); 240 } 241 while(nv_nextsub(np)); 242 sz += n*sizeof(char*); 243 if(!(ep = newof(0,struct Enum,1,sz))) 244 error(ERROR_system(1), "out of space"); 245 ep->iflag = iflag; 246 ep->nelem = n; 247 cp = (char*)&ep->values[n+1]; 248 nv_putsub(np, (char*)0, ARRAY_SCAN); 249 ep->values[n] = 0; 250 i = 0; 251 do 252 { 253 ep->values[i++] = cp; 254 sp = nv_getval(np); 255 n = strlen(sp); 256 memcpy(cp,sp,n+1); 257 cp += n+1; 258 } 259 while(nv_nextsub(np)); 260 ep->hdr.dsize = sizeof(struct Enum)+sz; 261 ep->hdr.disc = &ENUM_disc; 262 ep->hdr.type = tp; 263 nv_onattr(tp, NV_RDONLY); 264 nv_disc(tp, &ep->hdr,NV_FIRST); 265 memset(&optdisc,0,sizeof(optdisc)); 266 optdisc.opt.infof = enuminfo; 267 optdisc.np = tp; 268 nv_addtype(tp, enum_type, &optdisc.opt, sizeof(optdisc)); 269 } 270 return error_info.errors != 0; 271 } 272 273 #ifdef STANDALONE 274 void lib_init(int flag, void* context) 275 { 276 Shell_t *shp = ((Shbltin_t*)context)->shp; 277 Namval_t *mp,*bp; 278 if(flag) 279 return; 280 bp = sh_addbuiltin("Enum", enum_create, (void*)0); 281 mp = nv_search("typeset",shp->bltin_tree,0); 282 nv_onattr(bp,nv_isattr(mp,NV_PUBLIC)); 283 } 284 #endif 285