libnv: Add nvlist_append_*_array() family of functions.

The nvlist_append_{bool,number,string,nvlist,descriptor}_array() functions
allows to dynamically extend array stored in the nvlist.

Submitted by:	Mindaugas Rasiukevicius <rmind@netbsd.org>
This commit is contained in:
Mariusz Zaborski 2018-06-18 22:57:32 +00:00
parent 936a20bb1c
commit 24881c060c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=335347
7 changed files with 331 additions and 2 deletions

View File

@ -7,6 +7,7 @@ ATF_TESTS_CXX= \
nv_tests \ nv_tests \
TAP_TESTS_C+= nvlist_add_test TAP_TESTS_C+= nvlist_add_test
TAP_TESTS_C+= nvlist_append_test
TAP_TESTS_C+= nvlist_exists_test TAP_TESTS_C+= nvlist_exists_test
TAP_TESTS_C+= nvlist_free_test TAP_TESTS_C+= nvlist_free_test
TAP_TESTS_C+= nvlist_get_test TAP_TESTS_C+= nvlist_get_test

View File

@ -0,0 +1,120 @@
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/nv.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int ntest = 1;
#define CHECK(expr) do { \
if ((expr)) \
printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
else \
printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
ntest++; \
} while (0)
int
main(void)
{
const bool *bool_result;
const char * const *string_result;
const nvlist_t * const *nvl_result;
nvlist_t *nvl, *nvl1, *nvl2, **items;
unsigned int i;
size_t nitems;
printf("1..32\n");
nvl = nvlist_create(0);
for (i = 0; i < 16; i++)
nvlist_append_bool_array(nvl, "nvl/bool", i % 2 == 0);
CHECK(nvlist_error(nvl) == 0);
CHECK(!nvlist_empty(nvl));
CHECK(nvlist_exists_bool_array(nvl, "nvl/bool"));
bool_result = nvlist_get_bool_array(nvl, "nvl/bool", &nitems);
CHECK(nitems == 16);
CHECK(bool_result != NULL);
for (i = 0; i < nitems; i++)
CHECK(bool_result[i] == (i % 2 == 0));
nvlist_append_string_array(nvl, "nvl/string", "a");
nvlist_append_string_array(nvl, "nvl/string", "abc");
string_result = nvlist_get_string_array(nvl, "nvl/string", &nitems);
CHECK(nitems == 2);
CHECK(strcmp(string_result[0], "a") == 0);
CHECK(strcmp(string_result[1], "abc") == 0);
nvl1 = nvlist_create(0);
nvlist_add_string(nvl1, "key1", "test1");
nvlist_append_nvlist_array(nvl, "nvl/nvl", nvl1);
nvlist_destroy(nvl1);
nvl2 = nvlist_create(0);
nvlist_add_string(nvl2, "key2", "test2");
nvlist_append_nvlist_array(nvl, "nvl/nvl", nvl2);
nvlist_destroy(nvl2);
nvl_result = nvlist_get_nvlist_array(nvl, "nvl/nvl", &nitems);
CHECK(nitems == 2);
CHECK(strcmp(nvlist_get_string(nvl_result[0], "key1"), "test1") == 0);
CHECK(strcmp(nvlist_get_string(nvl_result[1], "key2"), "test2") == 0);
nvl1 = nvlist_create(0);
nvlist_add_number(nvl1, "key1", 10);
nvlist_append_nvlist_array(nvl, "nvl/nvl_array", nvl1);
nvlist_destroy(nvl1);
nvl2 = nvlist_create(0);
nvlist_add_number(nvl2, "key1", 20);
nvlist_append_nvlist_array(nvl, "nvl/nvl_array", nvl2);
nvlist_destroy(nvl2);
items = nvlist_take_nvlist_array(nvl, "nvl/nvl_array", &nitems);
CHECK(nvlist_get_number(items[0], "key1") == 10);
CHECK(nvlist_get_number(items[1], "key1") == 20);
CHECK(nvlist_error(items[0]) == 0);
CHECK(nvlist_error(items[1]) == 0);
nvlist_move_nvlist_array(nvl, "nvl/nvl_new_array", items, nitems);
CHECK(nvlist_error(nvl) == 0);
nvlist_destroy(nvl);
return (0);
}

View File

