Update the manpage as well, and some whitespace to make its source more legible.
[tinc] / lib / list.c
index a09cbea..2f9f611 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-2005 Ivo Timmermans
+                  2000-2006 Guus Sliepen <guus@tinc-vpn.org>
 
     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.2.2 2000/11/16 22:13:08 zarq Exp $
+    $Id$
 */
 
-#include "config.h"
+#include "system.h"
 
-#include <malloc.h>
-#include <string.h>
-#include <syslog.h>
+#include "list.h"
+#include "xalloc.h"
 
-#include <error.h>
-#include <list.h>
-#include <xalloc.h>
+/* (De)constructors */
 
-#include <system.h>
+list_t *list_alloc(list_action_t delete)
+{
+       list_t *list;
 
-/*
-  list_new
+       list = xmalloc_and_zero(sizeof(list_t));
+       list->delete = delete;
 
-  Initialize a new list.
-*/
-list_t *list_new(void)
+       return list;
+}
+
+void list_free(list_t *list)
+{
+       free(list);
+}
+
+list_node_t *list_alloc_node(void)
+{
+       return xmalloc_and_zero(sizeof(list_node_t));
+}
+
+void list_free_node(list_t *list, list_node_t *node)
 {
-  list_t *list;
+       if(node->data && list->delete)
+               list->delete(node->data);
 
-  list = xmalloc_and_zero(sizeof(list_t));
-  return list;
+       free(node);
 }
 
-/*
-  list_delete
+/* Insertion and deletion */
 
-  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_insert_head(list_t *list, void *data)
 {
-  list_node_t *res;
-  
-  if(!list)
-    return NULL;
-  if(!idx)
-    return NULL;
-
-  if(list->callbacks->delete != NULL)
-    if(list->callbacks->delete(idx->data))
-      syslog(LOG_WARNING, _("List callback[delete] failed for %08lx - freeing anyway"), idx->data);
-  
-  free(idx->data);
-  
-  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;
-  else
-    if(list->tail == NULL)
-      list->head = NULL;
-  free(idx);
-  return res;
+       list_node_t *node;
+
+       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
+               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;
 
-  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))
+       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;
+
+       list->count++;
+
+       return node;
+}
+
+void list_unlink_node(list_t *list, list_node_t *node)
 {
-  list_node_t *p;
-  int res;
-  
-  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)
-    {
-      res = function(p->data);
-      if(res != 0)
-       p = list_delete(list, p);
-    }
+       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--;
 }
 
-/*
-  list_destroy
+void list_delete_node(list_t *list, list_node_t *node)
+{
+       list_unlink_node(list, node);
+       list_free_node(list, node);
+}
 
-  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_delete_head(list_t *list)
 {
-  if(!list)
-    return;
-/*  list_destroy_nodes(list); */
-  free(list);
+       list_delete_node(list, list->head);
 }
 
-/*
-  list_append
+void list_delete_tail(list_t *list)
+{
+       list_delete_node(list, list->tail);
+}
 
-  Append a new node to the list that points to data.
-*/
-void list_append(list_t *list, void *data)
+/* 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;
+
+       for(node = list->head; node; node = next) {
+               next = node->next;
+               list_free_node(list, node);
+       }
+
+       list_free(list);
+}
+
+/* Traversing */
+
+void list_foreach_node(list_t *list, list_action_node_t action)
+{
+       list_node_t *node, *next;
+
+       for(node = list->head; node; node = next) {
+               next = node->next;
+               action(node);
+       }
+}
+
+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);
+       }
 }