Mercurial > audlegacy
diff libvisual/lv_list.c @ 23:0db4a1dc75c4 trunk
[svn] libvisual.
P3 detection appears to be borked. I'll work on it later.
author | nenolod |
---|---|
date | Mon, 24 Oct 2005 23:13:56 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libvisual/lv_list.c Mon Oct 24 23:13:56 2005 -0700 @@ -0,0 +1,453 @@ +/* Libvisual - The audio visualisation framework. + * + * Copyright (C) 2004, 2005 Dennis Smit <ds@nerds-incorporated.org> + * + * List implementation from RCL. + * Copyright (C) 2002, 2003, 2004 + * Dennis Smit <ds@nerds-incorporated.org>, + * Sepp Wijnands <mrrazz@nerds-incorporated.org>, + * Tom Wimmenhove <nohup@nerds-incorporated.org> + * + * Authors: Dennis Smit <ds@nerds-incorporated.org> + * Sepp Wijnands <mrrazz@nerds-incorporated.org>, + * Tom Wimmenhove <nohup@nerds-incorporated.org> + * + * $Id: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> + +#include <lvconfig.h> +#include "lv_list.h" +#include "lv_log.h" +#include "lv_mem.h" + +static int list_dtor (VisObject *object); + +static int list_dtor (VisObject *object) +{ + VisList *list = VISUAL_LIST (object); + + visual_list_destroy_elements (list); + + return VISUAL_OK; +} + +/** + * @defgroup VisList VisList + * @{ + */ + +/** + * Creates a new VisList structure. + * The VisList system is a double linked list implementation. + * + * @return A newly allocated VisList. + */ +VisList *visual_list_new (VisListDestroyerFunc destroyer) +{ + VisList *list; + + list = visual_mem_new0 (VisList, 1); + + /* Do the VisObject initialization */ + visual_object_initialize (VISUAL_OBJECT (list), TRUE, list_dtor); + + list->destroyer = destroyer; + + return list; +} + +/** + * Frees the VisList. This frees the VisList data structure. + * + * @param list Pointer to a VisList that needs to be freed. + * + * @return VISUAL_OK on succes, -VISUAL_ERROR_LIST_NULL or error values returned by + * visual_mem_free () on failure. + */ +int visual_list_free (VisList *list) +{ + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + + return visual_mem_free (list); +} + +/** + * Destroys the entries that are in a list, but not the list itself. It uses the element + * destroyer set at visual_list_new or visual_list_set_destroyer. + * + * @param list Pointer to a VisList of which the elements need to be destroyed. + * + * @return VISUAL_OK on succes, or -VISUAL_ERROR_LIST_NULL on failure. + */ +int visual_list_destroy_elements (VisList *list) +{ + VisListEntry *le = NULL; + void *elem; + + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + + /* Walk through the given list, possibly calling the destroyer for it */ + if (list->destroyer == NULL) { + while ((elem = visual_list_next (list, &le)) != NULL) + visual_list_delete (list, &le); + } else { + while ((elem = visual_list_next (list, &le)) != NULL) { + list->destroyer (elem); + visual_list_delete (list, &le); + } + } + + return VISUAL_OK; +} + +/** + * Sets a VisListEntry destroyer function a VisList. + * + * @param list Pointer to a VisList to which the VisListDestroyerFunc is set. + * @param destroyer The VisListEntry destroyer function. + * + * @return VISUAL_OK on succes, -VISUAL_ERROR_LIST_NULL on failure. + */ +int visual_list_set_destroyer (VisList *list, VisListDestroyerFunc destroyer) +{ + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + + list->destroyer = destroyer; + + return VISUAL_OK; +} + +/** + * Go to the next entry in the list and return it's data element. + * This function will load the next entry in le and return a pointer + * to the data element. + * + * @see visual_list_prev + * + * @param list Pointer to the VisList we're traversing. + * @param le Pointer to a VisListEntry to store the next entry within + * and also to use as a reference to determine at which entry we're + * currently. To begin traversing do: VisListEntry *le = NULL and pass + * it as &le in the argument. + * + * @return The data element of the next entry, or NULL. + */ +void *visual_list_next (VisList *list, VisListEntry **le) +{ + visual_log_return_val_if_fail (list != NULL, NULL); + visual_log_return_val_if_fail (le != NULL, NULL); + + if (*le == NULL) + *le = list->head; + else + *le = (*le)->next; + + if (*le != NULL) + return (*le)->data; + + return NULL; +} + +/** + * Go to the previous entry in the list and return it's data element. + * This function will load the previous entry in le and return a pointer + * to the data element. + * + * @see visual_list_next + * + * @param list Pointer to the VisList we're traversing. + * @param le Pointer to a VisListEntry to store the previous entry within + * and also to use as a reference to determine at which entry we're + * currently. To begin traversing at the end of the list do: + * VisList *le = NULL and pass it as &le in the argument. + * + * @return The data element of the previous entry, or NULL. + */ +void *visual_list_prev (VisList *list, VisListEntry **le) +{ + visual_log_return_val_if_fail (list != NULL, NULL); + visual_log_return_val_if_fail (le != NULL, NULL); + + if (!*le) + *le = list->tail; + else + *le = (*le)->prev; + + if (*le) + return (*le)->data; + + return NULL; +} + +/** + * Get an data entry by index. This will give the pointer to an data + * element based on the index in the list. + * + * @param list Pointer to the VisList of which we want an element. + * @param index Index to determine which entry we want. The index starts at + * 1. + * + * @return The data element of the requested entry, or NULL. + */ +void *visual_list_get (VisList *list, int index) +{ + VisListEntry *le = NULL; + void *data = NULL; + int i, lc; + + visual_log_return_val_if_fail (list != NULL, NULL); + visual_log_return_val_if_fail (index >= 0, NULL); + + lc = visual_list_count (list); + + if (lc - 1 < index) + return NULL; + + for (i = 0; i <= index; i++) { + data = visual_list_next (list, &le); + + if (data == NULL) + return NULL; + } + + return data; +} + +/** + * Adds an entry at the beginning of the list. + * + * @param list Pointer to the VisList to which an entry needs to be added + * at it's head. + * @param data A pointer to the data that needs to be added to the list. + * + * @return VISUAL_OK on succes, -VISUAL_ERROR_LIST_NULL on failure. + */ +int visual_list_add_at_begin (VisList *list, void *data) +{ + VisListEntry *current, *next; + + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + + /* Allocate memory for new list entry */ + current = visual_mem_new0 (VisListEntry, 1); + + /* Assign data element */ + current->data = data; + + if (list->head == NULL) { + list->head = current; + list->tail = current; + } else { + next = list->head; + + current->next = next; + list->head = current; + } + + /* Done */ + list->count++; + + return VISUAL_OK; +} + +/** + * Adds an entry at the end of the list. + * + * @param list Pointer to the VisList to which an entry needs to be added + * at it's tail. + * @param data A pointer to the data that needs to be added to the list. + * + * @return VISUAL_OK on succes, -VISUAL_ERROR_LIST_NULL on failure. + */ +int visual_list_add (VisList *list, void *data) +{ + VisListEntry *current, *prev; + + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + + current = visual_mem_new0 (VisListEntry, 1); + + /* Assign data element */ + current->data = data; + + /* Add list entry to list */ + /* Is this the first entry for this list ? */ + if (list->head == NULL) { + list->head = current; + list->tail = current; + } else { + /* Nope, add to tail of this list */ + prev = list->tail; + + /* Exchange pointers */ + prev->next = current; + current->prev = prev; + + /* Point tail to new entry */ + list->tail = current; + } + + /* Done */ + list->count++; + + return VISUAL_OK; +} + +/** + * Insert an entry in the middle of a list. By adding it + * after the le entry. + * + * @param list Pointer to the VisList in which an entry needs to be inserted. + * @param le Pointer to a VisListEntry after which the entry needs to be inserted. + * @param data Pointer to the data the new entry represents. + * + * @return VISUAL_OK on succes, -VISUAL_ERROR_LIST_NULL, -VISUAL_ERROR_LIST_ENTRY_NULL or + * -VISUAL_ERROR_NULL on failure. + */ +int visual_list_insert (VisList *list, VisListEntry **le, void *data) +{ + VisListEntry *prev, *next, *current; + + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + visual_log_return_val_if_fail (le != NULL, -VISUAL_ERROR_LIST_ENTRY_NULL); + visual_log_return_val_if_fail (data != NULL, -VISUAL_ERROR_NULL); + + current = visual_mem_new0 (VisListEntry, 1); + + /* Assign data element */ + current->data = data; + + /* Add entry to list */ + if (list->head == NULL && *le == NULL) { + /* First entry */ + list->head = current; + list->tail = current; + } else if (*le == NULL) { + /* Insert entry at first position */ + next = list->head; + /* Exchange pointers */ + current->next = next; + next->prev = current; + /* Point head to current pointer */ + list->head = current; + } else { + /* Insert entry at *le's position */ + prev = *le; + next = prev->next; + + current->prev = prev; + current->next = next; + + prev->next = current; + if (next != NULL) + next->prev = current; + else + list->tail = current; + } + + /* Hop to new entry */ + *le = current; + + /* Done */ + list->count++; + + return VISUAL_OK; +} + +/** + * Removes an entry from the list. + * + * @param list A pointer to the VisList in which an entry needs to be deleted. + * @param le A pointer to the entry that needs to be deleted. + * + * @return VISUAL_OK on succes, -VISUAL_ERROR_LIST_NULL or -VISUAL_ERROR_LIST_ENTRY_NULL on failure. + */ +int visual_list_delete (VisList *list, VisListEntry **le) +{ + VisListEntry *prev, *current, *next; + + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + visual_log_return_val_if_fail (le != NULL, -VISUAL_ERROR_LIST_ENTRY_NULL); + + prev = current = next = NULL; + + /* Valid list entry ? */ + if (*le == NULL) { + visual_log (VISUAL_LOG_CRITICAL, "There is no list entry to delete"); + + return -VISUAL_ERROR_LIST_ENTRY_INVALID; /* Nope */ + } + + /* Point new to le's previous entry */ + current = *le; + prev = current->prev; + next = current->next; + + /* Does it have a previous entry ? */ + if (prev != NULL) + prev->next = next; + else + list->head = next; + + if (next != NULL) /* It does have a next entry ? */ + next->prev = prev; + else + list->tail = prev; + + /* Point current entry to previous one */ + *le = prev; + + /* Free 'old' pointer */ + list->count--; + visual_mem_free (current); + + return VISUAL_OK; +} + +/** + * Counts the number of entries within the list. + * + * @param list A pointer to the list from which an entry count is needed. + * + * @return The number of elements or -VISUAL_ERROR_LIST_NULL on failure. + */ +int visual_list_count (VisList *list) +{ + VisListEntry *le = NULL; + int count = 0; + + visual_log_return_val_if_fail (list != NULL, -VISUAL_ERROR_LIST_NULL); + + /* Walk through list */ + while (visual_list_next (list, &le) != NULL) + count++; + + list->count = count; + + return count; +} + +/** + * @} + */ +