From 6381c89f8cce23afbc67e5979b0b5e304a09db16 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 7 Jul 2016 16:52:47 +0100 Subject: [PATCH] virconf: add typed value accessor methods Currently many users of virConf APIs are defining the same macros for calling virConfValue() and then doing type checking. To remove this repeated code, add a set of typesafe accessor methods. Signed-off-by: Daniel P. Berrange --- src/libvirt_private.syms | 10 + src/util/virconf.c | 500 ++++++++++++++++++++++++++++++++++++++- src/util/virconf.h | 34 ++- tests/virconftest.c | 335 ++++++++++++++++++++++++++ 4 files changed, 873 insertions(+), 6 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ad0af76a7b..597ce5f3e8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1393,6 +1393,16 @@ virRun; virConfFree; virConfFreeValue; virConfGetValue; +virConfGetValueBool; +virConfGetValueInt; +virConfGetValueLLong; +virConfGetValueSizeT; +virConfGetValueSSizeT; +virConfGetValueString; +virConfGetValueStringList; +virConfGetValueType; +virConfGetValueUInt; +virConfGetValueULLong; virConfLoadConfig; virConfNew; virConfReadFile; diff --git a/src/util/virconf.c b/src/util/virconf.c index 33e7744c32..5085768eb8 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -99,7 +99,7 @@ struct _virConfEntry { }; struct _virConf { - const char* filename; + char *filename; unsigned int flags; virConfEntryPtr entries; }; @@ -204,10 +204,15 @@ static virConfPtr virConfCreate(const char *filename, unsigned int flags) { virConfPtr ret = virConfNew(); - if (ret) { - ret->filename = filename; - ret->flags = flags; + if (!ret) + return NULL; + + if (VIR_STRDUP(ret->filename, filename) < 0) { + VIR_FREE(ret); + return NULL; } + + ret->flags = flags; return ret; } @@ -233,6 +238,7 @@ virConfAddEntry(virConfPtr conf, char *name, virConfValuePtr value, char *comm) if ((comm == NULL) && (name == NULL)) return NULL; + VIR_DEBUG("Add entry %s %p", name, value); if (VIR_ALLOC(ret) < 0) return NULL; @@ -275,8 +281,10 @@ virConfSaveValue(virBufferPtr buf, virConfValuePtr val) case VIR_CONF_NONE: return -1; case VIR_CONF_LONG: + virBufferAsprintf(buf, "%lld", val->l); + break; case VIR_CONF_ULONG: - virBufferAsprintf(buf, "%ld", val->l); + virBufferAsprintf(buf, "%llu", val->l); break; case VIR_CONF_STRING: if (strchr(val->str, '\n') != NULL) { @@ -843,6 +851,7 @@ virConfFree(virConfPtr conf) VIR_FREE(tmp); tmp = next; } + VIR_FREE(conf->filename); VIR_FREE(conf); return 0; } @@ -877,6 +886,487 @@ virConfGetValue(virConfPtr conf, const char *setting) return NULL; } + +/** + * virConfGetValueType: + * @conf: the config object + * @setting: the config entry name + * + * Query the type of the configuration entry @setting. + * + * Returns: the entry type, or VIR_CONF_NONE if not set. + */ +virConfType virConfGetValueType(virConfPtr conf, + const char *setting) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + if (!cval) + return VIR_CONF_NONE; + + return cval->type; +} + + +/** + * virConfGetValueString: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold string value + * + * Get the string value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type. + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueString(virConfPtr conf, + const char *setting, + char **value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value string %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_STRING) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected a string for '%s' parameter"), + conf->filename, setting); + return -1; + } + + VIR_FREE(*value); + if (VIR_STRDUP(*value, cval->str) < 0) + return -1; + + return 1; +} + + +/** + * virConfGetValueStringList: + * @conf: the config object + * @setting: the config entry name + * @compatString: true to treat string entry as a 1 element list + * @value: pointer to hold NULL terminated string list + * + * Get the string list value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. If @compatString is set to true + * and the value is present as a string, this will be turned into + * a 1 element list. The returned @value will be NULL terminated + * if set. + * + * Reports an error if the config entry is set but has + * an unexpected type. + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueStringList(virConfPtr conf, + const char *setting, + bool compatString, + char ***values) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + size_t len; + virConfValuePtr eval; + + VIR_DEBUG("Get value string list %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + virStringFreeList(*values); + *values = NULL; + + switch (cval->type) { + case VIR_CONF_LIST: + /* Calc length and check items */ + for (len = 0, eval = cval->list; eval; len++, eval = eval->next) { + if (eval->type != VIR_CONF_STRING) { + virReportError(VIR_ERR_CONF_SYNTAX, + _("%s: expected a string list for '%s' parameter"), + conf->filename, setting); + return -1; + } + } + + if (VIR_ALLOC_N(*values, len + 1) < 0) + return -1; + + for (len = 0, eval = cval->list; eval; len++, eval = eval->next) { + if (VIR_STRDUP((*values)[len], eval->str) < 0) { + virStringFreeList(*values); + *values = NULL; + return -1; + } + } + break; + + case VIR_CONF_STRING: + if (compatString) { + if (VIR_ALLOC_N(*values, cval->str ? 2 : 1) < 0) + return -1; + if (cval->str && + VIR_STRDUP((*values)[0], cval->str) < 0) { + VIR_FREE(values); + return -1; + } + break; + } + /* fallthrough */ + + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + compatString ? + _("%s: expected a string or string list for '%s' parameter") : + _("%s: expected a string list for '%s' parameter"), + conf->filename, setting); + return -1; + } + + return 1; +} + + +/** + * virConfGetValueBool: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold boolean value + * + * Get the boolean value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type, or if the value set is not 1 or 0. + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueBool(virConfPtr conf, + const char *setting, + bool *value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value bool %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_ULONG) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected a bool for '%s' parameter"), + conf->filename, setting); + return -1; + } + + if (cval->l < 0 || cval->l > 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: value for '%s' parameter must be 0 or 1"), + conf->filename, setting); + return -1; + } + + *value = cval->l == 1; + + return 1; +} + + +/** + * virConfGetValueInt: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold integer value + * + * Get the integer value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type, or if the value is outside the + * range that can be stored in an 'int' + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueInt(virConfPtr conf, + const char *setting, + int *value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value int %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_LONG && + cval->type != VIR_CONF_ULONG) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected a signed integer for '%s' parameter"), + conf->filename, setting); + return -1; + } + + if (cval->l > INT_MAX || cval->l < INT_MIN) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: value for '%s' parameter must be in range %d:%d"), + conf->filename, setting, INT_MIN, INT_MAX); + return -1; + } + + *value = cval->l; + + return 1; +} + + +/** + * virConfGetValueUInt: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold integer value + * + * Get the unsigned integer value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type, or if the value is outside the + * range that can be stored in an 'unsigned int' + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueUInt(virConfPtr conf, + const char *setting, + unsigned int *value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value uint %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_ULONG) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected an unsigned integer for '%s' parameter"), + conf->filename, setting); + return -1; + } + + if (cval->l > UINT_MAX || cval->l < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: value for '%s' parameter must be in range 0:%u"), + conf->filename, setting, UINT_MAX); + return -1; + } + + *value = cval->l; + + return 1; +} + + +/** + * virConfGetValueSizeT: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold integer value + * + * Get the integer value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type, or if the value is outside the + * range that can be stored in a 'size_t' + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueSizeT(virConfPtr conf, + const char *setting, + size_t *value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value size_t %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_ULONG) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected an unsigned integer for '%s' parameter"), + conf->filename, setting); + return -1; + } + + if (cval->l > SIZE_MAX || cval->l < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: value for '%s' parameter must be in range 0:%zu"), + conf->filename, setting, SIZE_MAX); + return -1; + } + + *value = cval->l; + + return 1; +} + + +/** + * virConfGetValueSSizeT: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold integer value + * + * Get the integer value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type, or if the value is outside the + * range that can be stored in an 'ssize_t' + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueSSizeT(virConfPtr conf, + const char *setting, + ssize_t *value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value ssize_t %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_LONG && + cval->type != VIR_CONF_ULONG) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected a signed integer for '%s' parameter"), + conf->filename, setting); + return -1; + } + + if (cval->l > SSIZE_MAX || cval->l < (-SSIZE_MAX - 1)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: value for '%s' parameter must be in range %zd:%zd"), + conf->filename, setting, -SSIZE_MAX - 1, SSIZE_MAX); + return -1; + } + + *value = cval->l; + + return 1; +} + + +/** + * virConfGetValueLLong: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold integer value + * + * Get the integer value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type, or if the value is outside the + * range that can be stored in an 'long long' + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueLLong(virConfPtr conf, + const char *setting, + long long *value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value long long %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_LONG && + cval->type != VIR_CONF_ULONG) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected a signed integer for '%s' parameter"), + conf->filename, setting); + return -1; + } + + if (cval->type == VIR_CONF_ULONG && + cval->l > LLONG_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: value for '%s' parameter must be in range 0:%lld"), + conf->filename, setting, LLONG_MAX); + return -1; + } + + *value = cval->l; + + return 1; +} + + +/** + * virConfGetValueULongLong: + * @conf: the config object + * @setting: the config entry name + * @value: pointer to hold integer value + * + * Get the integer value of the config name @setting, storing + * it in @value. If the config entry is not present, then + * @value will be unmodified. + * + * Reports an error if the config entry is set but has + * an unexpected type. + * + * Returns: 1 if the value was present, 0 if missing, -1 on error + */ +int virConfGetValueULLong(virConfPtr conf, + const char *setting, + unsigned long long *value) +{ + virConfValuePtr cval = virConfGetValue(conf, setting); + + VIR_DEBUG("Get value unsigned long long %p %d", + cval, cval ? cval->type : VIR_CONF_NONE); + + if (!cval) + return 0; + + if (cval->type != VIR_CONF_LONG && + cval->type != VIR_CONF_ULONG) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s: expected an unsigned integer for '%s' parameter"), + conf->filename, setting); + return -1; + } + + *value = cval->l; + + return 1; +} + /** * virConfSetValue: * @conf: a configuration file handle diff --git a/src/util/virconf.h b/src/util/virconf.h index 239ab39b66..ccae9d9d08 100644 --- a/src/util/virconf.h +++ b/src/util/virconf.h @@ -61,7 +61,7 @@ typedef virConfValue *virConfValuePtr; struct _virConfValue { virConfType type; /* the virConfType */ virConfValuePtr next; /* next element if in a list */ - long l; /* long integer */ + long long l; /* very long integer */ char *str; /* pointer to 0 terminated string */ virConfValuePtr list; /* list of a list */ }; @@ -85,6 +85,38 @@ int virConfFree(virConfPtr conf); void virConfFreeValue(virConfValuePtr val); virConfValuePtr virConfGetValue(virConfPtr conf, const char *setting); + +virConfType virConfGetValueType(virConfPtr conf, + const char *setting); +int virConfGetValueString(virConfPtr conf, + const char *setting, + char **value); +int virConfGetValueStringList(virConfPtr conf, + const char *setting, + bool compatString, + char ***values); +int virConfGetValueBool(virConfPtr conf, + const char *setting, + bool *value); +int virConfGetValueInt(virConfPtr conf, + const char *setting, + int *value); +int virConfGetValueUInt(virConfPtr conf, + const char *setting, + unsigned int *value); +int virConfGetValueSizeT(virConfPtr conf, + const char *setting, + size_t *value); +int virConfGetValueSSizeT(virConfPtr conf, + const char *setting, + ssize_t *value); +int virConfGetValueLLong(virConfPtr conf, + const char *setting, + long long *value); +int virConfGetValueULLong(virConfPtr conf, + const char *setting, + unsigned long long *value); + int virConfSetValue(virConfPtr conf, const char *setting, virConfValuePtr value); diff --git a/tests/virconftest.c b/tests/virconftest.c index c71b491513..d9ebda4aaf 100644 --- a/tests/virconftest.c +++ b/tests/virconftest.c @@ -77,6 +77,329 @@ static int testConfRoundTrip(const void *opaque) } +static int testConfParseInt(const void *opaque ATTRIBUTE_UNUSED) +{ + const char *srcdata = \ + "int = -1729\n" \ + "uint = 1729\n" \ + "llong = -6963472309248\n" \ + "ullong = 6963472309248\n" \ + "size_t = 87539319\n" \ + "ssize_t = -87539319\n" \ + "string = \"foo\"\n"; + + int ret = -1; + virConfPtr conf = virConfReadMem(srcdata, strlen(srcdata), 0); + int iv; + unsigned int ui; + size_t s; + ssize_t ss; + long long l; + unsigned long long ul; + + if (!conf) + return -1; + + if (virConfGetValueType(conf, "int") != + VIR_CONF_LONG) { + fprintf(stderr, "expected a long for 'int'\n"); + goto cleanup; + } + + if (virConfGetValueInt(conf, "int", &iv) < 0) + goto cleanup; + + if (iv != -1729) { + fprintf(stderr, "Expected -1729 got %d\n", iv); + goto cleanup; + } + + if (virConfGetValueInt(conf, "string", &iv) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + + if (virConfGetValueType(conf, "uint") != + VIR_CONF_ULONG) { + fprintf(stderr, "expected a unsigned long for 'uint'\n"); + goto cleanup; + } + + if (virConfGetValueUInt(conf, "uint", &ui) < 0) + goto cleanup; + + if (ui != 1729) { + fprintf(stderr, "Expected 1729 got %u\n", ui); + goto cleanup; + } + + if (virConfGetValueUInt(conf, "string", &ui) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + + + if (virConfGetValueType(conf, "llong") != + VIR_CONF_LONG) { + fprintf(stderr, "expected a long for 'llong'\n"); + goto cleanup; + } + + if (virConfGetValueLLong(conf, "llong", &l) < 0) + goto cleanup; + + if (l != -6963472309248) { + fprintf(stderr, "Expected -6963472309248 got %lld\n", l); + goto cleanup; + } + + if (virConfGetValueLLong(conf, "string", &l) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + + + if (virConfGetValueType(conf, "ullong") != + VIR_CONF_ULONG) { + fprintf(stderr, "expected a unsigned long for 'ullong'\n"); + goto cleanup; + } + + if (virConfGetValueULLong(conf, "ullong", &ul) < 0) + goto cleanup; + + if (ul != 6963472309248) { + fprintf(stderr, "Expected 6963472309248 got %llu\n", ul); + goto cleanup; + } + + if (virConfGetValueULLong(conf, "string", &ul) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + + + if (virConfGetValueType(conf, "size_t") != + VIR_CONF_ULONG) { + fprintf(stderr, "expected a unsigned long for 'size_T'\n"); + goto cleanup; + } + + if (virConfGetValueSizeT(conf, "size_t", &s) < 0) + goto cleanup; + + if (s != 87539319) { + fprintf(stderr, "Expected 87539319 got %zu\n", s); + goto cleanup; + } + + if (virConfGetValueSizeT(conf, "string", &s) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + + + if (virConfGetValueType(conf, "ssize_t") != + VIR_CONF_LONG) { + fprintf(stderr, "expected a unsigned long for 'ssize_t'\n"); + goto cleanup; + } + + if (virConfGetValueSSizeT(conf, "ssize_t", &ss) < 0) + goto cleanup; + + if (ss != -87539319) { + fprintf(stderr, "Expected -87539319 got %zd\n", ss); + goto cleanup; + } + + if (virConfGetValueSSizeT(conf, "string", &ss) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + ret = 0; + cleanup: + virConfFree(conf); + return ret; +} + +static int testConfParseBool(const void *opaque ATTRIBUTE_UNUSED) +{ + const char *srcdata = \ + "false = 0\n" \ + "true = 1\n" \ + "int = 6963472309248\n" \ + "string = \"foo\"\n"; + + int ret = -1; + virConfPtr conf = virConfReadMem(srcdata, strlen(srcdata), 0); + bool f = true; + bool t = false; + + if (!conf) + return -1; + + if (virConfGetValueType(conf, "false") != + VIR_CONF_ULONG) { + fprintf(stderr, "expected a long for 'false'\n"); + goto cleanup; + } + + if (virConfGetValueBool(conf, "false", &f) < 0) + goto cleanup; + + if (f != false) { + fprintf(stderr, "Expected 0 got %d\n", f); + goto cleanup; + } + + + + if (virConfGetValueType(conf, "true") != + VIR_CONF_ULONG) { + fprintf(stderr, "expected a long for 'true'\n"); + goto cleanup; + } + + if (virConfGetValueBool(conf, "true", &t) < 0) + goto cleanup; + + if (t != true) { + fprintf(stderr, "Expected 1 got %d\n", t); + goto cleanup; + } + + + + if (virConfGetValueBool(conf, "int", &t) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + if (virConfGetValueBool(conf, "string", &t) != -1) { + fprintf(stderr, "Expected error for 'string' param\n"); + goto cleanup; + } + + + ret = 0; + cleanup: + virConfFree(conf); + return ret; +} + + +static int testConfParseString(const void *opaque ATTRIBUTE_UNUSED) +{ + const char *srcdata = \ + "int = 6963472309248\n" \ + "string = \"foo\"\n"; + + int ret = -1; + virConfPtr conf = virConfReadMem(srcdata, strlen(srcdata), 0); + char *str = NULL; + + if (!conf) + return -1; + + if (virConfGetValueType(conf, "string") != + VIR_CONF_STRING) { + fprintf(stderr, "expected a string for 'string'\n"); + goto cleanup; + } + + if (virConfGetValueString(conf, "string", &str) < 0) + goto cleanup; + + if (STRNEQ_NULLABLE(str, "foo")) { + fprintf(stderr, "Expected 'foo' got '%s'\n", str); + goto cleanup; + } + + if (virConfGetValueString(conf, "int", &str) != -1) { + fprintf(stderr, "Expected error for 'int'\n"); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(str); + virConfFree(conf); + return ret; +} + + +static int testConfParseStringList(const void *opaque ATTRIBUTE_UNUSED) +{ + const char *srcdata = \ + "string_list = [\"foo\", \"bar\"]\n" \ + "string = \"foo\"\n"; + + int ret = -1; + virConfPtr conf = virConfReadMem(srcdata, strlen(srcdata), 0); + char **str = NULL; + + if (!conf) + return -1; + + if (virConfGetValueType(conf, "string_list") != + VIR_CONF_LIST) { + fprintf(stderr, "expected a list for 'string_list'\n"); + goto cleanup; + } + + if (virConfGetValueStringList(conf, "string_list", false, &str) < 0) + goto cleanup; + + if (virStringListLength((const char *const*)str) != 2) { + fprintf(stderr, "expected a 2 element list\n"); + goto cleanup; + } + + if (STRNEQ_NULLABLE(str[0], "foo")) { + fprintf(stderr, "Expected 'foo' got '%s'\n", str[0]); + goto cleanup; + } + + if (STRNEQ_NULLABLE(str[1], "bar")) { + fprintf(stderr, "Expected 'bar' got '%s'\n", str[1]); + goto cleanup; + } + + + if (virConfGetValueStringList(conf, "string", false, &str) != -1) { + fprintf(stderr, "Expected error for 'string'\n"); + goto cleanup; + } + + if (virConfGetValueStringList(conf, "string", true, &str) < 0) + goto cleanup; + + if (virStringListLength((const char *const*)str) != 1) { + fprintf(stderr, "expected a 1 element list\n"); + goto cleanup; + } + + if (STRNEQ_NULLABLE(str[0], "foo")) { + fprintf(stderr, "Expected 'foo' got '%s'\n", str[0]); + goto cleanup; + } + + + ret = 0; + cleanup: + virStringFreeList(str); + virConfFree(conf); + return ret; +} + + static int mymain(void) { @@ -91,6 +414,18 @@ mymain(void) if (virTestRun("no-newline", testConfRoundTrip, "no-newline") < 0) ret = -1; + if (virTestRun("int", testConfParseInt, NULL) < 0) + ret = -1; + + if (virTestRun("bool", testConfParseBool, NULL) < 0) + ret = -1; + + if (virTestRun("string", testConfParseString, NULL) < 0) + ret = -1; + + if (virTestRun("string-list", testConfParseStringList, NULL) < 0) + ret = -1; + return ret; }