1 /* $NetBSD: map.c,v 1.3 2014/12/10 04:38:03 christos Exp $ */
2
3 /*
4 * Automated Testing Framework (atf)
5 *
6 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
19 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "atf-c/error.h"
37 #include "atf-c/utils.h"
38
39 #include "map.h"
40 #include "sanity.h"
41
42 /* ---------------------------------------------------------------------
43 * Auxiliary functions.
44 * --------------------------------------------------------------------- */
45
46 struct map_entry {
47 char *m_key;
48 void *m_value;
49 bool m_managed;
50 };
51
52 static
53 struct map_entry *
new_entry(const char * key,void * value,bool managed)54 new_entry(const char *key, void *value, bool managed)
55 {
56 struct map_entry *me;
57
58 me = (struct map_entry *)malloc(sizeof(*me));
59 if (me != NULL) {
60 me->m_key = strdup(key);
61 if (me->m_key == NULL) {
62 free(me);
63 me = NULL;
64 } else {
65 me->m_value = value;
66 me->m_managed = managed;
67 }
68 }
69
70 return me;
71 }
72
73 /* ---------------------------------------------------------------------
74 * The "atf_map_citer" type.
75 * --------------------------------------------------------------------- */
76
77 /*
78 * Getters.
79 */
80
81 const char *
atf_map_citer_key(const atf_map_citer_t citer)82 atf_map_citer_key(const atf_map_citer_t citer)
83 {
84 const struct map_entry *me = citer.m_entry;
85 PRE(me != NULL);
86 return me->m_key;
87 }
88
89 const void *
atf_map_citer_data(const atf_map_citer_t citer)90 atf_map_citer_data(const atf_map_citer_t citer)
91 {
92 const struct map_entry *me = citer.m_entry;
93 PRE(me != NULL);
94 return me->m_value;
95 }
96
97 atf_map_citer_t
atf_map_citer_next(const atf_map_citer_t citer)98 atf_map_citer_next(const atf_map_citer_t citer)
99 {
100 atf_map_citer_t newciter;
101
102 newciter = citer;
103 newciter.m_listiter = atf_list_citer_next(citer.m_listiter);
104 newciter.m_entry = ((const struct map_entry *)
105 atf_list_citer_data(newciter.m_listiter));
106
107 return newciter;
108 }
109
110 bool
atf_equal_map_citer_map_citer(const atf_map_citer_t i1,const atf_map_citer_t i2)111 atf_equal_map_citer_map_citer(const atf_map_citer_t i1,
112 const atf_map_citer_t i2)
113 {
114 return i1.m_map == i2.m_map && i1.m_entry == i2.m_entry;
115 }
116
117 /* ---------------------------------------------------------------------
118 * The "atf_map_iter" type.
119 * --------------------------------------------------------------------- */
120
121 /*
122 * Getters.
123 */
124
125 const char *
atf_map_iter_key(const atf_map_iter_t iter)126 atf_map_iter_key(const atf_map_iter_t iter)
127 {
128 const struct map_entry *me = iter.m_entry;
129 PRE(me != NULL);
130 return me->m_key;
131 }
132
133 void *
atf_map_iter_data(const atf_map_iter_t iter)134 atf_map_iter_data(const atf_map_iter_t iter)
135 {
136 const struct map_entry *me = iter.m_entry;
137 PRE(me != NULL);
138 return me->m_value;
139 }
140
141 atf_map_iter_t
atf_map_iter_next(const atf_map_iter_t iter)142 atf_map_iter_next(const atf_map_iter_t iter)
143 {
144 atf_map_iter_t newiter;
145
146 newiter = iter;
147 newiter.m_listiter = atf_list_iter_next(iter.m_listiter);
148 newiter.m_entry = ((struct map_entry *)
149 atf_list_iter_data(newiter.m_listiter));
150
151 return newiter;
152 }
153
154 bool
atf_equal_map_iter_map_iter(const atf_map_iter_t i1,const atf_map_iter_t i2)155 atf_equal_map_iter_map_iter(const atf_map_iter_t i1,
156 const atf_map_iter_t i2)
157 {
158 return i1.m_map == i2.m_map && i1.m_entry == i2.m_entry;
159 }
160
161 /* ---------------------------------------------------------------------
162 * The "atf_map" type.
163 * --------------------------------------------------------------------- */
164
165 /*
166 * Constructors and destructors.
167 */
168
169 atf_error_t
atf_map_init(atf_map_t * m)170 atf_map_init(atf_map_t *m)
171 {
172 return atf_list_init(&m->m_list);
173 }
174
175 atf_error_t
atf_map_init_charpp(atf_map_t * m,const char * const * array)176 atf_map_init_charpp(atf_map_t *m, const char *const *array)
177 {
178 atf_error_t err;
179 const char *const *ptr = array;
180
181 err = atf_map_init(m);
182 if (array != NULL) {
183 while (!atf_is_error(err) && *ptr != NULL) {
184 const char *key, *value;
185
186 key = *ptr;
187 INV(key != NULL);
188 ptr++;
189
190 if ((value = *ptr) == NULL) {
191 err = atf_libc_error(EINVAL, "List too short; no value for "
192 "key '%s' provided", key); /* XXX: Not really libc_error */
193 break;
194 }
195 ptr++;
196
197 err = atf_map_insert(m, key, strdup(value), true);
198 }
199 }
200
201 if (atf_is_error(err))
202 atf_map_fini(m);
203
204 return err;
205 }
206
207 void
atf_map_fini(atf_map_t * m)208 atf_map_fini(atf_map_t *m)
209 {
210 atf_list_iter_t iter;
211
212 atf_list_for_each(iter, &m->m_list) {
213 struct map_entry *me = atf_list_iter_data(iter);
214
215 if (me->m_managed)
216 free(me->m_value);
217 free(me->m_key);
218 free(me);
219 }
220 atf_list_fini(&m->m_list);
221 }
222
223 /*
224 * Getters.
225 */
226
227 atf_map_iter_t
atf_map_begin(atf_map_t * m)228 atf_map_begin(atf_map_t *m)
229 {
230 atf_map_iter_t iter;
231 iter.m_map = m;
232 iter.m_listiter = atf_list_begin(&m->m_list);
233 iter.m_entry = atf_list_iter_data(iter.m_listiter);
234 return iter;
235 }
236
237 atf_map_citer_t
atf_map_begin_c(const atf_map_t * m)238 atf_map_begin_c(const atf_map_t *m)
239 {
240 atf_map_citer_t citer;
241 citer.m_map = m;
242 citer.m_listiter = atf_list_begin_c(&m->m_list);
243 citer.m_entry = atf_list_citer_data(citer.m_listiter);
244 return citer;
245 }
246
247 atf_map_iter_t
atf_map_end(atf_map_t * m)248 atf_map_end(atf_map_t *m)
249 {
250 atf_map_iter_t iter;
251 iter.m_map = m;
252 iter.m_entry = NULL;
253 iter.m_listiter = atf_list_end(&m->m_list);
254 return iter;
255 }
256
257 atf_map_citer_t
atf_map_end_c(const atf_map_t * m)258 atf_map_end_c(const atf_map_t *m)
259 {
260 atf_map_citer_t iter;
261 iter.m_map = m;
262 iter.m_entry = NULL;
263 iter.m_listiter = atf_list_end_c(&m->m_list);
264 return iter;
265 }
266
267 atf_map_iter_t
atf_map_find(atf_map_t * m,const char * key)268 atf_map_find(atf_map_t *m, const char *key)
269 {
270 atf_list_iter_t iter;
271
272 atf_list_for_each(iter, &m->m_list) {
273 struct map_entry *me = atf_list_iter_data(iter);
274
275 if (strcmp(me->m_key, key) == 0) {
276 atf_map_iter_t i;
277 i.m_map = m;
278 i.m_entry = me;
279 i.m_listiter = iter;
280 return i;
281 }
282 }
283
284 return atf_map_end(m);
285 }
286
287 atf_map_citer_t
atf_map_find_c(const atf_map_t * m,const char * key)288 atf_map_find_c(const atf_map_t *m, const char *key)
289 {
290 atf_list_citer_t iter;
291
292 atf_list_for_each_c(iter, &m->m_list) {
293 const struct map_entry *me = atf_list_citer_data(iter);
294
295 if (strcmp(me->m_key, key) == 0) {
296 atf_map_citer_t i;
297 i.m_map = m;
298 i.m_entry = me;
299 i.m_listiter = iter;
300 return i;
301 }
302 }
303
304 return atf_map_end_c(m);
305 }
306
307 size_t
atf_map_size(const atf_map_t * m)308 atf_map_size(const atf_map_t *m)
309 {
310 return atf_list_size(&m->m_list);
311 }
312
313 char **
atf_map_to_charpp(const atf_map_t * l)314 atf_map_to_charpp(const atf_map_t *l)
315 {
316 char **array;
317 atf_map_citer_t iter;
318 size_t i;
319
320 array = malloc(sizeof(char *) * (atf_map_size(l) * 2 + 1));
321 if (array == NULL)
322 goto out;
323
324 i = 0;
325 atf_map_for_each_c(iter, l) {
326 array[i] = strdup(atf_map_citer_key(iter));
327 if (array[i] == NULL) {
328 atf_utils_free_charpp(array);
329 array = NULL;
330 goto out;
331 }
332
333 array[i + 1] = strdup((const char *)atf_map_citer_data(iter));
334 if (array[i + 1] == NULL) {
335 atf_utils_free_charpp(array);
336 array = NULL;
337 goto out;
338 }
339
340 i += 2;
341 }
342 array[i] = NULL;
343
344 out:
345 return array;
346 }
347
348 /*
349 * Modifiers.
350 */
351
352 atf_error_t
atf_map_insert(atf_map_t * m,const char * key,void * value,bool managed)353 atf_map_insert(atf_map_t *m, const char *key, void *value, bool managed)
354 {
355 struct map_entry *me;
356 atf_error_t err;
357 atf_map_iter_t iter;
358
359 iter = atf_map_find(m, key);
360 if (atf_equal_map_iter_map_iter(iter, atf_map_end(m))) {
361 me = new_entry(key, value, managed);
362 if (me == NULL)
363 err = atf_no_memory_error();
364 else {
365 err = atf_list_append(&m->m_list, me, false);
366 if (atf_is_error(err)) {
367 if (managed)
368 free(value);
369 free(me);
370 }
371 }
372 } else {
373 me = iter.m_entry;
374 if (me->m_managed)
375 free(me->m_value);
376
377 INV(strcmp(me->m_key, key) == 0);
378 me->m_value = value;
379 me->m_managed = managed;
380
381 err = atf_no_error();
382 }
383
384 return err;
385 }
386