[libvirt] [PATCH 2/3] virutil: Introduce virEnumFromString
John Ferlan
jferlan at redhat.com
Tue Sep 22 13:22:06 UTC 2015
On 09/17/2015 11:31 AM, Michal Privoznik wrote:
> 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 at redhat.com>
> ---
> src/libvirt_private.syms | 1 +
> src/util/virutil.c | 31 +++++++++++++++++++++++++++++++
> src/util/virutil.h | 32 +++++++++++++++++++++++++++++---
> 3 files changed, 61 insertions(+), 3 deletions(-)
>
Your example shows a comparison of "< 0"; however, your patch 3 examples
change a "<= 0" to a "< 0", e.g. (from patch 3):
- if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("unknown disk ioeventfd mode '%s'"),
- ioeventfd);
+ if (virTristateSwitchEnumFromString(ioeventfd, &def->ioeventfd,
+ _("unknown disk ioeventfd
mode '%s'"),
+ ioeventfd) < 0)
where essentially that's converted to:
+
+ if ((type = (convertFunc)(str)) < 0) {
+ if (fmt) {
For the tristate in particular, "0" is absent which is used as a marker
of sorts. It's not an error.
Similarly, for "many" a 0 would convert to some VIR_*_NONE and would be
deemed 'illegal'. Of course the "virtType" example in patch 3 shows a
case where a VIRT_*_NONE is not present (there's another recent patch
stream that wanted to change that...)
I think with a tweak to account for a min required value would be
necessary and perhaps for extra credit a non-zero max value.
As an aside, it looks strange to have an argument repeated. I would
think a majority of error messages are going to use the first argument
of the function to the first argument of the error message anyway.
John
> 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
>
More information about the libvir-list
mailing list