1 /* Generic linked list routine.
2 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "libfrr_trace.h"
28 DEFINE_MTYPE_STATIC(LIB
, LINK_LIST
, "Link List");
29 DEFINE_MTYPE_STATIC(LIB
, LINK_NODE
, "Link Node");
31 /* these *do not* cleanup list nodes and referenced data, as the functions
32 * do - these macros simply {de,at}tach a listnode from/to a list.
35 /* List node attach macro. */
36 #define LISTNODE_ATTACH(L, N) \
38 (N)->prev = (L)->tail; \
40 if ((L)->head == NULL) \
43 (L)->tail->next = (N); \
48 /* List node detach macro. */
49 #define LISTNODE_DETACH(L, N) \
52 (N)->prev->next = (N)->next; \
54 (L)->head = (N)->next; \
56 (N)->next->prev = (N)->prev; \
58 (L)->tail = (N)->prev; \
62 struct list
*list_new(void)
64 return XCALLOC(MTYPE_LINK_LIST
, sizeof(struct list
));
68 static void list_free_internal(struct list
*l
)
70 XFREE(MTYPE_LINK_LIST
, l
);
74 /* Allocate new listnode. Internal use only. */
75 static struct listnode
*listnode_new(struct list
*list
, void *val
)
77 struct listnode
*node
;
79 /* if listnode memory is managed by the app then the val
80 * passed in is the listnode
82 if (list
->flags
& LINKLIST_FLAG_NODE_MEM_BY_APP
) {
84 node
->prev
= node
->next
= NULL
;
86 node
= XCALLOC(MTYPE_LINK_NODE
, sizeof(struct listnode
));
93 static void listnode_free(struct list
*list
, struct listnode
*node
)
95 if (!(list
->flags
& LINKLIST_FLAG_NODE_MEM_BY_APP
))
96 XFREE(MTYPE_LINK_NODE
, node
);
99 struct listnode
*listnode_add(struct list
*list
, void *val
)
101 frrtrace(2, frr_libfrr
, list_add
, list
, val
);
103 struct listnode
*node
;
107 node
= listnode_new(list
, val
);
109 node
->prev
= list
->tail
;
111 if (list
->head
== NULL
)
114 list
->tail
->next
= node
;
122 void listnode_add_head(struct list
*list
, void *val
)
124 struct listnode
*node
;
128 node
= listnode_new(list
, val
);
130 node
->next
= list
->head
;
132 if (list
->head
== NULL
) {
136 list
->head
->prev
= node
;
142 bool listnode_add_sort_nodup(struct list
*list
, void *val
)
145 struct listnode
*new;
151 if (list
->flags
& LINKLIST_FLAG_NODE_MEM_BY_APP
) {
159 for (n
= list
->head
; n
; n
= n
->next
) {
160 ret
= (*list
->cmp
)(data
, n
->data
);
162 new = listnode_new(list
, val
);
175 /* found duplicate return false */
181 new = listnode_new(list
, val
);
183 LISTNODE_ATTACH(list
, new);
188 struct list
*list_dup(struct list
*list
)
191 struct listnode
*node
;
197 dup
->cmp
= list
->cmp
;
198 dup
->del
= list
->del
;
199 for (ALL_LIST_ELEMENTS_RO(list
, node
, data
))
200 listnode_add(dup
, data
);
205 void listnode_add_sort(struct list
*list
, void *val
)
208 struct listnode
*new;
212 new = listnode_new(list
, val
);
216 for (n
= list
->head
; n
; n
= n
->next
) {
217 if ((*list
->cmp
)(val
, n
->data
) < 0) {
232 new->prev
= list
->tail
;
235 list
->tail
->next
= new;
243 struct listnode
*listnode_add_after(struct list
*list
, struct listnode
*pp
,
250 nn
= listnode_new(list
, val
);
254 list
->head
->prev
= nn
;
258 nn
->next
= list
->head
;
277 struct listnode
*listnode_add_before(struct list
*list
, struct listnode
*pp
,
284 nn
= listnode_new(list
, val
);
288 list
->tail
->next
= nn
;
292 nn
->prev
= list
->tail
;
311 void listnode_move_to_tail(struct list
*l
, struct listnode
*n
)
313 LISTNODE_DETACH(l
, n
);
314 LISTNODE_ATTACH(l
, n
);
317 void listnode_delete(struct list
*list
, const void *val
)
319 frrtrace(2, frr_libfrr
, list_remove
, list
, val
);
321 struct listnode
*node
= listnode_lookup(list
, val
);
324 list_delete_node(list
, node
);
327 void *listnode_head(struct list
*list
)
329 struct listnode
*node
;
339 void list_delete_all_node(struct list
*list
)
341 struct listnode
*node
;
342 struct listnode
*next
;
345 for (node
= list
->head
; node
; node
= next
) {
348 (*list
->del
)(node
->data
);
349 listnode_free(list
, node
);
351 list
->head
= list
->tail
= NULL
;
355 void list_delete(struct list
**list
)
358 list_delete_all_node(*list
);
359 list_free_internal(*list
);
363 struct listnode
*listnode_lookup(struct list
*list
, const void *data
)
365 struct listnode
*node
;
368 for (node
= listhead(list
); node
; node
= listnextnode(node
))
369 if (data
== listgetdata(node
))
374 struct listnode
*listnode_lookup_nocheck(struct list
*list
, void *data
)
378 return listnode_lookup(list
, data
);
381 void list_delete_node(struct list
*list
, struct listnode
*node
)
383 frrtrace(2, frr_libfrr
, list_delete_node
, list
, node
);
386 node
->prev
->next
= node
->next
;
388 list
->head
= node
->next
;
390 node
->next
->prev
= node
->prev
;
392 list
->tail
= node
->prev
;
394 listnode_free(list
, node
);
397 void list_sort(struct list
*list
, int (*cmp
)(const void **, const void **))
399 frrtrace(1, frr_libfrr
, list_sort
, list
);
401 struct listnode
*ln
, *nn
;
404 size_t n
= list
->count
;
406 int (*realcmp
)(const void *, const void *) =
407 (int (*)(const void *, const void *))cmp
;
412 items
= XCALLOC(MTYPE_TMP
, (sizeof(void *)) * n
);
414 for (ALL_LIST_ELEMENTS(list
, ln
, nn
, data
)) {
416 list_delete_node(list
, ln
);
419 qsort(items
, n
, sizeof(void *), realcmp
);
421 for (unsigned int j
= 0; j
< n
; ++j
)
422 listnode_add(list
, items
[j
]);
424 XFREE(MTYPE_TMP
, items
);
427 struct listnode
*listnode_add_force(struct list
**list
, void *val
)
431 return listnode_add(*list
, val
);
434 void **list_to_array(struct list
*list
, void **arr
, size_t arrlen
)
440 for (ALL_LIST_ELEMENTS_RO(list
, ln
, vp
)) {