mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-12 16:14:23 +00:00
239 lines
4.2 KiB
C
239 lines
4.2 KiB
C
|
/*
|
||
|
llist.c
|
||
|
|
||
|
Linked list functions
|
||
|
|
||
|
Copyright (C) 2003 Brian Koropoff
|
||
|
|
||
|
This program 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
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program 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, write to:
|
||
|
|
||
|
Free Software Foundation, Inc.
|
||
|
59 Temple Place - Suite 330
|
||
|
Boston, MA 02111-1307, USA
|
||
|
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
# include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "QF/llist.h"
|
||
|
|
||
|
static __attribute__ ((unused)) const char rcsid[] =
|
||
|
"$Id$";
|
||
|
|
||
|
static llist_node_t *
|
||
|
llist_newnode (llist_t *list, void *data)
|
||
|
{
|
||
|
llist_node_t *node = calloc (1, sizeof (llist_node_t));
|
||
|
node->parent = list;
|
||
|
node->data = data;
|
||
|
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
llist_t *
|
||
|
llist_new (void (*freedata)(void *element, void *userdata), qboolean (*cmpdata)(const void *element, const void *comparison, void *userdata), void *userdata)
|
||
|
{
|
||
|
llist_t *new = calloc (1, sizeof (llist_t));
|
||
|
|
||
|
new->freedata = freedata;
|
||
|
new->cmpdata = cmpdata;
|
||
|
new->userdata = userdata;
|
||
|
|
||
|
return new;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
llist_flush (llist_t *list)
|
||
|
{
|
||
|
llist_node_t *node, *next;
|
||
|
|
||
|
if (!list)
|
||
|
return;
|
||
|
|
||
|
for (node = list->start; node; node = next) {
|
||
|
next = node->next;
|
||
|
list->freedata (node->data, list->userdata);
|
||
|
free (node);
|
||
|
}
|
||
|
list->start = list->end = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
llist_delete (llist_t *list)
|
||
|
{
|
||
|
if (!list)
|
||
|
return;
|
||
|
|
||
|
llist_flush (list);
|
||
|
free (list);
|
||
|
}
|
||
|
|
||
|
llist_node_t *
|
||
|
llist_append (llist_t *list, void *element)
|
||
|
{
|
||
|
llist_node_t *node = llist_newnode (list, element);
|
||
|
|
||
|
if (!list)
|
||
|
return 0;
|
||
|
|
||
|
if (list->end) {
|
||
|
list->end->next = node;
|
||
|
node->prev = list->end;
|
||
|
list->end = node;
|
||
|
} else
|
||
|
list->start = list->end = node;
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
llist_node_t *
|
||
|
llist_prefix (llist_t *list, void *element)
|
||
|
{
|
||
|
llist_node_t *node = llist_newnode (list, element);
|
||
|
|
||
|
if (!list)
|
||
|
return 0;
|
||
|
|
||
|
if (list->start) {
|
||
|
list->start->prev = node;
|
||
|
node->next = list->start;
|
||
|
list->start = node;
|
||
|
} else
|
||
|
list->start = list->end = node;
|
||
|
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
llist_node_t *
|
||
|
llist_getnode (llist_t *list, void *element)
|
||
|
{
|
||
|
llist_node_t *node;
|
||
|
|
||
|
if (!list)
|
||
|
return 0;
|
||
|
|
||
|
for (node = list->start; node; node = node->next)
|
||
|
if (node->data == element)
|
||
|
return node;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
llist_node_t *
|
||
|
llist_insertafter (llist_node_t *ref, void *element)
|
||
|
{
|
||
|
llist_node_t *node = llist_newnode (ref->parent, element);
|
||
|
|
||
|
if (!ref)
|
||
|
return 0;
|
||
|
|
||
|
if (ref->next)
|
||
|
ref->next->prev = node;
|
||
|
else
|
||
|
ref->parent->end = node;
|
||
|
node->prev = ref;
|
||
|
node->next = ref->next;
|
||
|
ref->next = node;
|
||
|
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
llist_node_t *
|
||
|
llist_insertbefore (llist_node_t *ref, void *element)
|
||
|
{
|
||
|
llist_node_t *node = llist_newnode (ref->parent, element);
|
||
|
|
||
|
if (!ref)
|
||
|
return 0;
|
||
|
|
||
|
if (ref->prev)
|
||
|
ref->prev->next = node;
|
||
|
else
|
||
|
ref->parent->start = node;
|
||
|
node->next = ref;
|
||
|
node->prev = ref->prev;
|
||
|
ref->prev = node;
|
||
|
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
llist_remove (llist_node_t *ref)
|
||
|
{
|
||
|
void *element;
|
||
|
|
||
|
if (!ref)
|
||
|
return 0;
|
||
|
|
||
|
if (ref == ref->parent->iter)
|
||
|
ref->parent->iter = ref->next;
|
||
|
if (ref->prev)
|
||
|
ref->prev->next = ref->next;
|
||
|
else
|
||
|
ref->parent->start = ref->next;
|
||
|
if (ref->next)
|
||
|
ref->next->prev = ref->prev;
|
||
|
else
|
||
|
ref->parent->end = ref->prev;
|
||
|
|
||
|
element = ref->data;
|
||
|
free (ref);
|
||
|
return element;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
llist_iterate (llist_t *list, llist_iterator_t iterate)
|
||
|
{
|
||
|
llist_node_t *node;
|
||
|
|
||
|
if (!list || !list->start)
|
||
|
return;
|
||
|
for (node = list->start; node; node = list->iter) {
|
||
|
list->iter = node->next;
|
||
|
if (!iterate (node->data, node))
|
||
|
break;
|
||
|
}
|
||
|
list->iter = 0;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
llist_find (llist_t *list, void *comparison)
|
||
|
{
|
||
|
llist_node_t *node;
|
||
|
|
||
|
if (!list)
|
||
|
return 0;
|
||
|
for (node = list->start; node; node = node->next)
|
||
|
if (list->cmpdata (node->data, comparison, list->userdata))
|
||
|
return node->data;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
llist_node_t *
|
||
|
llist_findnode (llist_t *list, void *comparison)
|
||
|
{
|
||
|
llist_node_t *node;
|
||
|
|
||
|
if (!list)
|
||
|
return 0;
|
||
|
for (node = list->start; node; node = node->next)
|
||
|
if (list->cmpdata (node->data, comparison, list->userdata))
|
||
|
return node;
|
||
|
return 0;
|
||
|
}
|
||
|
|