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 47 void 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 56 void 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 79 void 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 89 void 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 98 void 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 120 void 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 142 struct 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 171 void 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 198 void 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 224 void 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