/*------------------------------------------------------------------
			Debug Library
			-------------
 
	Header for C interface to debug library

	(C) Silicon Dream Ltd 1994

  ------------------------------------------------------------------

Changes:						Date:
* Created file						27/10/94
*/

#ifndef DEBUG
#define DEBUG

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

/* Defined operations:

	DebOut("debug.txt+")		First call to Deb should provide an output file name
					  The optional '+' provides additional output to the console
	DebOut("....", p1, p2...pn);	Outputs a formatted debug string with a timestamp
	DebOut(FLUSH)			Forces flushing buffer contents to file
	DebOut(STOP)			Flushes buffer to file and closes the file
	Malloc(size)			Allocates memory
	Free(ptr)			Frees memory
	DebListMem()			Lists details of all memory currently allocated to the
					debug output file

	Given that the debug library can be linked to many EXEs and/or DLLs at the
	same time the rules governing what appears in what file are quite straightforward.
	There is one output file per instance (ie. per data segment to which the library
	is linked). If say we link to a DLL with one data segment per instance, then each
	task using the DLL will have a seperate output file. The first call to DebOut() for
	each instance should provide the name of an output file. The allocated memory list
	also works on a per-instance basis, so for instance an EXE linked to the library will
	get only its allocated memory shown by DebListMem() and not that of some DLL linked
	to its own copy of the library
*/

#define FLUSH		"\xff\0"
#define STOP		"\xfe\0"

typedef void (* DebOutFunc) (char *sz, ...);
typedef void (* AddOutFunc) (char *sz);
typedef void *(* AppAllocFunc) (ulong ulSize);
typedef void (* AppFreeFunc) (void *pv);

extern void Deb (ulong ulClock, char *sz, AddOutFunc pfnAddOut, va_list val);
extern void *DebAlloc (ulong ulSizeIn, char *szFN, ushort usLine, bool bNew, AppAllocFunc DebAppAlloc);
extern void DebFree (void *pvMem, bool bDeb, AppFreeFunc DebAppFree);
extern void DebMem (DebOutFunc pfnDebOut);

extern void DebStart (void);

/* If we're linking the debug library with a windows DLL we will not get
   access to the standard C library function clock, instead we use the
   windows function GetTickCount. Also it seems the malloc function can
   corrupt memory under windows so instead we call two seperate memory
   allocation routines for windows and non windows programs */

//------------------ C PROGRAM -------------------------
#ifndef _WINDOWS

#include <time.h>

#ifdef _DEBUG
_st void AddOut (char *sz)
	{
	printf(sz);
	}

_st void DebOut (char *sz, ...)
	{
	va_list		val;

	va_start(val, sz);
	Deb(((ulong) clock())*1000L/CLOCKS_PER_SEC, sz, AddOut, val);
	va_end(val);
	}
#endif

_st void *DebAppAlloc (ulong ulSize)
	{
	return malloc((size_t) ulSize);
	}

_st void DebAppFree (void *pv)
	{
	free(pv);
	}

#endif

//------------------ WINDOWS PROGRAM -------------------
#ifdef _WINDOWS

#include <windows.h>

#ifdef _DEBUG
_st void AddOut (char *sz)
	{
	OutputDebugString(sz);
	}

_st void DebOut (char *sz, ...)
	{
	va_list		val;

	va_start(val, sz);
	Deb(((ulong) GetTickCount()), sz, AddOut, val);
	va_end(val);
	}
#endif

_st void *DebAppAlloc (ulong ulSize)
	{
	HGLOBAL		hg, *phg;

	if ((hg=GlobalAlloc(0, ulSize+sizeof(HGLOBAL)))==0)
		return NULL;
	phg=(HGLOBAL *) GlobalLock(hg);
	*phg=hg;
	return (void *) (phg+1);
	}

_st void DebAppFree (void *pv)
	{
	HGLOBAL		*phg=((HGLOBAL *) pv)-1;

	GlobalUnlock(*phg);
	GlobalFree(*phg);
	}

#endif

//------------------ ANY PROGRAM -----------------------
#ifdef _DEBUG
#define Malloc(x)	DebAlloc(x, __FILE__, __LINE__, FALSE, DebAppAlloc)
#define Free(x)		DebFree(x, TRUE, DebAppFree)
#define DebListMem()	DebMem(DebOut)
#endif
#ifndef _DEBUG
#define Malloc(x)	DebAlloc(x, NULL, 0, FALSE, DebAppAlloc)
#define Free(x)		DebFree(x, FALSE, DebAppFree)
#define DebListMem()	;
#endif

#endif DEBUG		// Do no include this file twice
