/******************************************************************************
* Module    :   List --- List building and maintenance module.
*
* Author    :   John Stevens.
******************************************************************************/

#include    "compiler.h"

#include    "unpost.h"
#include    "list.h"
#include    "utils.h"

#define INIT_SIZE   2
#define INCREASE    5

/*-----------------------------------------------------------------------------
| Routine   :   AddList() --- Add an element to a list.
|
| Inputs    :   Head    - Pointer to begining of list.
|               Elem    - New element to add to list.
|               InsPt   - List ordinal for add.
|
| Returns   :   Pointer to list head.
-----------------------------------------------------------------------------*/

void    *AddList(LIST   *Head,
                 void   *Elem,
                 int    InsPt)
{
    auto        char    *List;
    extern      FILE    *ErrFile;

    /*  Create or add to list.  */
    if (Head->NoElems >= Head->TotElems)
    {
        auto    int     NewSize;

        /*  Reallocate the list header. */
        NewSize = (Head->TotElems + INCREASE) * Head->ElemSz + sizeof( LIST );
        if ((Head = (LIST *) realloc(Head, NewSize)) == NULL)
        {
            fprintf(ErrFile,
                    "%s %d : Error - Out of memory.\n",
                    __FILE__,
                    __LINE__);
            exit( 1 );
        }

        /*  Update list size.   */
        Head->TotElems += INCREASE;
    }

    /*  Move list elements up to make room. */
    List = Head->List + Head->ElemSz * InsPt;
    if (InsPt < Head->NoElems)
    {
        MemMv(List +  Head->ElemSz,
              List,
              Head->ElemSz * (Head->NoElems - InsPt));
    }

    /*  Copy new element to it's proper location.   */
    MemCopy(List, Elem, Head->ElemSz);
    Head->NoElems++;
    return( Head );
}

/*-----------------------------------------------------------------------------
| Routine   :   CrtList() --- Create a new (empty) list.
|
| Inputs    :   ElemSz  - Size of element in bytes.
|
| Returns   :   Pointer to list head.
-----------------------------------------------------------------------------*/

void    *CrtList(int    ElemSz)
{
    auto    LIST    *Head;
    auto    int     Size;
    extern  FILE    *ErrFile;

    /*  Calculate the size of the new list and allocate it. */
    Size = INIT_SIZE * ElemSz + sizeof( LIST );
    if ((Head = (LIST *) calloc(1, Size)) == NULL)
    {
        fprintf(ErrFile,
                "%s %d : Error - Out of memory.\n",
                __FILE__,
                __LINE__);
        exit( 1 );
    }

    /*  Return the pointer to the list. */
    Head->ElemSz = ElemSz;
    Head->TotElems = INIT_SIZE;
    return( Head );
}

/*-----------------------------------------------------------------------------
| Routine   :   SrchList() --- Search the list.
|
| Inputs    :   Head    - Pointer to begining of list.
|               Elem    - Element to search list for.
|               CmpFn   - Function to compare in search.
| Outputs   :   InsPt   - List pointer for insert/found.
|
| Returns   :   TRUE for found, FALSE for not found.
-----------------------------------------------------------------------------*/

int     SrchList(LIST   *Head,
                 void   *Elem,
                 int    (*CmpFn)(void *, void *),
                 int    *InsPt)
{
    /*  Search the list for an element.
    *
    *   Do binary search.
    */
    if (Head->NoElems > 0)
    {
        auto    char    *List;
        auto    int     hi;
        auto    int     lo;
        auto    int     ret;
        auto    int     mid;

        lo = 0;
        hi = Head->NoElems - 1;
        do
        {
            /*  Get midpoint of list.   */
            mid = (hi + lo) >> 1;
            List = Head->List + Head->ElemSz * mid;

            /*  Do string compare.  */
            ret = CmpFn(Elem, List);

            /*  Adjust array pointers.  */
            if (ret <= 0)
                hi = mid - 1;
            if (ret >= 0)
                lo = mid + 1;
        } while (hi >= lo);

        /*  Did we find it? */
        if (ret == 0)
        {
            /*  We found it.    */
            *InsPt = mid;
            return( TRUE );
        }

        /*  We did not find it. */
        *InsPt = lo;
        return( FALSE );
    }

    /*  Return that we did not find it, and the point at
    *   which it should be inserted.
    */
    *InsPt = 0;
    return( FALSE );
}

/*-----------------------------------------------------------------------------
| Routine   :   ListIdx() --- Get pointer to a list element.
|
| Inputs    :   Head    - Pointer to begining of list.
|               Index   - Index of element to return pointer for.
|
| Returns   :   NULL for index outside of list limits, Pointer to list
|               element otherwise.
-----------------------------------------------------------------------------*/

void    *ListIdx(LIST   *Head,
                 int    Index)
{
    /*  Determine if index is inside list limits.   */
    if (Index < 0 || Index >= Head->NoElems)
        return( NULL );
    return( Head->List + Index * Head->ElemSz );
}

/*-----------------------------------------------------------------------------
| Routine   :   AppList() --- Append an element to a list.
|
| Inputs    :   Head    - Pointer to begining of list.
|               Elem    - New element to add to list.
|
| Returns   :   Pointer to list head.
-----------------------------------------------------------------------------*/

void    *AppList(LIST   *Head,
                 void   *Elem)
{
    auto        char    *List;
    extern      FILE    *ErrFile;

    /*  Create or add to list.  */
    if (Head->NoElems >= Head->TotElems)
    {
        auto    int     NewSize;

        /*  Reallocate the list header. */
        NewSize = (Head->TotElems + INCREASE) * Head->ElemSz + sizeof( LIST );
        if ((Head = (LIST *) realloc(Head, NewSize)) == NULL)
        {
            fprintf(ErrFile,
                    "%s %d : Error - Out of memory.\n",
                    __FILE__,
                    __LINE__);
            exit( 1 );
        }

        /*  Update list size.   */
        Head->TotElems += INCREASE;
    }

    /*  Copy new element to it's proper location.   */
    List = Head->List + Head->ElemSz * Head->NoElems;
    MemCopy(List, Elem, Head->ElemSz);
    Head->NoElems++;
    return( Head );
}


syntax highlighted by Code2HTML, v. 0.9.1