/*----------------------------------------------------------------------------
	Dbgutil.H
		Exported header file for Dbgutil module.

	Copyright (C) 1993 Microsoft Corporation
	All rights reserved.

	Authors:
		kennt	Kenn Takara
		GaryBu	Gary S. Burd

	History:
		05/07/93 suryanr Created.
		06/09/93 kennt	 Reorganized.
		07/06/93 kennt	 YAR (Yet Another Reorg), refactoring code
 ----------------------------------------------------------------------------*/

#ifndef _DBGUTIL_H
#define _DBGUTIL_H

//#ifndef _UTILCORE_H
//#include "utilcore.h"
//#endif

#ifdef __cplusplus
extern "C" {
#else
#define NOENTRYEXITTRACE	1	
#endif

#if defined(_DEBUG) && !defined(DEBUG)
#define DEBUG
#endif


#define DBG_STRING(var, val) \
	static TCHAR var[] = TEXT(val);
#define DBG_STRING_NL(var, val) \
	static TCHAR var[] = TEXT(val "\r\n");

#ifndef DllExport
#define DllExport	__declspec ( dllexport )
#endif

#ifndef EXPORT
#define EXPORT
#endif

#define DBG_API(type)		DllExport type FAR PASCAL EXPORT
#define DBG_APIV(type)		DllExport type FAR CDECL EXPORT

/*---------------------------------------------------------------------------
	IfBUILD macros
 ---------------------------------------------------------------------------*/
#ifdef DEBUG
#define IfDebug(x)	x
#define IfNotDebug(x)
#else
#define IfDebug(x)
#define IfNotDebug(x) x
#endif

#ifdef RELEASE
#define IfRelease(x)	x
#define IfNotRelease(x)
#else
#define IfRelease(x)
#define IfNotRelease(x) x
#endif

/*---------------------------------------------------------------------------
	Assert
 ---------------------------------------------------------------------------*/
	
#define Panic()						Assert0(FDbgFalse(), TEXT("Panic"))
#define Panic0(szFmt)				Assert0(FDbgFalse(), TEXT(szFmt))
#define Panic1(szFmt, p1)			Assert1(FDbgFalse(), TEXT(szFmt), p1)
#define Panic2(szFmt, p1, p2)		Assert2(FDbgFalse(), TEXT(szFmt), p1, p2)
#define Panic3(szFmt, p1, p2, p3)	Assert3(FDbgFalse(), TEXT(szFmt), p1, p2, p3)
#define Panic4(szFmt, p1, p2, p3, p4)	Assert4(FDbgFalse(), TEXT(szFmt), p1, p2, p3, p4)
#define Panic5(szFmt, p1, p2, p3, p4, p5)	Assert5(FDbgFalse(), TEXT(szFmt), p1, p2, p3, p4, p5)
#define SideAssert(f)				Verify(f)
#define AssertSz(f, sz)				Assert0(f, TEXT(sz))

#if !defined(DEBUG) && !defined(DEBUGASSERT)

#define Verify(f)							((void)(f))

#define Assert(f)							((void)0)
#define Assert0(f, szFmt)					((void)0)
#define Assert1(f, szFmt, p1)				((void)0)
#define Assert2(f, szFmt, p1, p2)			((void)0)
#define Assert3(f, szFmt, p1, p2, p3)		((void)0)
#define Assert4(f, szFmt, p1, p2, p3, p4)	((void)0)
#define Assert5(f, szFmt, p1, p2, p3, p4, p5)	((void)0)
#define AssertFL0(szFile, iLine, f, szFmt)	((void)0)

#else   //!defined(DEBUG) && !defined(DEBUGASSERT)

#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif

#define Verify(f) Assert(f)

DBG_APIV(void)	DbgAssert(LPCTSTR szFileName, int iLine, LPCTSTR szFmt, ...);

// If you use the utilna.lib version of util (No Assert), you must define
// the following function

void DoAssert(LPCSTR szFile, int iLine, LPCSTR szAssert);

#ifdef FDBGFALSE_API
DBG_API(BOOL)	FDbgFalse(void);
#else
#define FDbgFalse()		(0)
#endif

#define Assert(f) \
	do { DBG_STRING(_sz, #f) \
		 DBG_STRING(_szFmt, "%s") \
	if (!(f)) DbgAssert(THIS_FILE, __LINE__,_szFmt,(LPSTR)_sz); } while (FDbgFalse())
#define Assert0(f, szFmt) \
	do { DBG_STRING(_sz, szFmt)\
	if (!(f)) DbgAssert(THIS_FILE, __LINE__, _sz); } while (FDbgFalse())
#define Assert1(f, szFmt, p1) \
	do { DBG_STRING(_sz, szFmt)\
	if (!(f)) DbgAssert(THIS_FILE, __LINE__, _sz, p1); } while (FDbgFalse())
#define Assert2(f, szFmt, p1, p2) \
	do { DBG_STRING(_sz, szFmt)\
	if (!(f)) DbgAssert(THIS_FILE, __LINE__, _sz, p1, p2); } while (FDbgFalse())
#define Assert3(f, szFmt, p1, p2, p3) \
	do { DBG_STRING(_sz, szFmt)\
	if (!(f)) DbgAssert(THIS_FILE, __LINE__, _sz, p1, p2, p3); } while (FDbgFalse())
#define Assert4(f, szFmt, p1, p2, p3, p4) \
	do { DBG_STRING(_sz, szFmt)\
	if (!(f)) DbgAssert(THIS_FILE, __LINE__, _sz, p1, p2, p3, p4); } while (FDbgFalse())
#define Assert5(f, szFmt, p1, p2, p3, p4, p5) \
	do { DBG_STRING(_sz, szFmt)\
	if (!(f)) DbgAssert(THIS_FILE, __LINE__, _sz, p1, p2, p3, p4, p5); } while (FDbgFalse())
#define AssertFL0(szFile, iLine, f, szFmt) \
	do { DBG_STRING(_sz, szFmt)\
	if (!(f)) DbgAssert(szFile, iLine, _sz); } while (FDbgFalse())

#endif  //else - !defined(DEBUG) && !defined(DEBUGASSERT)

/*---------------------------------------------------------------------------
	Trace
 ---------------------------------------------------------------------------*/

#if !defined(DEBUG) && !defined(DEBUGTRACE)

#ifdef __cplusplus
inline void CDECL DbgTrace(LPTSTR, ...) {}
#define Trace_ 1 ? (void)0 : ::DbgTrace
#endif

#define ODS(sz)                             /* nothing */

#define Trace0(szFmt)						((void)0)
#define Trace1(szFmt, p1)					((void)0)
#define Trace2(szFmt, p1, p2)				((void)0)
#define Trace3(szFmt, p1, p2, p3)			((void)0)
#define Trace4(szFmt, p1, p2, p3, p4)		((void)0)
#define Trace5(szFmt, p1, p2, p3, p4, p5)	((void)0)

#define TraceN0(szFmt)						((void)0)
#define TraceN1(szFmt, p1)					((void)0)
#define TraceN2(szFmt, p1, p2)				((void)0)
#define TraceN3(szFmt, p1, p2, p3)			((void)0)
#define TraceN4(szFmt, p1, p2, p3, p4)		((void)0)
#define TraceN5(szFmt, p1, p2, p3, p4, p5)	((void)0)

#define DBG_PROC_ENTRY(szFunctionName)      /* nothing */

#else   //!defined(DEBUG) && !defined(DEBUGTRACE)

DBG_API(void)		OutputTrace(LPCTSTR szTrace);

DBG_APIV(void)		DbgTrace(LPTSTR szFormat, ...);
DBG_API(void)		DbgTraceV(LPCTSTR szFormat, char FAR *pvargs);

#define ODS(sz)     OutputDebugString(sz)


// Trace_ can be called if you are too lazy to count your arguments and call
// the appropriate TraceN macro.
#define Trace_ ::DbgTrace
#define Trace0(szFmt) \
	 do { DBG_STRING_NL(_sz, szFmt) DbgTrace(_sz); } while (FDbgFalse())
#define Trace1(szFmt, p1) \
	 do { DBG_STRING_NL(_sz, szFmt) DbgTrace(_sz, p1); } while (FDbgFalse())
#define Trace2(szFmt, p1, p2) \
	 do { DBG_STRING_NL(_sz, szFmt) DbgTrace(_sz, p1, p2); } while (FDbgFalse())
#define Trace3(szFmt, p1, p2, p3) \
	 do { DBG_STRING_NL(_sz, szFmt) DbgTrace(_sz, p1, p2, p3); } while (FDbgFalse())
#define Trace4(szFmt, p1, p2, p3, p4) \
	 do { DBG_STRING_NL(_sz, szFmt) DbgTrace(_sz, p1, p2, p3, p4); } while (FDbgFalse()) 
#define Trace5(szFmt, p1, p2, p3, p4, p5) \
	 do { DBG_STRING_NL(_sz, szFmt) DbgTrace(_sz, p1, p2, p3, p4, p5); } while (FDbgFalse())

#define TraceN0(szFmt) \
	 do { DBG_STRING(_sz, szFmt) DbgTrace(_sz); } while (FDbgFalse())
#define TraceN1(szFmt, p1) \
	 do { DBG_STRING(_sz, szFmt) DbgTrace(_sz, p1); } while (FDbgFalse())
#define TraceN2(szFmt, p1, p2) \
	 do { DBG_STRING(_sz, szFmt) DbgTrace(_sz, p1, p2); } while (FDbgFalse())
#define TraceN3(szFmt, p1, p2, p3) \
	 do { DBG_STRING(_sz, szFmt) DbgTrace(_sz, p1, p2, p3); } while (FDbgFalse())
#define TraceN4(szFmt, p1, p2, p3, p4) \
	 do { DBG_STRING(_sz, szFmt) DbgTrace(_sz, p1, p2, p3, p4); } while (FDbgFalse()) 
#define TraceN5(szFmt, p1, p2, p3, p4, p5) \
	 do { DBG_STRING(_sz, szFmt) DbgTrace(_sz, p1, p2, p3, p4, p5); } while (FDbgFalse())

#ifndef NOENTRYEXITTRACE

    //
    // @class This class is used in the DBG_PROC_ENTRY macro below.
    //
    class DbgProcEntryClass
    {
      public:                                                            
        DbgProcEntryClass(LPCSTR szFunctionName)  { m_lpszName = szFunctionName; Trace1("> Enter %s", szFunctionName); }
        ~DbgProcEntryClass()                      { Trace1("< Exit %s", m_lpszName); }
      private:
        LPCSTR m_lpszName;
    };

    //
    // @func Macro that causes the name of a function to get printed to debug output when the function is entered
    //  and when it is exited.  This is done by using C++ contructor and destructor.  Place the call to DBG_PROC_ENTRY
    //  at the to of each function that you wish to see debug traces for its entry and exit.  The uCategory parameter
    //  is used to clasify the module that this function is in.
    //
    #define DBG_PROC_ENTRY(szFunctionName)                    DbgProcEntryClass _DbgProcEntryClassObject(szFunctionName)
#else
#define DBG_PROC_ENTRY(szFunctionName)  /* nothing */	
#endif  //NOENTRYEXITTRACE

#endif  //else - !defined(DEBUG) && !defined(DEBUGTRACE)

/*---------------------------------------------------------------------------
	Debug Options Structure and APIs
 ---------------------------------------------------------------------------*/

#ifdef DEBUG
typedef struct dbiTag
{
	// Trace enable
	BOOL	fDoTrace;

	// Startup with NO tls trace buffering
	int		itlsTraceRGB;

	// No special trace function (defaults to OutputDebugString if NULL)
	void (CALLBACK * pfnTrace)(LPCTSTR);

	// UI Assert enable (determines whether DoAssert will be called)
	// Asserts will always be output as Trace (as per trace settings)
	BOOL	fShowAsserts;

	// Number of asserts since startup
	ULONG	cAssert;

	// Trigger assert on allocation failure
	BOOL	fAssertOnAllocFail;

	// This setting determines whether an assert calls DbgStop,
	// which triggers an INT 3. If no debugger is running, the INT 3
	// is handled internally, and execution continues.
	BOOL	fStopOnAssert;
	
} DebugInfo;

typedef struct
{
	DWORD	cchBuf;
	DWORD	ichStart;
	DWORD	ichEnd;
	char	rgch[1];
} DbgTraceBuf;

extern DebugInfo g_dbi;
#endif

/*---------------------------------------------------------------------------
	Misc
 ---------------------------------------------------------------------------*/

#ifdef DEBUG

DBG_API(void)	DbgStop(void);
DBG_API(BOOL)	FDbgFail(void);
DBG_API(long)	DbgSetFail(long iFail);
DBG_API(long)	DbgGetFail();

// Call this function first with (fSecondChunk = FALSE), then with
// (fSecondChunk = TRUE) to get the full trace buffer output
// If TLS trace buffering is not enabled, these will return error strings.
#ifdef __cplusplus
#define ITLSTRACE	itlsTrace = (DWORD)-1
#endif

DBG_API(DWORD)	        DbgSetThreadTraceBuffer(DWORD ITLSTRACE);
DBG_API(const char *)	DbgGetTraceBuffer(BOOL fSecondChunk);
DBG_API(BOOL)	        DbgSetTraceBuffer(void *rgbTrace, int cbTrace);

#endif  //DEBUG

#ifdef __cplusplus
} // extern "C"
#endif

#endif // _DBGUTIL_H