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 struct ec_keyval_elt {
41 ec_keyval_elt_free_t free;
46 struct ec_keyval_elt *vec;
49 struct ec_keyval *ec_keyval_new(void)
51 struct ec_keyval *keyval;
53 keyval = ec_calloc(1, sizeof(*keyval));
60 static struct ec_keyval_elt *ec_keyval_lookup(const struct ec_keyval *keyval,
63 struct ec_keyval_elt *elt;
66 if (keyval == NULL || keyval->vec == NULL)
69 for (i = 0; i < ec_keyval_len(keyval); i++) {
70 elt = &keyval->vec[i];
71 if (strcmp(elt->key, key) == 0)
78 static void ec_keyval_elt_free(struct ec_keyval_elt *elt)
84 if (elt->free != NULL)
88 void *ec_keyval_get(const struct ec_keyval *keyval, const char *key)
90 struct ec_keyval_elt *elt;
92 elt = ec_keyval_lookup(keyval, key);
99 int ec_keyval_del(struct ec_keyval *keyval, const char *key)
101 struct ec_keyval_elt *elt;
102 struct ec_keyval_elt *last = &keyval->vec[keyval->len - 1];
104 elt = ec_keyval_lookup(keyval, key);
108 ec_keyval_elt_free(elt);
111 memcpy(elt, last, sizeof(*elt));
118 int ec_keyval_set(struct ec_keyval *keyval, const char *key, void *val,
119 ec_keyval_elt_free_t free_cb)
121 struct ec_keyval_elt *elt, *new_vec;
123 assert(keyval != NULL);
126 ec_keyval_del(keyval, key);
128 new_vec = ec_realloc(keyval->vec,
129 sizeof(*keyval->vec) * (keyval->len + 1));
133 keyval->vec = new_vec;
135 elt = &new_vec[keyval->len];
136 elt->key = ec_strdup(key);
137 if (elt->key == NULL)
152 void ec_keyval_free(struct ec_keyval *keyval)
154 struct ec_keyval_elt *elt;
160 for (i = 0; i < ec_keyval_len(keyval); i++) {
161 elt = &keyval->vec[i];
162 ec_keyval_elt_free(elt);
164 ec_free(keyval->vec);
168 size_t ec_keyval_len(const struct ec_keyval *keyval)
173 void ec_keyval_dump(const struct ec_keyval *keyval, FILE *out)
177 if (keyval == NULL) {
178 fprintf(out, "empty keyval\n");
182 fprintf(out, "keyval:\n");
183 for (i = 0; i < ec_keyval_len(keyval); i++) {
184 fprintf(out, " %s: %p\n",
190 static int ec_keyval_testcase(void)
192 struct ec_keyval *keyval;
195 keyval = ec_keyval_new();
196 if (keyval == NULL) {
197 ec_log(EC_LOG_ERR, "cannot create keyval\n");
201 EC_TEST_ASSERT(ec_keyval_len(keyval) == 0);
202 ec_keyval_set(keyval, "key1", "val1", NULL);
203 ec_keyval_set(keyval, "key2", ec_strdup("val2"), ec_free2);
204 EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
206 val = ec_keyval_get(keyval, "key1");
207 EC_TEST_ASSERT(val != NULL && !strcmp(val, "val1"));
208 val = ec_keyval_get(keyval, "key2");
209 EC_TEST_ASSERT(val != NULL && !strcmp(val, "val2"));
210 val = ec_keyval_get(keyval, "key3");
211 EC_TEST_ASSERT(val == NULL);
213 ec_keyval_set(keyval, "key1", "another_val1", NULL);
214 ec_keyval_set(keyval, "key2", ec_strdup("another_val2"), ec_free2);
215 EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
217 val = ec_keyval_get(keyval, "key1");
218 EC_TEST_ASSERT(val != NULL && !strcmp(val, "another_val1"));
219 val = ec_keyval_get(keyval, "key2");
220 EC_TEST_ASSERT(val != NULL && !strcmp(val, "another_val2"));
222 ec_keyval_del(keyval, "key1");
223 EC_TEST_ASSERT(ec_keyval_len(keyval) == 1);
225 ec_keyval_free(keyval);
230 static struct ec_test ec_keyval_test = {
232 .test = ec_keyval_testcase,
235 EC_TEST_REGISTER(ec_keyval_test);