/*  -*- Mode: C;  -*- */

/******************************************************************************
*                                                                             *
*   Copyright 2005 University of Cambridge Computer Laboratory.               *
*                                                                             *
*   This file is part of Nprobe.                                              *
*                                                                             *
*   Nprobe is free software; you can redistribute it and/or modify            *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation; either version 2 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   Nprobe 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 General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with Nprobe; if not, write to the Free Software                     *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
*                                                                             *
******************************************************************************/

 
#ifndef _LIST_H_
#define _LIST_H_

#ifndef MACRO_BEGIN
#define  MACRO_BEGIN do {
#define MACRO_END } while (0)
#endif



/* A generic d.l. list type */

typedef struct list
{
  struct list *lnext;
  struct list *lprev;
} list_t;


typedef list_t listhdr_t;

#define L_INIT(lp) \
  MACRO_BEGIN      \
    (lp)->lnext = (lp)->lprev = (lp);\
  MACRO_END

#define L_EMPTY(lp) ((lp)->lnext == (lp))

#define L_REM(lp, itemp, field, type) \
  MACRO_BEGIN      \
    list_t *lprev = (itemp)->field.lprev; \
    list_t *lnext = (itemp)->field.lnext; \
                                           \
    list_t *prev_link = ((lprev) == (lp)) ? (lp) : &(((type *)(lprev))->field); \
    list_t *next_link = ((lnext) == (lp)) ? (lp) : &(((type *)(lnext))->field); \
    prev_link->lnext = lnext;\
    next_link->lprev = lprev;\
  MACRO_END

#define L_INS_HEAD(lp, itemp, field, type)\
  MACRO_BEGIN      \
    if (L_EMPTY((lp))) \
      { \
        (lp)->lnext = (lp)->lprev = (list_t *)(itemp); \
        (itemp)->field.lnext = (itemp)->field.lprev = (lp); \
      }\
    else \
      { \
        (itemp)->field.lnext = (lp)->lnext;\
        (itemp)->field.lprev = (lp);\
        ((type *)(lp)->lnext)->field.lprev = (list_t *)(itemp);\
        (lp)->lnext = (list_t *)(itemp); \
      }\
  MACRO_END

#define L_WALK(ptr, lp, field, type) \
  for ((ptr) = (type *)(lp)->lnext;  \
       (ptr) != (type *)(lp);       \
       (ptr) = (type *)ptr->field.lnext)

#define L_WALK_REV(ptr, lp, field, type) \
  for ((ptr) = (type *)(lp)->lprev;  \
       (ptr) != (type *)(lp);       \
       (ptr) = (type *)ptr->field.lprev)


#define L_INS_TAIL(lp, itemp, field, type) \
  MACRO_BEGIN                   \
    if (L_EMPTY((lp))) \
      {  \
        (lp)->lnext = (lp)->lprev = (list_t *)(itemp); \
        (itemp)->field.lnext = (itemp)->field.lprev = (lp); \
      }\
    else \
      { \
      (itemp)->field.lnext = (lp); \
      (itemp)->field.lprev = (lp)->lprev; \
      ((type *)(lp)->lprev)->field.lnext = (list_t *)(itemp); \
      (lp)->lprev = (list_t *)(itemp); \
      } \
  MACRO_END

#define L_MOVE_TO_TAIL(lp, itemp, field, type) \
  MACRO_BEGIN                   \
    L_REM((lp), (itemp), field, type); \
    L_INS_TAIL((lp), (itemp), field, type); \
  MACRO_END

#define L_MOVE_TO_HEAD(lp, itemp, field, type) \
  MACRO_BEGIN                   \
    L_REM((lp), (itemp), field, type); \
    L_INS_HEAD((lp), (itemp), field, type); \
  MACRO_END

#define L_INS_BEFORE(lp, befp, itemp, field, type) \
  MACRO_BEGIN                                      \
    list_t *back_link;\
      if ((list_t *)(befp) == (lp))\
        {\
          back_link = ((list_t *)(befp))->lprev;\
          ((list_t *)(befp))->lprev = (list_t *)(itemp);\
         }\
      else\
         {\
           back_link = (befp)->field.lprev;\
           (befp)->field.lprev =  (list_t *)(itemp);\
         }\
      (itemp)->field.lnext = (list_t *)(befp);\
      (itemp)->field.lprev = back_link; \
      if (back_link == (lp))                           \
        back_link->lnext = (list_t *)(itemp);        \
      else                                           \
        ((type *)back_link)->field.lnext = (list_t *)(itemp);\
  MACRO_END
  

#define L_INS_AFTER(lp, aftp, itemp, field, type)         \
  MACRO_BEGIN                                             \
    list_t *for_link;          \
    if ((list_t *)(aftp) == (lp))   \
      {                                \
         for_link = ((list_t *)(aftp))->lnext;     \
         ((list_t *)(aftp))->lnext = (list_t *)(itemp);              \
      }                   \
    else     \
      {     \
        for_link = (aftp)->field.lnext;               \
        (aftp)->field.lnext = (list_t *)(itemp);              \
      }    \
    (itemp)->field.lprev = (list_t *)(aftp);              \
    (itemp)->field.lnext = for_link;                      \
    if (for_link == (lp))                                 \
      for_link->lprev = (list_t *)(itemp);               \
    else                                                  \
      ((type *)for_link)->field.lprev = (list_t *)(itemp);\
  MACRO_END

#endif /* _LIST_H_ */

/*
 * end list.h
 */
