/*
 * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/lst_void.c,v 1.12 2004/04/30 13:41:56 aleigh Exp $ 
 */

/*
 * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */

#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

#include "mecha.h"

struct lstSlist_elem {
    void *data;
    lstTlist_elem *next;
    lstTlist_elem *prev;
};

struct lstSlist {
    int size;

    void (*destroy) (void *);   /* passed lstTlist_elem->data */

    lstTlist_elem *head;
    lstTlist_elem *tail;
};

/** Linked list code **/

/*
 * Initialize a new linked list, with the destructor destory.
 */
void lstFlist_init(lstTlist * list, void (*destroy) (void *))
{
    list->size = 0;
    list->destroy = destroy;

    list->head = NULL;
    list->tail = NULL;

    return;
}

/*
 * destroy the given list, freeing all memory
 */
void lstFlist_destroy(lstTlist * list)
{
    void *data;

    while (lstFlist_size(list) > 0) {
        if (lstFlist_remove(list, lstFlist_tail(list), &data) == 0 &&
            list->destroy != NULL)
            list->destroy(data);
    }

    memFclear(list, sizeof(lstTlist));
}

/*
 * THESE SHOULD REPLACE THE CURRENT INIT AND DESTROY FUNCTIONS
 */
lstTlist *lstFlist_create(void (*destroy) (void *))
{
    lstTlist *list = malloc(sizeof(lstTlist));

    lstFlist_init(list, destroy);

    return (list);
}

void lstFlist_free(lstTlist * list)
{
    lstFlist_destroy(list);

    free(list);
}

int lstFlist_add_next(lstTlist * list, lstTlist_elem * elem, void *data)
{
    lstTlist_elem *new_elem;

    if (lstFlist_size(list) != 0 && elem == NULL)
        return (-1);

    new_elem = (lstTlist_elem *) malloc(sizeof(lstTlist_elem));

    if (new_elem == NULL)
        return (-1);

    new_elem->data = data;

    if (lstFlist_size(list) == 0) {
        new_elem->next = new_elem->prev = NULL;

        list->head = list->tail = new_elem;
    } else {
        /* insert after elem */

        new_elem->next = elem->next;
        new_elem->prev = elem;

        if (elem->next == NULL)
            list->tail = new_elem;
        else
            elem->next->prev = new_elem;

        elem->next = new_elem;
    }

    list->size++;

    return (0);
}

int lstFlist_add_prev(lstTlist * list, lstTlist_elem * elem, void *data)
{
    lstTlist_elem *new_elem;

    if (lstFlist_size(list) != 0 && elem == NULL)
        return (-1);

    new_elem = (lstTlist_elem *) malloc(sizeof(lstTlist_elem));

    if (new_elem == NULL)
        return (-1);

    new_elem->data = data;

    if (lstFlist_size(list) == 0) {
        new_elem->next = new_elem->prev = NULL;

        list->head = list->tail = new_elem;
    } else {
        /* insert before elem */

        new_elem->prev = elem->prev;
        new_elem->next = elem;

        if (elem->prev == NULL)
            list->head = new_elem;
        else
            elem->prev->next = new_elem;

        elem->prev = new_elem;
    }

    list->size++;

    return (0);
}

int lstFlist_remove(lstTlist * list, lstTlist_elem * elem, void **data)
{
    if (lstFlist_size(list) == 0 || elem == NULL)
        return (-1);

    if (data)
        *data = elem->data;

    if (elem == list->head) {
        list->head = elem->next;

        if (list->head == NULL)
            list->tail = NULL;
        else
            list->head->prev = NULL;
    } else {
        elem->prev->next = elem->next;

        if (elem->next == NULL)
            list->tail = elem->prev;
        else
            elem->next->prev = elem->prev;
    }

    free(elem);

    list->size--;

    return (0);
}

lstTlist_elem *lstFlist_next(lstTlist_elem * elem)
{
    return (elem->next);
}

lstTlist_elem *lstFlist_prev(lstTlist_elem * elem)
{
    return (elem->prev);
}

void *lstFlist_data(lstTlist_elem * elem)
{
    return (elem->data);
}

int lstFlist_is_head(lstTlist * list, lstTlist_elem * elem)
{
    if (list->head == elem) {
        return (1);
    } else {
        return (0);
    }
}

int lstFlist_is_tail(lstTlist * list, lstTlist_elem * elem)
{
    if (list->tail == elem) {
        return (1);
    } else {
        return (0);
    }
}

lstTlist_elem *lstFlist_head(lstTlist * list)
{
    return (list->head);
}

lstTlist_elem *lstFlist_tail(lstTlist * list)
{
    return (list->tail);
}

int lstFlist_size(lstTlist * list)
{
    return (list->size);
}
