[libvirt] PATCH: Helper for enumerations

There are quite a few places in our code where we have to convert from a string to an int enumeration, and vica-verca. This is tedious code to write, and I'm about to introduce a tonne more enumerations in the new generic domain XML parser / generator. So I reckon its time for some helper APIs The current pattern is that we have an enumeration enum virStoragePoolDisk { VIR_STORAGE_POOL_DISK_DOS, VIR_STORAGE_POOL_DISK_DVH, VIR_STORAGE_POOL_DISK_GPT, VIR_STORAGE_POOL_DISK_MAC, VIR_STORAGE_POOL_DISK_BSD, VIR_STORAGE_POOL_DISK_PC98, VIR_STORAGE_POOL_DISK_SUN, }; And then 2 helpers static int virStorageBackendDiskPoolFormatFromString(const char *format) { if (STREQ(format, "dos")) return VIR_STORAGE_POOL_DISK_DOS; if (STREQ(format, "dvh")) return VIR_STORAGE_POOL_DISK_DVH; if (STREQ(format, "gpt")) return VIR_STORAGE_POOL_DISK_GPT; if (STREQ(format, "mac")) return VIR_STORAGE_POOL_DISK_MAC; if (STREQ(format, "bsd")) return VIR_STORAGE_POOL_DISK_BSD; if (STREQ(format, "pc98")) return VIR_STORAGE_POOL_DISK_PC98; if (STREQ(format, "sun")) return VIR_STORAGE_POOL_DISK_SUN; return -1; } static const char * virStorageBackendDiskPoolFormatToString(int format) { switch (format) { case VIR_STORAGE_POOL_DISK_DOS: return "dos"; case VIR_STORAGE_POOL_DISK_DVH: return "dvh"; case VIR_STORAGE_POOL_DISK_GPT: return "gpt"; case VIR_STORAGE_POOL_DISK_MAC: return "mac"; case VIR_STORAGE_POOL_DISK_BSD: return "bsd"; case VIR_STORAGE_POOL_DISK_PC98: return "pc98"; case VIR_STORAGE_POOL_DISK_SUN: return "sun"; } return NULL; } This patch adds 2 generic ToString and FromString methods to the util.c module, which take a list of strings, in the same order as the enum int virEnumFromString(const char *const*types, int ntypes, const char *type); const char *virEnumToString(const char *const*types, int ntypes, int type); Passing around the list of strings (the "char *const*types" arg) is a little tedious, so there are 2 macros to simplify this by defining wrappers around the virEnumXXX functions VIR_ENUM_DECL(name) will define the function prototypes, and should be used in a header file, while VIR_ENUM_IMPL(name, maxvals, types) will define the implementation, type checked at compile time So, going back to the earlier example - we need to adapt the enum to add a sentinal at the end enum virStoragePoolDisk { VIR_STORAGE_POOL_DISK_DOS, VIR_STORAGE_POOL_DISK_DVH, VIR_STORAGE_POOL_DISK_GPT, VIR_STORAGE_POOL_DISK_MAC, VIR_STORAGE_POOL_DISK_BSD, VIR_STORAGE_POOL_DISK_PC98, VIR_STORAGE_POOL_DISK_SUN, VIR_STORAGE_POOL_DISK_LAST }; Then, we can provide the ToString and FromString methods with just VIR_ENUM_DECL(virStoragePoolDisk) VIR_ENUM_IMPL(virStoragePoolDisk, VIR_STORAGE_POOL_DISK_LAST, "dos", "dvh", "gpt", "mac", "bsd", "pc98", "sun") This has compile time checking to ensure there are enough strings for every enumeration value. Daniel. diff -r bc1615919490 src/util.c --- a/src/util.c Fri Jun 13 15:43:20 2008 +0100 +++ b/src/util.c Fri Jun 13 18:52:39 2008 +0100 @@ -798,3 +798,24 @@ return idx; } +int virEnumFromString(const char *const*types, + int ntypes, + const char *type) +{ + int i; + for (i = 0 ; i < ntypes ; i++) + if (STREQ(types[i], type)) + return i; + + return -1; +} + +const char *virEnumToString(const char *const*types, + int ntypes, + int type) +{ + if (type < 0 || type >= ntypes) + return NULL; + + return types[type]; +} diff -r bc1615919490 src/util.h --- a/src/util.h Fri Jun 13 15:43:20 2008 +0100 +++ b/src/util.h Fri Jun 13 18:52:39 2008 +0100 @@ -25,6 +25,7 @@ #define __VIR_UTIL_H__ #include "util-lib.h" +#include "verify.h" int virExec(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd); @@ -88,4 +89,31 @@ int virDiskNameToIndex(const char* str); + +int virEnumFromString(const char *const*types, + int ntypes, + const char *type); + +const char *virEnumToString(const char *const*types, + int ntypes, + int type); + +#define VIR_ENUM_IMPL(name, lastVal, ...) \ + static const char const *name ## TypeList[] = { __VA_ARGS__ }; \ + verify(ARRAY_CARDINALITY(name ## TypeList) == lastVal); \ + const char *name ## TypeToString(int type) { \ + return virEnumToString(name ## TypeList, \ + ARRAY_CARDINALITY(name ## TypeList), \ + type); \ + } \ + int name ## TypeFromString(const char *type) { \ + return virEnumFromString(name ## TypeList, \ + ARRAY_CARDINALITY(name ## TypeList), \ + type); \ + } + +#define VIR_ENUM_DECL(name) \ + const char *name ## TypeToString(int type); \ + int name ## TypeFromString(const char*type); + #endif /* __VIR_UTIL_H__ */ -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
There are quite a few places in our code where we have to convert from a string to an int enumeration, and vica-verca. This is tedious code to write, and I'm about to introduce a tonne more enumerations in the new generic domain XML parser / generator. So I reckon its time for some helper APIs ...
Very nice. That's been annoying me for some time. ACK
diff -r bc1615919490 src/util.c --- a/src/util.c Fri Jun 13 15:43:20 2008 +0100 +++ b/src/util.c Fri Jun 13 18:52:39 2008 +0100 @@ -798,3 +798,24 @@ return idx; }
+int virEnumFromString(const char *const*types, + int ntypes,
If using an unsigned type (size_t or unsigned int) doesn't cause too much disruption among the callers, that'd be nice, since negative "ntypes" is not useful.
+ const char *type) +{ + int i;
matching type here, too. ACK, either way.

On Sun, Jun 15, 2008 at 11:55:10PM +0200, Jim Meyering wrote:
"Daniel P. Berrange" <berrange@redhat.com> wrote:
There are quite a few places in our code where we have to convert from a string to an int enumeration, and vica-verca. This is tedious code to write, and I'm about to introduce a tonne more enumerations in the new generic domain XML parser / generator. So I reckon its time for some helper APIs ...
Very nice. That's been annoying me for some time. ACK
diff -r bc1615919490 src/util.c --- a/src/util.c Fri Jun 13 15:43:20 2008 +0100 +++ b/src/util.c Fri Jun 13 18:52:39 2008 +0100 @@ -798,3 +798,24 @@ return idx; }
+int virEnumFromString(const char *const*types, + int ntypes,
If using an unsigned type (size_t or unsigned int) doesn't cause too much disruption among the callers, that'd be nice, since negative "ntypes" is not useful.
Yep, unsigned int works just fine, so I've made that change and committed the patch. Regards Daniel. -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Sun, Jun 15, 2008 at 09:59:38PM +0100, Daniel P. Berrange wrote:
There are quite a few places in our code where we have to convert from a string to an int enumeration, and vica-verca. This is tedious code to write, and I'm about to introduce a tonne more enumerations in the new generic domain XML parser / generator. So I reckon its time for some helper APIs
Looks fine to me, +1 Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Jim Meyering