/* $Id: llist.c 295 2005-12-16 19:44:24Z tsaviran $
 * -------------------------------------------------------
 * Copyright (C) 2002-2005 Tommi Saviranta <wnd@iki.fi>
 *	(C) 2002 Lee Hardy <lee@leeh.co.uk>
 * * -------------------------------------------------------
 * 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.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* ifdef HAVE_CONFIG_H */

#include "llist.h"
#include "common.h"



/*
 * Create a new node with no links to other nodes.
 *
 * Return pointer to this node.
 */
llist_node *
llist_create(void *data)
{
	llist_node	*node;

	node = (llist_node *) xmalloc(sizeof(llist_node));
	node->data = data;
	/*
	 * Basically we wouldn't have to do this...
	node->next = NULL;
	node->prev = NULL;
	 */

	return node;
} /* llist_node *llist_create(void *data) */



/*
 * Add node to the beginning of the list.
 */
void
llist_add(llist_node *node, llist_list *list)
{
	/* New node has no previous node. */
	node->next = list->head;
	node->prev = NULL;

	if (list->head != NULL) {
		list->head->prev = node;
	} else if (list->tail == NULL) {
		list->tail = node;
	}

	list->head = node;
} /* void llist_add(llist_node *node, llist_list *list) */



/*
 * Add node to the end of list.
 */
void
llist_add_tail(llist_node *node, llist_list *list)
{
	node->next = NULL;
	node->prev = list->tail;
  
	if (list->head == NULL) {
		list->head = node;
	} else if (list->tail != NULL) {
		list->tail->next = node;
	}

	list->tail = node;
} /* void llist_add_tail(llist_node *node, llist_list *list) */



/*
 * Delete links to node and free memory allocated by node.
 *
 * Note that user _must_ free memory that was possibly allocated in
 * node->data.
 */
void
llist_delete(llist_node *node, llist_list *list)
{
	/* Item is at head. */
	if (node->prev == NULL) {
		list->head = node->next;
	} else {
		node->prev->next = node->next;
	}

	/* Item is at tail. */
	if (node->next == NULL) {
		list->tail = node->prev;
	} else {
		node->next->prev = node->prev;
	}

	/*
	 * Free some resources. Use _must_ free m->data _before_ calling
	 * llist_delete.
	 */
	xfree(node);
} /* void llist_delete(llist_node *node, llist_list *list) */



/*
 * Find node that points to data.
 *
 * Return pointer to this node.
 */
llist_node *
llist_find(void *data, llist_list *list)
{
	llist_node	*ptr;

	for (ptr = list->head; ptr; ptr = ptr->next) {
		if (ptr->data == data) {
			return ptr;
		}
	}
	
	return NULL;
} /* llist_node *llist_find(void *data, llist_list *list) */



#ifdef OBSOLETE	/* Ignore this. */
/*
 * We don't want to use this - it just takes more space that doind it by
 * hand time after time.
 */
void
llist_empty(llist_list *list, void (* action) (void *))
{
	llist_node	*node = list->head;
	llist_node	*nextnode;

	while (node != NULL) {
		nextnode = node->next;
		action(node->data);
		llist_delete(node, list);
		node = nextnode;
	}
} /* void llist_empty(llist_list *list, void (* action) (void *) */



llist_node **
llist_get_indexed(const llist_list *list)
{
	llist_node	**ret = xmalloc(sizeof(llist_node *));
	llist_node	*ptr = list->head;
	int		size = 0;

	do {
		if (ptr != NULL) {
			ret = xrealloc(ret, sizeof(llist_node *) * (size + 2));
			ret[size] = ptr;
			size++;
			ptr = ptr->next;
		}
		ret[size] = NULL;
	} while (ptr != NULL);

	return ret;
} /* llist_node **llist_get_indexed(const llist_list *list) */
#endif /* OBSOLETE */


syntax highlighted by Code2HTML, v. 0.9.1