ReGameDLL_CS/regamedll/public/tier0/dbg.cpp
2017-11-23 00:43:30 +07:00

402 lines
9.5 KiB
C++

/*
*
* 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.
*
*/
#include "precompiled.h"
// Internal structures
enum
{
MAX_GROUP_NAME_LENGTH = 48
};
struct SpewGroup_t
{
char m_GroupName[MAX_GROUP_NAME_LENGTH];
int m_Level;
};
// Templates to assist in validating pointers:
void _AssertValidReadPtr(void *ptr, int count)
{
#ifdef _WIN32
Assert(!IsBadReadPtr(ptr, count));
#else
Assert(ptr);
#endif
}
void _AssertValidWritePtr(void *ptr, int count)
{
#ifdef _WIN32
Assert(!IsBadWritePtr(ptr, count));
#else
Assert(ptr);
#endif
}
void _AssertValidReadWritePtr(void *ptr, int count)
{
#ifdef _WIN32
Assert(!(IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr, count)));
#else
Assert(ptr);
#endif
}
void AssertValidStringPtr(const char *ptr, int maxchar)
{
#ifdef _WIN32
Assert(!IsBadStringPtr(ptr, maxchar));
#else
Assert(ptr);
#endif
}
// Globals
SpewRetval_t DefaultSpewFunc(SpewType_t type, 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_pFileName;
static int s_Line;
static SpewType_t s_SpewType;
static SpewGroup_t *s_pSpewGroups = 0;
static int s_GroupCount = 0;
static int s_DefaultLevel = 0;
// 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;
}
}
// Spew functions
void _SpewInfo(SpewType_t type, const char *pFile, int line)
{
// Only grab the file name. Ignore the path.
const char *pSlash = strrchr(pFile, '\\');
const char *pSlash2 = strrchr(pFile, '/');
if (pSlash < pSlash2) pSlash = pSlash2;
s_pFileName = pSlash ? pSlash + 1 : pFile;
s_Line = line;
s_SpewType = type;
}
SpewRetval_t _SpewMessage(SpewType_t spewType, const char *pMsgFormat, va_list args)
{
char pTempBuffer[1024];
// Printf the file and line for warning + assert only...
int len = 0;
if ((spewType == SPEW_ASSERT))
{
len = sprintf(pTempBuffer, "%s (%d) : ", s_pFileName, s_Line);
}
// Create the message....
len += vsprintf(&pTempBuffer[len], pMsgFormat, args);
// Add \n for warning and assert
if ((spewType == SPEW_ASSERT))
{
len += sprintf(&pTempBuffer[len], "\n");
}
assert(len < 1024); // use normal assert here; to avoid recursion.
assert(s_SpewOutputFunc);
// direct it to the appropriate target(s)
SpewRetval_t ret = s_SpewOutputFunc(spewType, pTempBuffer);
switch (ret)
{
// Put the break into the macro so it would occur in the right place
//case SPEW_DEBUGGER:
// DebuggerBreak();
// break;
case SPEW_ABORT:
// MessageBox(nullptr, "Error in _SpewMessage", "Error", MB_OK);
exit(0);
default:
break;
}
return ret;
}
SpewRetval_t _SpewMessage(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args);
va_end(args);
return ret;
}
SpewRetval_t _DSpewMessage(const char *pGroupName, int level, const char *pMsgFormat, ...)
{
if (!IsSpewActive(pGroupName, level))
return SPEW_CONTINUE;
va_list args;
va_start(args, pMsgFormat);
SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args);
va_end(args);
return ret;
}
void Msg(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_MESSAGE, pMsgFormat, args);
va_end(args);
}
void DMsg(const char *pGroupName, int level, const char *pMsgFormat, ...)
{
if (!IsSpewActive(pGroupName, level))
return;
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_MESSAGE, pMsgFormat, args);
va_end(args);
}
void Warning(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_WARNING, pMsgFormat, args);
va_end(args);
}
void DWarning(const char *pGroupName, int level, const char *pMsgFormat, ...)
{
if (!IsSpewActive(pGroupName, level))
return;
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_WARNING, pMsgFormat, args);
va_end(args);
}
void Log(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_LOG, pMsgFormat, args);
va_end(args);
}
void DLog(const char *pGroupName, int level, const char *pMsgFormat, ...)
{
if (!IsSpewActive(pGroupName, level))
return;
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_LOG, pMsgFormat, args);
va_end(args);
}
void Error(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_ERROR, pMsgFormat, args);
va_end(args);
}
// A couple of super-common dynamic spew messages, here for convenience
// These looked at the "developer" group, print if it's level 1 or higher
void DevMsg(int level, char const *pMsgFormat, ...)
{
if (!IsSpewActive("developer", level))
return;
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_MESSAGE, pMsgFormat, args);
va_end(args);
}
void DevWarning(int level, const char *pMsgFormat, ...)
{
if (!IsSpewActive("developer", level))
return;
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_WARNING, pMsgFormat, args);
va_end(args);
}
void DevLog(int level, const char *pMsgFormat, ...)
{
if (!IsSpewActive("developer", level))
return;
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_LOG, pMsgFormat, args);
va_end(args);
}
void DevMsg(const char *pMsgFormat, ...)
{
if (!IsSpewActive("developer", 1))
return;
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_MESSAGE, pMsgFormat, args);
va_end(args);
}
void DevWarning(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_WARNING, pMsgFormat, args);
va_end(args);
}
void DevLog(const char *pMsgFormat, ...)
{
va_list args;
va_start(args, pMsgFormat);
_SpewMessage(SPEW_LOG, pMsgFormat, args);
va_end(args);
}
// Find a group, return true if found, false if not. Return in ind the
// index of the found group, or the index of the group right before where the
// group should be inserted into the list to maintain sorted order.
bool FindSpewGroup(const char *pGroupName, int *pInd)
{
int s = 0;
if (s_GroupCount)
{
int e = (int)(s_GroupCount - 1);
while (s <= e)
{
int m = (s + e) >> 1;
int cmp = Q_stricmp(pGroupName, s_pSpewGroups[m].m_GroupName);
if (!cmp)
{
*pInd = m;
return true;
}
if (cmp < 0)
e = m - 1;
else
s = m + 1;
}
}
*pInd = s;
return false;
}
// Sets the priority level for a spew group
void SpewActivate(const char *pGroupName, int level)
{
Assert(pGroupName);
// check for the default group first...
if ((pGroupName[0] == '*') && (pGroupName[1] == '\0'))
{
s_DefaultLevel = level;
return;
}
// Normal case, search in group list using binary search.
// If not found, grow the list of groups and insert it into the
// right place to maintain sorted order. Then set the level.
int ind;
if (!FindSpewGroup(pGroupName, &ind))
{
// not defined yet, insert an entry.
s_GroupCount++;
if (s_pSpewGroups)
{
s_pSpewGroups = (SpewGroup_t *)realloc(s_pSpewGroups, s_GroupCount * sizeof(SpewGroup_t));
// shift elements down to preserve order
int numToMove = s_GroupCount - ind - 1;
memmove(&s_pSpewGroups[ind + 1], &s_pSpewGroups[ind], numToMove * sizeof(SpewGroup_t));
}
else
s_pSpewGroups = (SpewGroup_t *)malloc(s_GroupCount * sizeof(SpewGroup_t));
Assert(strlen(pGroupName) < MAX_GROUP_NAME_LENGTH);
strcpy(s_pSpewGroups[ind].m_GroupName, pGroupName);
}
s_pSpewGroups[ind].m_Level = level;
}
// Tests to see if a particular spew is active
bool IsSpewActive(const char *pGroupName, int level)
{
// If we don't find the spew group, use the default level.
int ind;
if (FindSpewGroup(pGroupName, &ind))
return s_pSpewGroups[ind].m_Level >= level;
else
return s_DefaultLevel >= level;
}