/*
 *
 *	$Header: /usr/u/wjr/src/ADT/RCS/list.h,v 1.12 1993/07/26 22:15:42 wjr Exp $
 *
 * Copyright (c) 1990, 1991, 1992, 1993 Cornell University.  All Rights
 * Reserved.
 *
 * Copyright (c) 1991, 1992 Xerox Corporation.  All Rights Reserved.
 *
 * Use, reproduction and preparation of derivative works of this software is
 * permitted.  Any copy of this software or of any derivative work must
 * include both the above copyright notices of Cornell University and Xerox
 * Corporation and this paragraph.  This software is made available AS IS, and
 * XEROX CORPORATION DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE, AND NOTWITHSTANDING ANY OTHER PROVISION CONTAINED
 * HEREIN, ANY LIABILITY FOR DAMAGES RESULTING FROM THE SOFTWARE OR ITS USE IS
 * EXPRESSLY DISCLAIMED, WHETHER ARISING IN CONTRACT, TORT (INCLUDING
 * NEGLIGENCE) OR STRICT LIABILITY, EVEN IF XEROX CORPORATION IS ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGES.
 */
/*
 * list.h - header file for the list module
 */
#ifndef LIST_H
#define LIST_H

#if      0
BEGIN DOCUMENTATION

/*
 *	list.c - Yet Another List Module
 *
 * How many times have you seen this implemented? I know I've implemented it
 * a few too many times...
 *
 * This module handles generic lists.
 *
 * Exports:
 *	type List
 *	type ListNode
 *
 *	constant List NULLLIST
 *	constant ListNode NULLLISTNODE
 *
 *	List liNew(void) - create a new, empty list
 *
 *	void liFree(List l) - free list l
 *
 *	ListNode liFirst(List l) - return the first entry in list l
 *
 *	ListNode liLast(List l) - return the last entry in list l
 *
 *	ListNode liNext(ListNode ln) - return the next entry after
 *		ln in whatever list ln is in
 *
 *	ListNode liPrevious(ListNode ln) - return the entry before
 *		ln in whatever list ln is in
 *
 *	ListNode liPrepend(List l, void *userdata) - prepend a node containing
 *		userdata to list l
 *
 *	ListNode liAppend(List l, void *userdata) - append a node containing
 *		userdata to list l
 *
 *	ListNode liAdd(List l, void *userdata) - alias for liAppend()
 *
 *	void liRem(ListNode ln) - remove node ln from whatever list it
 *		is in
 *
 *	ListNode liRemAndNext(ListNode ln) - remove node ln from whatever list
 *		it is in, and return the ListNode which followed it.
 *
 *	void *liGet(ListNode ln) - return the userdata of node ln
 *
 *	ListNode liIsIn(List l, void *userdata) - search l for a node
 *		containing that userdata value
 *
 *	unsigned int liLen(List l) - return the length of l
 *
 *	void liApp(List l1, List l2) - append l2 to l1
 *
 *	macro foreach(ln, l) - iterate over each node in a list
 *
 *	macro forafter(ln1, ln2) - iterate over each node in a list after
 *		a given node
 *
 * An object of type List is used as a handle on a list, which consists of
 *	multiple ListNodes. Each ListNode contains a void *
 *	field, which is used for whatever data the user wishes to attach
 *	to that node. It is standard C idiom that (void *) pointers can
 *	be cast to and from any other type of pointer without error or loss.
 *
 * liNew creates an empty list. If this is not possible, it returns NULLLIST.
 *
 * liFree frees the storage associated with a List and the ListNodes it
 *	contains. Note that it does not free the userdata; the user
 *	must do this before freeing the list structure
 *
 * liFirst returns the first entry of the given list. If the list is
 *	empty, it returns NULLLISTNODE.
 *
 * liNext returns the ListNode after the given one. A call to liFirst
 *	followed by multiple calls to liNext will return all entries
 *	in that list, in the order in which they were added. When liNext
 *	is called on the last entry of a list, it returns NULLLISTNODE.
 *
 * liAdd appends a node to the given list. The userdata pointer is
 *	stored in that node. If it is not possible to append to that
 *	list, it returns NULLLISTNODE.
 *
 * liRem removes a node from the list it is in.
 *
 * liRemAndNext removes a node from the list it is in, and returns the
 *	ListNode that followed it. If the ListNode was the last in its list,
 *	liRemAndNext returns NULLLISTNODE.

 * liGet gets the userdata associated with the given node.
 *
 * liIsIn searches the userdata fields of a list and returns where
 *	that field appeared in the list. This is the only routine which
 *	does anything to the userdata fields other than copy them. liIsIn
 *	compares them for equality. If the field does not appear in the list,
 *	it returns NULLLISTNODE.
 *
 * liLen counts the number of nodes which are on the given list.
 *
 * liApp appends the list l2 to the list l1. They must not be the same list.
 *	l2 becomes invalid after the call.
 *
 * foreach is a replacement for the C "for" construct which successively
 *	assigns ln to each node in l.
 *
 * forafter is a replacement for the C "for" construct which successively
 *	assigns ln1 to each node in the list containing ln2, starting with
 *	the successor of ln2 (liNext(ln2)). ln1 and ln2 may be the same
 *	variable.
 *
 * Note that all ListNodes must be part of some list. When a ListNode is
 * removed from a list, or when its list is freed, it becomes invalid.
 * When a List is freed, it becomes invalid.
 * Interleaving liAdd, liRem and liNext will produce undefined results.
 * If a List is modified, you must start at the beginning with liFirst
 * and scan through it; all ListNodes become invalid when the list is
 * modified.
 * However, since scanning through a list removing some of the entries is
 * a common operation, liRemAndNext has been provided. Scanning through
 * a list using liNext in the case than a node is not to be deleted, and
 * liRemAndNext in the case that it is is guaranteed to work.
 *
 */

