2002-12-13 21:15:29 +01:00
|
|
|
/* Generic linked list routine.
|
|
|
|
* Copyright (C) 1997, 2000 Kunihiro Ishiguro
|
|
|
|
*
|
|
|
|
* This file is part of GNU Zebra.
|
|
|
|
*
|
|
|
|
* GNU Zebra is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
2017-05-13 10:25:29 +02:00
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2002-12-13 21:15:29 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
2018-05-24 09:04:48 +02:00
|
|
|
#include <stdlib.h>
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
#include "linklist.h"
|
|
|
|
#include "memory.h"
|
2020-09-28 21:49:22 +02:00
|
|
|
#include "libfrr_trace.h"
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2015-05-29 05:48:31 +02:00
|
|
|
DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List")
|
|
|
|
DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node")
|
|
|
|
|
2005-05-06 Paul Jakma <paul@dishone.st>
* (general) extern and static'ification of functions in code and
header.
Cleanup any definitions with unspecified arguments.
Add casts for callback assignments where the callback is defined,
typically, as passing void *, but the function being assigned has
some other pointer type defined as its argument, as gcc complains
about casts from void * to X* via function arguments.
Fix some old K&R style function argument definitions.
Add noreturn gcc attribute to some functions, as appropriate.
Add unused gcc attribute to some functions (eg ones meant to help
while debugging)
Add guard defines to headers which were missing them.
* command.c: (install_node) add const qualifier, still doesnt shut
up the warning though, because of the double pointer.
(cmp_node) ditto
* keychain.c: (key_str2time) Add GET_LONG_RANGE() macro, derived
fromn vty.h ones to fix some of the (long) < 0 warnings.
* thread.c: (various) use thread_empty
(cpu_record_hash_key) should cast to uintptr_t, a stdint.h type
* vty.h: Add VTY_GET_IPV4_ADDRESS and VTY_GET_IPV4_PREFIX so they
removed from ospfd/ospf_vty.h
* zebra.h: Move definition of ZEBRA_PORT to here, to remove
dependence of lib on zebra/zserv.h
2005-05-06 23:25:49 +02:00
|
|
|
struct list *list_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2008-08-18 23:13:29 +02:00
|
|
|
return XCALLOC(MTYPE_LINK_LIST, sizeof(struct list));
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Free list. */
|
2017-09-28 03:19:20 +02:00
|
|
|
static void list_free_internal(struct list *l)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
XFREE(MTYPE_LINK_LIST, l);
|
|
|
|
}
|
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Allocate new listnode. Internal use only. */
|
2020-03-27 15:28:32 +01:00
|
|
|
static struct listnode *listnode_new(struct list *list, void *val)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-03-27 15:28:32 +01:00
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
/* if listnode memory is managed by the app then the val
|
|
|
|
* passed in is the listnode
|
|
|
|
*/
|
|
|
|
if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) {
|
|
|
|
node = val;
|
|
|
|
node->prev = node->next = NULL;
|
|
|
|
} else {
|
|
|
|
node = XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode));
|
|
|
|
node->data = val;
|
|
|
|
}
|
|
|
|
return node;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Free listnode. */
|
2020-03-27 15:28:32 +01:00
|
|
|
static void listnode_free(struct list *list, struct listnode *node)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-03-27 15:28:32 +01:00
|
|
|
if (!(list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP))
|
|
|
|
XFREE(MTYPE_LINK_NODE, node);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2019-03-19 19:39:51 +01:00
|
|
|
struct listnode *listnode_add(struct list *list, void *val)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-09-17 20:57:36 +02:00
|
|
|
tracepoint(frr_libfrr, list_add, list, val);
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
struct listnode *node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2008-02-28 01:09:04 +01:00
|
|
|
assert(val != NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
node = listnode_new(list, val);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
node->prev = list->tail;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (list->head == NULL)
|
|
|
|
list->head = node;
|
|
|
|
else
|
|
|
|
list->tail->next = node;
|
|
|
|
list->tail = node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
list->count++;
|
2019-03-19 19:39:51 +01:00
|
|
|
|
|
|
|
return node;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2018-05-28 15:15:09 +02:00
|
|
|
void listnode_add_head(struct list *list, void *val)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
assert(val != NULL);
|
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
node = listnode_new(list, val);
|
2018-05-28 15:15:09 +02:00
|
|
|
|
|
|
|
node->next = list->head;
|
|
|
|
|
|
|
|
if (list->head == NULL)
|
|
|
|
list->head = node;
|
|
|
|
else
|
|
|
|
list->head->prev = node;
|
|
|
|
list->head = node;
|
|
|
|
|
|
|
|
list->count++;
|
|
|
|
}
|
|
|
|
|
2019-05-03 15:57:57 +02:00
|
|
|
bool listnode_add_sort_nodup(struct list *list, void *val)
|
|
|
|
{
|
|
|
|
struct listnode *n;
|
|
|
|
struct listnode *new;
|
|
|
|
int ret;
|
2020-03-27 15:28:32 +01:00
|
|
|
void *data;
|
2019-05-03 15:57:57 +02:00
|
|
|
|
|
|
|
assert(val != NULL);
|
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) {
|
|
|
|
n = val;
|
|
|
|
data = n->data;
|
|
|
|
} else {
|
|
|
|
data = val;
|
|
|
|
}
|
|
|
|
|
2019-05-03 15:57:57 +02:00
|
|
|
if (list->cmp) {
|
|
|
|
for (n = list->head; n; n = n->next) {
|
2020-03-27 15:28:32 +01:00
|
|
|
ret = (*list->cmp)(data, n->data);
|
2019-05-03 15:57:57 +02:00
|
|
|
if (ret < 0) {
|
2020-03-27 15:28:32 +01:00
|
|
|
new = listnode_new(list, val);
|
2019-05-03 15:57:57 +02:00
|
|
|
|
|
|
|
new->next = n;
|
|
|
|
new->prev = n->prev;
|
|
|
|
|
|
|
|
if (n->prev)
|
|
|
|
n->prev->next = new;
|
|
|
|
else
|
|
|
|
list->head = new;
|
|
|
|
n->prev = new;
|
|
|
|
list->count++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/* found duplicate return false */
|
|
|
|
if (ret == 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
new = listnode_new(list, val);
|
2019-05-03 15:57:57 +02:00
|
|
|
|
|
|
|
LISTNODE_ATTACH(list, new);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-11 04:21:59 +02:00
|
|
|
struct list *list_dup(struct list *list)
|
|
|
|
{
|
|
|
|
struct list *dup;
|
|
|
|
struct listnode *node;
|
|
|
|
void *data;
|
|
|
|
|
|
|
|
assert(list);
|
|
|
|
|
|
|
|
dup = list_new();
|
|
|
|
dup->cmp = list->cmp;
|
|
|
|
dup->del = list->del;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(list, node, data))
|
|
|
|
listnode_add(dup, data);
|
|
|
|
|
|
|
|
return dup;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
void listnode_add_sort(struct list *list, void *val)
|
|
|
|
{
|
|
|
|
struct listnode *n;
|
|
|
|
struct listnode *new;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2008-02-28 01:09:04 +01:00
|
|
|
assert(val != NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
new = listnode_new(list, val);
|
|
|
|
val = new->data;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (list->cmp) {
|
|
|
|
for (n = list->head; n; n = n->next) {
|
2003-12-22 17:49:15 +01:00
|
|
|
if ((*list->cmp)(val, n->data) < 0) {
|
2002-12-13 21:15:29 +01:00
|
|
|
new->next = n;
|
|
|
|
new->prev = n->prev;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (n->prev)
|
|
|
|
n->prev->next = new;
|
|
|
|
else
|
|
|
|
list->head = new;
|
|
|
|
n->prev = new;
|
|
|
|
list->count++;
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
new->prev = list->tail;
|
|
|
|
|
|
|
|
if (list->tail)
|
|
|
|
list->tail->next = new;
|
|
|
|
else
|
|
|
|
list->head = new;
|
|
|
|
|
|
|
|
list->tail = new;
|
|
|
|
list->count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct listnode *listnode_add_after(struct list *list, struct listnode *pp,
|
|
|
|
void *val)
|
|
|
|
{
|
|
|
|
struct listnode *nn;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2008-02-28 01:09:04 +01:00
|
|
|
assert(val != NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
nn = listnode_new(list, val);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (pp == NULL) {
|
|
|
|
if (list->head)
|
|
|
|
list->head->prev = nn;
|
|
|
|
else
|
|
|
|
list->tail = nn;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
nn->next = list->head;
|
|
|
|
nn->prev = pp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
list->head = nn;
|
|
|
|
} else {
|
|
|
|
if (pp->next)
|
|
|
|
pp->next->prev = nn;
|
|
|
|
else
|
|
|
|
list->tail = nn;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
nn->next = pp->next;
|
|
|
|
nn->prev = pp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
pp->next = nn;
|
|
|
|
}
|
2007-11-12 15:55:01 +01:00
|
|
|
list->count++;
|
2016-07-28 17:23:46 +02:00
|
|
|
return nn;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-07-28 17:23:41 +02:00
|
|
|
struct listnode *listnode_add_before(struct list *list, struct listnode *pp,
|
|
|
|
void *val)
|
|
|
|
{
|
|
|
|
struct listnode *nn;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 17:23:41 +02:00
|
|
|
assert(val != NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-27 15:28:32 +01:00
|
|
|
nn = listnode_new(list, val);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 17:23:41 +02:00
|
|
|
if (pp == NULL) {
|
|
|
|
if (list->tail)
|
|
|
|
list->tail->next = nn;
|
|
|
|
else
|
|
|
|
list->head = nn;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 17:23:41 +02:00
|
|
|
nn->prev = list->tail;
|
|
|
|
nn->next = pp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 17:23:41 +02:00
|
|
|
list->tail = nn;
|
|
|
|
} else {
|
|
|
|
if (pp->prev)
|
|
|
|
pp->prev->next = nn;
|
|
|
|
else
|
|
|
|
list->head = nn;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 17:23:41 +02:00
|
|
|
nn->prev = pp->prev;
|
|
|
|
nn->next = pp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 17:23:41 +02:00
|
|
|
pp->prev = nn;
|
|
|
|
}
|
|
|
|
list->count++;
|
|
|
|
return nn;
|
|
|
|
}
|
|
|
|
|
2014-10-09 17:05:15 +02:00
|
|
|
void listnode_move_to_tail(struct list *l, struct listnode *n)
|
|
|
|
{
|
|
|
|
LISTNODE_DETACH(l, n);
|
|
|
|
LISTNODE_ATTACH(l, n);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-05-22 18:27:16 +02:00
|
|
|
void listnode_delete(struct list *list, const void *val)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-09-17 20:57:36 +02:00
|
|
|
tracepoint(frr_libfrr, list_remove, list, val);
|
|
|
|
|
2018-06-28 16:16:35 +02:00
|
|
|
struct listnode *node = listnode_lookup(list, val);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-06-28 16:16:35 +02:00
|
|
|
if (node)
|
|
|
|
list_delete_node(list, node);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void *listnode_head(struct list *list)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
|
2002-12-13 22:44:27 +01:00
|
|
|
assert(list);
|
2002-12-13 21:15:29 +01:00
|
|
|
node = list->head;
|
|
|
|
|
|
|
|
if (node)
|
|
|
|
return node->data;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void list_delete_all_node(struct list *list)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct listnode *next;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 22:44:27 +01:00
|
|
|
assert(list);
|
2002-12-13 21:15:29 +01:00
|
|
|
for (node = list->head; node; node = next) {
|
|
|
|
next = node->next;
|
2017-10-05 16:51:01 +02:00
|
|
|
if (*list->del)
|
2002-12-13 21:15:29 +01:00
|
|
|
(*list->del)(node->data);
|
2020-03-27 15:28:32 +01:00
|
|
|
listnode_free(list, node);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
list->head = list->tail = NULL;
|
|
|
|
list->count = 0;
|
|
|
|
}
|
|
|
|
|
2019-05-03 15:57:57 +02:00
|
|
|
void list_filter_out_nodes(struct list *list, bool (*cond)(void *data))
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct listnode *next;
|
|
|
|
void *data;
|
|
|
|
|
|
|
|
assert(list);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(list, node, next, data)) {
|
|
|
|
if ((cond && cond(data)) || (!cond)) {
|
|
|
|
if (*list->del)
|
|
|
|
(*list->del)(data);
|
|
|
|
list_delete_node(list, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-02 11:39:51 +02:00
|
|
|
void list_delete(struct list **list)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-10-05 16:51:01 +02:00
|
|
|
assert(*list);
|
|
|
|
list_delete_all_node(*list);
|
2017-09-28 03:19:20 +02:00
|
|
|
list_free_internal(*list);
|
2017-10-05 16:51:01 +02:00
|
|
|
*list = NULL;
|
|
|
|
}
|
|
|
|
|
2019-05-22 18:27:16 +02:00
|
|
|
struct listnode *listnode_lookup(struct list *list, const void *data)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2004-09-23 21:18:23 +02:00
|
|
|
struct listnode *node;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2002-12-13 22:44:27 +01:00
|
|
|
assert(list);
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
for (node = listhead(list); node; node = listnextnode(node))
|
|
|
|
if (data == listgetdata(node))
|
2002-12-13 21:15:29 +01:00
|
|
|
return node;
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2019-03-28 17:59:27 +01:00
|
|
|
struct listnode *listnode_lookup_nocheck(struct list *list, void *data)
|
|
|
|
{
|
|
|
|
if (!list)
|
|
|
|
return NULL;
|
|
|
|
return listnode_lookup(list, data);
|
|
|
|
}
|
|
|
|
|
2004-09-23 21:18:23 +02:00
|
|
|
void list_delete_node(struct list *list, struct listnode *node)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-09-17 20:57:36 +02:00
|
|
|
tracepoint(frr_libfrr, list_delete_node, list, node);
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (node->prev)
|
|
|
|
node->prev->next = node->next;
|
|
|
|
else
|
|
|
|
list->head = node->next;
|
|
|
|
if (node->next)
|
|
|
|
node->next->prev = node->prev;
|
|
|
|
else
|
|
|
|
list->tail = node->prev;
|
|
|
|
list->count--;
|
2020-03-27 15:28:32 +01:00
|
|
|
listnode_free(list, node);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2018-05-24 09:04:48 +02:00
|
|
|
void list_sort(struct list *list, int (*cmp)(const void **, const void **))
|
|
|
|
{
|
2020-09-17 20:57:36 +02:00
|
|
|
tracepoint(frr_libfrr, list_sort, list);
|
|
|
|
|
2018-05-24 09:04:48 +02:00
|
|
|
struct listnode *ln, *nn;
|
|
|
|
int i = -1;
|
|
|
|
void *data;
|
|
|
|
size_t n = list->count;
|
|
|
|
void **items = XCALLOC(MTYPE_TMP, (sizeof(void *)) * n);
|
|
|
|
int (*realcmp)(const void *, const void *) =
|
|
|
|
(int (*)(const void *, const void *))cmp;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(list, ln, nn, data)) {
|
|
|
|
items[++i] = data;
|
|
|
|
list_delete_node(list, ln);
|
|
|
|
}
|
|
|
|
|
|
|
|
qsort(items, n, sizeof(void *), realcmp);
|
|
|
|
|
2018-09-12 12:25:27 +02:00
|
|
|
for (unsigned int j = 0; j < n; ++j)
|
|
|
|
listnode_add(list, items[j]);
|
2018-05-24 09:04:48 +02:00
|
|
|
|
|
|
|
XFREE(MTYPE_TMP, items);
|
|
|
|
}
|
2019-03-28 18:06:51 +01:00
|
|
|
|
2019-04-22 21:49:16 +02:00
|
|
|
struct listnode *listnode_add_force(struct list **list, void *val)
|
2019-03-28 18:06:51 +01:00
|
|
|
{
|
|
|
|
if (*list == NULL)
|
|
|
|
*list = list_new();
|
|
|
|
return listnode_add(*list, val);
|
|
|
|
}
|
2018-12-07 23:06:42 +01:00
|
|
|
|
|
|
|
void **list_to_array(struct list *list, void **arr, size_t arrlen)
|
|
|
|
{
|
|
|
|
struct listnode *ln;
|
|
|
|
void *vp;
|
|
|
|
size_t idx = 0;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(list, ln, vp)) {
|
|
|
|
arr[idx++] = vp;
|
|
|
|
if (idx == arrlen)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return arr;
|
|
|
|
}
|