xref: /freebsd/contrib/atf/atf-c/detail/map.c (revision 43d55325406e96e37be661de52289c2592c82ec9)
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             err = atf_map_insert(m, key, strdup(value), true);
192         }
193     }
194 
195     if (atf_is_error(err))
196         atf_map_fini(m);
197 
198     return err;
199 }
200 
201 void
202 atf_map_fini(atf_map_t *m)
203 {
204     atf_list_iter_t iter;
205 
206     atf_list_for_each(iter, &m->m_list) {
207         struct map_entry *me = atf_list_iter_data(iter);
208 
209         if (me->m_managed)
210             free(me->m_value);
211         free(me->m_key);
212         free(me);
213     }
214     atf_list_fini(&m->m_list);
215 }
216 
217 /*
218  * Getters.
219  */
220 
221 atf_map_iter_t
222 atf_map_begin(atf_map_t *m)
223 {
224     atf_map_iter_t iter;
225     iter.m_map = m;
226     iter.m_listiter = atf_list_begin(&m->m_list);
227     iter.m_entry = atf_list_iter_data(iter.m_listiter);
228     return iter;
229 }
230 
231 atf_map_citer_t
232 atf_map_begin_c(const atf_map_t *m)
233 {
234     atf_map_citer_t citer;
235     citer.m_map = m;
236     citer.m_listiter = atf_list_begin_c(&m->m_list);
237     citer.m_entry = atf_list_citer_data(citer.m_listiter);
238     return citer;
239 }
240 
241 atf_map_iter_t
242 atf_map_end(atf_map_t *m)
243 {
244     atf_map_iter_t iter;
245     iter.m_map = m;
246     iter.m_entry = NULL;
247     iter.m_listiter = atf_list_end(&m->m_list);
248     return iter;
249 }
250 
251 atf_map_citer_t
252 atf_map_end_c(const atf_map_t *m)
253 {
254     atf_map_citer_t iter;
255     iter.m_map = m;
256     iter.m_entry = NULL;
257     iter.m_listiter = atf_list_end_c(&m->m_list);
258     return iter;
259 }
260 
261 atf_map_iter_t
262 atf_map_find(atf_map_t *m, const char *key)
263 {
264     atf_list_iter_t iter;
265 
266     atf_list_for_each(iter, &m->m_list) {
267         struct map_entry *me = atf_list_iter_data(iter);
268 
269         if (strcmp(me->m_key, key) == 0) {
270             atf_map_iter_t i;
271             i.m_map = m;
272             i.m_entry = me;
273             i.m_listiter = iter;
274             return i;
275         }
276     }
277 
278     return atf_map_end(m);
279 }
280 
281 atf_map_citer_t
282 atf_map_find_c(const atf_map_t *m, const char *key)
283 {
284     atf_list_citer_t iter;
285 
286     atf_list_for_each_c(iter, &m->m_list) {
287         const struct map_entry *me = atf_list_citer_data(iter);
288 
289         if (strcmp(me->m_key, key) == 0) {
290             atf_map_citer_t i;
291             i.m_map = m;
292             i.m_entry = me;
293             i.m_listiter = iter;
294             return i;
295         }
296     }
297 
298     return atf_map_end_c(m);
299 }
300 
301 size_t
302 atf_map_size(const atf_map_t *m)
303 {
304     return atf_list_size(&m->m_list);
305 }
306 
307 char **
308 atf_map_to_charpp(const atf_map_t *l)
309 {
310     char **array;
311     atf_map_citer_t iter;
312     size_t i;
313 
314     array = malloc(sizeof(char *) * (atf_map_size(l) * 2 + 1));
315     if (array == NULL)
316         goto out;
317 
318     i = 0;
319     atf_map_for_each_c(iter, l) {
320         array[i] = strdup(atf_map_citer_key(iter));
321         if (array[i] == NULL) {
322             atf_utils_free_charpp(array);
323             array = NULL;
324             goto out;
325         }
326 
327         array[i + 1] = strdup((const char *)atf_map_citer_data(iter));
328         if (array[i + 1] == NULL) {
329             atf_utils_free_charpp(array);
330             array = NULL;
331             goto out;
332         }
333 
334         i += 2;
335     }
336     array[i] = NULL;
337 
338 out:
339     return array;
340 }
341 
342 /*
343  * Modifiers.
344  */
345 
346 atf_error_t
347 atf_map_insert(atf_map_t *m, const char *key, void *value, bool managed)
348 {
349     struct map_entry *me;
350     atf_error_t err;
351     atf_map_iter_t iter;
352 
353     iter = atf_map_find(m, key);
354     if (atf_equal_map_iter_map_iter(iter, atf_map_end(m))) {
355         me = new_entry(key, value, managed);
356         if (me == NULL)
357             err = atf_no_memory_error();
358         else {
359             err = atf_list_append(&m->m_list, me, false);
360             if (atf_is_error(err)) {
361                 if (managed)
362                     free(value);
363                 free(me);
364             }
365         }
366     } else {
367         me = iter.m_entry;
368         if (me->m_managed)
369             free(me->m_value);
370 
371         INV(strcmp(me->m_key, key) == 0);
372         me->m_value = value;
373         me->m_managed = managed;
374 
375         err = atf_no_error();
376     }
377 
378     return err;
379 }
380