/*
 * list.c  -  Single linked list handling routines
 *
 * Copyright (C) 2006-2007 Gero Kuhlmann <gero@gkminix.han.de>
 *
 * This file is based on code which carries the following copyright:
 *
 *       Copyright (C) 2004  Southern Storm Software, Pty Ltd.
 *
 *       Author: Thong Nguyen (tum@veridicus.com)
 *
 * The original code has been released under the GNU General Public
 * License, and has been modified significantly for the use by netboot.
 *
 *
 *  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
 *  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 the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: list.c,v 1.2 2007/01/06 18:31:38 gkminix Exp $
 */

#include <common.h>
#include <nblib.h>



/*
 * Structure holding the data of one single list entry
 */
struct listentry {
	struct listentry *next;
	voidstar          data;
};



/*
 * Structure holding information about the whole list
 */
struct listdef {
	struct listentry *first;
	struct listentry *last;
	listfreecb        freecb;
	int               count;
};



/*
 * Delete a  list entry
 */
static void delentry __F((list, entry),
				struct listdef *list AND
				struct listentry *entry)
{
  if (entry->data != NULL) {
	if (list->freecb == NULL)
		free(entry->data);
	else
		list->freecb((LISTHDL)list, entry->data);
  }
  free(entry);
}



/*
 * Destroy the whole list
 */
void releaselist __F((handle), LISTHDL handle)
{
  struct listdef *list = (struct listdef *)handle;
  struct listentry *entry, *next;

  entry = list->first;
  while (entry) {
	next = entry->next;
	delentry(list, entry);
	entry = next;
  }
  free(list);
}



/*
 * Append a new entry to the list
 */
int appendlist __F((handle, data), LISTHDL handle AND voidstar data)
{
  struct listdef *list = (struct listdef *)handle;
  struct listentry *entry;

  entry = (struct listentry *)nbmalloc(sizeof(struct listentry));
  entry->data = data;
  entry->next = NULL;

  list->count++;
  if (list->last != NULL) {
	list->last->next = entry;
	list->last = entry;
  } else {
	list->first = entry;
	list->last = entry;
  }
  return(list->count - 1);
}



/*
 * Get the data of a list entry through it's index number
 */
voidstar *getatlist __F((handle, index), LISTHDL handle AND int index)
{
  struct listdef *list = (struct listdef *)handle;
  struct listentry *entry;

  if (index < 0 || index >= list->count)
	return(NULL);

  entry = list->first;
  while (entry != NULL) {
	if (index == 0)
		return(&(entry->data));
	entry = entry->next;
	index--;
  }
  return(NULL);
}



/*
 * Find list data and return a pointer to the data pointer
 */
voidstar *findlist __F((handle, data), LISTHDL handle AND voidstar data)
{
  struct listdef *list = (struct listdef *)handle;
  struct listentry *entry;

  entry = list->first;
  while (entry != NULL) {
	if (entry->data == data)
		return(&(entry->data));
	entry = entry->next;
  }
  return(NULL);
}



/*
 * Remove an entry from the list
 */
int removelist __F((handle, data), LISTHDL handle AND voidstar data)
{
  struct listdef *list = (struct listdef *)handle;
  struct listentry *entry, *prev;

  prev = NULL;
  entry = list->first;
  while (entry != NULL) {
	if (entry->data == data) {
		if (prev == NULL)
			list->first = entry->next;
		else
			prev->next = entry->next;
		if (entry->next == NULL)
			list->last = prev;
		delentry(list, entry);
		list->count--;
		return(TRUE);
	}
	prev = entry;
	entry = entry->next;
  }
  return(FALSE);
}



/*
 * Remove an entry from the list through it's index number
 */
int removeatlist __F((handle, index), LISTHDL handle AND int index)
{
  struct listdef *list = (struct listdef *)handle;
  struct listentry *entry, *prev;

  if (index < 0 || index >= list->count)
	return(FALSE);

  prev = NULL;
  entry = list->first;
  while (entry != NULL) {
	if (index == 0) {
		if (prev == NULL)
			list->first = entry->next;
		else
			prev->next = entry->next;
		if (entry->next == NULL)
			list->last = prev;
		delentry(list, entry);
		list->count--;
		return(TRUE);
	}
	prev = entry;
	entry = entry->next;
	index--;
  }
  return(FALSE);
}



/*
 * Walk through all list entries
 */
int walklist __F((handle, callback, state),
				LISTHDL handle AND
				listwalkcb callbackfunc AND
				const voidstar state)
{
  struct listdef *list = (struct listdef *)handle;
  struct listentry *entry;
  int count = 0;

  entry = list->first;
  while (entry != NULL) {		
	if (callbackfunc(handle, &(entry->data), state))
		return(count);
	entry = entry->next;
	count++;
  }
  return(-1);
}



/*
 * Get number of elements in a list
 */
int getcountlist __F((handle), LISTHDL handle)
{
  struct listdef *list = (struct listdef *)handle;

  return(list->count);
}



/*
 * Create a new list
 */
LISTHDL createlist __F((freecb), listfreecb freecb)
{
  struct listdef *list;

  list = (struct listdef *)nbmalloc(sizeof(struct listdef));
  list->count = 0;
  list->first = NULL;
  list->last = NULL;
  list->freecb = freecb;
  return((LISTHDL)list);
}

