ReGameDLL_CS/regamedll/public/tier0/dbg.cpp
2024-08-06 03:26:10 +07:00

238 lines
5.3 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#include "precompiled.h"
// Templates to assist in validating pointers:
void _AssertValidReadPtr(void *ptr, int count)
{
#if defined(_WIN32)
Assert(!IsBadReadPtr(ptr, count));
#else
Assert(ptr);
#endif
}
void _AssertValidWritePtr(void *ptr, int count)
{
#if defined(_WIN32)
Assert(!IsBadWritePtr(ptr, count));
#else
Assert(ptr);
#endif
}
void _AssertValidReadWritePtr(void *ptr, int count)
{
#if defined(_WIN32)
Assert(!(IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr, count)));
#else
Assert(ptr);
#endif
}
#if defined(DBGFLAG_ASSERT)
void AssertValidStringPtr(const char *ptr, int maxchar)
{
#if defined(_WIN32)
Assert(!IsBadStringPtr(ptr, maxchar));
#else
Assert(ptr);
#endif
}
#endif // DBGFLAG_ASSERT
// Globals
SpewRetval_t DefaultSpewFunc(SpewType_t type, int level, const char *pMsg)
{
printf("%s", pMsg);
if (type == SPEW_ASSERT)
return SPEW_DEBUGGER;
else if (type == SPEW_ERROR)
return SPEW_ABORT;
else
return SPEW_CONTINUE;
}
static SpewOutputFunc_t s_SpewOutputFunc = DefaultSpewFunc;
static const char *s_pMessage = nullptr;
static const char *s_pFileName = nullptr;
static int s_Line = 0;
static SpewType_t s_SpewType = SPEW_MESSAGE;
// Spew output management.
void SpewOutputFunc(SpewOutputFunc_t func)
{
s_SpewOutputFunc = func ? func : DefaultSpewFunc;
}
SpewOutputFunc_t GetSpewOutputFunc()
{
if (s_SpewOutputFunc)
{
return s_SpewOutputFunc;
}
else
{
return DefaultSpewFunc;
}
}
void _ExitOnFatalAssert()
{
Msg("Fatal assert failed: %s, file %s line %d. Application exiting.\n", s_pMessage, s_pFileName, s_Line);
#if defined(WIN32)
TerminateProcess(GetCurrentProcess(), EXIT_FAILURE); // die, die RIGHT NOW! (don't call exit() so destructors will not get run)
#else
exit(EXIT_FAILURE); // forcefully shutdown of the process without destructors running
#endif
}
// Spew functions
void _SpewInfo(SpewType_t type, const char *pFile, int line)
{
// Only grab the file name. Ignore the path
const char *pSlash = Q_strrchr(pFile, '\\');
const char *pSlash2 = Q_strrchr(pFile, '/');
if (pSlash < pSlash2) pSlash = pSlash2;
s_pFileName = pSlash ? pSlash + 1 : pFile;
s_Line = line;
s_SpewType = type;
}
SpewRetval_t _SpewMessageV(SpewType_t spewType, int level, const char *pMsgFormat, va_list args)
{
if (level < 0) level = DBG_DEFAULT_LEVEL;
static char szTempBuffer[4096]{};
szTempBuffer[0] = '\0';
s_pMessage = szTempBuffer;
// check that we won't artifically truncate the string
assert(Q_strlen(pMsgFormat) < sizeof(szTempBuffer));
// Printf the file and line for warning + assert only...
int len = 0;
if (spewType == SPEW_ASSERT)
{
len = Q_snprintf(szTempBuffer, sizeof(szTempBuffer), "%s (%d) : ", s_pFileName, s_Line);
}
if (len == -1)
{
return SPEW_ABORT;
}
// Create the message....
len += Q_vsnprintf(&szTempBuffer[len], sizeof(szTempBuffer) - len, pMsgFormat, args);
// Use normal assert here; to avoid recursion
assert(len < sizeof(szTempBuffer));
// Add \n for warning and assert
if (spewType == SPEW_ASSERT)
{
len += Q_snprintf(&szTempBuffer[len], sizeof(szTempBuffer) - len, "\n");
Plat_OutputDebugString(szTempBuffer);
}
// use normal assert here; to avoid recursion
assert((size_t)len < (sizeof(szTempBuffer) / sizeof(szTempBuffer[0]) - 1));
assert(s_SpewOutputFunc);
// direct it to the appropriate target(s)
SpewRetval_t ret = s_SpewOutputFunc(spewType, level, szTempBuffer);
switch (ret)
{
// Put the break into the macro so it would occur in the right place
case SPEW_DEBUGGER:
{
if (spewType != SPEW_ASSERT)
DebuggerBreakIfDebugging();
break;
}
case SPEW_ABORT:
{
#if defined(WIN32)
TerminateProcess(GetCurrentProcess(), EXIT_FAILURE); // die, die RIGHT NOW! (don't call exit() so destructors will not get run)
#else
exit(EXIT_FAILURE); // forcefully shutdown of the process without destructors running
#endif
break;
}
default:
break;
}
return ret;
}
#if defined(_WIN32)
// Returns true if they want to break in the debugger
bool DoNewAssertDialog(const char *pFile, int line, const char *pExpression);
#endif
bool _SpewAssertDialog()
{
#if defined(_WIN32)
return DoNewAssertDialog(s_pFileName, s_Line, s_pMessage);
#else
return false;
#endif
}
SpewRetval_t _SpewAssert(const char *pFile, int line, int level, const char *pMsgFormat, ...)
{
_SpewInfo(SPEW_ASSERT, pFile, line);
va_list args;
va_start(args, pMsgFormat);
SpewRetval_t ret = _SpewMessageV(s_SpewType, level, pMsgFormat, args);
va_end(args);
return ret;
}
void _Msg(int level, const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessageV(SPEW_MESSAGE, level, pMsgFormat, args);
va_end(args);
}
void _Warning(int level, const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessageV(SPEW_WARNING, level, pMsgFormat, args);
va_end(args);
}
void _Log(int level, const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessageV(SPEW_LOG, level, pMsgFormat, args);
va_end(args);
}
void Error(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessageV(SPEW_ERROR, DBG_DEFAULT_LEVEL, pMsgFormat, args);
va_end(args);
}