/* * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * In addition, as a special exception, the author gives permission to * link the code of this program with the Half-Life Game Engine ("HL * Engine") and Modified Game Libraries ("MODs") developed by Valve, * L.L.C ("Valve"). You must obey the GNU General Public License in all * respects for all of the code used other than the HL Engine and MODs * from Valve. If you modify this file, you may extend this exception * to your version of the file, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. * */ #pragma once #include "basetypes.h" #include #include #include // dll export stuff #ifdef TIER0_DLL_EXPORT #define DBG_INTERFACE DLL_EXPORT #define DBG_OVERLOAD DLL_GLOBAL_EXPORT #define DBG_CLASS DLL_CLASS_EXPORT #else #define DBG_INTERFACE DLL_IMPORT #define DBG_OVERLOAD DLL_GLOBAL_IMPORT #define DBG_CLASS DLL_CLASS_IMPORT #endif // Usage model for the Dbg library // // 1. Spew. // // Spew can be used in a static and a dynamic mode. The static // mode allows us to display assertions and other messages either only // in debug builds, or in non-release builds. The dynamic mode allows us to // turn on and off certain spew messages while the application is running. // // Static Spew messages: // // Assertions are used to detect and warn about invalid states // Spews are used to display a particular status/warning message. // // To use an assertion, use // // Assert((f == 5)); // AssertMsg((f == 5), ("F needs to be %d here!\n", 5)); // AssertFunc((f == 5), BadFunc()); // AssertEquals(f, 5); // AssertFloatEquals(f, 5.0f, 1e-3); // // The first will simply report that an assertion failed on a particular // code file and line. The second version will display a print-f formatted message // along with the file and line, the third will display a generic message and // will also cause the function BadFunc to be executed, and the last two // will report an error if f is not equal to 5 (the last one asserts within // a particular tolerance). // // To use a warning, use // // Warning("Oh I feel so %s all over\n", "yummy"); // // Warning will do its magic in only Debug builds. To perform spew in *all* // builds, use RelWarning. // // Three other spew types, Msg, Log, and Error, are compiled into all builds. // These error types do *not* need two sets of parenthesis. // // Msg("Isn't this exciting %d?", 5); // Error("I'm just thrilled"); // // Dynamic Spew messages // // It is possible to dynamically turn spew on and off. Dynamic spew is // identified by a spew group and priority level. To turn spew on for a // particular spew group, use SpewActivate("group", level). This will // cause all spew in that particular group with priority levels <= the // level specified in the SpewActivate function to be printed. Use DSpew // to perform the spew: // // DWarning("group", level, "Oh I feel even yummier!\n"); // // Priority level 0 means that the spew will *always* be printed, and group // '*' is the default spew group. If a DWarning is encountered using a group // whose priority has not been set, it will use the priority of the default // group. The priority of the default group is initially set to 0. // // Spew output // // The output of the spew system can be redirected to an externally-supplied // function which is responsible for outputting the spew. By default, the // spew is simply printed using printf. // // To redirect spew output, call SpewOutput. // // SpewOutputFunc(OutputFunc); // // This will cause OutputFunc to be called every time a spew message is // generated. OutputFunc will be passed a spew type and a message to print. // It must return a value indicating whether the debugger should be invoked, // whether the program should continue running, or whether the program // should abort. // // 2. Code activation // // To cause code to be run only in debug builds, use DBG_CODE: // An example is below. // // DBG_CODE( // { // int x = 5; // ++x; // } // ); // // Code can be activated based on the dynamic spew groups also. Use // // DBG_DCODE("group", level, // { int x = 5; ++x; } // ); // // 3. Breaking into the debugger. // // To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK // // DBG_BREAK(); // // You can force a break in any build (release or debug) using // // DebuggerBreak(); // Various types of spew messages // I'm sure you're asking yourself why SPEW_ instead of DBG_ ? // It's because DBG_ is used all over the place in windows.h // For example, DBG_CONTINUE is defined. Feh. enum SpewType_t { SPEW_MESSAGE = 0, SPEW_WARNING, SPEW_ASSERT, SPEW_ERROR, SPEW_LOG, SPEW_TYPE_COUNT }; enum SpewRetval_t { SPEW_DEBUGGER = 0, SPEW_CONTINUE, SPEW_ABORT }; // Type of externally defined function used to display debug spew typedef SpewRetval_t (*SpewOutputFunc_t)(SpewType_t spewType, const char *pMsg); // Used to redirect spew output void SpewOutputFunc(SpewOutputFunc_t func); // Used ot get the current spew output function SpewOutputFunc_t GetSpewOutputFunc(); // Used to manage spew groups and subgroups void SpewActivate(const char *pGroupName, int level); bool IsSpewActive(const char *pGroupName, int level); // Used to display messages, should never be called directly. void _SpewInfo(SpewType_t type, const char *pFile, int line); SpewRetval_t _SpewMessage(const char *pMsg, ...); SpewRetval_t _DSpewMessage(const char *pGroupName, int level, const char *pMsg, ...); // Used to define macros, never use these directly. #define _Assert(_exp) \ do { \ if (!(_exp)) \ { \ _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ if (_SpewMessage("Assertion Failed: " #_exp) == SPEW_DEBUGGER) \ { \ DebuggerBreak(); \ } \ } \ } while (0) #define _AssertMsg(_exp, _msg) \ do { \ if (!(_exp)) \ { \ _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ if (_SpewMessage(_msg) == SPEW_DEBUGGER) \ { \ DebuggerBreak(); \ } \ } \ } while (0) #define _AssertFunc(_exp, _f) \ do { \ if (!(_exp)) \ { \ _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ SpewRetval_t ret = _SpewMessage("Assertion Failed!" #_exp); \ _f; \ if (ret == SPEW_DEBUGGER) \ { \ DebuggerBreak(); \ } \ } \ } while (0) #define _AssertEquals(_exp, _expectedValue) \ do { \ if ((_exp) != (_expectedValue)) \ { \ _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ SpewRetval_t ret = _SpewMessage("Expected %d but got %d!", (_expectedValue), (_exp)); \ if (ret == SPEW_DEBUGGER) \ { \ DebuggerBreak(); \ } \ } \ } while (0) #define _AssertFloatEquals(_exp, _expectedValue, _tol) \ do { \ if (fabs((_exp) - (_expectedValue)) > (_tol)) \ { \ _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ SpewRetval_t ret = _SpewMessage("Expected %f but got %f!", (_expectedValue), (_exp)); \ if (ret == SPEW_DEBUGGER) \ { \ DebuggerBreak(); \ } \ } \ } while (0) // Spew macros... #ifdef _DEBUG #define Assert(_exp) _Assert(_exp) #define AssertMsg(_exp, _msg) _AssertMsg(_exp, _msg) #define AssertFunc(_exp, _f) _AssertFunc(_exp, _f) #define AssertEquals(_exp, _expectedValue) _AssertEquals(_exp, _expectedValue) #define AssertFloatEquals(_exp, _expectedValue, _tol) _AssertFloatEquals(_exp, _expectedValue, _tol) #define Verify(_exp) _Assert(_exp) #define AssertMsg1(_exp, _msg, a1) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1)) #define AssertMsg2(_exp, _msg, a1, a2) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2)) #define AssertMsg3(_exp, _msg, a1, a2, a3) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3)) #define AssertMsg4(_exp, _msg, a1, a2, a3, a4) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4)) #define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5)) #define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6)) #define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6)) #define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7)) #define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8)) #define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8, a9)) #else // _DEBUG #define Assert(_exp) ((void)0) #define AssertMsg(_exp, _msg) ((void)0) #define AssertFunc(_exp, _f) ((void)0) #define AssertEquals(_exp, _expectedValue) ((void)0) #define AssertFloatEquals(_exp, _expectedValue, _tol) ((void)0) #define Verify(_exp) (_exp) #define AssertMsg1(_exp, _msg, a1) ((void)0) #define AssertMsg2(_exp, _msg, a1, a2) ((void)0) #define AssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) #define AssertMsg4(_exp, _msg, a1, a2, a3, a4) ((void)0) #define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) ((void)0) #define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) #define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) #define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) ((void)0) #define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) ((void)0) #define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) ((void)0) #endif // _DEBUG // These are always compiled in void Msg(const char *pMsg, ...); void DMsg(const char *pGroupName, int level, const char *pMsg, ...); void Warning(const char *pMsg, ...); void DWarning(const char *pGroupName, int level, const char *pMsg, ...); void Log(const char *pMsg, ...); void DLog(const char *pGroupName, int level, const char *pMsg, ...); void Error(const char *pMsg, ...); // You can use this macro like a runtime assert macro. // If the condition fails, then Error is called with the message. This macro is called // like AssertMsg, where msg must be enclosed in parenthesis: // // ErrorIfNot(bCondition, ("a b c %d %d %d", 1, 2, 3)); #define ErrorIfNot(condition, msg) \ if ((condition)) \ ; \ else \ { \ Error msg; \ } // A couple of super-common dynamic spew messages, here for convenience // These looked at the "developer" group void DevMsg(int level, char const* pMsg, ...); void DevWarning(int level, const char *pMsg, ...); void DevLog(int level, const char *pMsg, ...); // default level versions (level 1) void DevMsg(char const* pMsg, ...); void DevWarning(const char *pMsg, ...); void DevLog(const char *pMsg, ...); // Code macros, debugger interface #ifdef _DEBUG #define DBG_CODE(_code) if (0) ; else { _code } #define DBG_DCODE(_g, _l, _code) if (IsSpewActive(_g, _l)) { _code } else {} #define DBG_BREAK() DebuggerBreak() #else // _DEBUG #define DBG_CODE(_code) ((void)0) #define DBG_DCODE(_g, _l, _code) ((void)0) #define DBG_BREAK() ((void)0) #endif // _DEBUG // Macro to assist in asserting constant invariants during compilation #define UID_PREFIX generated_id_ #define UID_CAT1(a, c) a ## c #define UID_CAT2(a, c) UID_CAT1(a,c) #define UNIQUE_ID UID_CAT2(UID_PREFIX, __LINE__) #ifdef _DEBUG #define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;} #define ASSERT_INVARIANT(pred) static void UNIQUE_ID() { COMPILE_TIME_ASSERT(pred) } #else #define COMPILE_TIME_ASSERT(pred) #define ASSERT_INVARIANT(pred) #endif // Templates to assist in validating pointers: // Have to use these stubs so we don't have to include windows.h here. void _AssertValidReadPtr(void *ptr, int count = 1); void _AssertValidWritePtr(void *ptr, int count = 1); void _AssertValidReadWritePtr(void *ptr, int count = 1); void AssertValidStringPtr(const char *ptr, int maxchar = 0xFFFFFF); template inline void AssertValidReadPtr(T *ptr, int count = 1) { _AssertValidReadPtr((void *)ptr, count); } template inline void AssertValidWritePtr(T *ptr, int count = 1) { _AssertValidWritePtr((void *)ptr, count); } template inline void AssertValidReadWritePtr(T *ptr, int count = 1) { _AssertValidReadWritePtr((void *)ptr, count); } #define AssertValidThis() AssertValidReadWritePtr(this, sizeof(*this)) // Macro to protect functions that are not reentrant #ifdef _DEBUG class CReentryGuard { public: CReentryGuard(int *pSemaphore) : m_pSemaphore(pSemaphore) { ++(*m_pSemaphore); } ~CReentryGuard() { --(*m_pSemaphore); } private: int *m_pSemaphore; }; #define ASSERT_NO_REENTRY() \ static int fSemaphore##__LINE__; \ Assert(!fSemaphore##__LINE__); \ CReentryGuard ReentryGuard##__LINE__(&fSemaphore##__LINE__) #else // _DEBUG #define ASSERT_NO_REENTRY() #endif // _DEBUG // Inline string formatter class CDbgFmtMsg { public: CDbgFmtMsg(const char *pszFormat, ...) { va_list arg_ptr; va_start(arg_ptr, pszFormat); _vsnprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); va_end(arg_ptr); m_szBuf[sizeof(m_szBuf) - 1] = '\0'; } operator const char *() const { return m_szBuf; } private: char m_szBuf[256]; }; // Embed debug info in each file. //#ifdef _WIN32 //#ifdef _DEBUG //#pragma comment(compiler) //#pragma comment(exestr,"*** DEBUG file detected, Last Compile: " __DATE__ ", " __TIME__ " ***") //#endif //#endif