/*************************************************************************** list.c - description ------------------- begin : Sun Sep 2 2001 copyright : (C) 2001 by Michael Speck email : kulkanie@gmx.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 * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "list.h" /* ==================================================================== Create a new list auto_delete: Free memory of data pointer when deleting entry callback: Use this callback to free memory of data including the data pointer itself. Return Value: List pointer ==================================================================== */ List *list_create( int auto_delete, void (*callback)(void*) ) { List *list = calloc( 1, sizeof( List ) ); list->head = calloc( 1, sizeof( ListEntry ) ); list->tail = calloc( 1, sizeof( ListEntry ) ); list->head->next = list->tail; list->head->prev = list->head; list->tail->next = list->tail; list->tail->prev = list->head; list->auto_delete = auto_delete; list->callback = callback; list->cur_entry = list->head; return list; } /* ==================================================================== Delete list and entries. ==================================================================== */ void list_delete( List *list ) { list_clear( list ); free( list->head ); free( list->tail ); free( list ); } /* ==================================================================== Delete all entries but keep the list. Reset current_entry to head pointer. ==================================================================== */ void list_clear( List *list ) { while( !list_empty( list ) ) list_delete_pos( list, 0 ); } /* ==================================================================== Insert new item at position. Return Value: True if successful else False. ==================================================================== */ int list_insert( List *list, void *item, int pos ) { int i; ListEntry *cur = list->head; ListEntry *new_entry = 0; /* check if insertion possible */ if ( pos < 0 || pos > list->count ) return 0; if ( item == 0 ) return 0; /* get to previous entry */ for (i = 0; i < pos; i++) cur = cur->next; /* create and anchor new entry */ new_entry = calloc( 1, sizeof( ListEntry ) ); new_entry->item = item; new_entry->next = cur->next; new_entry->prev = cur; cur->next->prev = new_entry; cur->next = new_entry; list->count++; return 1; } /* ==================================================================== Add new item at the end of the list. ==================================================================== */ int list_add( List *list, void *item ) { ListEntry *new_entry = 0; /* check if insertion possible */ if ( item == 0 ) return 0; /* create and anchor new entry */ new_entry = calloc( 1, sizeof( ListEntry ) ); new_entry->item = item; new_entry->next = list->tail; new_entry->prev = list->tail->prev; list->tail->prev->next = new_entry; list->tail->prev = new_entry; list->count++; return 1; } /* ==================================================================== Delete item at position. If this was the current entry update current_entry to valid previous pointer. Return Value: True if successful else False. ==================================================================== */ int list_delete_pos( List *list, int pos ) { int i; ListEntry *cur = list->head; /* check if deletion possbile */ if ( list_empty( list ) ) return 0; if ( pos < 0 || pos >= list->count ) return 0; /* get to correct entry */ for ( i = 0; i <= pos; i++ ) cur = cur->next; /* modify anchors */ cur->next->prev = cur->prev; cur->prev->next = cur->next; /* decrease counter */ list->count--; /* check current_entry */ if ( list->cur_entry == cur ) list->cur_entry = list->cur_entry->prev; /* free memory */ if ( list->auto_delete ) { if ( list->callback ) (list->callback)( cur->item ); else free( cur->item ); } free( cur ); return 1; } /* ==================================================================== Delete item if in list. If this was the current entry update current_entry to valid previous pointer. Return Value: True if successful else False. ==================================================================== */ int list_delete_item( List *list, void *item ) { return list_delete_pos( list, list_check( list, item ) ); } /* ==================================================================== Delete entry. Return Value: True if successful else False. ==================================================================== */ int list_delete_entry( List *list, ListEntry *entry ) { /* delete possible? */ if ( entry == 0 ) return 0; if ( list->count == 0 ) return 0; if ( entry == list->head || entry == list->tail ) return 0; /* adjust anchor and counter */ entry->prev->next = entry->next; entry->next->prev = entry->prev; list->count--; /* check current_entry */ if ( list->cur_entry == entry ) list->cur_entry = list->cur_entry->prev; /* free memory */ if ( list->auto_delete ) { if ( list->callback ) (list->callback)( entry->item ); else free( entry->item ); } free( entry ); return 1; } /* ==================================================================== Get item from position if in list. Return Value: Item pointer if found else Null pointer. ==================================================================== */ void* list_get( List *list, int pos ) { int i; ListEntry *cur = list->head; if ( pos < 0 || pos >= list->count ) return 0; for ( i = 0; i <= pos; i++ ) cur = cur->next; return cur->item; } /* ==================================================================== Check if item's in list. Return Value: Position of item else -1. ==================================================================== */ int list_check( List *list, void *item ) { int pos = -1; ListEntry *cur = list->head->next; while ( cur != list->tail ) { pos++; if ( cur->item == item ) break; cur = cur->next; } if ( cur == list->tail ) pos = -1; /* item not found */ return pos; } /* ==================================================================== Return first item stored in list and set current_entry to this entry. Return Value: Item pointer if found else Null pointer. ==================================================================== */ void* list_first( List *list ) { list->cur_entry = list->head->next; return list->head->next->item; } /* ==================================================================== Return last item stored in list and set current_entry to this entry. Return Value: Item pointer if found else Null pointer. ==================================================================== */ void* list_last( List *list ) { list->cur_entry = list->tail->prev; return list->tail->prev->item; } /* ==================================================================== Return item in current_entry. Return Value: Item pointer if found else Null pointer. ==================================================================== */ void* list_current( List *list ) { return list->cur_entry->item; } /* ==================================================================== Reset current_entry to head of list. ==================================================================== */ void list_reset( List *list ) { list->cur_entry = list->head; } /* ==================================================================== Get next item and update current_entry (reset if tail reached) Return Value: Item pointer if found else Null (if tail of list). ==================================================================== */ void* list_next( List *list ) { list->cur_entry = list->cur_entry->next; if ( list->cur_entry == list->tail ) list_reset( list ); return list->cur_entry->item; } /* ==================================================================== Get previous item and update current_entry. Return Value: Item pointer if found else Null (if head of list). ==================================================================== */ void* list_prev( List *list ) { list->cur_entry = list->cur_entry->prev; return list->cur_entry->item; } /* ==================================================================== Delete the current entry if not tail or head. This is the entry that contains the last returned item by list_next/prev(). Return Value: True if it was a valid deleteable entry. ==================================================================== */ int list_delete_current( List *list ) { if ( list->cur_entry == 0 || list->cur_entry == list->head || list->cur_entry == list->tail ) return 0; list_delete_entry( list, list->cur_entry ); return 1; } /* ==================================================================== Check if list is empty. Return Value: True if list counter is 0 else False. ==================================================================== */ int list_empty( List *list ) { return list->count == 0; } /* ==================================================================== Return entry containing the passed item. Return Value: True if entry found else False. ==================================================================== */ ListEntry *list_entry( List *list, void *item ) { ListEntry *entry = list->head->next; while ( entry != list->tail ) { if ( entry->item == item ) return entry; entry = entry->next; } return 0; } /* ==================================================================== Transfer an entry from one list to another list by removing from 'source' and adding to 'dest' thus if source does not contain the item this is equvalent to list_add( dest, item ). ==================================================================== */ void list_transfer( List *source, List *dest, void *item ) { int old_auto_flag; /* add to destination */ list_add( dest, item ); /* as the pointer is added to dest without changes only the empty entry must be deleted in source */ old_auto_flag = source->auto_delete; source->auto_delete = LIST_NO_AUTO_DELETE; list_delete_item( source, item ); source->auto_delete = old_auto_flag; } /* ==================================================================== Deqeue the first list entry. (must not use auto_delete therefore) ==================================================================== */ void *list_dequeue( List *list ) { void *item; if ( list->count > 0 ) { item = list->head->next->item; list_delete_pos( list, 0 ); return item; } else return 0; }