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

/* list.c --- singly linked lists */

/* Author:	       Gary V. Vaughan <gvv@techie.com>
 * Maintainer:	       Gary V. Vaughan <gvv@techie.com>
 * Created:	       Thu Apr 22 23:55:20 1999
 * Last Modified:      Wed Jul 14 15:09:03 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: */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#ifndef NULL
#  ifdef STDC_HEADERS
#    include <stdlib.h>
#  else
#    define NULL 0
#  endif
#endif

#define  COMPILING_LIST_C
#include "list.h"

/**
 * 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.
 **/
void
slist_delete (list, delfunc)
    slist *list;
    slist_delete_func *delfunc;
{
    slist *stale = list;

    while (stale)
    {
	list = slist_tail(list);
	(*delfunc)(stale);
	stale = list;
    }
}

/**
 * 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);
 **/
slist*
slist_reverse (head)
    slist *head;
{
    slist *plist = head;
    slist *pprev = NIL;
    
    while (plist != NIL)
    {
	slist *node = plist->next;
	plist->next = pprev;
	pprev = plist;
	plist = node;
    }

    return pprev;
}

/**
 * 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.
 **/
slist*
slist_nth (head, n)
    slist *head;
    unsigned n;
{
    while (head != NIL && n > 0)
    {
	n--, head = head->next;
    }

    return head;
}

/**
 * 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.
 **/
slist*
slist_get (head, data, cmp)
    slist *head;
    slist *data;
    slist_cmp_func *cmp;
{
    while (head != NIL)
    {
	if (!(*cmp)(head, data)) {
	    break;
	}
	head = head->next;
    }

    return head;
}

/* list.c ends here */
