/*********************************************************************** gutenfetch - query and fetch electronic texts from Project Gutenberg Copyright (C) 2001, 2002, 2003 Russell Francis 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 the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Last updated on $Date: 2004/03/21 05:14:18 $ by $Author: johntabularasa $. ***********************************************************************/ #include "stddefs.h" #include "list.h" #if (HAVE_ASSERT_H == 1) # include #endif #if (HAVE_STDIO_H == 1) # include #endif #if (HAVE_STDLIB_H == 1) # include #endif #if (HAVE_STRING_H == 1) # include #endif #if (HAVE_STRINGS_H == 1) # include #endif /** * create a list node. * * Create a list node to be used only from list.c. * * @param data The data to store in the node. * @return The list node which was created, will never be NULL. */ static list_t* list_make_node( void *data) { list_t *list = (list_t*)malloc(sizeof(list_t)); if (list == NULL) { fprintf(stderr, _("Unable to allocate %u bytes of memory."), sizeof(list_t)); abort(); } list->next = NULL; list->prev = NULL; list->data = data; return list; } /** * add an item to the front of the list. * * @param list An element of the list which we wish to add * the item to. * @param data The data to prepend to the list. * @return A valid list node. Will never be NULL. */ list_t* list_prepend( list_t *list, void *data) { list_t *ret_list = list_make_node( data ); if (list != NULL) { list = list_first(list); assert( list->prev == NULL ); list->prev = (list_ptr_t)ret_list; ret_list->next = (list_ptr_t)list; } return ret_list; } /** * Append an item to the list. * * @param list A node of the list we wish to append an * item to. * @param data The data we wish to append to the list. * @return A valid list node. This will never be NULL. */ list_t* list_append( list_t *list, void *data) { list_t *ret_list = list_make_node( data ); if (list != NULL) { list = list_last(list); assert ( list->next == NULL ); list->next = (list_ptr_t)ret_list; ret_list->prev = (list_ptr_t)list; } return ret_list; } /** * Get the previous node. * * @param list A list node. * @return The previous node or NULL if none exists. */ list_t* list_previous( list_t *list) { return (list_t*)((list != NULL) ? list->prev : NULL); } /** * Get the next node. * * @param list A list node. * @return The next node or NULL if none exists. */ list_t* list_next( list_t *list) { return (list_t*)((list != NULL) ? list->next : NULL); } /** * Get the first node of the list. * * @param list A list node. * @return The first list node in the list. */ list_t* list_first(list_t *list) { if (list == NULL) return NULL; if (list->prev == NULL) return list; return list_first( (list_t*)list->prev ); } /** * Get the last node in the list. * * @param list A list node. * @return The list node in the list. */ list_t* list_last(list_t *list) { if (list == NULL) return NULL; if (list->next == NULL) return list; return list_last( (list_t*)list->next ); } /** * Destroy a list * * Destroy all nodes in a list and optionally * call a function to destroy the data held in * the list node. * * @param list The list to obliterate. * @param data_destroy_func The function to call * with the list node data as a parameter. * should free all resources held by data. */ void list_remove_all( list_t *list, void (*data_destroy_func)(void*)) { list_t *last_node; list = list_first(list); while (list != NULL) { if ((list->data != NULL) && (data_destroy_func != NULL)) data_destroy_func(list->data); last_node = list; list = (list_t*)list->next; FREE_NULL(last_node); } } /** * Remove the node from the list * * @param list The node we wish to remove from the list. * @param data_destroy_func The function to be called to free the data or NULL * @return A valid node in the list or NULL if the list is empty. */ list_t* list_remove_node(list_t *list, void (*data_destroy_func)(void*)) { list_t *prev, *next; if (list == NULL) return NULL; if (data_destroy_func != NULL) data_destroy_func(list->data); prev = list_previous(list); next = list_next(list); FREE_NULL(list); // update the previous node link if (prev != NULL) { prev->next = (list_ptr_t)next; list = prev; } // update the next node link; if (next != NULL) { next->prev = (list_ptr_t)prev; list = next; } return list; }