258 lines
8.1 KiB
C++

/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: Debug.h
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: Debug.h
//
// Created: Steven Johnson, August 2001
//
// Desc: Debug Utilities
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __DEBUG_H_
#define __DEBUG_H_
class AsciiString;
#if defined(_DEBUG) && defined(_INTERNAL)
#error "Only one at a time of these should ever be defined"
#endif
// These are stolen from the WW3D Debug file. REALLY useful. :-)
#define STRING_IT(a) #a
#define TOKEN_IT(a) STRING_IT(,##a)
#define MESSAGE(a) message (__FILE__ "(" TOKEN_IT(__LINE__) ") : " a)
// BGC, 3/26/03 - put this in so we can build internal worldbuilder for a patch that doesn't
// have any debugging of any kind.
//#define DISABLE_DEBUG_LOGGING
// by default, turn on ALLOW_DEBUG_UTILS if _DEBUG is turned on.
#if (defined(_DEBUG) || defined(_INTERNAL)) && !defined(ALLOW_DEBUG_UTILS) && !defined(DISABLE_ALLOW_DEBUG_UTILS)
#define ALLOW_DEBUG_UTILS 1
#endif
// these are predicated on ALLOW_DEBUG_UTILS, not _DEBUG, and allow you to selectively disable
// bits of the debug stuff for special builds.
#if defined(ALLOW_DEBUG_UTILS) && !defined(DEBUG_LOGGING) && !defined(DISABLE_DEBUG_LOGGING)
#define DEBUG_LOGGING 1
#endif
#if defined(ALLOW_DEBUG_UTILS) && !defined(DEBUG_CRASHING) && !defined(DISABLE_DEBUG_CRASHING)
#define DEBUG_CRASHING 1
#endif
// BGC - added the DEBUG_LOGGING term...doesn't make sense to do stack debugging without a debug log to print to.
#if defined(ALLOW_DEBUG_UTILS) && !defined(DEBUG_STACKTRACE) && !defined(DISABLE_DEBUG_STACKTRACE) && defined(DEBUG_LOGGING)
#define DEBUG_STACKTRACE 1
#endif
#if defined(ALLOW_DEBUG_UTILS) && !defined(DEBUG_PROFILE) && !defined(DISABLE_DEBUG_PROFILE)
#define DEBUG_PROFILE 1
#endif
#ifdef __cplusplus
#define DEBUG_EXTERN_C extern "C"
#else
#define DEBUG_EXTERN_C extern
#endif
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////
// FORWARD REFERENCES /////////////////////////////////////////////////////////
// TYPE DEFINES ///////////////////////////////////////////////////////////////
// INLINING ///////////////////////////////////////////////////////////////////
// EXTERNALS //////////////////////////////////////////////////////////////////
/// @todo: the standard line-to-string trick isn't working correctly in vc6; figure out why
#define DEBUG_STRING_IT(b) #b
#define DEBUG_TOKEN_IT(a) DEBUG_STRING_IT(a)
#define DEBUG_FILENLINE __FILE__ ":" DEBUG_TOKEN_IT(__LINE__)
#ifdef ALLOW_DEBUG_UTILS
enum
{
DEBUG_FLAG_LOG_TO_FILE = 0x01,
DEBUG_FLAG_LOG_TO_CONSOLE = 0x02,
DEBUG_FLAG_PREPEND_TIME = 0x04,
#ifdef _INTERNAL
// by default, _INTERNAL builds log to file, but not to console, in the interest
// of speed. want console output? just change this line:
DEBUG_FLAGS_DEFAULT = (DEBUG_FLAG_LOG_TO_FILE)
#else
DEBUG_FLAGS_DEFAULT = (DEBUG_FLAG_LOG_TO_FILE | DEBUG_FLAG_LOG_TO_CONSOLE)
#endif
};
DEBUG_EXTERN_C void DebugInit(int flags);
DEBUG_EXTERN_C void DebugShutdown();
DEBUG_EXTERN_C int DebugGetFlags();
DEBUG_EXTERN_C void DebugSetFlags(int flags);
#define DEBUG_INIT(f) do { DebugInit(f); } while (0)
#define DEBUG_SHUTDOWN() do { DebugShutdown(); } while (0)
#else
#define DEBUG_INIT(f) ((void)0)
#define DEBUG_SHUTDOWN() ((void)0)
#endif
#ifdef DEBUG_LOGGING
DEBUG_EXTERN_C void DebugLog(const char *format, ...);
// This defines a bitmask of log types that we care about, to allow some flexability
// in what gets logged. This should be extended to asserts, too, but the assert box
// is waiting to be rewritten. -MDC 3/19/2003
extern unsigned int DebugLevelMask;
enum
{
DEBUG_LEVEL_NET = 0, // in-game network
DEBUG_LEVEL_MAX
};
extern const char *TheDebugLevels[DEBUG_LEVEL_MAX];
#define DEBUG_LOG(m) do { { DebugLog m ; } } while (0)
#define DEBUG_LOG_LEVEL(l, m) do { if (l & DebugLevelMask) { DebugLog m ; } } while (0)
#define DEBUG_ASSERTLOG(c, m) do { { if (!(c)) DebugLog m ; } } while (0)
#else
#define DEBUG_LOG(m) ((void)0)
#define DEBUG_LOG_LEVEL(l, m) ((void)0)
#define DEBUG_ASSERTLOG(c, m) ((void)0)
#endif
#ifdef DEBUG_CRASHING
DEBUG_EXTERN_C void DebugCrash(const char *format, ...);
/*
Yeah, it's a sleazy global, since we can't reasonably add
any args to DebugCrash due to the varargs nature of it.
We'll just let it slide in this case...
*/
DEBUG_EXTERN_C char* TheCurrentIgnoreCrashPtr;
#define DEBUG_CRASH(m) \
do { \
{ \
static char ignoreCrash = 0; \
if (!ignoreCrash) { \
TheCurrentIgnoreCrashPtr = &ignoreCrash; \
DebugCrash m ; \
TheCurrentIgnoreCrashPtr = NULL; \
} \
} \
} while (0)
#define DEBUG_ASSERTCRASH(c, m) do { { if (!(c)) DEBUG_CRASH(m); } } while (0)
//Note: RELEASE_CRASH(m) is now always defined.
//#define RELEASE_CRASH(m) DEBUG_CRASH((m))
#else
#define DEBUG_CRASH(m) ((void)0)
#define DEBUG_ASSERTCRASH(c, m) ((void)0)
// DEBUG_EXTERN_C void ReleaseCrash(const char* reason);
// #define RELEASE_CRASH(m) do { ReleaseCrash(m); } while (0)
#endif
DEBUG_EXTERN_C void ReleaseCrash(const char* reason);
DEBUG_EXTERN_C void ReleaseCrashLocalized(const AsciiString& p, const AsciiString& m);
#define RELEASE_CRASH(m) do { ReleaseCrash(m); } while (0)
#define RELEASE_CRASHLOCALIZED(p, m) do { ReleaseCrashLocalized(p, m); } while (0)
#ifdef DEBUG_PROFILE
class SimpleProfiler
{
private:
__int64 m_freq;
__int64 m_startThisSession;
__int64 m_totalThisSession;
__int64 m_totalAllSessions;
int m_numSessions;
public:
SimpleProfiler();
void start();
void stop();
void stopAndLog(const char *msg, int howOftenToLog, int howOftenToResetAvg);
double getTime(); // of most recent session, in milliseconds
int getNumSessions();
double getTotalTime(); // total over all sessions, in milliseconds
double getAverageTime(); // averaged over all sessions, in milliseconds
};
#define BEGIN_PROFILE(uniqueid) \
static SimpleProfiler prof_##uniqueid; \
prof_##uniqueid.start();
#define END_PROFILE(uniqueid, msg, howoftentolog, howoftentoreset) \
prof_##uniqueid.stopAndLog(msg, howoftentolog, howoftentoreset);
#else
#define BEGIN_PROFILE(uniqueid)
#define END_PROFILE(uniqueid, msg, howoftentolog, howoftentoreset)
#endif
// MACROS //////////////////////////////////////////////////////////////////
#endif // __DEBUG_H_