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