From 952907f5401512013a1296d7888b1217abecff76 Mon Sep 17 00:00:00 2001 From: Pavel Boldin Date: Tue, 16 Jun 2015 01:42:08 +0300 Subject: [PATCH] util: virTypedParams{Filter,GetStringList} Add multikey API: * virTypedParamsFilter that filters all the parameters with specified name. * virTypedParamsGetStringList that returns a list with all the values for specified name and string type. Signed-off-by: Pavel Boldin Signed-off-by: Michal Privoznik --- src/libvirt_private.syms | 2 + src/util/virtypedparam.c | 102 ++++++++++++++++++++++++++++++++++++++ src/util/virtypedparam.h | 14 ++++++ tests/virtypedparamtest.c | 101 +++++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2d4ab2171d..bf8ef76327 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2274,6 +2274,8 @@ virTypedParameterTypeFromString; virTypedParameterTypeToString; virTypedParamsCheck; virTypedParamsCopy; +virTypedParamsFilter; +virTypedParamsGetStringList; virTypedParamsReplaceString; virTypedParamsValidate; diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index 6f608d648b..a9cc1bc48a 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, \ @@ -749,6 +794,63 @@ virTypedParamsGetString(virTypedParameterPtr params, } +/** + * virTypedParamsGetStringList: + * @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 +virTypedParamsGetStringList(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 diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h index b4ae007cbf..9bef2041db 100644 --- a/src/util/virtypedparam.h +++ b/src/util/virtypedparam.h @@ -45,6 +45,20 @@ bool virTypedParamsCheck(virTypedParameterPtr params, const char **names, int nnames); +int +virTypedParamsGetStringList(virTypedParameterPtr params, + int nparams, + const char *name, + const char ***values); +int +virTypedParamsFilter(virTypedParameterPtr params, + int nparams, + const char *name, + virTypedParameterPtr **ret) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(4); + + int virTypedParameterAssign(virTypedParameterPtr param, const char *name, int type, /* TYPE arg */ ...) ATTRIBUTE_RETURN_CHECK; diff --git a/tests/virtypedparamtest.c b/tests/virtypedparamtest.c index 95e22a7e2d..ef0be46e32 100644 --- a/tests/virtypedparamtest.c +++ b/tests/virtypedparamtest.c @@ -80,6 +80,101 @@ testTypedParamsValidate(const void *opaque) .params = PARAMS_ARRAY(__VA_ARGS__), \ .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 +testTypedParamsGetStringList(const void *opaque ATTRIBUTE_UNUSED) +{ + size_t i; + int picked; + 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 = virTypedParamsGetStringList(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) { @@ -159,6 +254,12 @@ mymain(void) if (testTypedParamsValidator() < 0) rv = -1; + if (virtTestRun("Filtering", testTypedParamsFilter, NULL) < 0) + rv = -1; + + if (virtTestRun("Get All Strings", testTypedParamsGetStringList, NULL) < 0) + rv = -1; + if (rv < 0) return EXIT_FAILURE; return EXIT_SUCCESS;