1/* 2 * Copyright 2011 Tresys Technology, LLC. 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 are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS 15 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * The views and conclusions contained in the software and documentation are those 26 * of the authors and should not be interpreted as representing official policies, 27 * either expressed or implied, of Tresys Technology, LLC. 28 */ 29 30#include <stdlib.h> 31#include <stdarg.h> 32 33#include "cil_internal.h" 34#include "cil_flavor.h" 35#include "cil_log.h" 36#include "cil_mem.h" 37 38__attribute__((noreturn)) __attribute__((format (printf, 1, 2))) void cil_list_error(const char* msg, ...) 39{ 40 va_list ap; 41 va_start(ap, msg); 42 cil_vlog(CIL_ERR, msg, ap); 43 va_end(ap); 44 exit(1); 45} 46 47void cil_list_init(struct cil_list **list, enum cil_flavor flavor) 48{ 49 struct cil_list *new_list = cil_malloc(sizeof(*new_list)); 50 new_list->head = NULL; 51 new_list->tail = NULL; 52 new_list->flavor = flavor; 53 *list = new_list; 54} 55 56void cil_list_destroy(struct cil_list **list, unsigned destroy_data) 57{ 58 if (*list == NULL) { 59 return; 60 } 61 62 struct cil_list_item *item = (*list)->head; 63 struct cil_list_item *next = NULL; 64 while (item != NULL) 65 { 66 next = item->next; 67 if (item->flavor == CIL_LIST) { 68 cil_list_destroy((struct cil_list**)&(item->data), destroy_data); 69 free(item); 70 } else { 71 cil_list_item_destroy(&item, destroy_data); 72 } 73 item = next; 74 } 75 free(*list); 76 *list = NULL; 77} 78 79void cil_list_item_init(struct cil_list_item **item) 80{ 81 struct cil_list_item *new_item = cil_malloc(sizeof(*new_item)); 82 new_item->next = NULL; 83 new_item->flavor = CIL_NONE; 84 new_item->data = NULL; 85 86 *item = new_item; 87} 88 89void cil_list_item_destroy(struct cil_list_item **item, unsigned destroy_data) 90{ 91 if (destroy_data) { 92 cil_destroy_data(&(*item)->data, (*item)->flavor); 93 } 94 free(*item); 95 *item = NULL; 96} 97 98void cil_list_append(struct cil_list *list, enum cil_flavor flavor, void *data) 99{ 100 struct cil_list_item *item; 101 102 if (list == NULL) { 103 cil_list_error("Attempt to append data to a NULL list"); 104 } 105 106 cil_list_item_init(&item); 107 item->flavor = flavor; 108 item->data = data; 109 110 if (list->tail == NULL) { 111 list->head = item; 112 list->tail = item; 113 return; 114 } 115 116 list->tail->next = item; 117 list->tail = item; 118} 119 120void cil_list_prepend(struct cil_list *list, enum cil_flavor flavor, void *data) 121{ 122 struct cil_list_item *item; 123 124 if (list == NULL) { 125 cil_list_error("Attempt to prepend data to a NULL list"); 126 } 127 128 cil_list_item_init(&item); 129 item->flavor = flavor; 130 item->data = data; 131 132 if (list->tail == NULL) { 133 list->head = item; 134 list->tail = item; 135 return; 136 } 137 138 item->next = list->head; 139 list->head = item; 140} 141 142struct cil_list_item *cil_list_insert(struct cil_list *list, struct cil_list_item *curr, enum cil_flavor flavor, void *data) 143{ 144 struct cil_list_item *item; 145 146 if (list == NULL) { 147 cil_list_error("Attempt to append data to a NULL list"); 148 } 149 150 if (curr == NULL) { 151 /* Insert at the front of the list */ 152 cil_list_prepend(list, flavor, data); 153 return list->head; 154 } 155 156 if (curr == list->tail) { 157 cil_list_append(list, flavor, data); 158 return list->tail; 159 } 160 161 cil_list_item_init(&item); 162 item->flavor = flavor; 163 item->data = data; 164 item->next = curr->next; 165 166 curr->next = item; 167 168 return item; 169} 170 171void cil_list_append_item(struct cil_list *list, struct cil_list_item *item) 172{ 173 struct cil_list_item *last = item; 174 175 if (list == NULL) { 176 cil_list_error("Attempt to append an item to a NULL list"); 177 } 178 179 if (item == NULL) { 180 cil_list_error("Attempt to append a NULL item to a list"); 181 } 182 183 while (last->next != NULL) { 184 last = last->next; 185 } 186 187 if (list->tail == NULL) { 188 list->head = item; 189 list->tail = last; 190 return; 191 } 192 193 list->tail->next = item; 194 list->tail = last; 195 196} 197 198void cil_list_prepend_item(struct cil_list *list, struct cil_list_item *item) 199{ 200 struct cil_list_item *last = item; 201 202 if (list == NULL) { 203 cil_list_error("Attempt to prepend an item to a NULL list"); 204 } 205 206 if (item == NULL) { 207 cil_list_error("Attempt to prepend a NULL item to a list"); 208 } 209 210 while (last->next != NULL) { 211 last = last->next; 212 } 213 214 if (list->tail == NULL) { 215 list->head = item; 216 list->tail = last; 217 return; 218 } 219 220 last->next = list->head; 221 list->head = item; 222} 223 224void cil_list_remove(struct cil_list *list, enum cil_flavor flavor, void *data, unsigned destroy_data) 225{ 226 struct cil_list_item *item; 227 struct cil_list_item *previous = NULL; 228 229 if (list == NULL) { 230 cil_list_error("Attempt to remove data from a NULL list"); 231 } 232 233 cil_list_for_each(item, list) { 234 if (item->data == data && item->flavor == flavor) { 235 if (previous == NULL) { 236 list->head = item->next; 237 } else { 238 previous->next = item->next; 239 } 240 if (item->next == NULL) { 241 list->tail = previous; 242 } 243 cil_list_item_destroy(&item, destroy_data); 244 break; 245 } 246 previous = item; 247 } 248} 249 250int cil_list_contains(struct cil_list *list, void *data) 251{ 252 struct cil_list_item *curr = NULL; 253 254 cil_list_for_each(curr, list) { 255 if (curr->data == data) { 256 return CIL_TRUE; 257 } 258 } 259 260 return CIL_FALSE; 261} 262 263int cil_list_match_any(struct cil_list *l1, struct cil_list *l2) 264{ 265 struct cil_list_item *i1; 266 struct cil_list_item *i2; 267 268 cil_list_for_each(i1, l1) { 269 cil_list_for_each(i2, l2) { 270 if (i1->data == i2->data && i1->flavor == i2->flavor) { 271 return CIL_TRUE; 272 } 273 } 274 } 275 276 return CIL_FALSE; 277} 278