/*
 * Copyright (c)2004 Cat's Eye Technologies.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 *   Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 *   Neither the name of Cat's Eye Technologies nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

/*
 * chain.c
 * $Id: chain.c,v 1.2 2004/07/10 01:06:43 cpressey Exp $
 */

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "chain.h"
#include "mem.h"
#include "dump.h"

/*
 * Create a new chain of arbitrary strings.
 */
struct chain *
chain_new(void)
{
	struct chain *ch;

	DFUI_MALLOC(ch, chain);
	ch->head = NULL;
	ch->tail = NULL;

	return(ch);
}

/*
 * Free the memory allocated to hold the set of arbitrary strings.
 */
void
chain_free(struct chain *ch)
{
	struct chain_link *cl = ch->head, *next;

	while (cl != NULL) {
		next = cl->next;
		free(cl->string);
		DFUI_FREE(cl, chain_link);
		cl = next;
	}

	DFUI_FREE(ch, chain);
}

struct chain_link *
chain_first(struct chain *ch)
{
	return(ch->head);
}

struct chain_link *
chain_last(struct chain *ch)
{
	return(ch->tail);
}

struct chain_link *
chain_link_next(struct chain_link *cl)
{
	return(cl->next);
}

struct chain_link *
chain_link_prev(struct chain_link *cl)
{
	return(cl->prev);
}

char *
chain_link_get_string(struct chain_link *cl)
{
	return(cl->string);
}

/*
 * Add a string to a chain of arbitrary strings.
 */
struct chain_link *
chain_add(struct chain *ch, char *fmt, ...)
{
	struct chain_link *cl;
	va_list args;

	DFUI_MALLOC(cl, chain_link);

	va_start(args, fmt);
	vasprintf(&cl->string, fmt, args);
	va_end(args);

	cl->next = NULL;
	if (ch->head == NULL) {
		ch->head = cl;
	} else {
		ch->tail->next = cl;
	}
	cl->prev = ch->tail;
	ch->tail = cl;

	return(cl);
}

/*
 * Find an arbitrary string
 */
struct chain_link *
chain_find(struct chain *ch, char *fmt, ...)
{
	struct chain_link *cl;
	va_list args;
	char *string;

	va_start(args, fmt);
	vasprintf(&string, fmt, args);
	va_end(args);

	for (cl = ch->head; cl != NULL; cl = cl->next) {
		if (strcmp(string, cl->string) == 0) {
			free(string);
			return(cl);
		}
	}

	free(string);
	return(NULL);
}

/*
 * Find the number of entries in a chain
 */
int
chain_length(struct chain *ch)
{
	struct chain_link *cl = ch->head;
	size_t length = 0;

	while (cl != NULL) {
		length += 1;
		cl = cl->next;
	}

	return(length);
}
