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 bool ec_keyval_has_key(const struct ec_keyval *keyval, const char *key)
92 return !!ec_keyval_lookup(keyval, key);
95 void *ec_keyval_get(const struct ec_keyval *keyval, const char *key)
97 struct ec_keyval_elt *elt;
99 elt = ec_keyval_lookup(keyval, key);
106 int ec_keyval_del(struct ec_keyval *keyval, const char *key)
108 struct ec_keyval_elt *elt;
109 struct ec_keyval_elt *last = &keyval->vec[keyval->len - 1];
111 elt = ec_keyval_lookup(keyval, key);
115 ec_keyval_elt_free(elt);
118 memcpy(elt, last, sizeof(*elt));
125 int ec_keyval_set(struct ec_keyval *keyval, const char *key, void *val,
126 ec_keyval_elt_free_t free_cb)
128 struct ec_keyval_elt *elt, *new_vec;
130 assert(keyval != NULL);
133 ec_keyval_del(keyval, key);
135 new_vec = ec_realloc(keyval->vec,
136 sizeof(*keyval->vec) * (keyval->len + 1));
140 keyval->vec = new_vec;
142 elt = &new_vec[keyval->len];
143 elt->key = ec_strdup(key);
144 if (elt->key == NULL)
159 void ec_keyval_free(struct ec_keyval *keyval)
161 struct ec_keyval_elt *elt;
167 for (i = 0; i < ec_keyval_len(keyval); i++) {
168 elt = &keyval->vec[i];
169 ec_keyval_elt_free(elt);
171 ec_free(keyval->vec);
175 size_t ec_keyval_len(const struct ec_keyval *keyval)
180 void ec_keyval_dump(const struct ec_keyval *keyval, FILE *out)
184 if (keyval == NULL) {
185 fprintf(out, "empty keyval\n");
189 fprintf(out, "keyval:\n");
190 for (i = 0; i < ec_keyval_len(keyval); i++) {
191 fprintf(out, " %s: %p\n",
197 /* LCOV_EXCL_START */
198 static int ec_keyval_testcase(void)
200 struct ec_keyval *keyval;
203 keyval = ec_keyval();
204 if (keyval == NULL) {
205 EC_LOG(EC_LOG_ERR, "cannot create keyval\n");
209 EC_TEST_ASSERT(ec_keyval_len(keyval) == 0);
210 ec_keyval_set(keyval, "key1", "val1", NULL);
211 ec_keyval_set(keyval, "key2", ec_strdup("val2"), ec_free2);
212 EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
214 val = ec_keyval_get(keyval, "key1");
215 EC_TEST_ASSERT(val != NULL && !strcmp(val, "val1"));
216 val = ec_keyval_get(keyval, "key2");
217 EC_TEST_ASSERT(val != NULL && !strcmp(val, "val2"));
218 val = ec_keyval_get(keyval, "key3");
219 EC_TEST_ASSERT(val == NULL);
221 ec_keyval_set(keyval, "key1", "another_val1", NULL);
222 ec_keyval_set(keyval, "key2", ec_strdup("another_val2"), ec_free2);
223 EC_TEST_ASSERT(ec_keyval_len(keyval) == 2);
225 val = ec_keyval_get(keyval, "key1");
226 EC_TEST_ASSERT(val != NULL && !strcmp(val, "another_val1"));
227 val = ec_keyval_get(keyval, "key2");
228 EC_TEST_ASSERT(val != NULL && !strcmp(val, "another_val2"));
230 ec_keyval_del(keyval, "key1");
231 EC_TEST_ASSERT(ec_keyval_len(keyval) == 1);
233 ec_keyval_free(keyval);
239 static struct ec_test ec_keyval_test = {
241 .test = ec_keyval_testcase,
244 EC_TEST_REGISTER(ec_keyval_test);