
On 16.06.2015 00:42, Pavel Boldin wrote:
The `virTypedParamsValidate' function now can be instructed to allow multiple entries for some of the keys. For this flag the type with the `VIR_TYPED_PARAM_MULTIPLE' flag.
Add unit tests for this new behaviour.
Signed-off-by: Pavel Boldin <pboldin@mirantis.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virtypedparam.c | 109 +++++++++++++++++++----------- src/util/virtypedparam.h | 10 +++ tests/Makefile.am | 6 ++ tests/virtypedparamtest.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+), 39 deletions(-) create mode 100644 tests/virtypedparamtest.c
diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index de2d447..68620f5 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -47,11 +47,19 @@ VIR_ENUM_IMPL(virTypedParameter, VIR_TYPED_PARAM_LAST, * internal utility functions (those in libvirt_private.syms) may * report errors that the caller will dispatch. */
+static int +virTypedParamsSortName(const void *left, const void *right) +{ + const virTypedParameter *param_left = left, *param_right = right; + return strcmp(param_left->field, param_right->field); +} + /* Validate that PARAMS contains only recognized parameter names with - * correct types, and with no duplicates. Pass in as many name/type - * pairs as appropriate, and pass NULL to end the list of accepted - * parameters. Return 0 on success, -1 on failure with error message - * already issued. */ + * correct types, and with no duplicates except for parameters + * specified with VIR_TYPED_PARAM_MULTIPLE flag in type. + * Pass in as many name/type pairs as appropriate, and pass NULL to end + * the list of accepted parameters. Return 0 on success, -1 on failure + * with error message already issued. */ int virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...) { @@ -60,60 +68,83 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...) size_t i, j; const char *name; int type; + size_t nkeys = 0, nkeysalloc = 0; + virTypedParameterPtr sorted = NULL, keys = NULL;
va_start(ap, nparams);
- /* Yes, this is quadratic, but since we reject duplicates and - * unknowns, it is constrained by the number of var-args passed - * in, which is expected to be small enough to not be - * noticeable. */ - for (i = 0; i < nparams; i++) { - va_end(ap); - va_start(ap, nparams); + if (VIR_ALLOC_N(sorted, nparams) < 0) + goto cleanup;
- name = va_arg(ap, const char *); - while (name) { - type = va_arg(ap, int); - if (STREQ(params[i].field, name)) { - if (params[i].type != type) { - const char *badtype; - - badtype = virTypedParameterTypeToString(params[i].type); - if (!badtype) - badtype = virTypedParameterTypeToString(0); - virReportError(VIR_ERR_INVALID_ARG, - _("invalid type '%s' for parameter '%s', " - "expected '%s'"), - badtype, params[i].field, - virTypedParameterTypeToString(type)); - } - break; - } - name = va_arg(ap, const char *); - } - if (!name) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, - _("parameter '%s' not supported"), - params[i].field); + /* Here we intentionally don't copy values */ + memcpy(sorted, params, sizeof(*params) * nparams); + qsort(sorted, nparams, sizeof(*sorted), virTypedParamsSortName); + + name = va_arg(ap, const char *); + while (name) { + type = va_arg(ap, int); + if (VIR_RESIZE_N(keys, nkeysalloc, nkeys, 1) < 0) + goto cleanup; + + if (virStrcpyStatic(keys[nkeys].field, name) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Field name '%s' too long"), name); goto cleanup; } - for (j = 0; j < i; j++) { - if (STREQ(params[i].field, params[j].field)) { + + keys[nkeys].type = type & ~VIR_TYPED_PARAM_MULTIPLE; + /* Value is not used anyway */ + keys[nkeys].value.i = type & VIR_TYPED_PARAM_MULTIPLE; + + nkeys++; + name = va_arg(ap, const char *); + } + + qsort(keys, nkeys, sizeof(*keys), virTypedParamsSortName); + + for (i = 0, j = 0; i < nparams && j < nkeys;) { + if (STRNEQ(sorted[i].field, keys[j].field)) { + j++; + } else { + if (i > j && !(keys[j].value.i & VIR_TYPED_PARAM_MULTIPLE)) { virReportError(VIR_ERR_INVALID_ARG, _("parameter '%s' occurs multiple times"), - params[i].field); + sorted[i].field); + goto cleanup; + } + if (sorted[i].type != keys[j].type) { + const char *badtype; + + badtype = virTypedParameterTypeToString(sorted[i].type); + if (!badtype) + badtype = virTypedParameterTypeToString(0); + virReportError(VIR_ERR_INVALID_ARG, + _("invalid type '%s' for parameter '%s', " + "expected '%s'"), + badtype, sorted[i].field, + virTypedParameterTypeToString(keys[j].type)); goto cleanup; } + i++; } }
+ if (j == nkeys && i != nparams) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("parameter '%s' not supported"), + sorted[i].field); + goto cleanup; + } + ret = 0; cleanup: va_end(ap); + VIR_FREE(sorted); + VIR_FREE(keys); return ret; - }
+ /* Check if params contains only specified parameter names. Return true if * only specified names are present in params, false if params contains any * unspecified parameter name. */ diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h index 0c18504..9f2d08c 100644 --- a/src/util/virtypedparam.h +++ b/src/util/virtypedparam.h @@ -26,6 +26,16 @@ # include "internal.h" # include "virutil.h"
+/** + * VIR_TYPED_PARAM_MULTIPLE: + * + * Flag indiciating that the params has multiple occurences of the parameter.
s/indiciating/indicating/ s/occurences/occurrences/
+ * Only used as a flag for @type argument of the virTypedParamsValidate. + */ +# define VIR_TYPED_PARAM_MULTIPLE (1 << 31) + +verify(!(VIR_TYPED_PARAM_LAST & VIR_TYPED_PARAM_MULTIPLE)); +
Michal