Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!think.com!mintaka!bloom-beacon!eru!kth.se!sunic!mcsun!cernvax!burow From: burow@cernvax.cern.ch (burkhard burow) Newsgroups: comp.lang.c Subject: Re: Grouse: What's the point of enum? Message-ID: <4972@cernvax.cern.ch> Date: 21 Apr 91 08:37:25 GMT References: Organization: CERN, European Laboratory for Particle Physics Lines: 223 [] On 18 Apr 91 04:26:15 GMT, rogue@cellar.UUCP (Rogue Winter) said: RW> If the names given to enumerated values cannot be printed, why do RW> they exist? The only purpose I can see is that they become local RW> symbolic constants. Below, in enum.h, is a souped up 'enum' and an example program follows in enum.c. Cut 'em out, compile, and a demo's ready for you. In no more code than a regular typedef enum, the macros ENUMn(...), where n is the number of constants in the enumeration, provides: i) the constants. ii) the number of constants. iii) an array of the constant names as strings. iv) a macro to recognize a particular constant in the enumeration. v) addition of another constant to the enumeration without changing a single line of code elsewhere. WARNING: In the following, as far as I know, the only deviation from ANSI C is the '/**/' kludge for the preprocessor concatenation operator '##'. I use ENUMn on: VAX VMS: C 3.1 and MIPS Computer Systems 2.0 (e.g. SGI and DECstations). Some 'guidelines' for these two machines are given in enum.h. May it amuse, burkhard burow@vxdesy.cern.ch ------------cut here for enum.c------------------------------------------------ /* enum.c An example of the macros in enum.h */ /* Burkhard Burow, University of Toronto, 1990. */ #include "enum.h" #include #define MIN(A,B) ((A)<(B)?(A):(B)) /* Note that adding another constant to the following line requires no change in any other line of code. */ #ifndef mips ENUM5(LIST, JUST, SOME, SILLY, STUFF, AGAIN); #else ENUM5(LIST,JUST,SOME,SILLY,STUFF,AGAIN); #endif main () { int i, loop; char s[99]; LIST list; puts("The enum 'LIST' has the following enumerated constants."); for (i=0; i<(int)LISTS; i++) printf(" %s", enum_str(LIST)[i]); puts("\n Please enter one of the above constants: "); gets(s); for (loop=0; loop<4; loop++) { switch (loop) { case 0: printf("An exact comparison"); ENUMno(LIST, s, 9999, i); break; case 1: printf("A comparison of the first strlen('LIST' element) characters"); ENUMno(LIST, s, strlen(enum_str(LIST)[i]), i); break; case 2: printf("A comparison of the first strlen(%s) characters",s); ENUMno(LIST, s, strlen(s), i); break; case 3: printf("A comparison of the first "); printf("MIN(strlen(%s), strlen('LIST' element) ) characters", s); ENUMno(LIST, s, MIN(strlen(s),strlen(enum_str(LIST)[i])), i); break; } if (i==(int)LISTS) printf("\n does not recognize %s as a constant in 'LIST'\n\n", s); else printf("\n recognizes %s as the constant %s in 'LIST'\n\n", s, enum_str(LIST)[i]); } } ------------cut here for enum.h------------------------------------------------ /* enum.h */ /* Burkhard Burow, University of Toronto, 1990. */ #ifndef __ENUM_LOADED #define __ENUM_LOADED 1 static char *nonindent(char *s) { while(*s==' ')s++; return s; } #include #include /* Souped up enum => ENUM1->ENUMn. Typedef's NAME as enumerated with the n given constants. enum_str(NAME) is an array of the constants as strings and NAMES is the number of constants. Macro ENUMno recognizes constant from a string. VAX WARNING: The arguments to ENUMn should be be immediately followed by the ',' or ')'. Trailing whitespace characters are part of the argument, and as such will be included in the string created for each tag and hence will cause difficulties when ENUMno searching for tags. MIPS WARNING: Same as the VAX but space after the comma and before the argument is also included in that argument. Therefore to maintain portability across VAXen and MIPS', remove all spaces in ENUMi(...) and in enum_str(...) calls. Alternatively, to preserve readability, use #ifndef mips for calls to ENUMi(..) and enum_str(...) with spaces for readability and behind the #else have the same calls with all spaces removed. N.B. MIPS machines include SGI's and DECstations. */ #define enum_str(NAME) ENUM_/**/NAME #define ENUMNO(ENUM_NAME, NAMES, STRING, LENGTH, NO) \ for (NO=0; NO<(int)NAMES; NO++) \ if (strncmp(STRING,ENUM_NAME[NO],LENGTH)==0) break; #define ENUMno(NAME, STRING, LENGTH, NO) \ ENUMNO(enum_str(NAME), NAME/**/S, STRING, LENGTH, NO) /* char *ENUM_NAME[]; int NAMES; char *STRING; int LENGTH; int NO; - NO returns enum. tag of ENUM_NAME matching LENGTH characters of STRING. - If none of the NAMES tags match STRING, NO returns NAMES. - For exact comparison with STRING use LENGTH as a_really_big_int. - For prefix comparison on STRING use LENGTH as strlen(ENUM_NAME[NO]). - For prefix comparison on ENUM_NAME's use LENGTH as strlen(STRING). - For prefix comparison on either use LENGTH as MIN(strlen(STRING),STRLEN(ENUM_NAME[NO])). */ #define ENUM1(NAME, A) typedef enum{A,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A"} #define ENUM2(NAME, A,B) typedef enum{A,B,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B"} #define ENUM3(NAME, A,B,C) typedef enum{A,B,C,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C"} #define ENUM4(NAME, A,B,C,D) typedef enum{A,B,C,D,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D"} #define ENUM5(NAME, A,B,C,D,E) typedef enum{A,B,C,D,E,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E"} #define ENUM6(NAME, A,B,C,D,E,F) typedef enum{A,B,C,D,E,F,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F"} #define ENUM7(NAME, A,B,C,D,E,F,G) \ typedef enum{A,B,C,D,E,F,G,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G"} #define ENUM8(NAME, A,B,C,D,E,F,G,H) \ typedef enum{A,B,C,D,E,F,G,H,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H"} #define ENUM11(NAME, A,B,C,D,E,F,G,H,I,J,K) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K"} #define ENUM12(NAME, A,B,C,D,E,F,G,H,I,J,K,L) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L"} #define ENUM13(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M"} #define ENUM15(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O"} #define ENUM16(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P"} #define ENUM20(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U"} #define ENUM46(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,NAME/**/S}NAME;\ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV"} #define ENUM48(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX, \ NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX"} #define EXPAND16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) \ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P #define QEXPAND16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) \ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P" /* N.B. e.g. ENUM78(NAME, 52 args, (16 args) ) req.d because VAX C limits number of macro args to 64. */ #define ENUM78(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,ARGS16) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,EXPAND16/**/ARGS16,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX","AY","AZ", \ "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL", \ QEXPAND16/**/ARGS16} #define EXPAND18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) \ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R #define QEXPAND18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) \ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R" /* N.B. ENUM80(NAME, 52 args, (18 args) ) syntax req.d because VAX C limits number of macro args to 64. */ #define ENUM80(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,ARGS18) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,EXPAND18/**/ARGS18,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX","AY","AZ", \ "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL", \ QEXPAND18/**/ARGS18} #endif /* __ENUM_LOADED */