/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for 
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #                                      
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    LinkList.h
    Author:  Copyright  1992 John Winters
    Version: 1.33 (30 May 1994)
    Purpose: Linked list management routines
    History:
    	27 Aug 1996	JS	InsertBefore/After now work if pos is NULL.
*/


#ifndef __Desk_LinkList_h
#define __Desk_LinkList_h

#ifdef __cplusplus
	extern "C" {
#endif


#ifndef __Desk_Core_h
	#include "Desk.Core.h"
#endif


/*  Implementation notes
 *  ====================
 *  This module provides support for a linked list structure.
 *  YOU must supply an anchor for the list (a variable of type
 *  Desk_linklist_header). This is used to record pointers to the start and end
 *  of the list.
 *  The list itself is made up of your own structures, defined as follows:
 *    struct listelement
 *    {
 *      Desk_linklist_header header;
 *      ... Your own data here ...
 *    } listelement;
 *
 *  a list-terminating pointer is represented as NULL
 *
 *  The header's next field stores a pointer to the FIRST item
 *           its previous field stores a pointer to the LAST item
 *           (both these pointers will be nulls if the list is empty)
 *
 *  To insert items into the list, you must malloc memory for one of your
 *  own listelement data structures, then call the appropriate function
 *  To delete an item from the list, call the unlink function, and then free
 *  all memory used by your structure.
 */


typedef struct Desk_linklist_header
{
  struct Desk_linklist_header *next;
  struct Desk_linklist_header *previous;
} Desk_linklist_header ;



extern void Desk_LinkList_AddToHead(Desk_linklist_header *anchor, Desk_linklist_header *item);
/*
inserts the given item at the head of the list
*/

extern void Desk_LinkList_AddToTail(Desk_linklist_header *anchor, Desk_linklist_header *item);
/*
inserts the given item at the end of the list
*/

extern void Desk_LinkList_InsertBefore(Desk_linklist_header *anchor,
                                  Desk_linklist_header *pos,
                                  Desk_linklist_header *item);
/*
inserts the given item BEFORE the item "pos"
If 'pos' is NULL, adds to head of list.
*/

extern void Desk_LinkList_InsertAfter(Desk_linklist_header *anchor,
                                 Desk_linklist_header *pos,
                                 Desk_linklist_header *item);
/*
inserts the given item AFTER the item "pos"
If 'pos' is NULL, adds to tail of list.
*/



extern Desk_bool Desk_LinkList_InList( const Desk_linklist_header *anchor, const Desk_linklist_header *item);
  /*
   *  Returns Desk_bool_TRUE if the item is curently in the list. Note that this does
   *  NOT check item contents, merely compares item pointers.
   *  To check item contents, you must chain through the list yourself.
   */


extern int Desk_LinkList_ListLength( const Desk_linklist_header *anchor);
  /*
   *  Returns the number of items in the list. It follows all the links
   *  and counts them... if you need this value a lot, I suggest you modify
   *  LinkList to keep a count in the anchor...
   */



extern void Desk_LinkList_Unlink(Desk_linklist_header *anchor, Desk_linklist_header *item);
  /*
   *  Unlinks the item "item" from the given list.
   *  You must then free the memory used by it yourself.
   */


#define Desk_LinkList_FirstItem(x) ((void *)(x)->next)
  /*  Return pointer to the first item in the list
   */

#define Desk_LinkList_LastItem(x) ((void *)(x)->previous)
  /*  Return pointer to the last item in the list
   */


#define Desk_LinkList_Init(x)  \
  {                       \
    (x)->next = NULL;     \
    (x)->previous = NULL; \
  }
  /*
   *  Initialises a list anchor. Should be called before anchor used
   *    extern void Desk_LinkList_Init(Desk_linklist_header *item);
   */


#define Desk_LinkList_InitItem(x) \
  {                          \
    (x)->next = NULL;        \
    (x)->previous = NULL;    \
  }
  /*
   *  Initialises a list item. Should be called before item used,
   *  except when that item is immediately linked into a list
   *    extern void Desk_LinkList_InitItem(Desk_linklist_header *item);
   */


#define Desk_LinkList_NextItem(x) ((void *) ((Desk_linklist_header *)(x))->next)
  /*  Return the next item of a given one. If the current item is at
   *  the tail of the list, NULLPOINTER will be returned.
   *    extern void *Desk_LinkList_NextItem(Desk_linklist_header *item);
   *
   *  Old definition:
   *    #define Desk_LinkList_NextItem(x) ((void *)(x)->next)
   *
   *  NEW definition:
   *    you can now use   Desk_LinkList_NextItem(&item);
   *    instead of        Desk_LinkList_NextItem(&item->header);
   */


#define Desk_LinkList_PreviousItem(x) ((void *) ((Desk_linklist_header *)(x))->previous)
  /*  Return the previous item of a given one. If the current item is at
   *  the head of the list, NULLPOINTER will be returned.
   *    extern void *Desk_LinkList_PreviousItem(Desk_linklist_header *item);
   *
   *  Old definition:
   *    #define Desk_LinkList_PreviousItem(x) ((void *)(x)->previous)
   *
   *  NEW definition:
   *    you can now use   Desk_LinkList_PreviousItem(&item);
   *    instead of        Desk_LinkList_PreviousItem(&item->header);
   */

#ifdef __cplusplus
}
#endif


#endif
