/* This file is part of GNU cflow
Copyright (C) 1997, 2005-2007, 2009-2010, 2014-2016 Sergey Poznyakoff
GNU cflow 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 3 of the License, or
(at your option) any later version.
GNU cflow 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include
static struct linked_list *
deref_linked_list(struct linked_list **plist)
{
if (!*plist) {
struct linked_list *list = xmalloc(sizeof(*list));
list->free_data = NULL;
list->head = list->tail = NULL;
*plist = list;
}
return *plist;
}
struct linked_list *
linked_list_create(linked_list_free_data_fp fun)
{
struct linked_list *list = xmalloc(sizeof(*list));
list->free_data = fun;
list->head = list->tail = NULL;
return list;
}
void
linked_list_append(struct linked_list **plist, void *data)
{
struct linked_list *list = deref_linked_list (plist);
struct linked_list_entry *entry = xmalloc(sizeof(*entry));
entry->list = list;
entry->data = data;
entry->next = NULL;
entry->prev = list->tail;
if (list->tail)
list->tail->next = entry;
else
list->head = entry;
list->tail = entry;
}
#if 0
void
linked_list_prepend(struct linked_list **plist, void *data)
{
struct linked_list *list = deref_linked_list (plist);
struct linked_list_entry *entry = xmalloc(sizeof(*entry));
entry->list = list;
entry->data = data;
if (list->head)
list->head->prev = entry;
entry->next = list->head;
entry->prev = NULL;
list->head = entry;
if (!list->tail)
list->tail = entry;
}
#endif
void
linked_list_destroy(struct linked_list **plist)
{
if (plist && *plist) {
struct linked_list *list = *plist;
struct linked_list_entry *p;
for (p = list->head; p; ) {
struct linked_list_entry *next = p->next;
if (list->free_data)
list->free_data(p->data);
free(p);
p = next;
}
free(list);
*plist = NULL;
}
}
void
linked_list_unlink(struct linked_list *list, struct linked_list_entry *ent)
{
struct linked_list_entry *p;
if ((p = ent->prev))
p->next = ent->next;
else
list->head = ent->next;
if ((p = ent->next))
p->prev = ent->prev;
else
list->tail = ent->prev;
if (list->free_data)
list->free_data(ent->data);
free(ent);
}
void
linked_list_iterate(struct linked_list **plist,
int (*itr) (void *, void *), void *data)
{
struct linked_list *list;
struct linked_list_entry *p;
if (!*plist)
return;
list = *plist;
for (p = linked_list_head(list); p; ) {
struct linked_list_entry *next = p->next;
if (itr(p->data, data))
linked_list_unlink(list, p);
p = next;
}
if (!list->head)
linked_list_destroy(&list);
*plist = list;
}
int
data_in_list(void *data, struct linked_list *list)
{
struct linked_list_entry *p;
for (p = linked_list_head(list); p; p = p->next)
if (p->data == data)
return 1;
return 0;
}
size_t
linked_list_size(struct linked_list *list)
{
size_t size = 0;
if (list) {
struct linked_list_entry *p;
for (p = linked_list_head(list); p; p = p->next)
size++;
}
return size;
}