Mercurial > libjeffpc
changeset 464:b1e4c7607050
val: introduce VT_NVL
This replaces the previous implementation of nvlists.
Unfortunately, there is no cbor packing test for VT_NVL because it is
complicated to differentiate between a list and an assoc sexpr. However,
there are tests for the nvl_pack API, and so the code isn't completely
untested.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sat, 31 Mar 2018 17:34:16 -0400 |
parents | 8f455913bfd0 |
children | c4ac06c3ee4a |
files | CMakeLists.txt fmt_cbor.c include/jeffpc/cbor.h include/jeffpc/nvl.h include/jeffpc/val.h jeffpc.mapfile-vers nvl.c nvl_convert.c nvl_dump.c nvl_fmt_cbor.c nvl_fmt_json.c nvl_impl.h nvl_pack.c scgisvc.c sexpr.c sexpr_dump.c sexpr_eval.c tests/test_cbor_pack.c tests/test_nvl.c tests/test_nvl_pack.c tests/test_qstring.c val.c val_impl.h val_nvl.c |
diffstat | 24 files changed, 461 insertions(+), 666 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Sat Mar 31 19:05:41 2018 -0400 +++ b/CMakeLists.txt Sat Mar 31 17:34:16 2018 -0400 @@ -99,7 +99,6 @@ mem_array.c nvl.c nvl_convert.c - nvl_dump.c nvl_fmt_cbor.c nvl_fmt_json.c nvl_pack.c @@ -122,6 +121,7 @@ uuid.c val.c val_array.c + val_nvl.c version.c ${UMEM_EXTRA_SOURCE} )
--- a/fmt_cbor.c Sat Mar 31 19:05:41 2018 -0400 +++ b/fmt_cbor.c Sat Mar 31 17:34:16 2018 -0400 @@ -21,6 +21,7 @@ */ #include <jeffpc/cbor.h> +#include <jeffpc/nvl.h> enum major_type { CMT_UINT = 0, @@ -231,6 +232,35 @@ return cbor_pack_break(buffer); } +int cbor_pack_map_val(struct buffer *buffer, struct val *val) +{ + struct bst_tree *tree = &val->_set_nvl.values; + struct nvpair *cur; + size_t npairs; + int ret; + + if (val->type != VT_NVL) + return -EINVAL; + + npairs = bst_numnodes(tree); + + ret = cbor_pack_map_start(buffer, npairs); + if (ret) + return ret; + + bst_for_each(tree, cur) { + ret = cbor_pack_str(buffer, cur->name); + if (ret) + return ret; + + ret = cbor_pack_val(buffer, cur->value); + if (ret) + return ret; + } + + return cbor_pack_map_end(buffer, npairs); +} + int cbor_pack_val(struct buffer *buffer, struct val *val) { switch (val->type) { @@ -258,6 +288,8 @@ */ return cbor_pack_array_vals(buffer, val->_set_array.vals, val->array.nelem); + case VT_NVL: + return cbor_pack_map_val(buffer, val); } return -ENOTSUP;
--- a/include/jeffpc/cbor.h Sat Mar 31 19:05:41 2018 -0400 +++ b/include/jeffpc/cbor.h Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -49,6 +49,7 @@ extern int cbor_pack_map_start(struct buffer *buffer, size_t npairs); extern int cbor_pack_map_end(struct buffer *buffer, size_t npairs); extern int cbor_pack_val(struct buffer *buffer, struct val *val); +extern int cbor_pack_map_val(struct buffer *buffer, struct val *val); static inline int cbor_pack_cstr(struct buffer *buffer, const char *str) {
--- a/include/jeffpc/nvl.h Sat Mar 31 19:05:41 2018 -0400 +++ b/include/jeffpc/nvl.h Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,24 +25,11 @@ #include <stdbool.h> -#include <jeffpc/list.h> #include <jeffpc/val.h> -#include <jeffpc/refcnt.h> #include <jeffpc/buffer.h> struct nvlist { - struct list values; - refcnt_t refcnt; -}; - -enum nvtype { - NVT_ARRAY, - NVT_BLOB, - NVT_BOOL, - NVT_INT, - NVT_NULL, - NVT_NVL, - NVT_STR, + struct val val; }; /* serialization formats */ @@ -53,26 +40,10 @@ /* do not access these directly */ struct nvpair { - struct list_node node; + struct bst_node node; - const char *name; - struct nvval { - enum nvtype type; - union { - struct { - struct nvval *vals; - size_t nelem; - } array; - struct { - void *ptr; - size_t size; - } blob; - bool b; - uint64_t i; - struct nvlist *nvl; - struct str *str; - }; - } value; + struct str *name; + struct val *value; }; enum nvcvtcond { @@ -82,14 +53,45 @@ struct nvl_convert_info { const char *name; - enum nvtype tgt_type; + enum val_type tgt_type; enum nvcvtcond cond; }; -extern struct nvlist *nvl_alloc(void); -extern void nvl_free(struct nvlist *nvl); +#define nvl_alloc() ((struct nvlist *) val_alloc_nvl()) + +/* + * struct val reference counting & casting to struct nvl + */ + +static inline struct nvlist *val_cast_to_nvl(struct val *val) +{ + ASSERT(!val || (val->type == VT_NVL)); + + return container_of(val, struct nvlist, val); +} + +#define val_getref_nvl(v) val_cast_to_nvl(val_getref(v)) + +/* + * struct nvl reference counting & casting to struct val + */ + +#define nvl_getref(nvl) ((struct nvlist *) val_getref(nvl_cast_to_val(nvl))) + +#define nvl_putref(nvl) val_putref(nvl_cast_to_val(nvl)) + +#define nvl_getref_val(nvl) val_getref(nvl_cast_to_val(nvl)) + +static inline struct val *nvl_cast_to_val(struct nvlist *nvl) +{ + return &nvl->val; +} + +/* + * Misc functions + */ + extern int nvl_merge(struct nvlist *dest, struct nvlist *src); -extern void nvl_dump_file(FILE *out, struct nvlist *nvl); /* * If convert_all is true, then all errors except -ENOTSUP encountered @@ -105,14 +107,10 @@ enum nvformat format); /* iteration */ +extern const struct nvpair *nvl_iter_start(struct nvlist *nvl); extern const struct nvpair *nvl_iter_next(struct nvlist *nvl, const struct nvpair *prev); -static inline const struct nvpair *nvl_iter_start(struct nvlist *nvl) -{ - return nvl_iter_next(nvl, NULL); -} - #define nvl_for_each(pair, nvl) \ for (pair = nvl_iter_start(nvl); \ pair != NULL; \ @@ -129,7 +127,7 @@ * -ERANGE = wrong type (e.g., looking up an int, but stored value is a string) */ extern int nvl_lookup_array(struct nvlist *nvl, const char *name, - const struct nvval **vals, size_t *nelem); + struct val ***vals, size_t *nelem); extern int nvl_lookup_blob(struct nvlist *nvl, const char *name, const void **ptr, size_t *size); extern int nvl_lookup_bool(struct nvlist *nvl, const char *name, bool *out); @@ -147,11 +145,11 @@ * * -ENOMEM = out of memory */ -extern int nvl_set(struct nvlist *nvl, const char *name, struct nvval *val); +extern int nvl_set(struct nvlist *nvl, const char *name, struct val *val); extern int nvl_set_array(struct nvlist *nvl, const char *name, - struct nvval *vals, size_t nelem); + struct val **vals, size_t nelem); extern int nvl_set_array_copy(struct nvlist *nvl, const char *name, - const struct nvval *vals, size_t nelem); + struct val **vals, size_t nelem); extern int nvl_set_blob(struct nvlist *nvl, const char *name, void *ptr, size_t size); extern int nvl_set_blob_copy(struct nvlist *nvl, const char *name, @@ -171,7 +169,7 @@ * -ERANGE = existing item's type doesn't match requested type */ extern int nvl_unset(struct nvlist *nvl, const char *name); -extern int nvl_unset_type(struct nvlist *nvl, const char *name, enum nvtype type); +extern int nvl_unset_type(struct nvlist *nvl, const char *name, enum val_type type); /* * Check existence of a specific key, or key-valuetype pair from the list. @@ -187,7 +185,7 @@ */ extern bool nvl_exists(struct nvlist *nvl, const char *name); extern int nvl_exists_type(struct nvlist *nvl, const char *name, - enum nvtype type); + enum val_type type); /* * nvpair related functions @@ -195,12 +193,12 @@ static inline const char *nvpair_name(const struct nvpair *pair) { - return pair->name; + return str_cstr(pair->name); } -static inline enum nvtype nvpair_type(const struct nvpair *pair) +static inline enum val_type nvpair_type(const struct nvpair *pair) { - return pair->value.type; + return pair->value->type; } /* @@ -208,7 +206,7 @@ * integer. The meaning of the return values is the same as well. */ extern int nvpair_value_array(const struct nvpair *pair, - const struct nvval **vals, size_t *nelem); + struct val ***vals, size_t *nelem); extern int nvpair_value_blob(const struct nvpair *pair, const void **ptr, size_t *size); extern int nvpair_value_bool(const struct nvpair *pair, bool *out); @@ -217,18 +215,4 @@ extern struct nvlist *nvpair_value_nvl(const struct nvpair *pair); extern struct str *nvpair_value_str(const struct nvpair *pair); -/* - * nvval related functions - */ - -extern void nvval_release_array(struct nvval *vals, size_t nelem); - -static inline void nvval_release(struct nvval *val) -{ - if (val) - nvval_release_array(val, 1); -} - -REFCNT_INLINE_FXNS(struct nvlist, nvl, refcnt, nvl_free, NULL) - #endif
--- a/include/jeffpc/val.h Sat Mar 31 19:05:41 2018 -0400 +++ b/include/jeffpc/val.h Sat Mar 31 17:34:16 2018 -0400 @@ -30,6 +30,8 @@ #include <jeffpc/refcnt.h> #include <jeffpc/error.h> #include <jeffpc/types.h> +#include <jeffpc/list.h> +#include <jeffpc/bst.h> /* * A typed value structure. @@ -54,6 +56,7 @@ VT_CHAR, /* a single (unicode) character */ VT_BLOB, /* a byte string */ VT_ARRAY, /* an array of values */ + VT_NVL, /* an nvlist */ }; #define STR_INLINE_LEN 15 @@ -81,6 +84,15 @@ struct val **vals; size_t nelem; } array; + const struct { + /* + * TODO: Using an unbalanced binary search tree is + * not great, but it will do for now. Once we have + * a balanced binary search tree implementation, we + * should switch to it. + */ + struct bst_tree values; + } nvl; /* * We want to keep the normal members const to catch @@ -109,6 +121,9 @@ struct val **vals; size_t nelem; } _set_array; + struct { + struct bst_tree values; + } _set_nvl; }; }; @@ -133,6 +148,7 @@ extern struct val *val_alloc_char(uint64_t v); extern struct val *val_alloc_int(uint64_t v); extern struct val *val_alloc_null(void); +extern struct val *val_alloc_nvl(void); /* val_alloc_cons always consume the passed in references */ extern struct val *val_alloc_cons(struct val *head, struct val *tail); @@ -362,6 +378,7 @@ #define VAL_ALLOC_BOOL(v) val_alloc_bool(v) /* never fails */ #define VAL_ALLOC_NULL() val_alloc_null() /* never fails */ #define VAL_ALLOC_CONS(h, t) _VAL_ALLOC(struct val, val_alloc_cons((h), (t))) +#define VAL_ALLOC_NVL() _VAL_ALLOC(struct val, val_alloc_nvl()) #define VAL_ALLOC_ARRAY(v, l) _VAL_ALLOC(struct val, val_alloc_array((v), (l))) #define VAL_ALLOC_ARRAY_DUP(v, l) _VAL_ALLOC(struct val, val_alloc_array_dup((v), (l)))
--- a/jeffpc.mapfile-vers Sat Mar 31 19:05:41 2018 -0400 +++ b/jeffpc.mapfile-vers Sat Mar 31 17:34:16 2018 -0400 @@ -55,6 +55,7 @@ cbor_pack_int; cbor_pack_map_end; cbor_pack_map_start; + cbor_pack_map_val; cbor_pack_nint; cbor_pack_null; cbor_pack_str; @@ -104,13 +105,11 @@ mem_recallocarray; # nvlist - nvl_alloc; nvl_convert; - nvl_dump_file; nvl_exists; nvl_exists_type; - nvl_free; nvl_iter_next; + nvl_iter_start; nvl_lookup; nvl_lookup_array; nvl_lookup_blob; @@ -143,7 +142,6 @@ nvpair_value_null; nvpair_value_nvl; nvpair_value_str; - nvval_release_array; # padding check_padding; @@ -251,6 +249,7 @@ val_alloc_cons; val_alloc_int; val_alloc_null; + val_alloc_nvl; val_empty_cons; # urldecode
--- a/nvl.c Sat Mar 31 19:05:41 2018 -0400 +++ b/nvl.c Sat Mar 31 17:34:16 2018 -0400 @@ -24,225 +24,16 @@ #include <jeffpc/mem.h> #include <jeffpc/nvl.h> -static void nvpair_free(struct nvpair *pair); - -static struct mem_cache *nvlist_cache; -static struct mem_cache *nvpair_cache; - -static void __attribute__((constructor)) init_nvl_subsys(void) -{ - nvlist_cache = mem_cache_create("nvlist-cache", sizeof(struct nvlist), - 0); - ASSERT(!IS_ERR(nvlist_cache)); - nvpair_cache = mem_cache_create("nvpair-cache", sizeof(struct nvpair), - 0); - ASSERT(!IS_ERR(nvpair_cache)); -} - -struct nvlist *nvl_alloc(void) -{ - struct nvlist *nvl; - - nvl = mem_cache_alloc(nvlist_cache); - if (!nvl) - return NULL; - - refcnt_init(&nvl->refcnt, 1); - list_create(&nvl->values, sizeof(struct nvpair), - offsetof(struct nvpair, node)); - - return nvl; -} - -void nvl_free(struct nvlist *nvl) -{ - struct nvpair *cur, *safe; - - ASSERT(nvl); - ASSERT3U(refcnt_read(&nvl->refcnt), ==, 0); - - list_for_each_safe(cur, safe, &nvl->values) - nvpair_free(cur); - - mem_cache_free(nvlist_cache, nvl); -} - -static void __nvval_release(struct nvval *val) -{ - size_t i; - - switch (val->type) { - case NVT_ARRAY: - for (i = 0; i < val->array.nelem; i++) - __nvval_release(&val->array.vals[i]); - free(val->array.vals); - break; - case NVT_BLOB: - free(val->blob.ptr); - break; - case NVT_BOOL: - case NVT_INT: - case NVT_NULL: - break; - case NVT_NVL: - nvl_putref(val->nvl); - break; - case NVT_STR: - str_putref(val->str); - break; - } -} - -void nvval_release_array(struct nvval *vals, size_t nelem) -{ - size_t i; - - if (!vals && !nelem) - return; - - ASSERT(vals); - ASSERT(nelem); - - for (i = 0; i < nelem; i++) - __nvval_release(&vals[i]); -} - -static struct nvval *val_dup_array(const struct nvval *user_vals, size_t nelem) -{ - struct nvval *vals; - size_t i; - - vals = mem_reallocarray(NULL, nelem, sizeof(struct nvval)); - if (!vals) - return NULL; - - for (i = 0; i < nelem; i++) { - const struct nvval *uval = &user_vals[i]; - - vals[i].type = uval->type; - - switch (uval->type) { - case NVT_ARRAY: { - struct nvval *subvals; - - subvals = val_dup_array(uval->array.vals, - uval->array.nelem); - if (!subvals) - goto err; - - vals[i].array.vals = subvals; - vals[i].array.nelem = uval->array.nelem; - break; - } - case NVT_BLOB: { - void *tmp; - - tmp = malloc(uval->blob.size); - if (!tmp) - goto err; - - memcpy(tmp, uval->blob.ptr, uval->blob.size); - - vals[i].blob.ptr = tmp; - vals[i].blob.size = uval->blob.size; - break; - } - case NVT_BOOL: - vals[i].b = uval->b; - break; - case NVT_INT: - vals[i].i = uval->i; - break; - case NVT_NULL: - break; - case NVT_NVL: - vals[i].nvl = nvl_getref(uval->nvl); - break; - case NVT_STR: - vals[i].str = str_getref(uval->str); - break; - } - } - - return vals; - -err: - /* only free the copied elements */ - nelem = i; - - nvval_release_array(vals, nelem); - free(vals); - - return NULL; -} - -static struct nvpair *nvpair_alloc(const char *name) -{ - struct nvpair *pair; - - pair = mem_cache_alloc(nvpair_cache); - if (!pair) - return NULL; - - pair->name = strdup(name); - if (!pair->name) { - mem_cache_free(nvpair_cache, pair); - return NULL; - } - - pair->value.type = NVT_INT; - pair->value.i = 0; - - return pair; -} - -static void nvpair_free(struct nvpair *pair) -{ - __nvval_release(&pair->value); - - free((char *) pair->name); - - mem_cache_free(nvpair_cache, pair); -} +#include "val_impl.h" int nvl_merge(struct nvlist *dest, struct nvlist *src) { const struct nvpair *spair; nvl_for_each(spair, src) { - const struct nvval *val = &spair->value; int ret; - switch (spair->value.type) { - case NVT_ARRAY: - ret = nvl_set_array_copy(dest, spair->name, - val->array.vals, - val->array.nelem); - break; - case NVT_BLOB: - ret = nvl_set_blob_copy(dest, spair->name, - val->blob.ptr, - val->blob.size); - break; - case NVT_BOOL: - ret = nvl_set_bool(dest, spair->name, val->b); - break; - case NVT_INT: - ret = nvl_set_int(dest, spair->name, val->i); - break; - case NVT_NULL: - ret = nvl_set_null(dest, spair->name); - break; - case NVT_NVL: - ret = nvl_set_nvl(dest, spair->name, - nvl_getref(val->nvl)); - break; - case NVT_STR: - ret = nvl_set_str(dest, spair->name, - str_getref(val->str)); - break; - } - + ret = nvl_set(dest, str_cstr(spair->name), spair->value); if (ret) return ret; } @@ -252,23 +43,27 @@ static struct nvpair *find(struct nvlist *nvl, const char *name) { - struct nvpair *cur; + struct str name_str = STR_STATIC_INITIALIZER(name); + struct nvpair key = { + .name = &name_str, + }; - list_for_each(cur, &nvl->values) - if (!strcmp(cur->name, name)) - return cur; - - return NULL; + return bst_find(&nvl->val._set_nvl.values, &key, NULL); } /* * nvlist iteration */ +const struct nvpair *nvl_iter_start(struct nvlist *nvl) +{ + return bst_first(&nvl->val._set_nvl.values); +} + const struct nvpair *nvl_iter_next(struct nvlist *nvl, const struct nvpair *prev) { - return list_next(&nvl->values, (struct nvpair *) prev); + return bst_next(&nvl->val._set_nvl.values, (void *) prev); } /* @@ -297,7 +92,7 @@ } int nvl_lookup_array(struct nvlist *nvl, const char *name, - const struct nvval **vals, size_t *nelem) + struct val ***vals, size_t *nelem) { return nvpair_value_array(find(nvl, name), vals, nelem); } @@ -323,165 +118,73 @@ * nvlist set */ -static struct nvpair *__nvl_set_prep(struct nvlist *nvl, const char *name) +int nvl_set(struct nvlist *nvl, const char *name, struct val *val) { struct nvpair *pair; pair = find(nvl, name); if (!pair) { /* not found - allocate a new pair */ - pair = nvpair_alloc(name); - if (!pair) - return NULL; + pair = __nvpair_alloc(name); + if (!pair) { + val_putref(val); + return -ENOMEM; + } - list_insert_tail(&nvl->values, pair); - } else { - /* found & should reuse it */ - __nvval_release(&pair->value); - - pair->value.type = NVT_INT; - pair->value.i = 0; + bst_add(&nvl->val._set_nvl.values, pair); } - return pair; -} - -int nvl_set(struct nvlist *nvl, const char *name, struct nvval *val) -{ - struct nvpair *pair; - - pair = __nvl_set_prep(nvl, name); - if (!pair) - return -ENOMEM; - - pair->value = *val; - - return 0; -} - -#define SET(fxn, ctype, nvtype, nvmember, putref) \ -int fxn(struct nvlist *nvl, const char *name, ctype val) \ -{ \ - struct nvpair *pair; \ - \ - pair = __nvl_set_prep(nvl, name); \ - if (!pair) { \ - putref(val); \ - return -ENOMEM; \ - } \ - \ - pair->value.type = nvtype; \ - pair->value.nvmember = val; \ - \ - return 0; \ -} - -int nvl_set_array(struct nvlist *nvl, const char *name, - struct nvval *vals, size_t nelem) -{ - struct nvpair *pair; - - pair = __nvl_set_prep(nvl, name); - if (!pair) - return -ENOMEM; - - pair->value.type = NVT_ARRAY; - pair->value.array.vals = vals; - pair->value.array.nelem = nelem; + val_putref(pair->value); + pair->value = val; return 0; } -int nvl_set_array_copy(struct nvlist *nvl, const char *name, - const struct nvval *vals, size_t nelem) -{ - struct nvval *tmp; - int ret; - - tmp = val_dup_array(vals, nelem); - if (!tmp) - return -ENOMEM; - - ret = nvl_set_array(nvl, name, tmp, nelem); - if (ret) { - nvval_release_array(tmp, nelem); - free(tmp); - } +#define SET(nvl, name, valalloc) \ + do { \ + struct val *val; \ + \ + val = valalloc; \ + if (IS_ERR(val)) \ + return PTR_ERR(val); \ + \ + return nvl_set(nvl, name, val); \ + } while (0) - return ret; -} - -int nvl_set_blob(struct nvlist *nvl, const char *name, void *ptr, size_t size) -{ - struct nvpair *pair; - - pair = __nvl_set_prep(nvl, name); - if (!pair) - return -ENOMEM; - - pair->value.type = NVT_BLOB; - pair->value.blob.ptr = ptr; - pair->value.blob.size = size; - - return 0; +#define SET_ARG0(fxn, valalloc) \ +int fxn(struct nvlist *nvl, const char *name) \ +{ \ + SET(nvl, name, valalloc()); \ } -int nvl_set_blob_copy(struct nvlist *nvl, const char *name, const void *ptr, - size_t size) -{ - void *tmp; - int ret; - - tmp = malloc(size); - if (!tmp) - return -ENOMEM; - - memcpy(tmp, ptr, size); - - ret = nvl_set_blob(nvl, name, tmp, size); - if (ret) - free(tmp); - - return ret; - +#define SET_ARG1(fxn, ctype, valalloc) \ +int fxn(struct nvlist *nvl, const char *name, ctype v) \ +{ \ + SET(nvl, name, valalloc(v)); \ } -SET(nvl_set_bool, bool, NVT_BOOL, b, (void)); - -int nvl_set_cstr_dup(struct nvlist *nvl, const char *name, const char *val) -{ - struct str *str; - - str = str_dup(val); - if (!str) - return -ENOMEM; - - return nvl_set_str(nvl, name, str); +#define SET_ARG2(fxn, ctype1, ctype2, valalloc) \ +int fxn(struct nvlist *nvl, const char *name, ctype1 a, ctype2 b) \ +{ \ + SET(nvl, name, valalloc(a, b)); \ } -SET(nvl_set_int, uint64_t, NVT_INT, i, (void)); - -int nvl_set_null(struct nvlist *nvl, const char *name) -{ - struct nvpair *pair; - - pair = __nvl_set_prep(nvl, name); - if (!pair) - return -ENOMEM; - - pair->value.type = NVT_NULL; - - return 0; -} - -SET(nvl_set_nvl, struct nvlist *, NVT_NVL, nvl, nvl_putref); -SET(nvl_set_str, struct str *, NVT_STR, str, str_putref); +SET_ARG2(nvl_set_array, struct val **, size_t, val_alloc_array); +SET_ARG2(nvl_set_array_copy, struct val **, size_t, val_alloc_array_dup); +SET_ARG2(nvl_set_blob, void *, size_t, val_alloc_blob); +SET_ARG2(nvl_set_blob_copy, const void *, size_t, val_alloc_blob_dup); +SET_ARG1(nvl_set_bool, bool, val_alloc_bool); +SET_ARG1(nvl_set_cstr_dup, const char *, val_dup_str); +SET_ARG1(nvl_set_int, uint64_t, val_alloc_int); +SET_ARG0(nvl_set_null, val_alloc_null); +SET_ARG1(nvl_set_nvl, struct nvlist *, nvl_cast_to_val); +SET_ARG1(nvl_set_str, struct str *, str_cast_to_val); /* * nvlist unset */ -static int unset(struct nvlist *nvl, const char *name, enum nvtype type, +static int unset(struct nvlist *nvl, const char *name, enum val_type type, bool matchtype) { struct nvpair *pair; @@ -490,22 +193,22 @@ if (!pair) return -ENOENT; - if (matchtype && (pair->value.type != type)) + if (matchtype && (pair->value->type != type)) return -ERANGE; - list_remove(&nvl->values, pair); + bst_remove(&nvl->val._set_nvl.values, pair); - nvpair_free(pair); + __nvpair_free(pair); return 0; } int nvl_unset(struct nvlist *nvl, const char *name) { - return unset(nvl, name, NVT_NULL, false); + return unset(nvl, name, VT_NULL, false); } -int nvl_unset_type(struct nvlist *nvl, const char *name, enum nvtype type) +int nvl_unset_type(struct nvlist *nvl, const char *name, enum val_type type) { return unset(nvl, name, type, true); } @@ -518,7 +221,7 @@ return find(nvl, name) != NULL; } -int nvl_exists_type(struct nvlist *nvl, const char *name, enum nvtype type) +int nvl_exists_type(struct nvlist *nvl, const char *name, enum val_type type) { struct nvpair *pair; @@ -526,7 +229,7 @@ if (!pair) return -ENOENT; - if (pair->value.type != type) + if (pair->value->type != type) return -ERANGE; return 0; @@ -536,43 +239,43 @@ * nvpair value */ -#define VALUE_INT(fxn, ctype, nvtype, nvmember) \ +#define VALUE_INT(fxn, ctype, nvtype, valmember) \ int fxn(const struct nvpair *pair, ctype *out) \ { \ if (!pair) \ return -ENOENT; \ \ - if (pair->value.type != nvtype) \ + if (pair->value->type != nvtype) \ return -ERANGE; \ \ - *out = pair->value.nvmember; \ + *out = pair->value->valmember; \ \ return 0; \ } -#define VALUE_PTR(fxn, ctype, nvtype, nvmember, getref) \ +#define VALUE_PTR(fxn, ctype, valtype, getref) \ ctype fxn(const struct nvpair *pair) \ { \ if (!pair) \ return ERR_PTR(-ENOENT); \ \ - if (pair->value.type != nvtype) \ + if (pair->value->type != valtype) \ return ERR_PTR(-ERANGE); \ \ - return getref(pair->value.nvmember); \ + return getref(pair->value); \ } -int nvpair_value_array(const struct nvpair *pair, const struct nvval **vals, +int nvpair_value_array(const struct nvpair *pair, struct val ***vals, size_t *nelem) { if (!pair) return -ENOENT; - if (pair->value.type != NVT_ARRAY) + if (pair->value->type != VT_ARRAY) return -ERANGE; - *vals = pair->value.array.vals; - *nelem = pair->value.array.nelem; + *vals = pair->value->_set_array.vals; + *nelem = pair->value->array.nelem; return 0; } @@ -582,28 +285,28 @@ if (!pair) return -ENOENT; - if (pair->value.type != NVT_BLOB) + if (pair->value->type != VT_BLOB) return -ERANGE; - *ptr = pair->value.blob.ptr; - *size = pair->value.blob.size; + *ptr = pair->value->blob.ptr; + *size = pair->value->blob.size; return 0; } -VALUE_INT(nvpair_value_bool, bool, NVT_BOOL, b); -VALUE_INT(nvpair_value_int, uint64_t, NVT_INT, i); +VALUE_INT(nvpair_value_bool, bool, VT_BOOL, b); +VALUE_INT(nvpair_value_int, uint64_t, VT_INT, i); int nvpair_value_null(const struct nvpair *pair) { if (!pair) return -ENOENT; - if (pair->value.type != NVT_NULL) + if (pair->value->type != VT_NULL) return -ERANGE; return 0; } -VALUE_PTR(nvpair_value_nvl, struct nvlist *, NVT_STR, nvl, nvl_getref); -VALUE_PTR(nvpair_value_str, struct str *, NVT_STR, str, str_getref); +VALUE_PTR(nvpair_value_nvl, struct nvlist *, VT_NVL, val_getref_nvl); +VALUE_PTR(nvpair_value_str, struct str *, VT_STR, val_getref_str);
--- a/nvl_convert.c Sat Mar 31 19:05:41 2018 -0400 +++ b/nvl_convert.c Sat Mar 31 17:34:16 2018 -0400 @@ -42,14 +42,14 @@ } static int cvt_string(struct nvlist *nvl, const struct nvpair *pair, - enum nvtype tgt, enum nvcvtcond cond) + enum val_type tgt, enum nvcvtcond cond) { const char *name = nvpair_name(pair); struct str *str; uint64_t intval; int ret = -ENOTSUP; - ASSERT3U(nvpair_type(pair), ==, NVT_STR); + ASSERT3U(nvpair_type(pair), ==, VT_STR); str = nvpair_value_str(pair); if (IS_ERR(str)) { @@ -66,23 +66,26 @@ } switch (tgt) { - case NVT_ARRAY: - case NVT_BLOB: - case NVT_BOOL: + case VT_ARRAY: + case VT_BLOB: + case VT_BOOL: + case VT_SYM: + case VT_CONS: + case VT_CHAR: ret = -ENOTSUP; break; - case NVT_INT: + case VT_INT: ret = str2u64(str_cstr(str), &intval); if (!ret) ret = nvl_set_int(nvl, name, intval); break; - case NVT_NULL: + case VT_NULL: ret = nvl_set_null(nvl, name); break; - case NVT_NVL: + case VT_NVL: ret = -ENOTSUP; break; - case NVT_STR: + case VT_STR: /* nothing to do */ ret = 0; break; @@ -121,14 +124,17 @@ } switch (nvpair_type(pair)) { - case NVT_ARRAY: - case NVT_BLOB: - case NVT_BOOL: - case NVT_INT: - case NVT_NULL: - case NVT_NVL: + case VT_ARRAY: + case VT_BLOB: + case VT_BOOL: + case VT_INT: + case VT_NULL: + case VT_NVL: + case VT_SYM: + case VT_CONS: + case VT_CHAR: return -ENOTSUP; - case NVT_STR: + case VT_STR: ret = cvt_string(nvl, pair, table->tgt_type, table->cond); break;
--- a/nvl_dump.c Sat Mar 31 19:05:41 2018 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2014-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <jeffpc/error.h> -#include <jeffpc/nvl.h> -#include <jeffpc/thread.h> - -#define INDENT 4 - -static void __dump_nvl(FILE *out, struct nvlist *nvl, int indent); - -static const char *typename(int type) -{ - static const char *typenames[] = { - [NVT_ARRAY] = "array", - [NVT_BLOB] = "blob", - [NVT_BOOL] = "bool", - [NVT_INT] = "int", - [NVT_NVL] = "nvlist", - [NVT_NULL] = "null", - [NVT_STR] = "string", - }; - - static __thread char badname[10]; - - if ((type < 0) || (type > NVT_STR)) - goto bad; - - if (typenames[type] == NULL) - goto bad; - - return typenames[type]; - -bad: - snprintf(badname, sizeof(badname), "<%d>", type); - return badname; -} - -static inline void doindent(FILE *out, int howmuch) -{ - fprintf(out, "%*s", INDENT * howmuch, ""); -} - -static void __dump_val(FILE *out, const struct nvval *val, int indent) -{ - size_t i; - - fprintf(out, " type=%s", typename(val->type)); - - switch (val->type) { - case NVT_ARRAY: - fprintf(out, " nelem=%zu\n", val->array.nelem); - for (i = 0; i < val->array.nelem; i++) { - doindent(out, indent); - fprintf(out, "[%zu]: ", i); - __dump_val(out, &val->array.vals[i], - indent + 1); - } - break; - case NVT_BLOB: - fprintf(out, " size=%zu\n", val->blob.size); - break; - case NVT_BOOL: - fprintf(out, "\n"); - doindent(out, indent); - fprintf(out, "value=%s\n", val->b ? "true" : "false"); - break; - case NVT_INT: - fprintf(out, "\n"); - doindent(out, indent); - fprintf(out, "value=%"PRIu64"\n", val->i); - break; - case NVT_NULL: - fprintf(out, "\n"); - break; - case NVT_NVL: - fprintf(out, "\n"); - __dump_nvl(out, val->nvl, indent); - break; - case NVT_STR: - fprintf(out, "\n"); - doindent(out, indent); - fprintf(out, "value='%s'\n", str_cstr(val->str)); - break; - } -} - -static void __dump_nvl(FILE *out, struct nvlist *nvl, int indent) -{ - const struct nvpair *pair; - - nvl_for_each(pair, nvl) { - doindent(out, indent); - fprintf(out, "name='%s'", pair->name); - __dump_val(out, &pair->value, indent + 1); - } -} - -void nvl_dump_file(FILE *out, struct nvlist *nvl) -{ - fprintf(out, "nvlist dump @ %p\n", nvl); - __dump_nvl(out, nvl, 1); -}
--- a/nvl_fmt_cbor.c Sat Mar 31 19:05:41 2018 -0400 +++ b/nvl_fmt_cbor.c Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -39,13 +39,13 @@ return cbor_pack_map_end(buffer, CBOR_UNKNOWN_NELEM); } -static int cbor_array_prologue(struct buffer *buffer, const struct nvval *vals, +static int cbor_array_prologue(struct buffer *buffer, struct val *const *vals, size_t nelem) { return cbor_pack_array_start(buffer, nelem); } -static int cbor_array_epilogue(struct buffer *buffer, const struct nvval *vals, +static int cbor_array_epilogue(struct buffer *buffer, struct val *const *vals, size_t nelem) { return cbor_pack_array_end(buffer, nelem);
--- a/nvl_fmt_json.c Sat Mar 31 19:05:41 2018 -0400 +++ b/nvl_fmt_json.c Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -44,18 +44,18 @@ return buffer_append_c(buffer, '}'); } -static int json_array_prologue(struct buffer *buffer, const struct nvval *vals, +static int json_array_prologue(struct buffer *buffer, struct val *const *vals, size_t nelem) { return buffer_append_c(buffer, '['); } -static int json_array_val_sep(struct buffer *buffer, const struct nvval *val) +static int json_array_val_sep(struct buffer *buffer, const struct val *val) { return buffer_append_c(buffer, ','); } -static int json_array_epilogue(struct buffer *buffer, const struct nvval *vals, +static int json_array_epilogue(struct buffer *buffer, struct val *const *vals, size_t nelem) { return buffer_append_c(buffer, ']');
--- a/nvl_impl.h Sat Mar 31 19:05:41 2018 -0400 +++ b/nvl_impl.h Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -80,10 +80,10 @@ * Required: At least one of prologue or epilogue. * Optional: The rest. */ - int (*array_prologue)(struct buffer *buffer, const struct nvval *vals, + int (*array_prologue)(struct buffer *buffer, struct val *const *vals, size_t nelem); - int (*array_val_sep)(struct buffer *buffer, const struct nvval *val); - int (*array_epilogue)(struct buffer *buffer, const struct nvval *vals, + int (*array_val_sep)(struct buffer *buffer, const struct val *val); + int (*array_epilogue)(struct buffer *buffer, struct val *const *vals, size_t nelem); /*
--- a/nvl_pack.c Sat Mar 31 19:05:41 2018 -0400 +++ b/nvl_pack.c Sat Mar 31 17:34:16 2018 -0400 @@ -28,10 +28,10 @@ static int pack_nvl(const struct nvpackops *ops, struct buffer *buffer, struct nvlist *nvl); static int pack_val(const struct nvpackops *ops, struct buffer *buffer, - const struct nvval *val); + struct val *val); static int pack_array(const struct nvpackops *ops, struct buffer *buffer, - const struct nvval *vals, size_t nelem) + struct val **vals, size_t nelem) { bool first = true; size_t i; @@ -44,7 +44,7 @@ return ret; for (i = 0; i < nelem; i++) { - const struct nvval *val = &vals[i]; + struct val *val = vals[i]; if (first) { first = false; @@ -85,51 +85,54 @@ return CALL_OR_FAIL(ops, val_null, (buffer)); } -static int pack_cstring(const struct nvpackops *ops, struct buffer *buffer, - const char *str) -{ - return CALL_OR_FAIL(ops, val_str, (buffer, str)); -} - static int pack_string(const struct nvpackops *ops, struct buffer *buffer, struct str *str) { + const char *s; + /* * Even though we try to avoid NULL pointers to indicate empty * strings, they can crop up from many places. So, it is safer to * do the check here. */ - return pack_cstring(ops, buffer, str ? str_cstr(str) : ""); + s = str ? str_cstr(str) : ""; + + return CALL_OR_FAIL(ops, val_str, (buffer, s)); } static int pack_val(const struct nvpackops *ops, struct buffer *buffer, - const struct nvval *val) + struct val *val) { int ret = -ENOTSUP; switch (val->type) { - case NVT_ARRAY: + case VT_ARRAY: ret = pack_array(ops, buffer, val->array.vals, val->array.nelem); break; - case NVT_BLOB: + case VT_BLOB: ret = pack_blob(ops, buffer, val->blob.ptr, val->blob.size); break; - case NVT_BOOL: + case VT_BOOL: ret = pack_bool(ops, buffer, val->b); break; - case NVT_INT: + case VT_INT: ret = pack_int(ops, buffer, val->i); break; - case NVT_NULL: + case VT_NULL: ret = pack_null(ops, buffer); break; - case NVT_NVL: - ret = pack_nvl(ops, buffer, val->nvl); + case VT_NVL: + ret = pack_nvl(ops, buffer, val_cast_to_nvl(val)); break; - case NVT_STR: - ret = pack_string(ops, buffer, val->str); + case VT_STR: + ret = pack_string(ops, buffer, val_cast_to_str(val)); + break; + case VT_SYM: + case VT_CONS: + case VT_CHAR: + /* not supported */ break; } @@ -144,13 +147,13 @@ if ((ret = CALL(ops, pair_prologue, (buffer, pair)))) return ret; - if ((ret = pack_cstring(ops, buffer, pair->name))) + if ((ret = pack_string(ops, buffer, pair->name))) return ret; if ((ret = CALL(ops, nvl_name_sep, (buffer, pair)))) return ret; - if ((ret = pack_val(ops, buffer, &pair->value))) + if ((ret = pack_val(ops, buffer, pair->value))) return ret; if ((ret = CALL(ops, pair_epilogue, (buffer, pair))))
--- a/scgisvc.c Sat Mar 31 19:05:41 2018 -0400 +++ b/scgisvc.c Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2014-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -150,10 +150,10 @@ */ static const struct nvl_convert_info scgi_convert_headers[] = { - { .name = "SCGI", .tgt_type = NVT_INT, }, - { .name = SCGI_CONTENT_LENGTH, .tgt_type = NVT_INT, }, - { .name = SCGI_REMOTE_PORT, .tgt_type = NVT_INT, }, - { .name = SCGI_SERVER_PORT, .tgt_type = NVT_INT, }, + { .name = "SCGI", .tgt_type = VT_INT, }, + { .name = SCGI_CONTENT_LENGTH, .tgt_type = VT_INT, }, + { .name = SCGI_REMOTE_PORT, .tgt_type = VT_INT, }, + { .name = SCGI_SERVER_PORT, .tgt_type = VT_INT, }, { .name = NULL, }, };
--- a/sexpr.c Sat Mar 31 19:05:41 2018 -0400 +++ b/sexpr.c Sat Mar 31 17:34:16 2018 -0400 @@ -343,6 +343,33 @@ goto out; } + case VT_NVL: { + struct bst_tree *ltree = &lhs->_set_nvl.values; + struct bst_tree *rtree = &rhs->_set_nvl.values; + struct nvpair *lcur; + struct nvpair *rcur; + + lcur = bst_first(ltree); + rcur = bst_first(rtree); + + while (lcur && rcur) { + ret = (str_cmp(lcur->name, rcur->name) == 0); + if (!ret) + goto out; + + ret = sexpr_equal(val_getref(lcur->value), + val_getref(rcur->value)); + if (!ret) + goto out; + + lcur = bst_next(ltree, lcur); + rcur = bst_next(rtree, rcur); + } + + /* if both sides reached the end, then they are equal */ + ret = !lcur && !rcur; + goto out; + } } panic("unknown struct val type %u", lhs->type);
--- a/sexpr_dump.c Sat Mar 31 19:05:41 2018 -0400 +++ b/sexpr_dump.c Sat Mar 31 17:34:16 2018 -0400 @@ -137,6 +137,7 @@ panic("%s: VT_CONS is not an atom", __func__); case VT_BLOB: case VT_ARRAY: + case VT_NVL: return ERR_PTR(-ENOTSUP); } @@ -258,6 +259,7 @@ case VT_INT: case VT_BLOB: case VT_ARRAY: + case VT_NVL: return dump_atom(lv); case VT_CONS: if (raw)
--- a/sexpr_eval.c Sat Mar 31 19:05:41 2018 -0400 +++ b/sexpr_eval.c Sat Mar 31 17:34:16 2018 -0400 @@ -198,6 +198,8 @@ panic("function name cannot be a VT_BLOB"); case VT_ARRAY: panic("function name cannot be a VT_ARRAY"); + case VT_NVL: + panic("function name cannot be a VT_NVL"); case VT_SYM: break; /* ok */ } @@ -252,6 +254,7 @@ case VT_CHAR: case VT_BLOB: case VT_ARRAY: + case VT_NVL: return expr; case VT_SYM: if (!env->symlookup)
--- a/tests/test_cbor_pack.c Sat Mar 31 19:05:41 2018 -0400 +++ b/tests/test_cbor_pack.c Sat Mar 31 17:34:16 2018 -0400 @@ -91,24 +91,36 @@ if (input->type != VT_CONS) return input; - len = sexpr_length(val_getref(input)); - if (len < 0) - fail("failed to get length of array"); + /* + * We are dealing with either a list or an assoc, we need to figure + * out which it is... + * FIXME + */ - arr = mem_reallocarray(NULL, len, sizeof(struct val *)); - if (!arr) - fail("failed to allocate val array"); + if (0) { + /* it is an assoc; turn it into a VT_NVL */ + fail("not yet implemented"); + } else { + /* it is a list; turn it into a VT_ARRAY */ + len = sexpr_length(val_getref(input)); + if (len < 0) + fail("failed to get length of array"); - ret = sexpr_list_to_array(input, arr, len); - if (ret < 0) - fail("failed to construct an array"); + arr = mem_reallocarray(NULL, len, sizeof(struct val *)); + if (!arr) + fail("failed to allocate val array"); + + ret = sexpr_list_to_array(input, arr, len); + if (ret < 0) + fail("failed to construct an array"); - for (i = 0; i < len; i++) - arr[i] = convert_input(arr[i]); + for (i = 0; i < len; i++) + arr[i] = convert_input(arr[i]); - val_putref(input); + val_putref(input); - return VAL_ALLOC_ARRAY(arr, len); + return VAL_ALLOC_ARRAY(arr, len); + } } static void onefile(struct val *input, struct buffer *expected) @@ -122,7 +134,7 @@ if (IS_ERR(got)) fail("failed to allocate output buffer"); - /* possibly an VT_ARRAY in sexpr list form */ + /* possibly an VT_ARRAY or VT_NVL in sexpr list form */ if (input->type == VT_CONS) input = convert_input(input); @@ -150,6 +162,10 @@ input->array.nelem), got, expected, input); break; + case VT_NVL: + TEST_ONE(cbor_pack_map_val(got, input), got, + expected, input); + break; case VT_SYM: case VT_CONS: case VT_CHAR:
--- a/tests/test_nvl.c Sat Mar 31 19:05:41 2018 -0400 +++ b/tests/test_nvl.c Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -96,7 +96,7 @@ static void check_key_not_exists(struct nvlist *nvl, const char *key) { const struct nvpair *pair; - const struct nvval *vals; + struct val **vals; struct nvlist *cnvl; size_t nelem, size; const void *ptr; @@ -134,10 +134,10 @@ } static void check_key_exists(struct nvlist *nvl, const char *key, - enum nvtype type) + enum val_type type) { const struct nvpair *pair; - const struct nvval *vals; + struct val **vals; struct nvlist *cnvl; size_t nelem, size; const void *ptr; @@ -150,36 +150,36 @@ __check_lookup_err(IS_ERR(pair), false, PTR_ERR(pair), 0, "nvl_lookup", key); - if (pair->value.type != type) + if (pair->value->type != type) fail("nvl_lookup(..., '%s') returned wrong type; got %u, " - "expected %u", key, pair->value.type, type); + "expected %u", key, pair->value->type, type); ret = nvl_lookup_array(nvl, key, &vals, &nelem); - __check_lookup_err(!!ret, type != NVT_ARRAY, ret, -ERANGE, + __check_lookup_err(!!ret, type != VT_ARRAY, ret, -ERANGE, "nvl_lookup_array", key); ret = nvl_lookup_blob(nvl, key, &ptr, &size); - __check_lookup_err(!!ret, type != NVT_BLOB, ret, -ERANGE, + __check_lookup_err(!!ret, type != VT_BLOB, ret, -ERANGE, "nvl_lookup_blob", key); ret = nvl_lookup_bool(nvl, key, &bool_val); - __check_lookup_err(!!ret, type != NVT_BOOL, ret, -ERANGE, + __check_lookup_err(!!ret, type != VT_BOOL, ret, -ERANGE, "nvl_lookup_bool", key); ret = nvl_lookup_int(nvl, key, &int_val); - __check_lookup_err(!!ret, type != NVT_INT, ret, -ERANGE, + __check_lookup_err(!!ret, type != VT_INT, ret, -ERANGE, "nvl_lookup_int", key); ret = nvl_lookup_null(nvl, key); - __check_lookup_err(!!ret, type != NVT_NULL, ret, -ERANGE, + __check_lookup_err(!!ret, type != VT_NULL, ret, -ERANGE, "nvl_lookup_null", key); cnvl = nvl_lookup_nvl(nvl, key); - __check_lookup_err(IS_ERR(cnvl), type != NVT_NVL, PTR_ERR(cnvl), + __check_lookup_err(IS_ERR(cnvl), type != VT_NVL, PTR_ERR(cnvl), -ERANGE, "nvl_lookup_nvl", key); str = nvl_lookup_str(nvl, key); - __check_lookup_err(IS_ERR(str), type != NVT_STR, PTR_ERR(str), + __check_lookup_err(IS_ERR(str), type != VT_STR, PTR_ERR(str), -ERANGE, "nvl_lookup_str", key); } @@ -259,20 +259,20 @@ set_int(nvl, "abc", 1); check_key_not_exists(nvl, "non-existent"); - check_key_exists(nvl, "abc", NVT_INT); + check_key_exists(nvl, "abc", VT_INT); set_bool(nvl, "def", true); check_key_not_exists(nvl, "non-existent"); - check_key_exists(nvl, "abc", NVT_INT); - check_key_exists(nvl, "def", NVT_BOOL); + check_key_exists(nvl, "abc", VT_INT); + check_key_exists(nvl, "def", VT_BOOL); set_null(nvl, "ghi"); check_key_not_exists(nvl, "non-existent"); - check_key_exists(nvl, "abc", NVT_INT); - check_key_exists(nvl, "def", NVT_BOOL); - check_key_exists(nvl, "ghi", NVT_NULL); + check_key_exists(nvl, "abc", VT_INT); + check_key_exists(nvl, "def", VT_BOOL); + check_key_exists(nvl, "ghi", VT_NULL); nvl_putref(nvl); @@ -295,9 +295,9 @@ if ((mask & bit) == 0) check_key_not_exists(nvl, name); else if (imask & bit) - check_key_exists(nvl, name, NVT_INT); + check_key_exists(nvl, name, VT_INT); else if (bmask & bit) - check_key_exists(nvl, name, NVT_BOOL); + check_key_exists(nvl, name, VT_BOOL); } }
--- a/tests/test_nvl_pack.c Sat Mar 31 19:05:41 2018 -0400 +++ b/tests/test_nvl_pack.c Sat Mar 31 17:34:16 2018 -0400 @@ -260,11 +260,13 @@ break; case VT_BLOB: case VT_ARRAY: + case VT_NVL: /* * We couldn't have possibly read * this from the input sexpr! */ - fail("sexprs don't support blobs/arrays"); + fail("sexprs don't support " + "blobs/arrays/nvlists"); break; case VT_BOOL: set_bool(nvl, var, op[2]->b, 0);
--- a/tests/test_qstring.c Sat Mar 31 19:05:41 2018 -0400 +++ b/tests/test_qstring.c Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2014-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,12 +37,14 @@ return -ENOMEM; ret = qstring_parse_len(vars, ibuf, len); +#if 0 if (!ret) nvl_dump_file(stderr, vars); +#endif nvl_putref(vars); - return 0; + return ret; } static void test(const char *fname)
--- a/val.c Sat Mar 31 19:05:41 2018 -0400 +++ b/val.c Sat Mar 31 17:34:16 2018 -0400 @@ -28,6 +28,7 @@ #include <ctype.h> #include <inttypes.h> +#include <jeffpc/val.h> #include <jeffpc/jeffpc.h> #include <jeffpc/error.h> #include <jeffpc/types.h> @@ -117,6 +118,9 @@ free(val->_set_array.vals); break; } + case VT_NVL: + __val_free_nvl(val); + break; } mem_cache_free(val_cache, val); @@ -309,6 +313,10 @@ indent + 2); break; } + case VT_NVL: + /* TODO: dump the contents of the pairs */ + fprintf(out, "%*snvlist\n", indent, ""); + break; default: fprintf(out, "Unknown type %d\n", val->type); break;
--- a/val_impl.h Sat Mar 31 19:05:41 2018 -0400 +++ b/val_impl.h Sat Mar 31 17:34:16 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,13 @@ #define __VAL_IMPL_H #include <jeffpc/val.h> +#include <jeffpc/nvl.h> extern struct val *__val_alloc(enum val_type type); +extern void __val_free_nvl(struct val *val); + +extern struct nvpair *__nvpair_alloc(const char *name); +extern void __nvpair_free(struct nvpair *pair); static inline bool val_is_null_cons(struct val *v) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/val_nvl.c Sat Mar 31 17:34:16 2018 -0400 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <jeffpc/mem.h> + +#include "val_impl.h" + +static struct mem_cache *nvpair_cache; + +static void __attribute__((constructor)) init_val_subsys(void) +{ + nvpair_cache = mem_cache_create("nvpair-cache", sizeof(struct nvpair), + 0); + ASSERT(!IS_ERR(nvpair_cache)); +} + +struct nvpair *__nvpair_alloc(const char *name) +{ + struct nvpair *pair; + + pair = mem_cache_alloc(nvpair_cache); + if (!pair) + return NULL; + + pair->name = str_dup(name); + if (IS_ERR(pair->name)) { + mem_cache_free(nvpair_cache, pair); + return NULL; + } + + /* + * Avoid returning with a NULL pointer. Of all the types, VT_NULL + * is the least out of place. + * + * (We use VAL_ALLOC_NULL here to make it painfully clear that + * ->value is valid later on, even though we could have used + * val_alloc_null directly as it never fails.) + */ + pair->value = VAL_ALLOC_NULL(); + + return pair; +} + +void __nvpair_free(struct nvpair *pair) +{ + str_putref(pair->name); + val_putref(pair->value); + + mem_cache_free(nvpair_cache, pair); +} + +static int val_nvl_cmp(const void *va, const void *vb) +{ + const struct nvpair *a = va; + const struct nvpair *b = vb; + + return str_cmp(a->name, b->name); +} + +struct val *val_alloc_nvl(void) +{ + struct val *val; + + val = __val_alloc(VT_NVL); + if (IS_ERR(val)) + return val; + + bst_create(&val->_set_nvl.values, val_nvl_cmp, sizeof(struct nvpair), + offsetof(struct nvpair, node)); + + return val; +} + +void __val_free_nvl(struct val *val) +{ + struct bst_cookie cookie; + struct nvpair *cur; + + ASSERT(val); + ASSERT3U(refcnt_read(&val->refcnt), ==, 0); + ASSERT3U(val->type, ==, VT_NVL); + + memset(&cookie, 0, sizeof(struct bst_cookie)); + while ((cur = bst_destroy_nodes(&val->_set_nvl.values, &cookie))) + __nvpair_free(cur); + + bst_destroy(&val->_set_nvl.values); +}