/*
**	termDebug.h
**
**	Support routines for memory allocation debugging
**
**	Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* The original system routines. */

APTR OldAllocVec(LONG,ULONG);
VOID OldFreeVec(APTR);

#pragma libcall SysBase OldAllocVec 2AC 1002
#pragma libcall SysBase OldFreeVec 2B2 901

APTR OldAllocMem(LONG,ULONG);
VOID OldFreeMem(APTR,LONG);

#pragma libcall SysBase OldAllocMem C6 1002
#pragma libcall SysBase OldFreeMem D2 0902

	/* A custom node type. */

struct SomeNode
{
	struct MinNode	MinNode;	/* Exec link. */

	APTR		Data;		/* Actual data instance. */
	LONG		Size;		/* Actual data size. */
	ULONG		Attributes;	/* Allocation attributes. */
	UBYTE		Name[32];	/* The name of the task to make the call. */

	UBYTE		File[80];	/* The file the call came from. */
	LONG		Line;		/* The file line the call came from. */
};

	/* Local data. */

STATIC struct MinList		*SomeList;
STATIC struct SignalSemaphore	*SomeSemaphore;

#ifdef DEBUG_COVER

extern long __far _CoverStart;
extern long __far _CoverLength;

VOID
CoverInit()
{
	STATIC BYTE CoverInfoRead = FALSE;

	if(!CoverInfoRead)
	{
		BPTR FileHandle;

		if(FileHandle = Open("cover.dat",MODE_OLDFILE))
		{
			UBYTE Tag[4];

			if(Read(FileHandle,Tag,4) == 4)
			{
				if(!memcmp(Tag,"COV",4))
				{
					LONG Length;

					if(Read(FileHandle,&Length,sizeof(LONG)) == sizeof(LONG))
					{
						if(Length == (LONG)&_CoverLength)
							Read(FileHandle,&_CoverStart,Length);
					}
				}
			}

			Close(FileHandle);
		}

		CoverInfoRead = TRUE;
	}
}

VOID
CoverExit()
{
	BPTR FileHandle;

	if(FileHandle = Open("cover.dat",MODE_NEWFILE))
	{
		BYTE Success	= FALSE;
		LONG Length	= (LONG)&_CoverLength;

		if(Write(FileHandle,"COV",4) == 4)
		{
			if(Write(FileHandle,&Length,sizeof(LONG)) == sizeof(LONG))
			{
				if(Write(FileHandle,&_CoverStart,Length) == Length)
					Success = TRUE;
			}
		}

		Close(FileHandle);

		if(Success)
			SetProtection("cover.dat",FIBF_EXECUTE);
		else
			DeleteFile("cover.dat");
	}
}

#endif	/* DEBUG_COVER */

	/* DebugExit(VOID):
	 *
	 *	Unlink the debugging support code.
	 */

VOID
DebugExit(VOID)
{
	if(SomeList)
	{
		struct SomeNode *Node,*Next;

		ObtainSemaphore(SomeSemaphore);

		Node = (struct SomeNode *)SomeList -> mlh_Head;

		if(Node -> MinNode . mln_Succ)
		{
			kprintf("Adress     Size       Attributes Allocated by\n---------- ---------- ---------- --------------------------------\n");

			while(Next = (struct SomeNode *)Node -> MinNode . mln_Succ)
			{
				kprintf("0x%08lx %10ld 0x%08lx »%s«\n",Node -> Data,Node -> Size,Node -> Attributes,Node -> Name);
	
				if(Node -> File[0])
					kprintf(": File »%s», Line %ld\n",Node -> File,Node -> Line);

				Remove((struct Node *)Node);

				OldFreeMem(Node,Node -> Size + sizeof(struct SomeNode));

				Node = Next;
			}
		}
		else
			kprintf("*** No remaining memory blocks\n");

		ReleaseSemaphore(SomeSemaphore);

		OldFreeVec(SomeList);

		SomeList = NULL;

		OldFreeVec(SomeSemaphore);

		SomeSemaphore = NULL;
	}
}

	/* DebugInit(VOID):
	 *
	 *	Initialize the debugging support code.
	 */

