Files
lcdproc/shared/LL.c
T

978 lines
19 KiB
C
Raw Normal View History

2008-11-28 10:48:39 +00:00
/** \file LL.c
* Define routines to deal with doubly linked lists
*/
/* This file is part of LCDproc.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright(c) 1999, William Ferrell
* (c) 2000, Guillaume Filion
* (c) 2001, Joris Robijn
* (c) 2008, Peter Marschall
*
*/
1999-12-09 23:15:14 +00:00
#include <stdlib.h>
#include <stdio.h>
#include "LL.h"
#ifdef DEBUG
#undef DEBUG
#endif
//TODO: Test everything?
2008-11-28 10:48:39 +00:00
/** Create new linked list.
* \return Pointer to freshly created list object; \c NULL on error.
2008-11-28 10:48:39 +00:00
*/
LinkedList *
LL_new(void)
1999-12-09 23:15:14 +00:00
{
LinkedList *list;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
list = malloc(sizeof(LinkedList));
if (list == NULL)
2000-04-03 22:13:57 +00:00
return NULL;
2000-04-03 22:13:57 +00:00
list->head.data = NULL;
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.data = NULL;
list->tail.prev = &list->head;
list->tail.next = NULL;
list->current = &list->head;
2000-04-03 22:13:57 +00:00
return list;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Destroy the entire list.
*
* Note: this does not free the data, only the list itself
*
* \param list List object to be destroyed.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_Destroy(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *node, *next;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
2000-04-03 22:13:57 +00:00
node = &list->head;
2000-04-03 22:13:57 +00:00
for (node = node->next; node && node->next; node = next) {
// Avoid accessing "node" after it's freed.. :)
next = node->next;
2008-11-28 10:48:39 +00:00
if (LL_node_Destroy(node) < 0)
2000-04-03 22:13:57 +00:00
return -1;
}
2008-11-28 10:48:39 +00:00
free(list);
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Destroy a node.
*
* Warning! This does not assert that the node data is free!
*
* \param node Node to be destroyed.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_node_Destroy(LL_node *node)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!node)
return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (LL_node_Unlink(node) < 0)
2000-04-03 22:13:57 +00:00
return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
free(node);
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Unlink a node from the list.
* \param node Node to be unlinked.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_node_Unlink(LL_node *node)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *next, *prev;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!node)
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
next = node->next;
prev = node->prev;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (next)
next->prev = prev;
if (prev)
prev->next = next;
2000-04-03 22:13:57 +00:00
node->next = NULL;
node->prev = NULL;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Free the data in a list node.
* \param node Node, whose data is to be destroyed.
* \retval <0 error: illegal node, or no node data to destroy.
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_node_DestroyData(LL_node *node)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!node)
return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (node->data) {
free(node->data);
// prevent accidential double free()
node->data = NULL;
}
2000-04-03 22:13:57 +00:00
else
return -1;
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/* Return to the beginning of the list.
* Set list's "current" pointer to the first node in the list.
* \param list List object.
* \retval <0 error: no list given
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_Rewind(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (list->head.next != &list->tail)
list->current = list->head.next;
else
list->current = &list->head;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Jump to the end of the list.
* Set list's "current" pointer to the last node in the list.
* \param list List object.
* \retval <0 error: no list given
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_End(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (list->tail.prev != &list->head)
list->current = list->tail.prev;
else
list->current = &list->tail;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Go to the next node of the list.
* Advance list's "current" pointer to the next node in the list.
* \param list List object.
* \retval <0 error: no list given or no next node
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_Next(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!list->current)
return -1;
2000-04-03 22:13:57 +00:00
if (list->current->next != &list->tail) {
list->current = list->current->next;
return 0;
} else {
return -1;
}
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Go to the previous node of the list.
* Set list's "current" pointer to the previous node in the list.
* \param list List object.
* \retval <0 error: no list given or no previous node
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_Prev(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!list->current)
return -1;
2000-04-03 22:13:57 +00:00
if (list->current->prev != &list->head) {
list->current = list->current->prev;
return 0;
} else {
return -1;
}
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Access current node's data.
* \param list List object.
* \retval <0 error: no list given, or no data in current node
* \retval 0 success
*/
void *
2008-11-28 10:48:39 +00:00
LL_Get(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
if (!list->current)
return NULL;
2000-04-03 22:13:57 +00:00
return list->current->data;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Set/change current node's data.
* \param list List object.
* \param data Pointer to data to be set.
* \retval <0 error: no list given, or no current node
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_Put(LinkedList *list, void *data)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!list->current)
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
list->current->data = data;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Get current node in list.
* \param list List object.
* \return Pointer to current node.
*/
LL_node *
2008-11-28 10:48:39 +00:00
LL_GetNode(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return list->current;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Set list's current pointr to a specific node.
*
* Warning: Don't use this unless you know what you're doing.
*
* \param list List object.
* \param list List object.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_PutNode(LinkedList *list, LL_node *node)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!node)
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
list->current = node;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Access list's first node's data.
* Set list's "current" pointer to the first node and return its data.
* \param list List object.
* \return Pointer to first node's data; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_GetFirst(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_Rewind(list))
2000-04-03 22:13:57 +00:00
return NULL;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
return LL_Get(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Access next node's data.
* Advance list's "current" pointer to the next node and return its data.
* \param list List object.
* \return Pointer to next node's data; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_GetNext(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_Next(list))
2000-04-03 22:13:57 +00:00
return NULL;
2008-11-28 10:48:39 +00:00
return LL_Get(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Access previous node's data.
* Set list's "current" pointer to the previous node, and return its data.
* \param list List object.
* \return Pointer to previous node's data; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_GetPrev(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_Prev(list))
2000-04-03 22:13:57 +00:00
return NULL;
2008-11-28 10:48:39 +00:00
return LL_Get(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Access list's last node's data.
* Set list's "current" pointer to the last node and return its data.
* \param list List object.
* \return Pointer to last node's data; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_GetLast(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_End(list))
2000-04-03 22:13:57 +00:00
return NULL;
2008-11-28 10:48:39 +00:00
return LL_Get(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Add/append a new node after current one in the list.
* \param list List object.
* \param add Pointer to new node's data.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_AddNode(LinkedList *list, void *add)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *node;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
//if(!add) return -1; // Nevermind.. NULL entries can be good...
if (!list->current)
return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
node = malloc(sizeof(LL_node));
if (node == NULL)
2000-04-03 22:13:57 +00:00
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (list->current == &list->tail) {
list->current = list->current->prev;
}
// Set node data
2000-04-03 22:13:57 +00:00
node->next = list->current->next;
node->prev = list->current;
node->data = add;
// Re-link
2000-04-03 22:13:57 +00:00
if (node->next)
node->next->prev = node;
2000-04-03 22:13:57 +00:00
list->current->next = node;
2000-04-03 22:13:57 +00:00
list->current = node;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Add/insert a new node before current one in the list.
* \param list List object.
* \param add Pointer to new node's data.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_InsertNode(LinkedList *list, void *add)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *node;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!add)
return -1;
if (!list->current)
return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
node = malloc(sizeof(LL_node));
if (node == NULL)
2000-04-03 22:13:57 +00:00
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (list->current == &list->head)
list->current = list->current->next;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
node->next = list->current;
node->prev = list->current->prev;
node->data = add;
2000-04-03 22:13:57 +00:00
if (list->current->prev)
list->current->prev->next = node;
2000-04-03 22:13:57 +00:00
list->current->prev = node;
2000-04-03 22:13:57 +00:00
list->current = node;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
/** Remove current node from the list.
* Set the current pointer to the node after the deleted one.
* \param list List object.
* \return Pointer to data of deleted node; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_DeleteNode(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *next, *prev;
void *data;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
if (!list->current)
return NULL;
if (list->current == &list->head)
return NULL;
if (list->current == &list->tail)
return NULL;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
next = list->current->next;
prev = list->current->prev;
data = list->current->data;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (prev)
prev->next = next;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (next)
next->prev = prev;
2000-04-03 22:13:57 +00:00
list->current->prev = NULL;
list->current->next = NULL;
// This should not free things; the user should do it explicitly.
//if(list->current->data) free(list->current->data);
list->current->data = NULL;
2008-11-28 10:48:39 +00:00
free(list->current);
2000-04-03 22:13:57 +00:00
list->current = next;
2000-04-03 22:13:57 +00:00
return data;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Remove a specific node from the list.
* Find a node by a pointer to its data and remove it.
* After te deletion the "current" pointer is on the node after the deleted one.
2008-11-28 10:48:39 +00:00
* \param list List object.
* \param data Pointer to data of node to delete.
2008-11-28 10:48:39 +00:00
* \return Pointer to data of deleted node; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_Remove(LinkedList *list, void *data)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
2008-11-28 10:48:39 +00:00
LL_Rewind(list);
2000-04-03 22:13:57 +00:00
do {
void * find = LL_Get(list);
2000-04-03 22:13:57 +00:00
if (find == data)
2008-11-28 10:48:39 +00:00
return LL_DeleteNode(list);
} while (LL_Next(list) == 0);
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return NULL;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Add/append a new node after the last one in the list.
* Jump to the last node in the list and append a new node.
* \param list List object.
* \param add Pointer to new node's data.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_Push(LinkedList *list, void *add) // Add node to end of list
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!add)
return -1;
2008-11-28 10:48:39 +00:00
LL_End(list);
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
return LL_AddNode(list, add);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Remove the last node from the list, and return its data.
* Jump to the last node in the list, remove it from the list and return its data.
* \param list List object.
* \return Pointer to data of deleted node; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_Pop(LinkedList *list) // Remove node from end of list
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
2008-11-28 10:48:39 +00:00
if (0 > LL_End(list))
2000-04-03 22:13:57 +00:00
return NULL;
2008-11-28 10:48:39 +00:00
return LL_DeleteNode(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Access list's last node's data.
* Set list's "current" pointer to the last node and return its data.
* \param list List object.
* \return Pointer to last node's data; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_Top(LinkedList *list) // Peek at end node
1999-12-09 23:15:14 +00:00
{
2008-11-28 10:48:39 +00:00
return LL_GetLast(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Remove the first node from the list, and return its data.
* Jump to the first node in the list, remove it from the list and return its data.
* \param list List object.
* \return Pointer to data of deleted node; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_Shift(LinkedList *list) // Remove node from start of list
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_Rewind(list))
2000-04-03 22:13:57 +00:00
return NULL;
2008-11-28 10:48:39 +00:00
return LL_DeleteNode(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Access list's first node's data.
* Set list's "current" pointer to the first node and return its data.
* \param list List object.
* \return Pointer to first node's data; \c NULL on error.
*/
void *
2008-11-28 10:48:39 +00:00
LL_Look(LinkedList *list) // Peek at first node
1999-12-09 23:15:14 +00:00
{
2008-11-28 10:48:39 +00:00
return LL_GetFirst(list);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Add/insert a new node before the first one in the list.
* Jump to the first node in the list and insert a new node before that one.
* \param list List object.
* \param add Pointer to new node's data.
* \retval <0 error
* \retval 0 success
*/
int
2008-11-28 10:48:39 +00:00
LL_Unshift(LinkedList *list, void *add) // Add node to beginning of list
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!add)
return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
LL_Rewind(list);
2008-11-28 10:48:39 +00:00
return LL_InsertNode(list, add);
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
1999-12-09 23:15:14 +00:00
//////////////////////////////////////////////////////////////////////
int
2008-11-28 10:48:39 +00:00
LL_Roll(LinkedList *list) // Make last node first
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *node, *next;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
//if(!list->current) return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_End(list))
2000-04-03 22:13:57 +00:00
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
// Avoid rolling an empty list, or unlinking the head/tail...
if (list->current == &list->head)
list->current = list->current->next;
if (list->current == &list->tail)
list->current = list->current->prev;
// List is empty
if (list->current == &list->head)
return 0;
// List has one item
if (list->current->prev == &list->head)
return 0;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
node = list->current;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
LL_node_Unlink(node);
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_Rewind(list))
2000-04-03 22:13:57 +00:00
return -1;
2000-04-03 22:13:57 +00:00
next = list->head.next;
2000-04-03 22:13:57 +00:00
list->head.next = node;
next->prev = node;
node->prev = &list->head;
node->next = next;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
1999-12-09 23:15:14 +00:00
//////////////////////////////////////////////////////////////////////
int
2008-11-28 10:48:39 +00:00
LL_UnRoll(LinkedList *list) // Roll the other way...
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *node, *prev;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
//if(!list->current) return -1;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_Rewind(list))
2000-04-03 22:13:57 +00:00
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
// Avoid rolling an empty list, or unlinking the head/tail...
if (list->current == &list->tail)
list->current = list->current->prev;
if (list->current == &list->head)
list->current = list->current->next;
// List is empty
if (list->current == &list->tail)
return 0;
// List has one item
if (list->current->next == &list->tail)
return 0;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
node = list->current;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
LL_node_Unlink(node);
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
if (0 > LL_End(list))
2000-04-03 22:13:57 +00:00
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
prev = list->tail.prev;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
list->tail.prev = node;
prev->next = node;
node->next = &list->tail;
node->prev = prev;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
1999-12-09 23:15:14 +00:00
//////////////////////////////////////////////////////////////////////
// Add an item to the end of its "priority group"
// The list is assumed to be sorted already...
int
2008-11-28 10:48:39 +00:00
LL_PriorityEnqueue(LinkedList *list, void *add, int compare(void *, void *))
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
void *data;
int i;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!add)
return -1;
if (!compare)
return -1;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
// From the end of the list, keep searching while we're "less than"
// the given nodes...
2008-11-28 10:48:39 +00:00
LL_End(list);
2000-04-03 22:13:57 +00:00
do {
2008-11-28 10:48:39 +00:00
data = LL_Get(list);
2000-04-03 22:13:57 +00:00
if (data) {
2008-11-28 10:48:39 +00:00
i = compare(add, data);
2000-04-03 22:13:57 +00:00
if (i >= 0) // If we're in the right place, add it and exit
{
2008-11-28 10:48:39 +00:00
LL_AddNode(list, add);
2000-04-03 22:13:57 +00:00
return 0;
}
}
2008-11-28 10:48:39 +00:00
} while (LL_Prev(list) == 0);
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
// If we're less than *everything*, put it at the beginning
2008-11-28 10:48:39 +00:00
LL_Unshift(list, add);
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
1999-12-09 23:15:14 +00:00
//////////////////////////////////////////////////////////////////////
int
2008-11-28 10:48:39 +00:00
LL_SwapNodes(LL_node *one, LL_node *two) // Switch two nodes positions...
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *firstprev, *firstnext;
LL_node *secondprev, *secondnext;
2000-04-03 22:13:57 +00:00
if (!one || !two)
return -1;
if (one == two)
return 0; // Do nothing
2000-04-03 22:13:57 +00:00
firstprev = one->prev; // Look up the nodes neighbors...
firstnext = one->next;
secondprev = two->prev;
secondnext = two->next;
2000-04-03 22:13:57 +00:00
if (firstprev != NULL)
firstprev->next = two; // Swap the neighboring
if (firstnext != NULL)
firstnext->prev = two; // nodes pointers...
if (secondprev != NULL)
secondprev->next = one;
if (secondprev != NULL)
secondnext->prev = one;
2000-04-03 22:13:57 +00:00
one->next = secondnext; // Swap the nodes pointers
one->prev = secondprev;
two->next = firstnext;
two->prev = firstprev;
2000-04-03 22:13:57 +00:00
if (firstnext == two)
one->prev = two; // Fix things in case
if (firstprev == two)
one->next = two; // they were next to
if (secondprev == one)
two->next = one; // each other...
if (secondnext == one)
two->prev = one;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
1999-12-09 23:15:14 +00:00
//////////////////////////////////////////////////////////////////////
int
2008-11-28 10:48:39 +00:00
LL_nSwapNodes(int one, int two) // Switch two nodes positions...
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
return -1;
}
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
/** Calculate the length of a list.
* \param list List object.
* \return Number of nodes in the list; \c -1 on error.
*/
int
LL_Length(LinkedList *list)
{
2000-04-03 22:13:57 +00:00
LL_node *node;
int num = 0;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
2000-04-03 22:13:57 +00:00
node = &list->head;
2000-04-03 22:13:57 +00:00
for (num = -1; node != &list->tail; num++)
node = node->next;
2000-04-03 22:13:57 +00:00
return num;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
/** Find a node by giving a comparison function and a value.
* Go to to the list node whose data matches the given value
* and return the data.
*
* Note that this does *not* rewind the list first!
* Do it yourself if you want to start from the beginning!
*
* \param list List object.
* \param compare Pointer to a comparison function, that takes to void pointers
* is arguments and returns an int. If must return 0 exactly when
* the node's data matches \c value.
* \param value Pointer to the value used for matching.
* \return The found node's data pointer; \c NULL otherwise
*/
void *
2008-11-28 10:48:39 +00:00
LL_Find(LinkedList *list, int compare(void *, void *), void *value)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
void *data;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return NULL;
if (!compare)
return NULL;
if (!value)
return NULL;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
do {
2008-11-28 10:48:39 +00:00
data = LL_Get(list);
if (0 == compare(data, value))
2000-04-03 22:13:57 +00:00
return data;
2008-11-28 10:48:39 +00:00
} while (LL_Next(list) == 0);
2000-04-03 22:13:57 +00:00
return NULL;
1999-12-09 23:15:14 +00:00
}
2008-11-28 10:48:39 +00:00
2002-05-26 19:21:23 +00:00
//////////////////////////////////////////////////////////////////////
// Array like...
// Goes to the nth list item, and returns the
// data found there.
//
void *
2008-11-28 10:48:39 +00:00
LL_GetByIndex(LinkedList *list, int index)
2002-05-26 19:21:23 +00:00
{
LL_node *node;
int num = 0;
if (!list)
return NULL;
if (index<0)
return NULL;
for (node = list->head.next; node != &list->tail; node = node->next) {
if (num == index)
return node->data;
num ++;
}
return NULL; // got past the end
}
2008-11-28 10:48:39 +00:00
/** Sort list by its contents.
* The list gets sorted using a comparison function for the data of its nodes.
* After the sorting, the list's current pointer is set to the first node.
* \param list List object.
* \param compare Pointer to a comparison function, that takes to void pointers
* is arguments and returns an int > 0 when the first argument
* is considered greater then the second.
2008-11-28 10:48:39 +00:00
* \retval <0 error
* \retval 0 success.
*/
int
2008-11-28 10:48:39 +00:00
LL_Sort(LinkedList *list, int compare(void *, void *))
1999-12-09 23:15:14 +00:00
{
int i, j; // Junk / loop variables
int numnodes; // number of nodes in list
2000-04-03 22:13:57 +00:00
LL_node *best, *last; // best match and last node in the list
LL_node *current;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!list)
return -1;
if (!compare)
return -1;
2008-11-28 10:48:39 +00:00
numnodes = LL_Length(list); // get the number of nodes...
if (0 > LL_End(list))
return -1; // Find the last node.
2008-11-28 10:48:39 +00:00
last = LL_GetNode(list);
2000-04-03 22:13:57 +00:00
if (numnodes < 2)
return 0;
2000-04-03 22:13:57 +00:00
for (i = numnodes - 1; i > 0; i--) {
2008-11-28 10:48:39 +00:00
LL_Rewind(list); // get the first node again
2000-04-03 22:13:57 +00:00
best = last; // reset our "best" node
2000-04-03 22:13:57 +00:00
for (j = 0; j < i; j++) {
2008-11-28 10:48:39 +00:00
current = LL_GetNode(list);
2000-04-03 22:13:57 +00:00
// If we found a better match...
2008-11-28 10:48:39 +00:00
if (compare(current->data, best->data) > 0) {
2000-04-03 22:13:57 +00:00
best = current; // keep track of the "best" match
}
2008-11-28 10:48:39 +00:00
LL_Next(list); // Go to the next node.
2000-04-03 22:13:57 +00:00
}
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
LL_SwapNodes(last, best); // Switch two nodes...
2000-04-03 22:13:57 +00:00
if (best)
last = best->prev;
else
return -1;
2000-04-03 22:13:57 +00:00
//last = LL_FindPrev(best); // And go backwards by one node.
}
2000-04-03 22:13:57 +00:00
//return LLFindFirst(current); // return pointer to the first node.
2008-11-28 10:48:39 +00:00
LL_Rewind(list);
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
void
2008-11-28 10:48:39 +00:00
LL_dprint(LinkedList *list)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
LL_node *current;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
current = &list->head;
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
printf("Head: prev:\t0x%p\taddr:\t0x%p\tnext:\t0x%p\n", list->head.prev, &list->head, list->head.next);
2000-04-03 22:13:57 +00:00
for (current = current->next; current != &list->tail; current = current->next) {
2008-11-28 10:48:39 +00:00
printf("node: prev:\t0x%p\taddr:\t0x%p\tnext:\t0x%p\n", current->prev, current, current->next);
2000-04-03 22:13:57 +00:00
}
1999-12-09 23:15:14 +00:00
2008-11-28 10:48:39 +00:00
printf("Tail: prev:\t0x%p\taddr:\t0x%p\tnext:\t0x%p\n", list->tail.prev, &list->tail, list->tail.next);
1999-12-09 23:15:14 +00:00
}