//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File:      F3DEBUG.H
//
// Contains:  Debugging stuff -- uses MSHTML's mshtmdbg.dll for debugging
//            utilities.
//
//            Stolen from Trident
//
//--------------------------------------------------------------------------

#include <mshtmdbg.h>

//--------------------------------------------------------------------------
// Assert, Verify && WHEN_DBG
//--------------------------------------------------------------------------

#if defined(_M_IX86)
    #define F3DebugBreak() _asm { int 3 }
#else
    #define F3DebugBreak() DebugBreak()
#endif

#if DBG != 1

#define Verify(x)   x
#define Assert(x)
#define AssertSz(x, sz)
#define IF_DBG(x)
#define WHEN_DBG(x)
#define IF_NOT_DBG(x) x
#define WHEN_NOT_DBG(x) x
#define StartupAssert(x)
#define AssertThreadDisable(fb)


#else // #if DBG != 1

#define AssertThreadDisable(fDisable)   DbgExAssertThreadDisable(fDisable)

extern DWORD g_dwFALSE;

#define Verify(x)       Assert(x)
#define Assert(x)       do { if (!((DWORD_PTR)(x)|g_dwFALSE) && DbgExAssertImpl(__FILE__, __LINE__, #x))\
                               F3DebugBreak(); } while (g_dwFALSE)

#define AssertSz(x, sz) do { if (!((DWORD_PTR)(x)|g_dwFALSE) && DbgExAssertImpl(__FILE__, __LINE__, sz))\
                               F3DebugBreak(); } while (g_dwFALSE)

#define AssertLocSz(x, File, Line, sz)   do { if (!((DWORD_PTR)(x)|g_dwFALSE) && DbgExAssertImpl(File, Line, sz))\
                               F3DebugBreak(); } while (g_dwFALSE)
#define IF_DBG(x) x
#define WHEN_DBG(x) x
#define IF_NOT_DBG(x)
#define WHEN_NOT_DBG(x)


#define concat_name(x, y) x##y
#define concat_line_impl(x, y) concat_name(x, y)
#define concat_LINE(x) concat_line_impl(x, __LINE__)

//
// Startup assertion:
// The assertion is called by initializing a global variable with
// a function that performs the assertion and returns 1. The name
// of the global variable and function name are suffixed with the
// line number to make them unique. Unfortunatly, one cannot just
// write StartupAssert_##__LINE__, because __LINE__ is not an
// argument to the macro and so the expansion is, e.g. StartupAssert__##53.
// So we indirect through another macro which concatenates its
// two arguments.
//

#define StartupAssert(x)                                                    \
static int                                                                  \
concat_LINE(StartupAssert_) ()                                              \
{                                                                           \
    Assert(x);                                                              \
    return 1;                                                               \
}                                                                           \
                                                                            \
static int concat_LINE(g_StartupAssert_) = concat_LINE(StartupAssert_)()    \

#endif // #if DBG != 1

//--------------------------------------------------------------------------
// Trace Tags
//--------------------------------------------------------------------------

#if DBG != 1
    #define TraceTag(x)
    #define TraceTagEx(x)
    #define TaggedTraceListEx(tag, usFlags, szFmt, valMarker)
    #define TraceCallers(tag, iStart, cTotal)
    #define DeclareTag(tag, szOwner, szDescription)
    #define DeclareTagOther(tag, szOwner, szDescription)
    #define ExternTag(tag)
    #define IsTagEnabled(tag) FALSE
    #define EnableTag(tag, fEnable)
    #define SetDiskFlag(tag, fSendToDisk)
    #define SetBreakFlag(tag, fBreak)
    #define FindTag(szTagDesc) NULL
    #define PerfDbgTag(tag, szOwner, szDescrip) \
            PerfTag(tag, szOwner, szDescrip)
    #define PerfDbgExtern(tag) \
            PerfExtern(tag)
    #define PerfDbgLog(tag,pv,f) PerfLog(tag,pv,f)
    #define PerfDbgLog1(tag,pv,f,a1) PerfLog1(tag,pv,f,a1)
    #define PerfDbgLog2(tag,pv,f,a1,a2) PerfLog2(tag,pv,f,a1,a2)
    #define PerfDbgLog3(tag,pv,f,a1,a2,a3) PerfLog3(tag,pv,f,a1,a2,a3)
    #define PerfDbgLog4(tag,pv,f,a1,a2,a3,a4) PerfLog4(tag,pv,f,a1,a2,a3,a4)
    #define PerfDbgLog5(tag,pv,f,a1,a2,a3,a4,a5) PerfLog5(tag,pv,f,a1,a2,a3,a4,a5)
    #define PerfDbgLog6(tag,pv,f,a1,a2,a3,a4,a5,a6) PerfLog6(tag,pv,f,a1,a2,a3,a4,a5,a6)
    #define PerfDbgLog7(tag,pv,f,a1,a2,a3,a4,a5,a6,a7) PerfLog7(tag,pv,f,a1,a2,a3,a4,a5,a6,a7)
    #define PerfDbgLog8(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8) PerfLog8(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8)
    #define PerfDbgLog9(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8,a9) PerfLog9(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8,a9)
    #define PerfDbgLogN(x) PerfLogFn x
    #define IsPerfDbgEnabled(tag) IsPerfEnabled(tag)

