/* -------------------------------
 * vim:tabstop=4:shiftwidth=4
 * list.h
 * Fri, 10 Sep 2004 23:34:48 +0700
 * -------------------------------
 * Simple double linked list
 * -------------------------------*/

#ifndef _LIST_H_
#define _LIST_H_

/* Implement basic functions for doubly-linked list. 
 * Each structure to hold an element of the list must have two
 * fields pointer fields: prev and next. */

/* Add item i_ to the head of the list h_ (pointer to the head) */
#define LIST_ADD_ITEM(h_, i_) do { \
	(i_)->prev = NULL;             \
	if ((h_) != NULL) {            \
		(i_)->next = (h_);         \
		(h_)->prev = (i_);         \
	} else {                       \
		(i_)->next = NULL;         \
	}                              \
	(h_) = (i_);                   \
} while(0)

/* Insert item i_ after item t_ to the list h_ (pointer to the head) */
#define LIST_INSERT_AFTER(h_,t_,i_) do { \
	(i_)->prev = (t_);                   \
	if ((t_) != NULL) {                  \
		(i_)->next = (t_)->next;         \
		(t_)->next = (i_);               \
	} else {                             \
		if ((h_) != NULL) {              \
			(i_)->next = (h_);           \
			(h_)->prev = (i_);           \
		} else {                         \
			(i_)->next = NULL;           \
		}                                \
		(h_) = (i_);                     \
	}                                    \
} while(0)

/* Delete item i_ from the list h_ (pointer to the head) */
#define LIST_DEL_ITEM(h_, i_) do { \
	if (i_->prev != NULL)          \
		i_->prev->next = i_->next; \
	if (i_->next != NULL)          \
    	i_->next->prev = i_->prev; \
    if (i_ == h_)                  \
		h_ = i_->next;             \
} while(0)

/* Clean the list h_ (pointer to the head);
 * tmp_ is a temporary variable */
#define LIST_CLEAN(h_, tmp_) do {                                      \
	for (tmp_ = h_, h_ = (h_ != NULL) ? h_->next : NULL; tmp_ != NULL; \
			tmp_ = h_, h_ = h_ != NULL ? h_->next : NULL) {            \
		free(tmp_);                                                    \
	}                                                                  \
	h_ = NULL;                                                         \
} while(0)

/* Clean the list h_ (pointer to the head) calling cbk_ for every
 * element of the list; tmp_ is a temporary variable */
/* Do not call free(), deletion must be done by the callback */
#define LIST_CLEAN_CBK(h_, tmp_, cbk_) do  {                           \
	for (tmp_ = h_, h_ = (h_ != NULL) ? h_->next : NULL; tmp_ != NULL; \
			tmp_ = h_, h_ = h_ != NULL ? h_->next : NULL) {            \
		cbk_(tmp_);                                                    \
	}                                                                  \
	h_ = NULL;                                                         \
} while(0)

#endif
