static char rcsid[] = "ccache_list.c,v 1.11 1995/11/29 00:48:30 duane Exp";
/*
 *  list.c - linked list routines
 *
 *  David Merkel & Mark Peterson, University of Colorado - Boulder, July 1994  
 *
 *  ----------------------------------------------------------------------
 *  Copyright (c) 1994, 1995.  All rights reserved.
 *  
 *    The Harvest software was developed by the Internet Research Task
 *    Force Research Group on Resource Discovery (IRTF-RD):
 *  
 *          Mic Bowman of Transarc Corporation.
 *          Peter Danzig of the University of Southern California.
 *          Darren R. Hardy of the University of Colorado at Boulder.
 *          Udi Manber of the University of Arizona.
 *          Michael F. Schwartz of the University of Colorado at Boulder.
 *          Duane Wessels of the University of Colorado at Boulder.
 *  
 *    This copyright notice applies to software in the Harvest
 *    ``src/'' directory only.  Users should consult the individual
 *    copyright notices in the ``components/'' subdirectories for
 *    copyright information about other software bundled with the
 *    Harvest source code distribution.
 *  
 *  TERMS OF USE
 *    
 *    The Harvest software may be used and re-distributed without
 *    charge, provided that the software origin and research team are
 *    cited in any use of the system.  Most commonly this is
 *    accomplished by including a link to the Harvest Home Page
 *    (http://harvest.cs.colorado.edu/) from the query page of any
 *    Broker you deploy, as well as in the query result pages.  These
 *    links are generated automatically by the standard Broker
 *    software distribution.
 *    
 *    The Harvest software is provided ``as is'', without express or
 *    implied warranty, and with no support nor obligation to assist
 *    in its use, correction, modification or enhancement.  We assume
 *    no liability with respect to the infringement of copyrights,
 *    trade secrets, or any patents, and are not responsible for
 *    consequential damages.  Proper use of the Harvest software is
 *    entirely the responsibility of the user.
 *  
 *  DERIVATIVE WORKS
 *  
 *    Users may make derivative works from the Harvest software, subject 
 *    to the following constraints:
 *  
 *      - You must include the above copyright notice and these 
 *        accompanying paragraphs in all forms of derivative works, 
 *        and any documentation and other materials related to such 
 *        distribution and use acknowledge that the software was 
 *        developed at the above institutions.
 *  
 *      - You must notify IRTF-RD regarding your distribution of 
 *        the derivative work.
 *  
 *      - You must clearly notify users that your are distributing 
 *        a modified version and not the original Harvest software.
 *  
 *      - Any derivative product is also subject to these copyright 
 *        and use restrictions.
 *  
 *    Note that the Harvest software is NOT in the public domain.  We
 *    retain copyright, as specified above.
 *  
 *  HISTORY OF FREE SOFTWARE STATUS
 *  
 *    Originally we required sites to license the software in cases
 *    where they were going to build commercial products/services
 *    around Harvest.  In June 1995 we changed this policy.  We now
 *    allow people to use the core Harvest software (the code found in
 *    the Harvest ``src/'' directory) for free.  We made this change
 *    in the interest of encouraging the widest possible deployment of
 *    the technology.  The Harvest software is really a reference
 *    implementation of a set of protocols and formats, some of which
 *    we intend to standardize.  We encourage commercial
 *    re-implementations of code complying to this set of standards.  
 *  
 */
#include <stdio.h>
#include <stdlib.h>
#include "ccache.h"
#include "ccache_list.h"

/*
 * list_apply is a function to be used with the list.h package.
 * list_apply is meant to take an address for a function, and then apply
 * that function to each node in the list.  This function checks to make
 * sure there is a function and a list.
 * 
 * If a false is returned an error has occured.
 * 
 * Preconditions:  The processor function should have been pre-written 
 * somewhere else, and its address passed into this function.  A list should
 * also be pre-made, and contain at least one node.
 * 
 * Postconditions:  If successful--list_apply will return the boolean TRUE,
 * and the processor function will have completed its task on every node.
 * If unsuccessful--list_apply will return FALSE, and the processor function
 * will abort at the point of the error.
 * 
 * Mark Peterson  9/91
 */

