/***************************************************************************
*	NAME:  MEMFREE.C
**	COPYRIGHT:
**	"Copyright (c) 1992, by FORTE
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
*  CREATION DATE: 11/18/92
*--------------------------------------------------------------------------*
*     VERSION	DATE	   NAME		DESCRIPTION
*>	1.0	11/18/92		Original
***************************************************************************/
#include <dos.h>

#include "forte.h"
#include "gf1proto.h"
#include "osproto.h"
#include "gf1hware.h"
#include "gf1os.h"
#include "ultraerr.h"

extern ULTRA_DATA _gf1_data;

static void combine_mem(void)
{
unsigned long ptr;
unsigned long next;
unsigned long next_next;
unsigned long pool_size;
unsigned long next_size;

ptr = _gf1_data.free_mem;

while (ptr != 0)
	{
	next = UltraPeekLong(ptr+NEXT_OFFSET);
	pool_size = UltraPeekLong(ptr+SIZE_OFFSET);

	if ((ptr+pool_size) == next)
		{
		next_next = UltraPeekLong(next+NEXT_OFFSET);
		next_size = UltraPeekLong(next+SIZE_OFFSET);
		pool_size += next_size;
		UltraPokeLong(ptr+SIZE_OFFSET,pool_size);
		UltraPokeLong(ptr+NEXT_OFFSET,next_next);
		if (next_next != 0L)
			UltraPokeLong(next_next+PREV_OFFSET,ptr);
		else
			ptr = 0L;		/* end of list */
		}
	else
		ptr = UltraPeekLong(ptr+NEXT_OFFSET);	/* next please */
	}
}

int
UltraMemFree(unsigned long size,unsigned long location)
{
unsigned long ptr;
unsigned long prev;
unsigned long next;
int flag = FALSE;

/* Round size up to next 32 byte boundary */
size += 31;
size &= -32L;

ptr = _gf1_data.free_mem;

if (ptr == 0L)
	{
	/* No free ram. Make this the first in the list */
	_gf1_data.free_mem = location;
	UltraPokeLong(location+NEXT_OFFSET,0L);
	UltraPokeLong(location+PREV_OFFSET,0L);
	UltraPokeLong(location+SIZE_OFFSET,size);
	flag = TRUE;
	}
else
	{
	while (ptr != 0L && !flag)
		{
		next = UltraPeekLong(ptr+NEXT_OFFSET);
		prev = UltraPeekLong(ptr+PREV_OFFSET);
		if (location < ptr)
			{
			if (prev == 0L)
				_gf1_data.free_mem = location;
			else
				UltraPokeLong(prev+NEXT_OFFSET,location);
			UltraPokeLong(location+NEXT_OFFSET,ptr);
			UltraPokeLong(location+PREV_OFFSET,prev);
			UltraPokeLong(location+SIZE_OFFSET,size);
			UltraPokeLong(ptr+PREV_OFFSET,location);
			flag = TRUE;
			}
		else
			{
			if (next == 0L)
				{
				UltraPokeLong(ptr+NEXT_OFFSET,location);
				UltraPokeLong(location+NEXT_OFFSET,0L);
				UltraPokeLong(location+PREV_OFFSET,ptr);
				UltraPokeLong(location+SIZE_OFFSET,size);
				flag = TRUE;
				}
			}
		ptr = UltraPeekLong(ptr+NEXT_OFFSET);	/* next please */
		}
	}

if (flag)
	{
	/* combine blocks here ... */
	combine_mem();

	return(ULTRA_OK);
	}
else
	return(CORRUPT_MEM);
}