@ -29,7 +29,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd September 16, 2017 .Dd June 19, 2018
.Dt NV 9 .Dt NV 9
.Os .Os
.Sh NAME .Sh NAME
@ -55,7 +55,8 @@
.Nm nvlist_add , .Nm nvlist_add ,
.Nm nvlist_move , .Nm nvlist_move ,
.Nm nvlist_get , .Nm nvlist_get ,
.Nm nvlist_take .Nm nvlist_take ,
.Nm nvlist_append
.Nd "library for name/value pairs" .Nd "library for name/value pairs"
.Sh LIBRARY .Sh LIBRARY
.Lb libnv .Lb libnv
@ -239,6 +240,17 @@
.Fn nvlist_take_descriptor_array "nvlist_t *nvl" "const char *name" "size_t *nitems" .Fn nvlist_take_descriptor_array "nvlist_t *nvl" "const char *name" "size_t *nitems"
.\" .\"
.Ft void .Ft void
.Fn nvlist_append_bool_array "nvlist_t *nvl" "const char *name" "const bool value"
.Ft void
.Fn nvlist_append_number_array "nvlist_t *nvl" "const char *name" "const uint64_t value"
.Ft void
.Fn nvlist_append_string_array "nvlist_t *nvl" "const char *name" "const char * const value"
.Ft void
.Fn nvlist_append_nvlist_array "nvlist_t *nvl" "const char *name" "const nvlist_t * const value"
.Ft void
.Fn nvlist_append_descriptor_array "nvlist_t *nvl" "const char *name" "int value"
.\"
.Ft void
.Fn nvlist_free "nvlist_t *nvl" "const char *name" .Fn nvlist_free "nvlist_t *nvl" "const char *name"
.Ft void .Ft void
.Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type" .Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type"
@ -710,6 +722,20 @@ function.
The nvlist must not be in error state. The nvlist must not be in error state.
.Pp .Pp
The The
.Fn nvlist_append_bool_array ,
.Fn nvlist_append_number_array ,
.Fn nvlist_append_string_array ,
.Fn nvlist_append_nvlist_array ,
.Fn nvlist_append_descriptor_array
functions append an element to the existing array using the same semantics
as the add functions (i.e. the element will be copied when applicable).
If the array for a given key does not exist, then it will be created
as if using the
.Fn nvlist_add_<type>_array
function.
The internal error is set on append failure.
.Pp
The
.Fn nvlist_free .Fn nvlist_free
function removes element of the given name from the nvlist (besides of its type) function removes element of the given name from the nvlist (besides of its type)
and frees all resources associated with it. and frees all resources associated with it.

View File

@ -143,6 +143,12 @@ nvpair_t *nvpair_move_descriptor_array(const char *name, int *value, size_t nite
nvpair_t *nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems); nvpair_t *nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems);
nvpair_t *nvpair_move_string_array(const char *name, char **value, size_t nitems); nvpair_t *nvpair_move_string_array(const char *name, char **value, size_t nitems);
int nvpair_append_bool_array(nvpair_t *nvp, const bool value);
int nvpair_append_number_array(nvpair_t *nvp, const uint64_t value);
int nvpair_append_string_array(nvpair_t *nvp, const char *value);
int nvpair_append_nvlist_array(nvpair_t *nvp, const nvlist_t *value);
int nvpair_append_descriptor_array(nvpair_t *nvp, const int value);
bool nvpair_get_bool(const nvpair_t *nvp); bool nvpair_get_bool(const nvpair_t *nvp);
uint64_t nvpair_get_number(const nvpair_t *nvp); uint64_t nvpair_get_number(const nvpair_t *nvp);
const char *nvpair_get_string(const nvpair_t *nvp); const char *nvpair_get_string(const nvpair_t *nvp);

View File

