souped up enum
burkhard burow
burow at cernvax.cern.ch
Fri Nov 23 07:17:19 AEST 1990
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 at 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]);
}
}
More information about the Comp.lang.c
mailing list