#else
    #define TraceTag(x)                         \
        do                                      \
        {                                       \
            if (TaggedTrace x)                  \
                F3DebugBreak();                 \
        } while  (g_dwFALSE)

    #define TraceTagEx(x)                       \
        do                                      \
        {                                       \
            if (TaggedTraceEx x)                \
                F3DebugBreak();                 \
        } while  (g_dwFALSE)

    #define TraceCallers(tag, iStart, cTotal)   \
        TaggedTraceCallers(tag, iStart, cTotal)
    #define DeclareTag(tag, szOwner, szDescrip) \
        TRACETAG tag(DbgExTagRegisterTrace(szOwner, szDescrip, FALSE));
    #define DeclareTagOther(tag, szOwner, szDescrip) \
        TRACETAG tag(DbgExTagRegisterOther(szOwner, szDescrip, FALSE));
    #define ExternTag(tag) extern TRACETAG tag;
    #define PerfDbgTag(tag, szOwner, szDescrip) DeclareTag(tag, szOwner, szDescrip)
    #define PerfDbgExtern(tag) ExternTag(tag)
    #define PerfDbgLog(tag,pv,f) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f)
    #define PerfDbgLog1(tag,pv,f,a1) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1)
    #define PerfDbgLog2(tag,pv,f,a1,a2) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2)
    #define PerfDbgLog3(tag,pv,f,a1,a2,a3) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2,a3)
    #define PerfDbgLog4(tag,pv,f,a1,a2,a3,a4) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2,a3,a4)
    #define PerfDbgLog5(tag,pv,f,a1,a2,a3,a4,a5) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2,a3,a4,a5)
    #define PerfDbgLog6(tag,pv,f,a1,a2,a3,a4,a5,a6) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2,a3,a4,a5,a6)
    #define PerfDbgLog7(tag,pv,f,a1,a2,a3,a4,a5,a6,a7) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2,a3,a4,a5,a6,a7)
    #define PerfDbgLog8(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8)
    #define PerfDbgLog9(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8,a9) if (IsPerfDbgEnabled(tag)) PerfDbgLogFn(tag,pv,f,a1,a2,a3,a4,a5,a6,a7,a8,a9)
    #define PerfDbgLogN(x) PerfDbgLogFn x
    #define IsPerfDbgEnabled(tag) IsTagEnabled(tag)

    int __cdecl PerfDbgLogFn(int tag, void * pvObj, char * pchFmt, ...);

    // Tag trace functions

    #define TaggedTrace         DbgExTaggedTrace
    #define TaggedTraceEx       DbgExTaggedTraceEx
    #define TaggedTraceListEx   DbgExTaggedTraceListEx
    #define TaggedTraceCallers  DbgExTaggedTraceCallers

    // TaggedTraceEx usFlags parameter defines

    #define TAG_NONAME      0x01
    #define TAG_NONEWLINE   0x02
    #define TAG_USECONSOLE  0x04
    #define TAG_INDENT      0x08
    #define TAG_OUTDENT     0x10

    // Register a new tag.

    // Standard tags
    #define tagError                DbgExTagError()
    #define tagWarning              DbgExTagWarning()
    #define tagThread               DbgExTagThread()
    #define tagAssertExit           DbgExTagAssertExit()
    #define tagAssertStacks         DbgExTagAssertStacks()
    #define tagMemoryStrict         DbgExTagMemoryStrict()
    #define tagCoMemoryStrict       DbgExTagCoMemoryStrict()
    #define tagMemoryStrictTail     DbgExTagMemoryStrictTail()
    #define tagMemoryStrictAlign    DbgExTagMemoryStrictAlign()
    #define tagOLEWatch             DbgExTagOLEWatch()
    #define tagPerf                 DbgExTagPerf()

    // Get/Set tag enabled status.

    #define IsTagEnabled            DbgExIsTagEnabled
    #define EnableTag               DbgExEnableTag
    #define SetDiskFlag             DbgExSetDiskFlag
    #define SetBreakFlag            DbgExSetBreakFlag
    #define FindTag                 DbgExFindTag