VOID
DebugInit(VOID)
{
	if(SomeList = (struct MinList *)OldAllocVec(sizeof(struct MinList),MEMF_ANY | MEMF_PUBLIC))
	{
		NewList((struct List *)SomeList);

		if(SomeSemaphore = (struct SignalSemaphore *)OldAllocVec(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
		{
			InitSemaphore(SomeSemaphore);

			return;
		}

		OldFreeVec(SomeList);

		SomeList = NULL;
	}
}

	/* New custom memory allocation routines. */

VOID __regargs
FreeVecNew(APTR Data)
{
	if(SomeList)
	{
		struct SomeNode *Node,*Next;

		ObtainSemaphore(SomeSemaphore);

		Node = (struct SomeNode *)SomeList -> mlh_Head;

		while(Next = (struct SomeNode *)Node -> MinNode . mln_Succ)
		{
			if(Node -> Data == Data)
			{
				Remove((struct Node *)Node);

				OldFreeMem(Node,Node -> Size + sizeof(struct SomeNode));

				break;
			}
			else
				Node = Next;
		}

		ReleaseSemaphore(SomeSemaphore);
	}
	else
		OldFreeVec(Data);
}

APTR __regargs
AllocVecNew(LONG Size,ULONG Attributes,LONG Line,STRPTR File)
{
	if(SomeList)
	{
		struct SomeNode *Node;

		if(Node = (struct SomeNode *)OldAllocMem(sizeof(struct SomeNode) + Size,Attributes))
		{
			Node -> Data		= (APTR)(Node + 1);
			Node -> Size		= Size;
			Node -> Attributes	= Attributes;

			if(SysBase -> ThisTask -> tc_Node . ln_Name)
			{
				memcpy(Node -> Name,SysBase -> ThisTask -> tc_Node . ln_Name,32);

				Node -> Name[31] = 0;
			}
			else
				strcpy(Node -> Name,"*** Namenlos ***");

			memcpy(Node -> File,File,80);

			Node -> File[79] = 0;

			Node -> Line = Line;

			ObtainSemaphore(SomeSemaphore);

			AddHead((struct List *)SomeList,(struct Node *)Node);

			ReleaseSemaphore(SomeSemaphore);

			return(Node -> Data);
		}
		else
			return(NULL);
	}
	else
		return(OldAllocVec(Size,Attributes));
}

VOID __regargs
FreeMemNew(APTR Data,LONG Size)
{
	if(SomeList)
	{
		struct SomeNode *Node,*Next;

		ObtainSemaphore(SomeSemaphore);

		Node = (struct SomeNode *)SomeList -> mlh_Head;

		while(Next = (struct SomeNode *)Node -> MinNode . mln_Succ)
		{
			if(Node -> Data == Data)
			{
				Remove((struct Node *)Node);

				OldFreeMem(Node,Node -> Size + sizeof(struct SomeNode));

				break;
			}
			else
				Node = Next;
		}

		ReleaseSemaphore(SomeSemaphore);
	}
	else
		OldFreeMem(Data,Size);
}

APTR __regargs
AllocMemNew(LONG Size,ULONG Attributes,LONG Line,STRPTR File)
{
	if(SomeList)
	{
		struct SomeNode *Node;

		if(Node = (struct SomeNode *)OldAllocMem(sizeof(struct SomeNode) + Size,Attributes))
		{
			Node -> Data		= (APTR)(Node + 1);
			Node -> Size		= Size;
			Node -> Attributes	= Attributes;

			if(SysBase -> ThisTask -> tc_Node . ln_Name)
			{
				memcpy(Node -> Name,SysBase -> ThisTask -> tc_Node . ln_Name,32);

				Node -> Name[31] = 0;
			}
			else
				strcpy(Node -> Name,"*** Namenlos ***");

			memcpy(Node -> File,File,80);

			Node -> File[79] = 0;

			Node -> Line = Line;

			ObtainSemaphore(SomeSemaphore);

			AddHead((struct List *)SomeList,(struct Node *)Node);

			ReleaseSemaphore(SomeSemaphore);

			return(Node -> Data);
		}
		else
			return(NULL);
	}
	else
		return(OldAllocMem(Size,Attributes));
}
