
/******************************************************************************
**
**  Copyright (C) 2001  - the shmoo group -
**
**  This program is free software; you can redistribute it and/or
**  modify it, however, you cannot sell it.
**
**  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.
**
**  You should have received a copy of the license attached to the
**  use of this software.  If not, visit www.shmoo.com/osiris for
**  details.
**
******************************************************************************/

/******************************************************************************
**
**    The Shmoo Group (TSG)
**
**    File:      list.c
**    Author:    Brian Wotring
**
**    Date:      June 22, 2001.
**    Project:   osiris
**
******************************************************************************/

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

#include <sys/types.h>
#include <sys/stat.h>

#include "utilities.h"
#include "list.h"

/******************************************************************************
**
**    Function: list_new
**
**    Purpose:  create a new list structure, which consists of
**              creating a dummy none.
**
******************************************************************************/

osi_list list_new()
{
    node *head = osi_malloc( sizeof( struct node ) );

    head->data = NULL;
    head->next = NULL;

    return head;
}

/******************************************************************************
**
**    Function: list_destroy
**
**    Purpose:  frees the nodes in the list.  careful, if you are
**              storing data, you will need to remove it by hand
**              before destroying the actual list.
**
******************************************************************************/

void list_destroy( osi_list head )
{
    node *temp;

    if( head != NULL )
    {
        while( head )
        {
            temp = head->next;
            osi_free( head );
            head = temp;
        }
    }
}

/******************************************************************************
**
**    Function: list_destroy_with_function
**
**    Purpose:  frees the nodes in the list.  with this method, the
**  	    	specified function will be called on all of the data
**	    	    items in the list, so as to free the complete list.
**
******************************************************************************/

void list_destroy_with_function( osi_list head, void (*data_destroy)(void *) )
{
    node *temp;

    if( ( head != NULL ) && ( data_destroy != NULL ) )
    {
        while( head )
        {
            temp = head->next;
            
            /* first free the data object with out function. */
            
            if( head->data != NULL )
            {
                data_destroy( head->data );
            }
            
            /* now free the node object. */
            
            osi_free( head );
            head = temp;
        }
    }
}


/******************************************************************************
**
**    Function: list_add
**
**    Purpose:  add an element to the back of the list.
**
******************************************************************************/

osi_bool list_add( osi_list head, void *new_data )
{
    node *new_node;
    node *temp;

    if( head == NULL )
    {
        return FALSE;
    }

    new_node = osi_malloc( sizeof( struct node ) );

    new_node->data = new_data;
    new_node->next = NULL;

    /* go through list and find the last valid node. */

    temp = head;

    while( temp->next != NULL )
    {
        temp = temp->next;
    }

    /* insert our new node. */

    temp->next = new_node;

    return TRUE;
}

/******************************************************************************
**
**    Function: list_remove_index
**
**    Purpose:  remove the specified element from the list, free it
**              with osi_free(), lists that require other free methods
**              will not be able to use this function. zero indexed list.
**
******************************************************************************/

osi_bool list_remove_index( osi_list head, int index )
{
    int current_index = 0;

    node *previous = head;
    node *temp = NULL;

    if( head == NULL )
    {
        return FALSE;
    }

    temp = list_get_first_node( head );

    /* no nodes. */

    if( temp == NULL )
    {
        return FALSE;
    }

    while( temp )
    {
        /* we need to remove this item. */

        if( current_index == index )
        {
            /* free data if it is there. */    
            
            osi_free( temp->data );

            /* close the gap. */

            previous->next = temp->next;

            /* free the node. */

            osi_free( temp );
            return TRUE;
        } 

        previous = temp;
        temp = temp->next;

        current_index++;
    }

    return FALSE;
}


/******************************************************************************
**
**    Function: list_get_size
**
**    Purpose:  return number of nodes in this linked list.
**
******************************************************************************/

int list_get_size( osi_list head )
{
    int count = 0;
    
    if( head != NULL )
    {
        /* skip over first dummy node. */
        
        head = head->next;
        
        while( head )
        {
            count++;
            head = head->next;
        }
    }
    
    return count;
}

/******************************************************************************
**
**    Function: list_get_first_node
**
**    Purpose:  skip over dummy node and return the first data node.
**
******************************************************************************/

node * list_get_first_node( osi_list head )
{
    /* first node is dummy, return node */
    /* after dummy node.                */

    return list_get_next_node( head );
}

/******************************************************************************
**
**    Function: list_get_next_node
**
**    Purpose:  attempt to get the node after the specified node.
**
******************************************************************************/

osi_list list_get_next_node( osi_list head )
{
    if( head == NULL )
    {
        return NULL;
    }

    return head->next;
}

/******************************************************************************
**
**    Function: list_dump
**
**    Purpose:  raw list data dump, used for debugging.
**
*****************************************************************************/

void list_dump( osi_list head )
{
    osi_list start = head;

    if( head == NULL )
    {
        return;
    }

    fprintf( stderr, " ----[ list dump ]----\n\n" );
    fprintf( stderr, " (head) " );

    head = head->next;

    while( head != NULL )
    {
        fprintf( stderr, "-> <node - data:" );

        if( head->data != NULL )
        {
            fprintf( stderr, "%d> ", head->data );
        }

        else
        {
            fprintf( stderr, "null> " );
        }

        head = head->next;

        if( head == NULL )
        {
            fprintf( stderr, "-> NULL" );
        }

        else
        {
            fprintf( stderr, "->data " );
        }
    }

    fprintf( stderr, "\n\n" );
}
