burow@cernvax.cern.ch (burkhard burow) (11/23/90)
Below, in enum.h, is a souped up 'enum' and an example program follows in enum.c. 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: The following works on VAX VMS: C 3.1. As far as I know, the only deviation from ANSI C is the '/**/' kludge for the preprocessor concatenation operator '##'. tschuess INTERNET: burow%13313.hepnet@csa3.lbl.gov burkhard DECNET: 13313::burow -------------------------cut here--------------------------------------------- /* enum.h */ /* Burkhard Burow, University of Toronto, 1990. */ #ifndef __ENUM_LOADED #define __ENUM_LOADED 1 #include <stdio.h> #include <string.h> /* 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.*/ #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[i],LENGTH)==0) break; /* 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 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 */ -------------------------cut here--------------------------------------------- /* enum.c An example of the macros in enum.h */ /* Burkhard Burow, University of Toronto, 1990. */ #include "enum.h" #include <stdio.h> #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. */ ENUM4(LIST, JUST, SOME, SILLY, STUFF); 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\n"); ENUMno(enum_str(LIST), LISTS, s, 9999, i); break; case 1: printf("A comparison, using the prefix of %s, \n", s); ENUMno(enum_str(LIST), LISTS, s, strlen(enum_str(LIST)[i]), i); break; case 2: printf("A comparison, using the prefices of 'list's' constants,\n"); ENUMno(enum_str(LIST), LISTS, s, strlen(s), i); break; case 3: printf("A comparison, using the prefices of either,\n"); ENUMno(enum_str(LIST), LISTS, s, MIN(strlen(s),strlen(enum_str(LIST)[i])), i); break; } if (i==(int)LISTS) printf(" does not recognize %s as a constant in 'list'\n\n", s); else printf(" recognizes %s as the constant %s in 'list'\n\n", s, enum_str(LIST)[i]); } }