Implement circular double-linked list
diff --git a/Makefile.am b/Makefile.am
index f387cf8..57a1da3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,7 +29,9 @@
 libkmod_libkmod_la_SOURCES =\
 	libkmod/libkmod.h \
 	libkmod/libkmod-private.h \
-	libkmod/libkmod.c
+	libkmod/libkmod-util.h \
+	libkmod/libkmod.c \
+	libkmod/libkmod-list.c
 
 EXTRA_DIST += libkmod/libkmod.sym
 
diff --git a/libkmod/libkmod-list.c b/libkmod/libkmod-list.c
new file mode 100644
index 0000000..b7673c4
--- /dev/null
+++ b/libkmod/libkmod-list.c
@@ -0,0 +1,153 @@
+/*
+ * libkmod - interface to kernel module operations
+ *
+ * Copyright (C) 2011  ProFUSION embedded systems
+ * Copyright (C) 2011  Lucas De Marchi <lucas.de.marchi@gmail.com>
+ *
+ * This library 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 version 2.1.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdlib.h>
+
+#include "libkmod.h"
+#include "libkmod-private.h"
+#include "libkmod-util.h"
+
+static inline struct list_node *list_node_init(struct list_node *node)
+{
+	node->next = node;
+	node->prev = node;
+
+	return node;
+}
+
+static inline struct list_node *list_node_next(struct list_node *node)
+{
+	if (node == NULL)
+		return NULL;
+
+	return node->next;
+}
+
+static inline struct list_node *list_node_prev(struct list_node *node)
+{
+	if (node == NULL)
+		return NULL;
+
+	return node->prev;
+}
+
+static inline void list_node_append(struct list_node *list,
+							struct list_node *node)
+{
+	if (list == NULL) {
+		list_node_init(node);
+		return;
+	}
+
+	node->prev = list->prev;
+	list->prev->next = node;
+	list->prev = node;
+	node->next = list;
+}
+
+static inline struct list_node *list_node_remove(struct list_node *node)
+{
+	if (node->prev == node || node->next == node)
+		return NULL;
+
+	node->prev->next = node->next;
+	node->next->prev = node->prev;
+
+	return node->prev;
+}
+
+struct kmod_list *kmod_list_append(struct kmod_list *list, void *data)
+{
+	struct kmod_list *new;
+
+	new = malloc(sizeof(*new));
+	if (new == NULL)
+		return NULL;
+
+	new->data = data;
+	list_node_append(list ? &list->node : NULL, &new->node);
+
+	return list ? list : new;
+}
+
+struct kmod_list *kmod_list_prepend(struct kmod_list *list, void *data)
+{
+	struct kmod_list *new;
+
+	new = malloc(sizeof(*new));
+	if (new == NULL)
+		return NULL;
+
+	new->data = data;
+	list_node_append(list ? &list->node : NULL, &new->node);
+
+	return new;
+}
+
+struct kmod_list *kmod_list_remove(struct kmod_list *list)
+{
+	struct list_node *node;
+
+	if (list == NULL)
+		return NULL;
+
+	node = list_node_remove(&list->node);
+	free(list);
+
+	if (node == NULL)
+		return NULL;
+
+	return container_of(node, struct kmod_list, node);
+}
+
+struct kmod_list *kmod_list_remove_data(struct kmod_list *list,
+							const void *data)
+{
+	struct kmod_list *itr;
+	struct list_node *node;
+
+	for (itr = list; itr != NULL; itr = kmod_list_next(list, itr)) {
+		if (itr->data == data)
+			break;
+	}
+
+	if (itr == NULL)
+		return list;
+
+	node = list_node_remove(&itr->node);
+	free(itr);
+
+	if (node == NULL)
+		return NULL;
+
+	return container_of(node, struct kmod_list, node);
+}
+
+KMOD_EXPORT struct kmod_list *kmod_list_next(struct kmod_list *list,
+							struct kmod_list *curr)
+{
+	if (list == NULL || curr == NULL)
+		return NULL;
+
+	if (curr->node.next == &list->node)
+		return NULL;
+
+	return container_of(curr->node.next, struct kmod_list, node);
+}
diff --git a/libkmod/libkmod-private.h b/libkmod/libkmod-private.h
index 24175f3..8208d94 100644
--- a/libkmod/libkmod-private.h
+++ b/libkmod/libkmod-private.h
@@ -35,4 +35,19 @@
 		int priority, const char *file, int line, const char *fn,
 		const char *format, ...) __attribute__((format(printf, 6, 7)));
 
+struct list_node {
+	struct list_node *next, *prev;
+};
+
+struct kmod_list {
+	struct list_node node;
+	void *data;
+};
+
+struct kmod_list *kmod_list_append(struct kmod_list *list, void *data);
+struct kmod_list *kmod_list_prepend(struct kmod_list *list, void *data);
+struct kmod_list *kmod_list_remove(struct kmod_list *list);
+struct kmod_list *kmod_list_remove_data(struct kmod_list *list,
+							const void *data);
+
 #endif
diff --git a/libkmod/libkmod-util.h b/libkmod/libkmod-util.h
new file mode 100644
index 0000000..81ccc99
--- /dev/null
+++ b/libkmod/libkmod-util.h
@@ -0,0 +1,32 @@
+#ifndef _LIBKMOD_UTIL_H_
+#define _LIBKMOD_UTIL_H_
+
+#include <stddef.h>
+
+#define BUILD_ASSERT(cond) \
+	do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
+
+#define EXPR_BUILD_ASSERT(cond) \
+	(sizeof(char [1 - 2*!(cond)]) - 1)
+
+#if HAVE_TYPEOF
+#define check_type(expr, type)			\
+	((typeof(expr) *)0 != (type *)0)
+
+#define check_types_match(expr1, expr2)		\
+	((typeof(expr1) *)0 != (typeof(expr2) *)0)
+#else
+/* Without typeof, we can only test the sizes. */
+#define check_type(expr, type)					\
+	EXPR_BUILD_ASSERT(sizeof(expr) == sizeof(type))
+
+#define check_types_match(expr1, expr2)				\
+	EXPR_BUILD_ASSERT(sizeof(expr1) == sizeof(expr2))
+#endif /* HAVE_TYPEOF */
+
+#define container_of(member_ptr, containing_type, member)		\
+	((containing_type *)						\
+	 ((char *)(member_ptr) - offsetof(containing_type, member))	\
+	 - check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
+#endif
diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h
index ff8c6a6..2f3006d 100644
--- a/libkmod/libkmod.h
+++ b/libkmod/libkmod.h
@@ -52,12 +52,13 @@
  *
  * access to kmod generated lists
  */
-struct kmod_list_entry;
-struct kmod_list_entry *kmod_list_entry_get_next(struct kmod_list_entry *list_entry);
-#define kmod_list_entry_foreach(list_entry, first_entry) \
+struct kmod_list;
+struct kmod_list *kmod_list_next(struct kmod_list *first_entry,
+						struct kmod_list *list_entry);
+#define kmod_list_foreach(list_entry, first_entry) \
 	for (list_entry = first_entry; \
 		list_entry != NULL; \
-		list_entry = kmod_list_entry_get_next(list_entry))
+		list_entry = kmod_list_next(first_entry, list_entry))
 
 #ifdef __cplusplus
 } /* extern "C" */