#endif

//--------------------------------------------------------------------------
// Memory Allocation
//--------------------------------------------------------------------------

#if DBG != 1

    #define DbgPreAlloc(cb)             cb
    #define DbgPostAlloc(pv)            pv
    #define DbgPreFree(pv)              pv
    #define DbgPostFree()
    #define DbgPreRealloc(pv, cb, ppv)  cb
    #define DbgPostRealloc(pv)          pv
    #define DbgPreGetSize(pv)           pv
    #define DbgPostGetSize(cb)          cb
    #define DbgPreDidAlloc(pv)          pv
    #define DbgPostDidAlloc(pv, fAct)   fAct

    #define DbgMemoryTrackDisable(fb)
    #define DbgCoMemoryTrackDisable(fb)
    #define DbgMemoryBlockTrackDisable(pv)

    #define CHECK_HEAP()

#else

    #define DbgPreAlloc                 DbgExPreAlloc
    #define DbgPostAlloc                DbgExPostAlloc
    #define DbgPreFree                  DbgExPreFree
    #define DbgPostFree                 DbgExPostFree
    #define DbgPreRealloc               DbgExPreRealloc
    #define DbgPostRealloc              DbgExPostRealloc
    #define DbgPreGetSize               DbgExPreGetSize
    #define DbgPostGetSize              DbgExPostGetSize
    #define DbgPreDidAlloc              DbgExPreDidAlloc
    #define DbgPostDidAlloc             DbgExPostDidAlloc

    #define DbgMemoryTrackDisable       DbgExMemoryTrackDisable
    #define DbgCoMemoryTrackDisable     DbgExCoMemoryTrackDisable
    #define DbgMemoryBlockTrackDisable  DbgExMemoryBlockTrackDisable

    //
    // Use the CHECK_HEAP macro to do thorough heap validation.
    //
    BOOL CheckSmallBlockHeap();
    #define CHECK_HEAP()    Assert(DbgExValidateInternalHeap() && CheckSmallBlockHeap() && "Corrupted heap!")

#endif


//+---------------------------------------------------------------------
//  Interface tracing.
//----------------------------------------------------------------------

#if DBG == 1 && !defined(WIN16)
    #define DbgTrackItf     DbgExTrackItf
#else
    #define DbgTrackItf(iid, pch, fTrackOnQi, ppv)
#endif

//--------------------------------------------------------------------------
// Failure testing
//--------------------------------------------------------------------------

#if DBG == 1 && defined(__cplusplus)

#define SetSimFailCounts    DbgExSetSimFailCounts
#define GetFailCount        DbgExGetFailCount
#define TraceFailL          DbgExTraceFailL
#define TraceWin32L         DbgExTraceWin32L
#define TraceHR             DbgExTraceHR
#define TraceOLE            DbgExTraceOLE
#define TraceEnter          DbgExTraceEnter
#define TraceExit           DbgExTraceExit

template <class t> inline t
TraceFail(t errExpr, LONG_PTR errTest, BOOL fIgnore, LPSTR pstrExpr, LPSTR pstrFile, int line)
{
    return (t) DbgExTraceFailL((LONG_PTR) errExpr, errTest, fIgnore, pstrExpr, pstrFile, line);
}

template <class t> inline t
TraceWin32(t errExpr, LONG_PTR errTest, BOOL fIgnore, LPSTR pstrExpr, LPSTR pstrFile, int line)
{
    return (t) DbgExTraceWin32L((LONG_PTR) errExpr, errTest, fIgnore, pstrExpr, pstrFile, line);
}

// disabled TraceEnter, we don't need it at this time
#undef TraceEnter
#define TraceEnter(x, y, z) NULL

#define TFAIL(e, x)             (TraceEnter(#x, __FILE__, __LINE__), TraceFail( (x), (e), FALSE, #x, __FILE__, __LINE__))
#define TW32(e, x)              (TraceEnter(#x, __FILE__, __LINE__), TraceWin32((x), (e), FALSE, #x, __FILE__, __LINE__))
#define THR(x)                  (TraceEnter(#x, __FILE__, __LINE__), TraceHR((x), FALSE, #x, __FILE__, __LINE__))

#define TFAIL_NOTRACE(e, x)     (x)
#define TW32_NOTRACE(e, x)      (x)
#define THR_NOTRACE(x)          (x)

