map.c revision 275988
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
40struct map_entry {
41    char *m_key;
42    void *m_value;
43    bool m_managed;
44};
45
46static
47struct map_entry *
48new_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
75const char *
76atf_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
83const void *
84atf_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
91atf_map_citer_t
92atf_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
104bool
105atf_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
119const char *
120atf_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
127void *
128atf_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
135atf_map_iter_t
136atf_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
148bool
149atf_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
163atf_error_t
164atf_map_init(atf_map_t *m)
165{
166    return atf_list_init(&m->m_list);
167}
168
169atf_error_t
170atf_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
201void
202atf_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
221atf_map_iter_t
222atf_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
231atf_map_citer_t
232atf_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
241atf_map_iter_t
242atf_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
251atf_map_citer_t
252atf_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
261atf_map_iter_t
262atf_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
281atf_map_citer_t
282atf_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
301size_t
302atf_map_size(const atf_map_t *m)
303{
304    return atf_list_size(&m->m_list);
305}
306
307char **
308atf_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
338out:
339    return array;
340}
341
342/*
343 * Modifiers.
344 */
345
346atf_error_t
347atf_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