@ -1607,6 +1607,37 @@ NVLIST_ADD_ARRAY(const int *, descriptor)
#undef NVLIST_ADD_ARRAY #undef NVLIST_ADD_ARRAY
#define NVLIST_APPEND_ARRAY(vtype, type, TYPE) \
void \
nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\
{ \
nvpair_t *nvp; \
\
if (nvlist_error(nvl) != 0) { \
ERRNO_SET(nvlist_error(nvl)); \
return; \
} \
nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
if (nvp == NULL) { \
nvlist_add_##type##_array(nvl, name, &value, 1); \
return; \
} \
if (nvpair_append_##type##_array(nvp, value) == -1) { \
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
ERRNO_SET(nvl->nvl_error); \
} \
}
NVLIST_APPEND_ARRAY(const bool, bool, BOOL)
NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER)
NVLIST_APPEND_ARRAY(const char *, string, STRING)
NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST)
#ifndef _KERNEL
NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR)
#endif
#undef NVLIST_APPEND_ARRAY
bool bool
nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
{ {

View File

@ -144,6 +144,28 @@ nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize,
return (nvp); return (nvp);
} }
static int
nvpair_append(nvpair_t *nvp, const void *value, size_t valsize, size_t datasize)
{
void *olddata, *data, *valp;
size_t oldlen;
oldlen = nvp->nvp_nitems * valsize;
olddata = (void *)(uintptr_t)nvp->nvp_data;
data = nv_realloc(olddata, oldlen + valsize);
if (data == NULL) {
ERRNO_SET(ENOMEM);
return (-1);
}
valp = (unsigned char *)data + oldlen;
memcpy(valp, value, valsize);
nvp->nvp_data = (uint64_t)(uintptr_t)data;
nvp->nvp_datasize += datasize;
nvp->nvp_nitems++;
return (0);
}
nvlist_t * nvlist_t *
nvpair_nvlist(const nvpair_t *nvp) nvpair_nvlist(const nvpair_t *nvp)
{ {
@ -1913,6 +1935,121 @@ nvpair_get_descriptor_array(const nvpair_t *nvp, size_t *nitems)
} }
#endif #endif
int
nvpair_append_bool_array(nvpair_t *nvp, const bool value)
{
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
return (nvpair_append(nvp, &value, sizeof(value), sizeof(value)));
}
int
nvpair_append_number_array(nvpair_t *nvp, const uint64_t value)
{
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
return (nvpair_append(nvp, &value, sizeof(value), sizeof(value)));
}
int
nvpair_append_string_array(nvpair_t *nvp, const char *value)
{
char *str;
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
if (value == NULL) {
ERRNO_SET(EINVAL);
return (-1);
}
str = nv_strdup(value);
if (str == NULL) {
return (-1);
}
if (nvpair_append(nvp, &str, sizeof(str), strlen(str) + 1) == -1) {
nv_free(str);
return (-1);
}
return (0);
}
int
nvpair_append_nvlist_array(nvpair_t *nvp, const nvlist_t *value)
{
nvpair_t *tmpnvp;
nvlist_t *nvl, *prev;
int flags;
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY);
if (value == NULL || nvlist_error(value) != 0 ||
nvlist_get_pararr(value, NULL) != NULL) {
ERRNO_SET(EINVAL);
return (-1);
}
nvl = nvlist_clone(value);
if (nvl == NULL) {
return (-1);
}
flags = nvlist_flags(nvl) | NV_FLAG_IN_ARRAY;
nvlist_set_flags(nvl, flags);
tmpnvp = NULL;
if (nvp->nvp_nitems > 0) {
nvlist_t **nvls = (void *)(uintptr_t)nvp->nvp_data;
prev = nvls[nvp->nvp_nitems - 1];
PJDLOG_ASSERT(prev != NULL);
tmpnvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
(uint64_t)(uintptr_t)nvl, 0, 0);
if (tmpnvp == NULL) {
goto fail;
}
}
if (nvpair_append(nvp, &nvl, sizeof(nvl), 0) == -1) {
goto fail;
}
if (tmpnvp) {
NVPAIR_ASSERT(tmpnvp);
nvlist_set_array_next(prev, tmpnvp);
}
nvlist_set_parent(nvl, nvp);
return (0);
fail:
if (tmpnvp) {
nvpair_free(tmpnvp);
}
nvlist_destroy(nvl);
return (-1);
}
#ifndef _KERNEL
int
nvpair_append_descriptor_array(nvpair_t *nvp, const int value)
{
int fd;
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
if (value < 0 || !fd_is_valid(value)) {
ERRNO_SET(EBADF);
return -1;
}
fd = fcntl(value, F_DUPFD_CLOEXEC, 0);
if (fd == -1) {
return (-1);
}
if (nvpair_append(nvp, &fd, sizeof(fd), sizeof(fd)) == -1) {
close(fd);
return (-1);
}
return (0);
}
#endif
void void
nvpair_free(nvpair_t *nvp) nvpair_free(nvpair_t *nvp)
{ {

View File

@ -162,6 +162,14 @@ void nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value);
void nvlist_add_descriptor_array(nvlist_t *nvl, const char *name, const int *value, size_t nitems); void nvlist_add_descriptor_array(nvlist_t *nvl, const char *name, const int *value, size_t nitems);
#endif #endif
void nvlist_append_bool_array(nvlist_t *nvl, const char *name, const bool value);
void nvlist_append_number_array(nvlist_t *nvl, const char *name, const uint64_t value);
void nvlist_append_string_array(nvlist_t *nvl, const char *name, const char * const value);
void nvlist_append_nvlist_array(nvlist_t *nvl, const char *name, const nvlist_t * const value);
#ifndef _KERNEL
void nvlist_append_descriptor_array(nvlist_t *nvl, const char *name, int value);
#endif
/* /*
* The nvlist_move functions add the given name/value pair. * The nvlist_move functions add the given name/value pair.
* The functions consumes provided buffer. * The functions consumes provided buffer.