On Mon, 7 Jun 2010 15:42:16 +0100 "Daniel P. Berrange" <berra...@redhat.com> wrote:
> There is quite alot of code using an enumeration of possible > values, which also needs todo conversions to/from a string > representation of enum values. These string <-> int conversions > have been repeated in an adhoc manner throughout the code. > > This makes it hard to report on the list of valid strings, > eg in help output, or todo proper validation in the qemu > config/option parsing routines. > > This addresses the first problem by introducing a standard > set of routines for performing string <-> int conversions > for enums. There are two restrictions on using these helpers, > the first enum value must be 0, and there must be a sentinal > in the enum to provide the max value. > > For each enumeration, three functions will be made available > > - string to int convertor: > > int XXXX_from_string(const char *value); > > Returns -1 if the value was not an allowed string for the > enumeration. Returns >= 0 for a valid value > > - int to string convertor > > const char * XXXX_to_string(int value); > > Returns NULL if the value was not a member of the > enumeration. Returns a non-NULL sstring for valid value > > - string list generator > > char * XXXX_to_string_list(void); > > Returns a malloc'd string containing all valid values, > separated by commas. Caller must free the string. > > The general usage pattern is as follows. > > In the header file (eg qemu-option.h): > > enum QemuOptType { > QEMU_OPT_STRING = 0, /* no parsing (use string as-is) > */ > QEMU_OPT_BOOL, /* on/off > */ > QEMU_OPT_NUMBER, /* simple number > */ > QEMU_OPT_SIZE, /* size, accepts (K)ilo, (M)ega, (G)iga, (T)era > postfix */ > > QEMU_OPT_LAST > }; > QEMU_ENUM_DECL(qemu_opt_type); > > This declares the function prototypes for the 3 methods > outlined above. > > In the corresponding source file (eg qemu-option.c): > > QEMU_ENUM_IMPL(qemu_opt_type, > QEMU_OPT_LAST, > "string", "bool", "number", "size"); > > This provides the implementation of the 3 methods. If there > are greater/fewer strings provided than the number of values > in the enumeration, this generates a compile time assertion > failure that looks like > > qemu-option.c:35: error: negative width in bit-field > ‘verify_error_if_negative_size__’ > > Signed-off-by: Daniel P. Berrange <berra...@redhat.com> > --- > Makefile.objs | 2 +- > qemu-enum.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ > qemu-enum.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 90 insertions(+), 1 deletions(-) > create mode 100644 qemu-enum.c > create mode 100644 qemu-enum.h > > diff --git a/Makefile.objs b/Makefile.objs > index 9796dcb..0ba9966 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -8,7 +8,7 @@ qobject-obj-y += qerror.o > # block-obj-y is code used by both qemu system emulation and qemu-img > > block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o > -block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o > +block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o qemu-enum.o > block-obj-$(CONFIG_POSIX) += posix-aio-compat.o > block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o > > diff --git a/qemu-enum.c b/qemu-enum.c > new file mode 100644 > index 0000000..9bb33ac > --- /dev/null > +++ b/qemu-enum.c > @@ -0,0 +1,44 @@ > +#include "qemu-enum.h" Missing license text. > + > +int qemu_enum_from_string(const char *const*types, > + unsigned int ntypes, > + const char *type) > +{ > + unsigned int i; > + if (!type) > + return -1; > + > + for (i = 0 ; i < ntypes ; i++) > + if (strcmp(types[i], type) == 0) > + return i; > + > + return -1; > +} > + > +const char *qemu_enum_to_string(const char *const*types, > + unsigned int ntypes, > + int type) > +{ > + if (type < 0 || type >= ntypes) > + return NULL; > + > + return types[type]; > +} > + > +char *qemu_enum_to_string_list(const char *const*types, > + unsigned int ntypes) > +{ > + size_t len = 0; > + char *ret; > + int i; > + for (i = 0 ; i < ntypes ; i++) > + len += strlen(types[i]) + 2; > + ret = qemu_malloc(len); > + *ret = '\0'; > + for (i = 0 ; i < ntypes ; i++) { > + if (i > 0) > + strcat(ret, ", "); > + strcat(ret, types[i]); > + } > + return ret; > +} > diff --git a/qemu-enum.h b/qemu-enum.h > new file mode 100644 > index 0000000..ff47798 > --- /dev/null > +++ b/qemu-enum.h > @@ -0,0 +1,45 @@ > +#ifndef QEMU_ENUM_H > +#define QEMU_ENUM_H > + > +#include "qemu-common.h" > +#include "verify.h" > + > + > +int qemu_enum_from_string(const char *const*types, > + unsigned int ntypes, > + const char *type); > + > +const char *qemu_enum_to_string(const char *const*types, > + unsigned int ntypes, > + int type); > + > +char *qemu_enum_to_string_list(const char *const*types, > + unsigned int ntypes); > + > +#define QEMU_ENUM_IMPL(name, lastVal, ...) \ > + static const char *const name ## _string_list[] = { __VA_ARGS__ }; > \ > + char *name ## _to_string_list(void) { \ > + return qemu_enum_to_string_list(name ## _string_list, > \ > + ARRAY_SIZE(name ## _string_list)); \ > + } \ > + const char *name ## _to_string(int type) { > \ > + return qemu_enum_to_string(name ## _string_list, \ > + ARRAY_SIZE(name ## _string_list), \ > + type); \ > + } \ > + int name ## _from_string(const char *type) { \ > + return qemu_enum_from_string(name ## _string_list, \ > + ARRAY_SIZE(name ## _string_list), \ > + type); \ > + } > \ > + extern int (* name ## Verify (void)) \ > + [verify_true (ARRAY_SIZE(name ## _string_list) == lastVal)] > + > +# define QEMU_ENUM_DECL(name) \ > + const char *name ## _to_string(int type); \ > + char *name ## _to_string_list(void); \ > + int name ## _from_string(const char*type) > + > + > + > +#endif /* QEMU_ENUM_H */