/* Copyright (c) 2008 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "atf-c/detail/list.h" #include #include #include "atf-c/detail/sanity.h" #include "atf-c/error.h" #include "atf-c/utils.h" /* --------------------------------------------------------------------- * Auxiliary functions. * --------------------------------------------------------------------- */ struct list_entry { struct list_entry *m_prev; struct list_entry *m_next; void *m_object; bool m_managed; }; static atf_list_citer_t entry_to_citer(const atf_list_t *l, const struct list_entry *le) { atf_list_citer_t iter; iter.m_list = l; iter.m_entry = le; return iter; } static atf_list_iter_t entry_to_iter(atf_list_t *l, struct list_entry *le) { atf_list_iter_t iter; iter.m_list = l; iter.m_entry = le; return iter; } static struct list_entry * new_entry(void *object, bool managed) { struct list_entry *le; le = (struct list_entry *)malloc(sizeof(*le)); if (le != NULL) { le->m_prev = le->m_next = NULL; le->m_object = object; le->m_managed = managed; } else free(object); return le; } static void delete_entry(struct list_entry *le) { if (le->m_managed) free(le->m_object); free(le); } static struct list_entry * new_entry_and_link(void *object, bool managed, struct list_entry *prev, struct list_entry *next) { struct list_entry *le; le = new_entry(object, managed); if (le != NULL) { le->m_prev = prev; le->m_next = next; prev->m_next = le; next->m_prev = le; } return le; } /* --------------------------------------------------------------------- * The "atf_list_citer" type. * --------------------------------------------------------------------- */ /* * Getters. */ const void * atf_list_citer_data(const atf_list_citer_t citer) { const struct list_entry *le = citer.m_entry; PRE(le != NULL); return le->m_object; } atf_list_citer_t atf_list_citer_next(const atf_list_citer_t citer) { const struct list_entry *le = citer.m_entry; atf_list_citer_t newciter; PRE(le != NULL); newciter = citer; newciter.m_entry = le->m_next; return newciter; } bool atf_equal_list_citer_list_citer(const atf_list_citer_t i1, const atf_list_citer_t i2) { return i1.m_list == i2.m_list && i1.m_entry == i2.m_entry; } /* --------------------------------------------------------------------- * The "atf_list_iter" type. * --------------------------------------------------------------------- */ /* * Getters. */ void * atf_list_iter_data(const atf_list_iter_t iter) { const struct list_entry *le = iter.m_entry; PRE(le != NULL); return le->m_object; } atf_list_iter_t atf_list_iter_next(const atf_list_iter_t iter) { const struct list_entry *le = iter.m_entry; atf_list_iter_t newiter; PRE(le != NULL); newiter = iter; newiter.m_entry = le->m_next; return newiter; } bool atf_equal_list_iter_list_iter(const atf_list_iter_t i1, const atf_list_iter_t i2) { return i1.m_list == i2.m_list && i1.m_entry == i2.m_entry; } /* --------------------------------------------------------------------- * The "atf_list" type. * --------------------------------------------------------------------- */ /* * Constructors and destructors. */ atf_error_t atf_list_init(atf_list_t *l) { struct list_entry *lebeg, *leend; lebeg = new_entry(NULL, false); if (lebeg == NULL) { return atf_no_memory_error(); } leend = new_entry(NULL, false); if (leend == NULL) { free(lebeg); return atf_no_memory_error(); } lebeg->m_next = leend; lebeg->m_prev = NULL; leend->m_next = NULL; leend->m_prev = lebeg; l->m_size = 0; l->m_begin = lebeg; l->m_end = leend; return atf_no_error(); } void atf_list_fini(atf_list_t *l) { struct list_entry *le; size_t freed; le = (struct list_entry *)l->m_begin; freed = 0; while (le != NULL) { struct list_entry *lenext; lenext = le->m_next; delete_entry(le); le = lenext; freed++; } INV(freed == l->m_size + 2); } /* * Getters. */ atf_list_iter_t atf_list_begin(atf_list_t *l) { struct list_entry *le = l->m_begin; return entry_to_iter(l, le->m_next); } atf_list_citer_t atf_list_begin_c(const atf_list_t *l) { const struct list_entry *le = l->m_begin; return entry_to_citer(l, le->m_next); } atf_list_iter_t atf_list_end(atf_list_t *l) { return entry_to_iter(l, l->m_end); } atf_list_citer_t atf_list_end_c(const atf_list_t *l) { return entry_to_citer(l, l->m_end); } void * atf_list_index(atf_list_t *list, const size_t idx) { atf_list_iter_t iter; PRE(idx < atf_list_size(list)); iter = atf_list_begin(list); { size_t pos = 0; while (pos < idx && !atf_equal_list_iter_list_iter((iter), atf_list_end(list))) { iter = atf_list_iter_next(iter); pos++; } } return atf_list_iter_data(iter); } const void * atf_list_index_c(const atf_list_t *list, const size_t idx) { atf_list_citer_t iter; PRE(idx < atf_list_size(list)); iter = atf_list_begin_c(list); { size_t pos = 0; while (pos < idx && !atf_equal_list_citer_list_citer((iter), atf_list_end_c(list))) { iter = atf_list_citer_next(iter); pos++; } } return atf_list_citer_data(iter); } size_t atf_list_size(const atf_list_t *l) { return l->m_size; } char ** atf_list_to_charpp(const atf_list_t *l) { char **array; atf_list_citer_t iter; size_t i; array = malloc(sizeof(char *) * (atf_list_size(l) + 1)); if (array == NULL) goto out; i = 0; atf_list_for_each_c(iter, l) { array[i] = strdup((const char *)atf_list_citer_data(iter)); if (array[i] == NULL) { atf_utils_free_charpp(array); array = NULL; goto out; } i++; } array[i] = NULL; out: return array; } /* * Modifiers. */ atf_error_t atf_list_append(atf_list_t *l, void *data, bool managed) { struct list_entry *le, *next, *prev; atf_error_t err; next = (struct list_entry *)l->m_end; prev = next->m_prev; le = new_entry_and_link(data, managed, prev, next); if (le == NULL) err = atf_no_memory_error(); else { l->m_size++; err = atf_no_error(); } return err; } void atf_list_append_list(atf_list_t *l, atf_list_t *src) { struct list_entry *e1, *e2, *ghost1, *ghost2; ghost1 = (struct list_entry *)l->m_end; ghost2 = (struct list_entry *)src->m_begin; e1 = ghost1->m_prev; e2 = ghost2->m_next; delete_entry(ghost1); delete_entry(ghost2); e1->m_next = e2; e2->m_prev = e1; l->m_end = src->m_end; l->m_size += src->m_size; }