Boolean list_apply(processor, list) Boolean(*processor) ();	/*Function to apply to each node. */
     Linked_List *list;		/*Pointer to head of list */
{
	List_Node *tmp_node;	/*temporary pointer to each node */

	/*Check for errors in declaration. */
	if (processor == NULL || list == NULL || list->first == NULL)
		return (FALSE);

	tmp_node = list_first(list);	/*Mark first node. */
	do {
		/* Check for errors in processor function. */
		if ((*processor) (tmp_node->data) == FALSE)
			return (FALSE);

		/* Advance pointer to next node. */
		tmp_node = list_next(tmp_node);
	} while (tmp_node != list_first(list));
	/* See if all nodes have been checked. */

	return (TRUE);
}

/*
 * This is a function which works with the list.h package.
 * It is designed to create a head or handle of type Linked_List.
 * 
 * Precondition:  A compare function must be prewritten and its address
 * must be passed into this function.  Generaly a search
 * function is passed, however, a person is not restricted
 * to this.
 * 
 * Postconditon:  list_create returns a pointer to a new Linked_List if it
 * is successful.  If it is not, then it will return a NULL
 * pointer.
 * 
 * Mark Peterson  9/91
 */


Linked_List *list_create(cmp)
     int (*cmp) ();		/*compare function for the user's data */

{
	static Linked_List *tmp;

	if (cmp == NULL)
		return (NULL);

	tmp = (Linked_List *) malloc(sizeof(Linked_List));

	if (tmp != NULL) {
		tmp->first = NULL;
		tmp->last = NULL;
		tmp->count = 0;
		tmp->compare = cmp;
	}
	return (tmp);		/*return pointer to list header */
}

/*
 * This procedure will delete a single node in a list, it is
 * meant to be used with the list.h package.
 * 
 * Precondition:  The header address must be passed in along with the address
 * of the node.
 * 
 * Postconditon:  The node is deleted and the lists pointers are reestablished.
 * If either the list pointer or the node pointer are NULL,
 * then NULL is returned.
 * 
 * Mark Peterson  9/91
 */

Datum *list_delete(list, node)
     Linked_List *list;		/*pointer to the list */
     List_Node *node;		/*node to delete from list */

{
	static Datum *tmp_data;	/*Stores pointer for data of erased node */

	if (list == NULL || node == NULL)
		return (NULL);
	tmp_data = (node->data);

	/*Checks to see if this is the only node in the list. */
	if (list_previous(node) == node) {
		list_first(list) = NULL;
		list_last(list) = NULL;
		(list->count) = 0;
	} else {
		/*Bypass the middle node. */
		list_previous(node)->next = list_next(node);
		list_next(node)->previous = list_previous(node);

		if (list_first(list) == node)
			list_first(list) = list_next(node);
		/*If this is the first node in the list reset list pointer. */

		if (list_last(list) == node)
			list_last(list) = list_previous(node);
		/*If this is the last node in the list reset list pointer. */

		(list->count)--;
	}
	free((char *) node);
	return (tmp_data);	/*Return pointer at data. */
}
/*
 * This procedure destroys a list made by list_create in the list.h
 * package.  
 * 
 * Precondition:  Enter the pointer to the head of the list.  It is irregardless
 * whether there are any list nodes or not.
 * 
 * Postcondition: List is destroyed!!!
 * 
 * Mark Peterson
 */

void list_destroy(list)
     Linked_List *list;		/*pointer to header block of a list. */
{
	Datum *data;

	if (list == NULL)
		return;		/*Make sure pointer is not null. */

	while (list->first != NULL) {	/*If there is a list, delete it. */
		data = list_delete(list, list_first(list));
		if (data != NULL)
			free((char *) data);
	}

	free((char *) list);
	return;
}
/*
 * list_find is a function which can be used to search a list to
 * find and retrieve data.
 * 
 * Precondition:  User passes in a pointer to a linked list, the 
 * target data he is searching for, and finally the node he/she wishes
 * to start searching from.
 * 
 * Postcondition:  A pointer to the node which contains the necessary
 * data.  If the data is not found or the list field is
 * set to NULL, a NULL pointer will be returned.  Stating that the
 * data was not found.
 * 
 * Mark Peterson  9/91
 */

