1 /* This file is part of GNU Radius.
2 Copyright (C) 2003,2004,2007,2008 Free Software Foundation
3
4 GNU Radius is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 GNU Radius is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public
15 License along with GNU Radius; if not, write to the Free
16 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301 USA. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 #include <sys/types.h>
23 #include <stdlib.h>
24 #include <radius/radius.h>
25 #include <radius/list.h>
26
27 struct grad_list_entry {
28 struct grad_list_entry *next;
29 void *data;
30 };
31
32 struct grad_list {
33 size_t count;
34 struct grad_list_entry *head, *tail;
35 struct grad_iterator *itr;
36 };
37
38 struct grad_iterator {
39 struct grad_iterator *next;
40 grad_list_t *list;
41 struct grad_list_entry *cur;
42 int advanced;
43 };
44
45 struct grad_list *
grad_list_create()46 grad_list_create()
47 {
48 struct grad_list *p = grad_emalloc(sizeof(*p));
49 p->head = p->tail = NULL;
50 p->itr = NULL;
51 return p;
52 }
53
54 void
grad_list_destroy(struct grad_list ** plist,list_iterator_t user_free,void * data)55 grad_list_destroy(struct grad_list **plist, list_iterator_t user_free, void *data)
56 {
57 struct grad_list_entry *p;
58 struct grad_list *list;
59
60 if (!*plist)
61 return;
62
63 list = *plist;
64 *plist = NULL;
65 p = list->head;
66 while (p) {
67 struct grad_list_entry *next = p->next;
68 if (user_free)
69 user_free(p->data, data);
70 grad_free(p);
71 p = next;
72 }
73 grad_free(list);
74 }
75
76 void *
grad_iterator_current(grad_iterator_t * ip)77 grad_iterator_current(grad_iterator_t *ip)
78 {
79 if (!ip)
80 return NULL;
81 return ip->cur ? ip->cur->data : NULL;
82 }
83
84 static void
grad_iterator_attach(grad_iterator_t * itr,grad_list_t * list)85 grad_iterator_attach(grad_iterator_t *itr, grad_list_t *list)
86 {
87 itr->list = list;
88 itr->cur = NULL;
89 itr->next = list->itr;
90 itr->advanced = 0;
91 list->itr = itr;
92 }
93
94 static grad_iterator_t *
grad_iterator_detach(grad_iterator_t * iter)95 grad_iterator_detach(grad_iterator_t *iter)
96 {
97 grad_iterator_t *cur, *prev;
98
99 for (cur = iter->list->itr, prev = NULL;
100 cur;
101 prev = cur, cur = cur->next)
102 if (cur == iter)
103 break;
104
105 if (cur) {
106 if (prev)
107 prev->next = cur->next;
108 else
109 cur->list->itr = cur->next;
110 }
111 return cur;
112 }
113
114 grad_iterator_t *
grad_iterator_create(grad_list_t * list)115 grad_iterator_create(grad_list_t *list)
116 {
117 grad_iterator_t *itr;
118
119 if (!list)
120 return NULL;
121 itr = grad_emalloc(sizeof(*itr));
122 grad_iterator_attach(itr, list);
123 return itr;
124 }
125
126 void
grad_iterator_destroy(grad_iterator_t ** ip)127 grad_iterator_destroy(grad_iterator_t **ip)
128 {
129 grad_iterator_t *itr;
130
131 if (!ip || !*ip)
132 return;
133 itr = grad_iterator_detach(*ip);
134 if (itr)
135 grad_free(itr);
136 *ip = NULL;
137 }
138
139 void *
grad_iterator_first(grad_iterator_t * ip)140 grad_iterator_first(grad_iterator_t *ip)
141 {
142 if (!ip)
143 return NULL;
144 ip->cur = ip->list->head;
145 ip->advanced = 0;
146 return grad_iterator_current(ip);
147 }
148
149 void *
grad_iterator_next(grad_iterator_t * ip)150 grad_iterator_next(grad_iterator_t *ip)
151 {
152 if (!ip || !ip->cur)
153 return NULL;
154 if (!ip->advanced)
155 ip->cur = ip->cur->next;
156 ip->advanced = 0;
157 return grad_iterator_current(ip);
158 }
159
160 static void
_iterator_advance(grad_iterator_t * ip,struct grad_list_entry * e)161 _iterator_advance(grad_iterator_t *ip, struct grad_list_entry *e)
162 {
163 for (; ip; ip = ip->next) {
164 if (ip->cur == e) {
165 ip->cur = e->next;
166 ip->advanced++;
167 }
168 }
169 }
170
171 void *
grad_list_item(struct grad_list * list,size_t n)172 grad_list_item(struct grad_list *list, size_t n)
173 {
174 struct grad_list_entry *p;
175 if (!list || n >= list->count)
176 return NULL;
177 for (p = list->head; n > 0 && p; p = p->next, n--)
178 ;
179 return p->data;
180 }
181
182 size_t
grad_list_count(struct grad_list * list)183 grad_list_count(struct grad_list *list)
184 {
185 if (!list)
186 return 0;
187 return list->count;
188 }
189
190 void
grad_list_append(struct grad_list * list,void * data)191 grad_list_append(struct grad_list *list, void *data)
192 {
193 struct grad_list_entry *ep;
194
195 if (!list)
196 return;
197 ep = grad_emalloc(sizeof(*ep));
198 ep->next = NULL;
199 ep->data = data;
200 if (list->tail)
201 list->tail->next = ep;
202 else
203 list->head = ep;
204 list->tail = ep;
205 list->count++;
206 }
207
208 void
grad_list_prepend(struct grad_list * list,void * data)209 grad_list_prepend(struct grad_list *list, void *data)
210 {
211 struct grad_list_entry *ep;
212
213 if (!list)
214 return;
215 ep = grad_emalloc(sizeof(*ep));
216 ep->data = data;
217 ep->next = list->head;
218 list->head = ep;
219 if (!list->tail)
220 list->tail = list->head;
221 list->count++;
222 }
223
224 static int
cmp_ptr(const void * a,const void * b)225 cmp_ptr(const void *a, const void *b)
226 {
227 return a != b;
228 }
229
230 void *
grad_list_remove(struct grad_list * list,void * data,list_comp_t cmp)231 grad_list_remove(struct grad_list *list, void *data, list_comp_t cmp)
232 {
233 struct grad_list_entry *p, *prev;
234
235 if (!list)
236 return NULL;
237 if (!list->head)
238 return NULL;
239 if (!cmp)
240 cmp = cmp_ptr;
241 for (p = list->head, prev = NULL; p; prev = p, p = p->next)
242 if (cmp(p->data, data) == 0)
243 break;
244
245 if (!p)
246 return 0;
247 _iterator_advance(list->itr, p);
248 if (p == list->head) {
249 list->head = list->head->next;
250 if (!list->head)
251 list->tail = NULL;
252 } else
253 prev->next = p->next;
254
255 if (p == list->tail)
256 list->tail = prev;
257
258 grad_free(p);
259 list->count--;
260
261 return data;
262 }
263
264 /* Note: if modifying this function, make sure it does not allocate any
265 memory! */
266 void
grad_list_iterate(struct grad_list * list,list_iterator_t func,void * data)267 grad_list_iterate(struct grad_list *list, list_iterator_t func, void *data)
268 {
269 grad_iterator_t itr;
270 void *p;
271
272 if (!list)
273 return;
274 grad_iterator_attach(&itr, list);
275 for (p = grad_iterator_first(&itr); p; p = grad_iterator_next(&itr)) {
276 if (func(p, data))
277 break;
278 }
279 grad_iterator_detach(&itr);
280 }
281
282 void *
grad_list_locate(struct grad_list * list,void * data,list_comp_t cmp)283 grad_list_locate(struct grad_list *list, void *data, list_comp_t cmp)
284 {
285 struct grad_list_entry *cur;
286 if (!list)
287 return NULL;
288 if (!cmp)
289 cmp = cmp_ptr;
290 for (cur = list->head; cur; cur = cur->next)
291 if (cmp(cur->data, data) == 0)
292 break;
293 return cur ? cur->data : NULL;
294 }
295
296 int
grad_list_insert_sorted(struct grad_list * list,void * data,list_comp_t cmp)297 grad_list_insert_sorted(struct grad_list *list, void *data, list_comp_t cmp)
298 {
299 struct grad_list_entry *cur, *prev;
300
301 if (!list)
302 return -1;
303 if (!cmp)
304 return -1;
305
306 for (cur = list->head, prev = NULL; cur; prev = cur, cur = cur->next)
307 if (cmp(cur->data, data) > 0)
308 break;
309
310 if (!prev) {
311 grad_list_prepend(list, data);
312 } else if (!cur) {
313 grad_list_append(list, data);
314 } else {
315 struct grad_list_entry *ep = grad_emalloc(sizeof(*ep));
316 ep->data = data;
317 ep->next = cur;
318 list->count++;
319 prev->next = ep;
320 }
321 return 0;
322 }
323
324