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