#define IGNORE_FAIL(e, x)       (TraceEnter(#x, __FILE__, __LINE__), (void) TraceFail((x), (e), TRUE, #x, __FILE__, __LINE__))
#define IGNORE_W32(e,x)         (TraceEnter(#x, __FILE__, __LINE__), (void) TraceWin32((x), (e), TRUE, #x, __FILE__, __LINE__))
#define IGNORE_HR(x)            (TraceEnter(#x, __FILE__, __LINE__), (void) TraceHR((x), TRUE, #x, __FILE__, __LINE__))

#else // #if DBG == 1

#define SetSimFailCounts(firstFailure, cInterval)

#define TFAIL(e, x)             (x)
#define TW32(e, x)              (x)
#define THR(x)                  (x)

#define TFAIL_NOTRACE(e, x)     (x)
#define TW32_NOTRACE(e, x)      (x)
#define THR_NOTRACE(x)          (x)

#define IGNORE_FAIL(e, x)       (x)
#define IGNORE_W32(e,x)         (x)
#define IGNORE_HR(x)            (x)

#endif // #if DBG == 1

//+-------------------------------------------------------------------------
//  Return tracing
//--------------------------------------------------------------------------

#if DBG == 1

    #define SRETURN(hr) \
        return DbgExCheckAndReturnResult((hr), TRUE, __FILE__, __LINE__, -1)
    #define RRETURN(hr) \
        return DbgExCheckAndReturnResult((hr), TRUE, __FILE__, __LINE__, 0)
    #define RRETURN1(hr, s1) \
        return DbgExCheckAndReturnResult((hr), TRUE, __FILE__, __LINE__, 1, (s1))
    #define RRETURN2(hr, s1, s2) \
        return DbgExCheckAndReturnResult((hr), TRUE, __FILE__, __LINE__, 2, (s1), (s2))
    #define RRETURN3(hr, s1, s2, s3) \
        return DbgExCheckAndReturnResult((hr), TRUE, __FILE__, __LINE__, 3, (s1), (s2), (s3))
    #define RRETURN4(hr, s1, s2, s3, s4) \
        return DbgExCheckAndReturnResult((hr), TRUE, __FILE__, __LINE__, 4, (s1), (s2), (s3), (s4))

    #define SRETURN_NOTRACE(hr) \
        return DbgExCheckAndReturnResult((hr), FALSE, __FILE__, __LINE__, -1)
    #define RRETURN_NOTRACE(hr) \
        return DbgExCheckAndReturnResult((hr), FALSE, __FILE__, __LINE__, 0)
    #define RRETURN1_NOTRACE(hr, s1) \
        return DbgExCheckAndReturnResult((hr), FALSE, __FILE__, __LINE__, 1, (s1))
    #define RRETURN2_NOTRACE(hr, s1, s2) \
        return DbgExCheckAndReturnResult((hr), FALSE, __FILE__, __LINE__, 2, (s1), (s2))
    #define RRETURN3_NOTRACE(hr, s1, s2, s3) \
        return DbgExCheckAndReturnResult((hr), FALSE, __FILE__, __LINE__, 3, (s1), (s2), (s3))
    #define RRETURN4_NOTRACE(hr, s1, s2, s3, s4) \
        return DbgExCheckAndReturnResult((hr), FALSE, __FILE__, __LINE__, 4, (s1), (s2), (s3), (s4))

#else   // DBG == 0

    #define SRETURN(hr)                 return (hr)
    #define RRETURN(hr)                 return (hr)
    #define RRETURN1(hr, s1)            return (hr)
    #define RRETURN2(hr, s1, s2)        return (hr)
    #define RRETURN3(hr, s1, s2, s3)    return (hr)
    #define RRETURN4(hr, s1, s2, s3, s4)return (hr)

    #define SRETURN_NOTRACE(hr)                 return (hr)
    #define RRETURN_NOTRACE(hr)                 return (hr)
    #define RRETURN1_NOTRACE(hr, s1)            return (hr)
    #define RRETURN2_NOTRACE(hr, s1, s2)        return (hr)
    #define RRETURN3_NOTRACE(hr, s1, s2, s3)    return (hr)
    #define RRETURN4_NOTRACE(hr, s1, s2, s3, s4)return (hr)

#endif  // DBG

//+-------------------------------------------------------------------------
//  Stack Spew
//--------------------------------------------------------------------------

#ifdef USE_STACK_SPEW
EXTERN_C void InitChkStk(DWORD);
#pragma check_stack(on)
#endif