List_Node *list_find(list, target, start)
     Linked_List *list;		/* ptr to list header */
     Datum *target;		/* ptr to data being searched for. */
     List_Node *start;		/* ptr to node from which to start searching */

{
	static List_Node *tmp_node;	/*temporary trace pointer */

	if (list == NULL || list_first(list) == NULL)
		return (NULL);

	if (start == NULL)
		start = list_last(list);	/*insert in front of list */

	tmp_node = start;	/*traces starts at start marker */
	do {
		/*start searching after start node */
		tmp_node = tmp_node->next;

		/*run compare function to determine if target equals data */
		if ((*list->compare) (target, tmp_node->data) == 1)
			return (tmp_node);
	} while (tmp_node != list_last(list));
	/*continue searching until you reach the end of the list */

	return (NULL);
}

/*
 * list_insert is a procedure used with the list.h package.
 * It inserts a new record in the linked list.
 * 
 * Precondition:  The list header must be passed in, along with a pointer
 * to the record to be inserted, and finally, the user
 * must pass in a pointer to the record he/she wants it placed
 * after.  If the record is to be placed in the front of the 
 * list, where should be passed in as NULL.
 * 
 * Postcondition:  If all goes well, the node will be made and the data record
 * will be placed into the list in the correct place.
 * Otherwise, a NULL pointer will be returned.
 * 
 * Mark Peterson  9/91
 */

List_Node *list_insert(list, datum, where)
     Linked_List *list;		/*pointer to the list */
     Datum *datum;		/*data to place into list */
     List_Node *where;		/*place to insert after */

{
	List_Node *tmp_node;	/*pointer to the new node */

	if (list == NULL)
		return (NULL);	/*Make sure there is a list. */

	tmp_node = (List_Node *) malloc(sizeof(List_Node));

	if (tmp_node == NULL)
		return (NULL);
	tmp_node->data = datum;	/*Place data in data field */
	if (where != NULL) {	/*Check to see if this record should
				 * be first.  If not then continue. */
		/*Rearrange link pointers. */
		list_previous(tmp_node) = where;
		list_next(tmp_node) = list_next(where);
		list_next(where)->previous = tmp_node;
		list_next(where) = tmp_node;
		/* If this is the last node rearrange last pointer. */
		if (list_last(list) == where)
			list_last(list) = tmp_node;
	} else {		/*Node will be first in list. */
		if (list_first(list) == NULL) {
			/*Set header pointers. */
			list_first(list) = tmp_node;
			list_last(list) = tmp_node;
		}
		/*Set previous/next pointers in node. */
		list_previous(tmp_node) = list_last(list);
		list_next(tmp_node) = list_first(list);
		/* Save time if list ptrs already empty list . */
		if (list_first(list) != tmp_node) {
			list_first(list)->previous = tmp_node;
			list_last(list)->next = tmp_node;
			list_first(list) = tmp_node;
		}
	}
	(list->count)++;
	return (tmp_node);
}

/*
 * This is the put_data function to be used with the list.h package.
 * It will take a pointer to a data record and a pointer to the 
 * correct node, then affix the data to that node.
 * 
 * Preconditions:  There must be a pointer to the proper node, and 
 * data record. 
 * 
 * Postconditions:  Old data is replaced with the new data.
 * **Note:This can be used to overwrite old data
 * or to free data slots before list_destroy, if
 * a NULL is passed in as data.**
 * 
 * Mark Peterson
 */

void list_putdata(node, data)
     List_Node *node;
     Datum *data;

{
	if (node == NULL)
		return;		/*Make sure there is a node. */

	free((char *) node->data);	/*Free old data memory space. */
	node->data = data;	/*Put in new data (or NULL). */
	return;
}
