/* usb/dlist.h
 *
 * (c) 2002 Simtec Electronics
 *
 * Ben Dooks
 *
 * simple doubly linked list code
 *
 * $Id: dlist.h,v 1.13 2003/08/06 15:56:11 ben Exp $
 *
 * This Library file is part of the Simtec Electronics USB stack development
 *   suite.
 * Specific licence is granted to use this file by third parties for the
 *   development of USB device drivers.
 *
*/

#ifndef __USB_DLIST_H
#define __USB_DLIST_H "$Id: dlist.h,v 1.13 2003/08/06 15:56:11 ben Exp $"

struct dlist_item;

/** dlist item structure (to put in each item in the list)
 * @memo dlist item structure
*/
struct dlist_item {
  struct dlist_item   *dl_next;
  struct dlist_item   *dl_prev;
  void		      *dl_data;
};

/** dlist head structure
 * @memo head structure for dlist
*/

struct dlist_head {
  struct dlist_item   first;
};


typedef struct dlist_head dlist_head_t;
typedef struct dlist_item dlist_item_t;

#define DLIST_INIT_HEAD { {  NULL , NULL , NULL } }

/** initialise the head structure for an dlist
 * @memo initialise the head structure for an dlist
 * @see dlist_head
*/

#define dlist_inithead(_dl) do { (_dl)->first.dl_next = NULL ; (_dl)->first.dl_prev = NULL ; } while(0)

/** initialise an dlist item structure
 * @memo initialise an dlist item structure
 * @see dlist_item
*/

#define dlist_init(_entry,_item) do { (_entry)->dl_data = (_item); } while(0)


#define dlist_add_to(_ent,_add) \
  do { struct dlist_item *dl_next = (_ent)->dl_next; \
       (_add)->dl_next = dl_next; \
       (_add)->dl_prev = (_ent);  \
       (_ent)->dl_next = (_add);  \
       if (dl_next != NULL) dl_next->dl_prev = (_add); }  while(0)

/** add an item to the front of an dlist
 * @memo add an item to the front of an dlist
*/

#define dlist_add_front(_dl,_entry) dlist_add_to(&(_dl)->first, _entry)

/** Return the first item's data from the front of a list
*/

#define dlist_get_front(_dl) (((_dl)->first.dl_next == NULL) ? NULL : (_dl)->first.dl_next->dl_data)

/** Is an dlist empty
*/

#define dlist_empty(_dl) ((_dl)->first.dl_next == NULL)

/** dlist enumeration function.
 *
 * @param _dl the dlist head
 * @param _to the variable to take each item
 * @param _entry the entry field name within the item
 * @param _type type to cast _to to
 * @see dlist_head
 * @see dlist_item
*/
#define dlist_foreach(_dl,_to,_entry,_type) \
  for ((_to) = ((_dl)->first.dl_next != NULL) ? (_type)((_dl)->first.dl_next->dl_data) : NULL; \
       (_to) != NULL; \
       (_to) = (_type)((_to)->_entry.dl_next == NULL ? NULL : ((_to)->_entry.dl_next->dl_data)))

/** remove item from an dlist
 * @param head head of list
 * @param item item to remove
 * @see dlist_item
 * @see dlist_head
 */

extern int dlist_remove(dlist_head_t *head, dlist_item_t *item);

extern void dlist_add_end(dlist_head_t *head, dlist_item_t *item);

extern void dlist_add_at(dlist_item_t *ptr, dlist_item_t *add);


#endif








