/* -------------------------------
 * 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 */
#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_);                                                      \
      free(tmp_);                                                      \
    }                                                                  \
    h_ = NULL;                                                         \
  } while (0)

#endif
