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