1/*
2 * Automated Testing Framework (atf)
3 *
4 * Copyright (c) 2008, 2010 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
44struct map_entry {
45    char *m_key;
46    void *m_value;
47    bool m_managed;
48};
49
50static
51struct map_entry *
52new_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
79const char *
80atf_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
87const void *
88atf_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
95atf_map_citer_t
96atf_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
108bool
109atf_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
123const char *
124atf_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
131void *
132atf_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
139atf_map_iter_t
140atf_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
152bool
153atf_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
167atf_error_t
168atf_map_init(atf_map_t *m)
169{
170    return atf_list_init(&m->m_list);
171}
172
173atf_error_t
174atf_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
205void
206atf_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
225atf_map_iter_t
226atf_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
235atf_map_citer_t
236atf_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
245atf_map_iter_t
246atf_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
255atf_map_citer_t
256atf_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
265atf_map_iter_t
266atf_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
285atf_map_citer_t
286atf_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
305size_t
306atf_map_size(const atf_map_t *m)
307{
308    return atf_list_size(&m->m_list);
309}
310
311char **
312atf_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
342out:
343    return array;
344}
345
346/*
347 * Modifiers.
348 */
349
350atf_error_t
351atf_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