2 * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
33 #include <ecoli_malloc.h>
34 #include <ecoli_log.h>
35 #include <ecoli_test.h>
36 #include <ecoli_keyval.h>
38 EC_LOG_TYPE_REGISTER(keyval);
40 struct ec_keyval_elt {
43 ec_keyval_elt_free_t free;
48 struct ec_keyval_elt *vec;
51 struct ec_keyval *ec_keyval(void)
53 struct ec_keyval *keyval;
55 keyval = ec_calloc(1, sizeof(*keyval));
62 static struct ec_keyval_elt *ec_keyval_lookup(const struct ec_keyval *keyval,
65 struct ec_keyval_elt *elt;
68 if (keyval == NULL || keyval->vec == NULL)
71 for (i = 0; i < ec_keyval_len(keyval); i++) {
72 elt = &keyval->vec[i];
73 if (strcmp(elt->key, key) == 0)
80 static void ec_keyval_elt_free(struct ec_keyval_elt *elt)
86 if (elt->free != NULL)
90 void *ec_keyval_get(const struct ec_keyval *keyval, const char *key)
92 struct ec_keyval_elt *elt;
94 elt = ec_keyval_lookup(keyval, key);
101 int ec_keyval_del(struct ec_keyval *keyval, const char *key)
103 struct ec_keyval_elt *elt;
104 struct ec_keyval_elt *last = &keyval->vec[keyval->len - 1];
106 elt = ec_keyval_lookup(keyval, key);
110 ec_keyval_elt_free(elt);
113 memcpy(elt, last, sizeof(*elt));
120 int ec_keyval_set(struct ec_keyval *keyval, const char *key, void *val,
121 ec_keyval_elt_free_t free_cb)
123 struct ec_keyval_elt *elt, *new_vec;
125 assert(keyval != NULL);
128 ec_keyval_del(keyval, key);
130 new_vec = ec_realloc(keyval->vec,
131 sizeof(*keyval->vec) * (keyval->len + 1));
135 keyval->vec = new_vec;
137 elt = &new_vec[keyval->len];
138 elt->key = ec_strdup(key);
139 if (elt->key == NULL)
154 void ec_keyval_free(struct ec_keyval *keyval)
156 struct ec_keyval_elt *elt;
162 for (i = 0; i < ec_keyval_len(keyval); i++) {
163 elt = &keyval->vec[i];
164 ec_keyval_elt_free(elt);
166 ec_free(keyval->vec);
170 size_t ec_keyval_len(const struct ec_keyval *keyval)
175 void ec_keyval_dump(const struct ec_keyval *keyval, FILE *out)
179 if (keyval == NULL) {
180 fprintf(out, "empty keyval\n");
184 fprintf(out, "keyval:\n");
185 for (i = 0; i < ec_keyval_len(keyval); i++) {
186 fprintf(out, " %s: %p\n",
192 /* LCOV_EXCL_START */
193 static int ec_keyval_testcase(void)
195 struct ec_keyval *keyval;
198 keyval = ec_keyval();
199 if (keyval == NULL) {
200 EC_LOG(EC_LOG_ERR, "cannot create keyval\n");
204 EC_TEST_ASSERT(ec_keyval_len(keyval) == 0);
205 ec_keyval_set(keyval, "key1", "val1", NULL);
206 ec_keyval_set(keyval, "key2", ec_strdup("val2"), ec_free2);
207 EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
209 val = ec_keyval_get(keyval, "key1");
210 EC_TEST_ASSERT(val != NULL && !strcmp(val, "val1"));
211 val = ec_keyval_get(keyval, "key2");
212 EC_TEST_ASSERT(val != NULL && !strcmp(val, "val2"));
213 val = ec_keyval_get(keyval, "key3");
214 EC_TEST_ASSERT(val == NULL);
216 ec_keyval_set(keyval, "key1", "another_val1", NULL);
217 ec_keyval_set(keyval, "key2", ec_strdup("another_val2"), ec_free2);
218 EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
220 val = ec_keyval_get(keyval, "key1");
221 EC_TEST_ASSERT(val != NULL && !strcmp(val, "another_val1"));
222 val = ec_keyval_get(keyval, "key2");
223 EC_TEST_ASSERT(val != NULL && !strcmp(val, "another_val2"));
225 ec_keyval_del(keyval, "key1");
226 EC_TEST_ASSERT(ec_keyval_len(keyval) == 1);
228 ec_keyval_free(keyval);
234 static struct ec_test ec_keyval_test = {
236 .test = ec_keyval_testcase,
239 EC_TEST_REGISTER(ec_keyval_test);