xref: /freebsd/contrib/atf/atf-c/detail/map.c (revision 40a8ac8f62b535d30349faf28cf47106b7041b83)
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 *
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 *
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 *
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
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
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 *
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 *
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
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
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
168 atf_map_init(atf_map_t *m)
169 {
170     return atf_list_init(&m->m_list);
171 }
172 
173 atf_error_t
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
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
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
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
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
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
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
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
306 atf_map_size(const atf_map_t *m)
307 {
308     return atf_list_size(&m->m_list);
309 }
310 
311 char **
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
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