/*
 * Copyright 1990 by Baylor College of Medicine ALL RIGHTS RESERVED. 
 *
 * This program is subject to a license agreement between 
 * Baylor College of Medicine and MIT. Any use inconsistent with
 * said license and any use by persons other than the faculty, 
 * students and staff at MIT or any use on a computer not operated 
 * as part of the Athena Computing Environment (ACE) is expressly 
 * prohibited.
 */
#include <stdio.h>
#include <malloc.h>
#include "ll.h"

static
LLINK
alloc_link(prev,ll)
	LLINK *prev ;
	LLIST ll ;
{
	LLINK new = (LLINK)malloc(sizeof *new) ;

	/* Fill in pointer to next (Which was former value in previous) */
	new->next = *prev ;

	/* Put in pointer to previous */
	new->prev = prev ;

	/* If there was a former value then make his previous equal
	   to  a pointer to our next field */
	if (*prev)
	{
		(*prev)->prev = &(new->next) ;
	}

	/* Slip us in */
	*prev = new ;

	/* If inserted after previous last the update last */
	if (ll->last == prev)
	{
		ll->last = &(new->next) ;
	}
	ll->size++ ;

	return new ;
}

/*
 *	Note that when add_link, add_beginning, add_last are called,
 *		the pointer to the structure being added must be
 *		allocated (or at least distinct such as a static variable)
 *		when a link is destroyed, the pointer is not freed.
 */
/*
 *	Adds a link after another link in a list.
 */
LLINK
add_link(lr,prev,ll)
	unsigned char *lr ;
	LLINK *prev ;
	LLIST ll ;
{
	LLINK new = alloc_link(prev,ll) ;
	new->lr = lr ;
	return new ;
}

/*
 *	Deletes a link from a list.
 */
void
del_link(link,ll)
	LLINK link ;
	LLIST ll ;
{
	LLINK next = link->next ;

	/* If anyhting afterwards then set its previous to our previous  */
	if (next)
	{
		next->prev = link->prev ;
	}

	/* If delete last then reset last to previous */
	if (ll->last == &(link->next))
	{
		ll->last = link->prev ;
	}

	/* Set previous equal to our next */
	*(link->prev) = next ;
	ll->size-- ;

	free((char *)link) ;
}

/*
 *	Initializes a list.
 */
LLIST
init_list()
{
	LLIST ll = (LLIST)malloc(sizeof *ll) ;
	ll->first = NULL ;
	ll->last = &ll->first ;
	ll->size = 0 ;
	return ll ;
}

/*
 *	Deletes a list.
 */
void
del_list(ll)
	LLIST ll ;
{
	while(ll->first)
	{
		del_link(ll->first,ll) ;
	}
	free((char *)ll) ;
}

/*
 *		Gets the nth element of a list.
 */
LLINK *
get_n_link(n,ll)
	LLIST ll ;
{
	LLINK *l = &(ll->first) ;
	if (n < 0 || n >= ll->size)
	{
		return NULL ;
	}
	while(n--)
	{
		l = &((*l)->next) ;
	}
	return l ;
}
