[libvirt] [PATCH v4 4/9] util: multi-value virTypedParameter

2015-06-15 Thread Pavel Boldin
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 
Signed-off-by: Michal Privoznik 
---
 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);
+  

Re: [libvirt] [PATCH v4 4/9] util: multi-value virTypedParameter

2015-06-16 Thread Michal Privoznik
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 
> Signed-off-by: Michal Privoznik 
> ---
>  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 && !(