So, now we have VIR_ENUM_DECL() and VIR_ENUM_IMPL() macros. They
will define a pair of functions for you to convert from and to
certain enum. Unfortunately, their usage is slightly cumbersome:
int tmp;
virMyAwesome ma;
if ((tmp = virMyAwesomeTypeFromString(str)) < 0) {
virReportError();
goto cleanup;
}
ma = tmp;
Ideally, we could avoid using the dummy @tmp variable:
virMyAwesome ma;
if (virMyAwesomeEnumFromString(str, &ma,
"Unable to convert '%s'", str) < 0)
goto cleanup;
So, the first @str is string to convert from. @ma should point to
the variable, where result is stored. Then, the third argument is
the error message to be printed if conversion fails, followed by
all the necessary arguments (message is in printf format).
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/virutil.c | 31 +++++++++++++++++++++++++++++++
src/util/virutil.h | 32 +++++++++++++++++++++++++++++---
3 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ee7c229..730f2f8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2343,6 +2343,7 @@ virUSBDeviceSetUsedBy;
# util/virutil.h
virDoubleToStr;
+virEnumFromString;
virFindFCHostCapableVport;
virFindSCSIHostByPCI;
virFormatIntDecimal;
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 3343e0d..6bb9e35 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -444,6 +444,37 @@ const char *virTypeToString(const char *const*types,
return types[type];
}
+int
+virEnumFromString(const char *str,
+ int *result,
+ virEnumConvertFunc convertFunc,
+ const char *enumName,
+ const char *fmt,
+ va_list ap)
+{
+ int ret = -1;
+ int type;
+ char *errMsg = NULL;
+
+ if ((type = (convertFunc)(str)) < 0) {
+ if (fmt) {
+ if (virVasprintf(&errMsg, fmt, ap) >= 0)
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", errMsg);
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unable to convert '%s' to %s type"),
+ str, enumName);
+ }
+ goto cleanup;
+ }
+
+ *result = type;
+ ret = 0;
+ cleanup:
+ VIR_FREE(errMsg);
+ return ret;
+}
+
/* In case thread-safe locales are available */
#if HAVE_NEWLOCALE
diff --git a/src/util/virutil.h b/src/util/virutil.h
index 648de28..5dd2790 100644
--- a/src/util/virutil.h
+++ b/src/util/virutil.h
@@ -27,6 +27,7 @@
# include "internal.h"
# include <unistd.h>
+# include <stdarg.h>
# include <sys/types.h>
# ifndef MIN
@@ -78,6 +79,16 @@ const char *virTypeToString(const char *const*types,
unsigned int ntypes,
int type);
+typedef int (*virEnumConvertFunc) (const char *str);
+
+int virEnumFromString(const char *str,
+ int *result,
+ virEnumConvertFunc convertFunc,
+ const char *enumName,
+ const char *fmt,
+ va_list ap)
+ ATTRIBUTE_FMT_PRINTF(5, 0);
+
# define VIR_ENUM_IMPL(name, lastVal, ...) \
static const char *const name ## TypeList[] = { __VA_ARGS__ }; \
verify(ARRAY_CARDINALITY(name ## TypeList) == lastVal); \
@@ -90,11 +101,26 @@ const char *virTypeToString(const char *const*types,
return virTypeFromString(name ## TypeList, \
ARRAY_CARDINALITY(name ## TypeList), \
type); \
+ } \
+ int name ## EnumFromString(const char *str, int *result, \
+ const char *fmt, ...) \
+ { \
+ int ret; \
+ va_list ap; \
+ va_start(ap, fmt); \
+ ret = virEnumFromString(str, result, \
+ name ## TypeFromString, \
+ #name, fmt, ap); \
+ va_end(ap); \
+ return ret; \
}
-# define VIR_ENUM_DECL(name) \
- const char *name ## TypeToString(int type); \
- int name ## TypeFromString(const char*type);
+# define VIR_ENUM_DECL(name) \
+ const char *name ## TypeToString(int type); \
+ int name ## TypeFromString(const char*type); \
+ int name ## EnumFromString(const char *str, int *result, \
+ const char *fmt, ...) \
+ ATTRIBUTE_FMT_PRINTF(3, 4);
/* No-op workarounds for functionality missing in mingw. */
# ifndef HAVE_GETUID
--
2.4.6