On 16.06.2015 00:42, Pavel Boldin wrote: > Add multikey API: > > * virTypedParamsFilter that filters all the parameters with specified name. > * virTypedParamsGetAllStrings that returns a list with all the values for > specified name and string type. > > Signed-off-by: Pavel Boldin <pboldin@xxxxxxxxxxxx> > Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> > --- > include/libvirt/libvirt-host.h | 5 ++ > src/libvirt_public.syms | 5 ++ > src/util/virtypedparam.c | 102 +++++++++++++++++++++++++++++++++++++++++ > src/util/virtypedparam.h | 9 ++++ > tests/Makefile.am | 2 +- > tests/virtypedparamtest.c | 100 ++++++++++++++++++++++++++++++++++++++++ > 6 files changed, 222 insertions(+), 1 deletion(-) > > diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h > index 070550b..8222cfb 100644 > --- a/include/libvirt/libvirt-host.h > +++ b/include/libvirt/libvirt-host.h > @@ -284,6 +284,11 @@ virTypedParamsGetString (virTypedParameterPtr params, > const char *name, > const char **value); > int > +virTypedParamsGetAllStrings(virTypedParameterPtr params, > + int nparams, > + const char *name, > + const char ***values); > +int > virTypedParamsAddInt (virTypedParameterPtr *params, > int *nparams, > int *maxparams, > diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms > index 716dd2f..0a1feea 100644 > --- a/src/libvirt_public.syms > +++ b/src/libvirt_public.syms > @@ -715,4 +715,9 @@ LIBVIRT_1.2.16 { > virDomainSetUserPassword; > } LIBVIRT_1.2.15; > > +LIBVIRT_1.3.0 { > + global: > + virTypedParamsGetAllStrings; > +} LIBVIRT_1.2.16; > + I don't think this symbol needs to be exported. > # .... define new API here using predicted next version number .... > diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c > index 6f608d6..a12006c 100644 > --- a/src/util/virtypedparam.c > +++ b/src/util/virtypedparam.c > @@ -482,6 +482,51 @@ virTypedParamsGet(virTypedParameterPtr params, > } > > > +/** > + * virTypedParamsFilter: > + * @params: array of typed parameters > + * @nparams: number of parameters in the @params array > + * @name: name of the parameter to find > + * @ret: pointer to the returned array > + * > + * Filters @params retaining only the parameters named @name in the > + * resulting array @ret. Caller should free the @ret array but not > + * the items since they are pointing to the @params elements. > + * > + * Returns amount of elements in @ret on success, -1 on error. > + */ > +int > +virTypedParamsFilter(virTypedParameterPtr params, > + int nparams, > + const char *name, > + virTypedParameterPtr **ret) > +{ > + size_t i, alloc = 0, n = 0; > + > + virCheckNonNullArgGoto(params, error); > + virCheckNonNullArgGoto(name, error); > + virCheckNonNullArgGoto(ret, error); > + > + *ret = NULL; > + > + for (i = 0; i < nparams; i++) { > + if (STREQ(params[i].field, name)) { > + if (VIR_RESIZE_N(*ret, alloc, n, 1) < 0) > + goto error; > + > + (*ret)[n] = ¶ms[i]; > + > + n++; > + } > + } > + > + return n; > + > + error: > + return -1; > +} > + > + > #define VIR_TYPED_PARAM_CHECK_TYPE(check_type) \ > do { if (param->type != check_type) { \ > virReportError(VIR_ERR_INVALID_ARG, \ > @@ -750,6 +795,63 @@ virTypedParamsGetString(virTypedParameterPtr params, > > > /** > + * virTypedParamsGetAllStrings: > + * @params: array of typed parameters > + * @nparams: number of parameters in the @params array > + * @name: name of the parameter to find > + * @values: array of returned values > + * > + * Finds all parameters with desired @name within @params and > + * store their values into @values. The @values array is self > + * allocated and its length is stored into @picked. When no > + * longer needed, caller should free the returned array, but not > + * the items since they are taken from @params array. > + * > + * Returns amount of strings in @values array on success, > + * -1 otherwise. > + */ > +int > +virTypedParamsGetAllStrings(virTypedParameterPtr params, > + int nparams, > + const char *name, > + const char ***values) > +{ > + size_t i, n; > + int nfiltered; > + virTypedParameterPtr *filtered = NULL; > + > + virResetLastError(); > + > + virCheckNonNullArgGoto(values, error); > + *values = NULL; > + > + nfiltered = virTypedParamsFilter(params, nparams, name, &filtered); > + > + if (nfiltered < 0) > + goto error; > + > + if (nfiltered && > + VIR_ALLOC_N(*values, nfiltered) < 0) > + goto error; > + > + for (n = 0, i = 0; i < nfiltered; i++) { > + if (filtered[i]->type == VIR_TYPED_PARAM_STRING) > + (*values)[n++] = filtered[i]->value.s; > + } > + > + VIR_FREE(filtered); > + return n; > + > + error: > + if (values) > + VIR_FREE(*values); > + VIR_FREE(filtered); > + virDispatchError(NULL); > + return -1; > +} > + > + > +/** > * virTypedParamsAddInt: > * @params: pointer to the array of typed parameters > * @nparams: number of parameters in the @params array > diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h > index 9f2d08c..ac7f3a1 100644 > --- a/src/util/virtypedparam.h > +++ b/src/util/virtypedparam.h > @@ -45,6 +45,15 @@ bool virTypedParamsCheck(virTypedParameterPtr params, > const char **names, > int nnames); > > +int > +virTypedParamsFilter (virTypedParameterPtr params, > + int nparams, > + const char *name, > + virTypedParameterPtr **ret) > + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) > + ATTRIBUTE_NONNULL(4); > + > + Since this is an internal API, it must go into src/libvirt_private.syms too. > int virTypedParameterAssign(virTypedParameterPtr param, const char *name, > int type, /* TYPE arg */ ...) > ATTRIBUTE_RETURN_CHECK; > diff --git a/tests/Makefile.am b/tests/Makefile.am > index 9efb441..2d02208 100644 > --- a/tests/Makefile.am > +++ b/tests/Makefile.am > @@ -1228,7 +1228,7 @@ objecteventtest_LDADD = $(LDADDS) > > virtypedparamtest_SOURCES = \ > virtypedparamtest.c testutils.h testutils.c > -virtypedparamtest_LDADD = $(LDADDS) > +virtypedparamtest_LDADD = $(LDADDS) ../src/libvirt_util.la $(GNULIB_LIBS) Once the virTypedParamsFilter symbol is exposed (internally), you will not need this. > > > if WITH_LINUX > diff --git a/tests/virtypedparamtest.c b/tests/virtypedparamtest.c > index 95e22a7..698255a 100644 > --- a/tests/virtypedparamtest.c > +++ b/tests/virtypedparamtest.c > @@ -81,6 +81,100 @@ testTypedParamsValidate(const void *opaque) > .nparams = PARAMS_SIZE(__VA_ARGS__), > > static int > +testTypedParamsFilter(const void *opaque ATTRIBUTE_UNUSED) > +{ > + size_t i, nfiltered; > + int rv = -1; > + virTypedParameter params[] = { > + { .field = "bar", .type = VIR_TYPED_PARAM_UINT }, > + { .field = "foo", .type = VIR_TYPED_PARAM_INT }, > + { .field = "bar", .type = VIR_TYPED_PARAM_UINT }, > + { .field = "foo", .type = VIR_TYPED_PARAM_INT }, > + { .field = "foobar", .type = VIR_TYPED_PARAM_STRING }, > + { .field = "foo", .type = VIR_TYPED_PARAM_INT } > + }; > + virTypedParameterPtr *filtered = NULL; > + > + > + nfiltered = virTypedParamsFilter(params, ARRAY_CARDINALITY(params), > + "foo", &filtered); > + if (nfiltered != 3) > + goto cleanup; > + > + for (i = 0; i < nfiltered; i++) { > + if (filtered[i] != ¶ms[1 + i * 2]) > + goto cleanup; > + } > + VIR_FREE(filtered); > + filtered = NULL; > + > + nfiltered = virTypedParamsFilter(params, ARRAY_CARDINALITY(params), > + "bar", &filtered); > + > + if (nfiltered != 2) > + goto cleanup; > + > + for (i = 0; i < nfiltered; i++) { > + if (filtered[i] != ¶ms[i * 2]) > + goto cleanup; > + } > + > + rv = 0; > + cleanup: > + VIR_FREE(filtered); > + return rv; > +} > + > +static int > +testTypedParamsGetAllStrings(const void *opaque ATTRIBUTE_UNUSED) > +{ > + int i, picked; A loop iterator needs to be size_t. 'syntax-check' would have warn you about this. > + int rv = -1; > + char l = '1'; > + const char **strings = NULL; > + > + virTypedParameter params[] = { > + { .field = "bar", .type = VIR_TYPED_PARAM_STRING, > + .value = { .s = (char*)"bar1"} }, > + { .field = "foo", .type = VIR_TYPED_PARAM_INT }, > + { .field = "bar", .type = VIR_TYPED_PARAM_STRING, > + .value = { .s = (char*)"bar2"} }, > + { .field = "foo", .type = VIR_TYPED_PARAM_INT }, > + { .field = "foobar", .type = VIR_TYPED_PARAM_STRING }, > + { .field = "bar", .type = VIR_TYPED_PARAM_STRING, > + .value = { .s = NULL } }, > + { .field = "foo", .type = VIR_TYPED_PARAM_INT }, > + { .field = "bar", .type = VIR_TYPED_PARAM_STRING, > + .value = { .s = (char*)"bar3"} } > + }; > + > + picked = virTypedParamsGetAllStrings(params, > + ARRAY_CARDINALITY(params), > + "bar", > + &strings); > + > + if (picked < 0) > + goto cleanup; > + > + for (i = 0; i < picked; i++) { > + if (i == 2) { > + if (strings[i] != NULL) > + goto cleanup; > + continue; > + } > + if (!STREQLEN(strings[i], "bar", 3)) > + goto cleanup; > + if (strings[i][3] != l++) > + goto cleanup; > + } > + > + rv = 0; > + cleanup: > + VIR_FREE(strings); > + return rv; > +} > + > +static int > testTypedParamsValidator(void) > { > size_t i; > @@ -159,6 +253,12 @@ mymain(void) > if (testTypedParamsValidator() < 0) > rv = -1; > > + if (virtTestRun("Filtering", testTypedParamsFilter, NULL) < 0) > + rv = -1; > + > + if (virtTestRun("Get All Strings", testTypedParamsGetAllStrings, NULL) < 0) > + rv = -1; > + > if (rv < 0) > return EXIT_FAILURE; > return EXIT_SUCCESS; > Michal -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list