/* 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 #endif #ifdef HAVE_STRINGS_H # include #endif #include #include "QF/llist.h" 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; }