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

/* list.h --- public declarations for generic lists */

/* Author:	       Gary V. Vaughan <gvv@techie.com>
 * Maintainer:	       Gary V. Vaughan <gvv@techie.com>
 * Created:	       Thu Apr 22 22:01:49 1999
 * Last Modified:      Wed Jul 14 15:08:56 1999
 *            by:      Gary V. Vaughan <gvv@techie.com>
 * ---------------------------------------------------------------------
 * @(#) $Id$
 * ---------------------------------------------------------------------
 */

/* Copyright (C) 1999 Gary V. Vaughan */

/* This program 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.
 *
 * This program 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 this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * As a special exception to the GNU General Public License, if you
 * distribute this file as part of a program that also links with and
 * uses the libopts library from AutoGen, you may include it under
 * the same distribution terms used by the libopts library.
 */

/* Code: */

#ifndef LIST_H
#define LIST_H 1

#ifndef PARAMS
#  ifdef __STDC__
#    ifndef NOPROTOS
#      define PARAMS(args)	args
#    endif
#  endif
#endif
#ifndef PARAMS
#  define PARAMS(args)		()
#endif

#ifndef NIL
/**
 * NIL:
 * Use NIL to denote the empty list, to avoid confusion with other
 * 0 valued pointers.
 **/
#define NIL NULL
#endif

#ifdef __cplusplus
extern "C" {
#if 0
/* This brace is so that emacs can still indent properly: */ }
#endif
#endif /* __cplusplus */

/**
 * slist:
 * The minimum fields which must be present in a structure which
 * will be manipulated by these functions.
 **/
typedef struct slist {
    struct slist *next;
} slist;

/**
 * slist_cons: constructor
 * @head: The new head.
 * @tail: The old head (and thus new tail).
 * 
 * @tail is linked into the %next pointer of @head.
 * 
 * Return value:
 * The new @head is returned.
 **/
#define slist_cons(head, tail)	((head) ? ((slist*)(head))->next=(slist*)(tail),(slist*)(head) : (slist*)(tail))

/**
 * slist_new: constructor
 * @head: The new head.
 * 
 * @tail is linked into the %next pointer of @head.
 * 
 * Return value:
 * The new @head is returned.
 **/
#define slist_new(head)		slist_cons((head), NIL)

/**
 * slist_head:
 * @head: A generic list object, or the empty list, %NIL.
 * 
 * Return value:
 * The address of the head of the list @head  is returned,
 * unless @head is %NIL, when NULL is returned.
 **/
#define slist_head(head)	(head)
    
/**
 * slist_tail:
 * @head: A generic list object, or the empty list, %NIL.
 * 
 * Return value:
 * The address of the head of a list which begins with the node
 * directly following @head is returned, unless @head is %NIL,
 * when NULL is returned.
 **/
#define slist_tail(head)	((head) ? (head)->next : NIL)

/**
 * slist_cmp_func:
 * @try: Parameter used for each element in turn of the list being tried.
 * @refer: Parameter used to pass the reference element for comparison,
 *
 * The type of function used by slist_get() to compare list elements.
 **/
typedef int slist_cmp_func	PARAMS((slist *try, slist *refer));

/**
 * slist_delete_func:
 * @node: Parameter used for each node of the list being recycled.
 *
 * The type of function used by slist_delete() to recycle list elements.
 **/
typedef void slist_delete_func	PARAMS((slist *node));

/**
 * slist_delete:  destructor 
 * @head: the head of the list pending recycling.
 * @delfunc: the address of a function to delete each node.
 * 
 * @delfunc is called with each element of @head in turn, and is
 * assumed to recycle the contents of each node before it returns.
 **/
extern void slist_delete PARAMS((slist *list, slist_delete_func *delfunc));

/**
 * slist_reverse:   
 * @head: A generic list object, or the empty list, %NIL.
 * 
 * The tails of each of the nodes in @head are destructively reordered
 * to point to the preceding node.  This reverses the order of the %next
 * pointers in the list.
 * 
 * Return value:
 * The new head of the list, formerly the last cons cell in @head, is
 * returned.  Under normal circumstances, @head now points to the new end
 * of the list, and should be reassigned to the return value of this function.
 *
 *	head = slist_reverse(head);
 **/
extern slist* slist_reverse PARAMS((slist *head));

/**
 * slist_nth:   
 * @head: A generic list object, or the empty list, `NIL'.
 * @n: The number of cells to count into @list before returning.
 * 
 * Return value:
 * If @head has at least @n cells following, the address
 * of the @n-th node in @head is returned, otherwise NULL.
 **/
extern slist* slist_nth PARAMS((slist *head, unsigned n));

/**
 * slist_get:   
 * @head: A generic list object, or the empty list, `NIL'.
 * @data: The address of the reference data for @cmp.
 * @cmp: A function to compare @data with each car cell in @head.
 * 
 * @cmp is called repeatedly until it returns 0 (i.e. @cmp should behave
 * in a similar fashion to strcmp()) or until @head is exhausted.  Each call
 * is made with @data, and the car of the next cons cell in @head, starting
 * at the beginning of the list.
 *
 * This is useful to find a particular node based on part of its
 * contents.  For example, you could store pointers to a structure which
 * has a key and a data field, and use this function to find the data
 * associated with the first instance of that key in @head.  Note the careful
 * use of casting, and that the reference element is both the second parameter
 * of slist_get(), and the second parameter passed to cmp():
 *
 *	struct cdr {
 *	    char *key;
 *	    struct data *data;
 *	};
 *	
 *	int
 *	cdrcmp (try, refer)
 *	    struct cdr *try;
 *	    const char *refer;
 *	{
 *	    return strcmp(try->key, refer);
 *	}
 *	
 *	struct data*
 *	lookup (table, key)
 *	    slist *table;
 *	    char *key;
 *	{
 *	    return (struct data*)slist_get(table, (ish_pointer)key,
 *	                                     (slist_cmp_func*)cdrcmp);
 *	}
 * 
 * Return value:
 * If a match was found with @cmp, then the matching node
 * is returned.  If not, then %NIL is returned.
 **/
extern slist* slist_get PARAMS((slist *head, slist *data, slist_cmp_func *cmp));


#ifdef __cplusplus
#if 0
/* This brace is so that emacs can still indent properly: */ {
#endif
}
#endif /* __cplusplus */

#endif /* LIST_H */

/* list.h ends here */

