mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 14:20:59 +00:00
268 lines
4.9 KiB
C
268 lines
4.9 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
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "QF/llist.h"
|
|
|
|
static __attribute__ ((used)) 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE void
|
|
llist_delete (llist_t *list)
|
|
{
|
|
if (!list)
|
|
return;
|
|
|
|
llist_flush (list);
|
|
free (list);
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE unsigned int
|
|
llist_size (llist_t *llist)
|
|
{
|
|
unsigned int i;
|
|
llist_node_t *n;
|
|
|
|
if (!llist->start)
|
|
return 0;
|
|
else for (i = 0, n = llist->start; n; n = n->next, i++);
|
|
|
|
return i;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE 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;
|
|
}
|
|
|
|
VISIBLE llist_node_t *
|
|
llist_findnode (llist_t *list, void *comparison)
|
|
{
|
|
llist_node_t *node;
|
|
|
|
if (!list || !list->cmpdata)
|
|
return 0;
|
|
for (node = list->start; node; node = node->next)
|
|
if (list->cmpdata (node->data, comparison, list->userdata))
|
|
return node;
|
|
return 0;
|
|
}
|
|
|
|
VISIBLE void *
|
|
llist_createarray (llist_t *list, size_t esize)
|
|
{
|
|
void *ptr, *array = malloc (llist_size (list) * esize);
|
|
llist_node_t *node;
|
|
|
|
for (ptr = array, node = list->start; node; node = node->next, ptr = (char*)ptr + esize)
|
|
memcpy (ptr, node->data, esize);
|
|
|
|
return array;
|
|
}
|