enum values to strings.

Derek Atkins warlord at MIT.EDU
Thu Mar 24 16:41:21 EST 2005


Note that in many cases this conversion is already done.  The Gnucash XML does
this in most cases.  Take a look at, e.g. src/engine/Account.c for an example. 
It's not _quite_ as clever as your code, but it does the job.

And yes, we should definitely be using strings instead of ints for enums. 
Remember when I asked why you needed QOF_TYPE_INT32?  ;)

I dont think we ever use an INT64 enum.

-derek

Quoting Neil Williams <linux at codehelp.co.uk>:

> That anti-software patent meeting has had an unexpected side effect. After
> the 
> meeting, I got chatting about GnuCash and my development work on QOF (as you
> 
> do). One of the results was a discussion about how to turn enum values 
> (integers) into strings (for text file readability) using #define. 
> 
> I experimented with the code that had been jotted down on the back of EU 
> software patent EP 0760140 (!) and also found this example:
> http://www.flipcode.com/cgi-bin/fcmsg.cgi?thread_show=24481
> 
> That doesn't work for me, so I've got a version here that DOES work as 
> straight C (I think):
> 
> Credit to Jamie Lokier for the original idea and Chad Austin for the flipcode
> 
> example in C++. I'm posting it here in case I've missed something obvious.
> ;-)
> 
> #include <stdio.h>
> #define ENUM_BODY(name, value) \
>     name = value,
> #define AS_STRING_CASE(name, value) \
>     case name: return #name;
> #define FROM_STRING_CASE(name, value) \
>     if (strcmp(str, #name) == 0) {    \
>         return name;                  \
>     }
> #define DEFINE_ENUM(name, list)                 \
>     typedef enum {                              \
>         list(ENUM_BODY)                         \
>     }name;                                      \
>     const char* asString(name n) {              \
>         switch (n) {                            \
>             list(AS_STRING_CASE)                \
>             default: return "";                 \
>         }                                       \
>     }                                           \
>     name fromString(const char* str) {          \
>         list(FROM_STRING_CASE)                  \
>         return 0; /* assert? throw? */     \
>     }
> #define ENUM_LIST(_)                             \
>     _(RED,   0)                                  \
>     _(GREEN, 1)                                  \
>     _(BLUE,  87)
> 
> DEFINE_ENUM(Color, ENUM_LIST)
> 
> int main() {
>     Color c = GREEN;
>     printf("%d\n",c);
>     printf("%s\n", asString(c));
>     printf("%d\n", fromString("BLUE"));
> }
> 
> gcc enum.c
> 
> Output:
> 
> neil at garfield:~/tmp/enum$ ./a.out
> 1
> GREEN
> 87
> 
>  I need this functionality to convert potentially any enum already defined in
> 
> GnuCash into a form that is usable AS an enum by all existing processes and 
> which can be converted to a const char* on demand, with only one piece of new
> 
> code, no duplication and as efficiently as possible. Only enums that are used
> 
> as QOF parameters (presently gint32/gint64) would actually take this new 
> form. The parameter would then be changed to QOF_TYPE_STRING and a function 
> defined. That would get the enum from the existing function (as a wrapper) 
> and then pass that to asString() above.
> 
> The parsed version of the defines (using gcc -E) shows the expanded section 
> as: (line breaks added)
> 
> typedef enum { RED = 0, GREEN = 1, BLUE = 87, }Color; 
> 
> const char* asString(Color n) { 
>   switch (n) { 
>      case RED:      return "RED"; 
>      case GREEN: return "GREEN"; 
>      case BLUE:    return "BLUE"; 
>      default: return ""; 
>    } 
> } 
> 
> Color 
> fromString(const char* str) 
> { 
>   if (strcmp(str, "RED") == 0) { return RED; } 
>   if (strcmp(str, "GREEN") == 0) { return GREEN; }
>   if (strcmp(str, "BLUE") == 0) { return BLUE; } 
>   return 0; 
> }
> 
> int main() {
>     Color c = GREEN;
>     printf("%d\n",c);
>     printf("%s\n", asString(c));
>     printf("%d\n", fromString("BLUE"));
> }
> 
> Can anyone see problems with this solution? Are the defines correct C?
> 
> Do we want to use safe_strcmp?
> Should the strings be translatable?
> #define AS_STRING_CASE(name, value) \
>     case name: return _(#name);
> instead of return #name?
> 
> Comments? Problems?
> 
> -- 
> 
> Neil Williams
> =============
> http://www.dcglug.org.uk/
> http://www.nosoftwarepatents.com/
> http://sourceforge.net/projects/isbnsearch/
> http://www.neil.williamsleesmill.me.uk/
> http://www.biglumber.com/x/web?qs=0x8801094A28BCB3E3
> 
> 


-- 
       Derek Atkins, SB '93 MIT EE, SM '95 MIT Media Laboratory
       Member, MIT Student Information Processing Board  (SIPB)
       URL: http://web.mit.edu/warlord/    PP-ASEL-IA     N1NWH
       warlord at MIT.EDU                        PGP key available



More information about the gnucash-devel mailing list