Updating HEAD branch #4; Merging CABAL -> HEAD.
[oweals/tinc.git] / lib / list.c
index 5358f1980ad6193b52516c238cd1240915d7556a..ae2385144396ff3bd9eaebd0ccdd677e7a062e72 100644 (file)
@@ -1,7 +1,7 @@
 /*
     list.c -- functions to deal with double linked lists
-    Copyright (C) 2000 Ivo Timmermans <itimmermans@bigfoot.com>
-                  2000 Guus Sliepen <guus@sliepen.warande.net>
+    Copyright (C) 2000,2001 Ivo Timmermans <itimmermans@bigfoot.com>
+                  2000,2001 Guus Sliepen <guus@sliepen.warande.net>
 
     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
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: list.c,v 1.1 2000/10/20 16:44:32 zarq Exp $
+    $Id: list.c,v 1.2 2002/04/09 15:26:00 zarq Exp $
 */
 
 #include "config.h"
 
-#include <string.h>
+#include <stdlib.h>
 
-#include <error.h>
-#include <list.h>
 #include <xalloc.h>
-
 #include <system.h>
 
-/*
-  list_new
+#include "list.h"
 
-  Initialize a new list.
-*/
-list_t *list_new(void)
+/* (De)constructors */
+
+list_t *list_alloc(list_action_t delete)
 {
   list_t *list;
 
   list = xmalloc_and_zero(sizeof(list_t));
+  list->delete = delete;
+
   return list;
 }
 
-/*
-  list_delete
+void list_free(list_t *list)
+{
+  free(list);
+}
 
-  Delete the element pointed to by idx from the list.
-*/
-list_node_t *list_delete(list_t *list, list_node_t *idx)
+list_node_t *list_alloc_node(void)
 {
-  list_node_t *res;
+  list_node_t *node;
   
-  if(!list)
-    return NULL;
-  if(!idx)
-    return NULL;
+  node = xmalloc_and_zero(sizeof(list_node_t));
+  
+  return node;
+}
 
-  if(list->callbacks->delete != NULL)
-    if(list->callbacks->delete(idx->data))
-      error(ERR_WARNING, N_("List callback[delete] failed for %08lx - freeing anyway"), idx->data);
+void list_free_node(list_t *list, list_node_t *node)
+{
+  if(node->data && list->delete)
+    list->delete(node->data);
   
-  free(idx->data);
+  free(node);
+}
+
+/* Insertion and deletion */
+
+list_node_t *list_insert_head(list_t *list, void *data)
+{
+  list_node_t *node;
   
-  if(idx->prev == NULL)
-    /* First element in list */
-    {
-      res = idx->next;
-      list->head = idx->next;
-    }
-  if(idx->next == NULL)
-    /* Last element in list */
-    {
-      res = NULL;
-      list->tail = idx->prev;
-    }
-  if(idx->prev != NULL && idx->next != NULL)
-    /* Neither first nor last element */
-    {
-      idx->prev->next = idx->next;
-      idx->next->prev = idx->prev;
-    }
-  if(list->head == NULL)
-    list->tail = NULL;
+  node = list_alloc_node();
+  
+  node->data = data;
+  node->prev = NULL;
+  node->next = list->head;
+  list->head = node;
+  
+  if(node->next)
+    node->next->prev = node;
   else
-    if(list->tail == NULL)
-      list->head = NULL;
-  free(idx);
-  return res;
+    list->tail = node;
+
+  list->count++;
+
+  return node;
 }
 
-/*
-  list_forall_nodes
+list_node_t *list_insert_tail(list_t *list, void *data)
+{
+  list_node_t *node;
+  
+  node = list_alloc_node();
+  
+  node->data = data;
+  node->next = NULL;
+  node->prev = list->tail;
+  list->tail = node;
+  
+  if(node->prev)
+    node->prev->next = node;
+  else
+    list->head = node;
 
-  Call function() on each element in the list.  If this function
-  returns non-zero, the element will be removed from the list.
-*/
-void list_forall_nodes(list_t *list, int (*function)(void *data))
+  list->count++;
+  
+  return node;
+}
+
+void list_unlink_node(list_t *list, list_node_t *node)
 {
-  list_node_t *p;
-  int res;
+  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--;
+}
+
+void list_delete_node(list_t *list, list_node_t *node)
+{
+  list_unlink_node(list, node);
+  list_free_node(list, node);
+}
+
+void list_delete_head(list_t *list)
+{
+  list_delete_node(list, list->head);
+}
+
+void list_delete_tail(list_t *list)
+{
+  list_delete_node(list, list->tail);
+}
+
+/* Head/tail lookup */
+
+void *list_get_head(list_t *list)
+{
+  if(list->head)
+    return list->head->data;
+  else
+    return NULL;
+}
+
+void *list_get_tail(list_t *list)
+{
+  if(list->tail)
+    return list->tail->data;
+  else
+    return NULL;
+}
+
+/* Fast list deletion */
+
+void list_delete_list(list_t *list)
+{
+  list_node_t *node, *next;
   
-  if(!list)       /* no list given */
-    return;
-  if(!function)   /* no function given */
-    return;
-  if(!list->head) /* list is empty */
-    return;
-  for(p = list->head; p != NULL; p = p->next)
+  for(node = list->head; node; node = next)
     {
-      res = function(p->data);
-      if(res != 0)
-       p = list_delete(list, p);
+      next = node->next;
+      list_free_node(list, node);
     }
+
+  list_free(list);
 }
 
-/*
-  list_destroy
+/* Traversing */
 
-  Free all datastructures contained in this list.  It uses the delete
-  callback for this list to free each element.
-*/
-void list_destroy(list_t *list)
+void list_foreach_node(list_t *list, list_action_node_t action)
 {
-  if(!list)
-    return;
-  list_destroy_nodes(list);
-  free(list);
-}
+  list_node_t *node, *next;
 
-/*
-  list_append
+  for(node = list->head; node; node = next)
+    {
+      next = node->next;
+      action(node);
+    }
+}
 
-  Append a new node to the list that points to data.
-*/
-list_append(list_t *list, void *data)
+void list_foreach(list_t *list, list_action_t action)
 {
-  list_node_t *n;
+  list_node_t *node, *next;
 
-  n = xmalloc_and_zero(sizeof(list_node_t));
-  n->data = data;
-  n->prev = list->tail;
-  list->tail->next = n;
-  list->tail = n;
+  for(node = list->head; node; node = next)
+    {
+      next = node->next;
+      if(node->data)
+        action(node->data);
+    }
 }