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@xxxxxxxxxxxx> > Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> > --- > 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list