1. linklist.c
#include "linklist.h"
/* Allocate new list. */
struct list *
list_new (void)
{
return (struct list *)calloc(1, sizeof(struct list));
}
/* Free list. */
void
list_free (struct list *l)
{
free(l);
}
/* Allocate new listnode. Internal use only. */
static struct listnode *
listnode_new (void)
{
return (struct listnode *)calloc(1,sizeof (struct listnode));
}
/* Free listnode. */
static void
listnode_free (struct listnode *node)
{
free(node);
}
/* Add new data to the list. */
void
listnode_add (struct list *list, void *val)
{
struct listnode *node;
assert (val != NULL);
node = listnode_new ();
node->prev = list->tail;
node->data = val;
if (list->head == NULL)
list->head = node;
else
list->tail->next = node;
list->tail = node;
list->count++;
}
/*
* Add a node to the list. If the list was sorted according to the
* cmp function, insert a new node with the given val such that the
* list remains sorted. The new node is always inserted; there is no
* notion of omitting duplicates.
*/
void
listnode_add_sort (struct list *list, void *val)
{
struct listnode *n;
struct listnode *new;
assert (val != NULL);
new = listnode_new ();
new->data = val;
if (list->cmp)
{
for (n = list->head; n; n = n->next)
{
if ((*list->cmp) (val, n->data) < 0)
{
new->next = n;
new->prev = n->prev;
if (n->prev)
n->prev->next = new;
else
list->head = new;
n->prev = new;
list->count++;
return;
}
}
}
new->prev = list->tail;
if (list->tail)
list->tail->next = new;
else
list->head = new;
list->tail = new;
list->count++;
}
void
listnode_add_after (struct list *list, struct listnode *pp, void *val)
{
struct listnode *nn;
assert (val != NULL);
nn = listnode_new ();
nn->data = val;
if (pp == NULL)
{
if (list->head)
list->head->prev = nn;
else
list->tail = nn;
nn->next = list->head;
nn->prev = pp;
list->head = nn;
}
else
{
if (pp->next)
pp->next->prev = nn;
else
list->tail = nn;
nn->next = pp->next;
nn->prev = pp;
pp->next = nn;
}
list->count++;
}
/* Delete specific date pointer from the list. */
void
listnode_delete (struct list *list, void *val)
{
struct listnode *node;
assert(list);
for (node = list->head; node; node = node->next)
{
if (node->data == val)
{
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
list->count--;
listnode_free (node);
return;
}
}
}
/* Return first node's data if it is there. */
void *
listnode_head (struct list *list)
{
struct listnode *node;
assert(list);
node = list->head;
if (node)
return node->data;
return NULL;
}
/* Delete all listnode from the list. */
void
list_delete_all_node (struct list *list)
{
struct listnode *node;
struct listnode *next;
assert(list);
for (node = list->head; node; node = next)
{
next = node->next;
if (list->del)
(*list->del) (node->data);
listnode_free (node);
}
list->head = list->tail = NULL;
list->count = 0;
}
/* Delete all listnode then free list itself. */
void
list_delete (struct list *list)
{
assert(list);
list_delete_all_node (list);
list_free (list);
}
/* Lookup the node which has given data. */
struct listnode *
listnode_lookup (struct list *list, void *data)
{
struct listnode *node;
assert(list);
for (node = listhead(list); node; node = listnextnode (node))
if (data == listgetdata (node))
return node;
return NULL;
}
/* Delete the node from list.. */
void
list_delete_node (struct list *list, struct listnode *node)
{
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
list->count--;
listnode_free (node);
}
void
list_add_node_prev (struct list *list, struct listnode *current, void *val)
{
struct listnode *node;
assert (val != NULL);
node = listnode_new ();
node->next = current;
node->data = val;
if (current->prev == NULL)
list->head = node;
else
current->prev->next = node;
node->prev = current->prev;
current->prev = node;
list->count++;
}
void
list_add_node_next (struct list *list, struct listnode *current, void *val)
{
struct listnode *node;
assert (val != NULL);
node = listnode_new ();
node->prev = current;
node->data = val;
if (current->next == NULL)
list->tail = node;
else
current->next->prev = node;
node->next = current->next;
current->next = node;
list->count++;
}
void
list_add_list (struct list *l, struct list *m)
{
struct listnode *n;
for (n = listhead (m); n; n = listnextnode (n))
listnode_add (l, n->data);
}
2. linklist.h
#ifndef __LINKLIST_H
#define __LINKLIST_H
/* listnodes must always contain data to be valid. Adding an empty node
* to a list is invalid
*/
struct listnode
{
struct listnode *next;
struct listnode *prev;
/* private member, use getdata() to retrieve, do not access directly */
void *data;
};
struct list
{
struct listnode *head;
struct listnode *tail;
/* invariant: count is the number of listnodes in the list */
unsigned int count;
/*
* Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2.
* Used as definition of sorted for listnode_add_sort
*/
int (*cmp) (void *val1, void *val2);
/* callback to free user-owned data when listnode is deleted. supplying
* this callback is very much encouraged!
*/
void (*del) (void *val);
};
#define listnextnode(X) ((X) ? ((X)->next) : NULL)
#define listhead(X) ((X) ? ((X)->head) : NULL)
#define listtail(X) ((X) ? ((X)->tail) : NULL)
#define listcount(X) ((X)->count)
#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
#define listgetdata(X) (assert((X)->data != NULL), (X)->data)
/* Prototypes. */
extern struct list *list_new(void); /* encouraged: set list.del callback on new lists */
extern void list_free (struct list *);
extern void listnode_add (struct list *, void *);
extern void listnode_add_sort (struct list *, void *);
extern void listnode_add_after (struct list *, struct listnode *, void *);
extern void listnode_delete (struct list *, void *);
extern struct listnode *listnode_lookup (struct list *, void *);
extern void *listnode_head (struct list *);
extern void list_delete (struct list *);
extern void list_delete_all_node (struct list *);
extern void list_delete_node (struct list *, struct listnode *);
extern void list_add_node_prev (struct list *, struct listnode *, void *);
extern void list_add_node_next (struct list *, struct listnode *, void *);
extern void list_add_list (struct list *, struct list *);
/* List iteration macro.
* Usage: for (ALL_LIST_ELEMENTS (...) { ... }
* It is safe to delete the listnode using this macro.
*/
#define ALL_LIST_ELEMENTS(list,node,nextnode,data) \
(node) = listhead(list), ((data) = NULL); \
(node) != NULL && \
((data) = listgetdata(node),(nextnode) = node->next, 1); \
(node) = (nextnode), ((data) = NULL)
/* read-only list iteration macro.
* Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only
* use this macro when it is *immediately obvious* the listnode is not
* deleted in the body of the loop. Does not have forward-reference overhead
* of previous macro.
*/
#define ALL_LIST_ELEMENTS_RO(list,node,data) \
(node) = listhead(list), ((data) = NULL);\
(node) != NULL && ((data) = listgetdata(node), 1); \
(node) = listnextnode(node), ((data) = NULL)
/* these *do not* cleanup list nodes and referenced data, as the functions
* do - these macros simply {de,at}tach a listnode from/to a list.
*/
/* List node attach macro. */
#define LISTNODE_ATTACH(L,N) \
do { \
(N)->prev = (L)->tail; \
if ((L)->head == NULL) \
(L)->head = (N); \
else \
(L)->tail->next = (N); \
(L)->tail = (N); \
(L)->count++; \
} while (0)
/* List node detach macro. */
#define LISTNODE_DETACH(L,N) \
do { \
if ((N)->prev) \
(N)->prev->next = (N)->next; \
else \
(L)->head = (N)->next; \
if ((N)->next) \
(N)->next->prev = (N)->prev; \
else \
(L)->tail = (N)->prev; \
(L)->count--; \
} while (0)
#endif /* __LINKLIST_H */