#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <_heap.h>



static unsigned char* V[256];



static char* Alloc (void)
/* Allocate a random sized chunk of memory */
{
    /* Determine the size */
    unsigned char Size = (((unsigned char)rand()) & 0x7F) + 1;

    /* Allocate memory */
    unsigned char* P = malloc (Size);

    /* Set the string to a defined value. We use the size, since this will
    ** also allow us to retrieve it later.
    */
    if (P) {
        memset (P, Size, Size);
    } else {
        printf ("Could not allocate %u bytes\n", Size);
        exit (EXIT_FAILURE);
    }
    return P;
}



static void Free (unsigned char* P)
/* Check a memory block and free it */
{
    unsigned char I;

    /* Get the size of the block */
    unsigned char Size = P[0];

    /* Scan the block */
    for (I = 1; I < Size; ++I) {
        if (P[I] != Size) {
            printf ("Scan failed - expected %02X, got %02X\n",
                    Size, P[I]);
            exit (EXIT_FAILURE);
        }
    }

    /* Free the block */
    free (P);
}



static void FillArray (void)
/* Fill the array with randomly allocated memory chunks */
{
    unsigned char I = 0;
    do {
        V[I] = Alloc ();
        ++I;
    } while (I != 0);
}



static void ShowInfo (void)
/* Show heap info */
{
    /* Count free blocks */
    unsigned Count = 0;
    register struct freeblock* P = _heapfirst;
    while (P) {
        ++Count;
        P = P->next;
    }
    printf ("%04X  %04X  %04X  %04X  %04X %u\n",
            _heaporg, _heapptr, _heapend, _heapfirst, _heaplast, Count);

    if (Count) {
        P = _heapfirst;
        while (P) {
            printf ("%04X  %04X  %04X %04X(%u)\n",
                    (unsigned) P, P[2], P[1], P[0], P[0]);
            P = P->next;
        }
        getchar ();
    }
}



static void Test1 (void)
{
    unsigned char I;
    FillArray ();
    for (I = 0; I < 0x80; ++I) {
        Free (V[0x7F-I]);
        Free (V[0x80+I]);
    }
    ShowInfo ();
}



static void Test2 (void)
{
    unsigned char I;
    FillArray ();
    I = 0;
    do {
        Free (V[I]);
        ++I;
    } while (I != 0);
    ShowInfo ();
}



static void Test3 (void)
{
    unsigned char I;
    FillArray ();
    I = 0;
    do {
        --I;
        Free (V[I]);
    } while (I != 0);
    ShowInfo ();
}



static void Test4 (void)
{
    unsigned char I;
    FillArray ();
    I = 0;
    do {
        Free (V[I]);
        I += 2;
    } while (I != 0);
    I = 1;
    do {
        Free (V[I]);
        I += 2;
    } while (I != 1);
    ShowInfo ();
}



static void Test5 (void)
{
    unsigned char I;
    FillArray ();
    I = 0;
    do {
        Free (V[I]);
        I += 2;
    } while (I != 0);
    do {
        V[I] = Alloc ();
        I += 2;
    } while (I != 0);
    I = 1;
    do {
        Free (V[I]);
        I += 2;
    } while (I != 1);
    do {
        V[I] = Alloc ();
        I += 2;
    } while (I != 1);
    I = 0;
    do {
        Free (V[I]);
        ++I;
    } while (I != 0);
    ShowInfo ();
}



static void Test6 (void)
{
    unsigned char I, J;
    FillArray ();
    I = J = 0;
    do {
        do {
            Free (V[I]);
            V[I] = Alloc ();
            ++I;
        } while (I != 0);
        ++J;
    } while (J < 5);
    do {
        Free (V[I]);
        ++I;
    } while (I != 0);
    ShowInfo ();
}



int main (void)
{
    unsigned long T;

    /* Show info at start */
    ShowInfo ();
#if !defined(__APPLE2__)
    /* Remember the time */
    T = clock ();
#endif
    /* Do the tests */
    Test1 ();
    Test2 ();
    Test3 ();
    Test4 ();
    Test5 ();
    Test6 ();

#if !defined(__APPLE2__)
    /* Calculate the time and print it */
    T = clock () - T;
    printf ("Time needed: %lu ticks\n", T);
#endif
    /* Done */
    return EXIT_SUCCESS;
}