END DOCUMENTATION
#endif   


/*
 * Types. These types are opaque. You can't see these, really...
 */
/*
 * Complain, complain: recursive types are messy in C.
 * Note that one structure has to be named, not anonymous.
 */
typedef void (*liRemHook)(void *data);

typedef struct {
    struct _ListNode *first, *last;
    liRemHook remhook;
    } *List;

struct _ListNode {
    struct _ListNode *next, *prev;
    List owner;
    void *userdata;
    };
typedef struct _ListNode *ListNode;

/*
 * Constants
 */
#define	NULLLIST	((List)NULL)
#define	NULLLISTNODE	((ListNode)NULL)

/*
 * Functions
 */
extern ListNode malloc_ln();
extern void free_ln(ListNode ln);


extern List liNew(void);
extern void liFree(List l);
extern ListNode liFirst(List l);
extern ListNode liLast(List l);
extern ListNode liNext(ListNode ln);
extern ListNode liPrevious(ListNode ln);
extern ListNode liAppend(List l, void *userdata);
extern ListNode liPrepend(List l, void *userdata);
extern void liRem(ListNode ln);
extern ListNode liRemAndNext(ListNode ln);
extern void *liGet(ListNode ln);
extern ListNode liIsIn(List l, void *userdata);
extern unsigned int liLen(List l);
extern void liApp(List l1, List l2);
extern liRemHook liSetRemHook(List l, liRemHook hook);

#ifdef   __GNUC__
extern inline ListNode liAdd(List l, void *userdata) { return liAppend(l, userdata); }
#else   
extern ListNode liAdd(List l, void *userdata);
#endif   

extern void liDoneWithLists();

/*
 * Macros
 */
#define foreach(ln, l) for((ln) = liFirst((l)); (ln) != NULLLISTNODE; (ln) = liNext((ln)))
#define forafter(ln1, ln2) for ((ln1) = liNext(ln2); (ln1) != NULLLISTNODE; (ln1) = liNext((ln1)))

#endif
