Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View file

@ -0,0 +1,29 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/_pch.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Precompiled header (module internal)
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"

View file

@ -0,0 +1,46 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/_pch.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Precompiled header (module internal)
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef _PCH_H // Include guard
#define _PCH_H
#include "debug.h"
// we need windows.h at too many places...
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "internal.h"
#include "internal_io.h"
#include "internal_except.h"
#endif // _PCH_H

View file

@ -0,0 +1,26 @@
@echo off
rem
rem This batch file generates DoxyGen info and compiles the separate
rem HTML files into CHMs.
rem
rem Assumptions:
rem ------------
rem - doxygen installed and in path
rem - hhc (HTML Help Compiler) installed and in path
rem - dot (Graphviz package) installed and in path
rem
rem Both generated CHM files are then copied over to the
rem common DOC area.
doxygen debug.dox
doxygen debug_priv.dox
cd doc\html
hhc index.hhp
copy index.chm ..\..\debug.chm
cd ..\html_priv
hhc index.hhp
copy index.chm ..\..\debug_priv.chm
cd ..\..
copy debug.chm ..\..\docs

View file

@ -0,0 +1,29 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug module main code
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"

View file

@ -0,0 +1,208 @@
# Doxyfile 1.3.1
#---------------------------------------------------------------------------
# General configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = "EA/Debug module"
PROJECT_NUMBER =
OUTPUT_DIRECTORY = doc/
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = YES
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = YES
HIDE_IN_BODY_DOCS = YES
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = YES
FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
SHORT_NAMES = NO
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 8
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ALIASES = "todo_opt=\todo"
ALIASES += "todo_urgent=\todo"
ALIASES += "todo_feature=\todo"
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
SHOW_USED_FILES = YES
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ./
FILE_PATTERNS = debug*.h
RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = YES
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = YES
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = _DEBUG \
DOXYGEN
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::addtions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
CLASS_GRAPH = YES
COLLABORATION_GRAPH = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 0
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::addtions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO
CGI_NAME = search.cgi
CGI_URL =
DOC_URL =
DOC_ABSPATH =
BIN_ABSPATH = /usr/local/bin/
EXT_DOC_PATHS =

View file

@ -0,0 +1,320 @@
# Microsoft Developer Studio Project File - Name="debug" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=debug - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "debug.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "debug.mak" CFG="debug - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "debug - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "debug - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE "debug - Win32 Internal" (based on "Win32 (x86) Static Library")
!MESSAGE "debug - Win32 Profile" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "debug"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "debug - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /G6 /MD /W3 /WX /Zi /Ot /Og /Oi /Oy /Ob2 /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"_pch.h" /FD /GF /Gs /c
# SUBTRACT CPP /Oa
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=copying
PostBuild_Cmds=copy release\debug.lib ..\..\lib
# End Special Build Tool
!ELSEIF "$(CFG)" == "debug - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /G6 /MDd /W3 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Yu"_pch.h" /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"Debug\debugdebug.lib"
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=copying
PostBuild_Cmds=copy debug\debugdebug.lib ..\..\lib
# End Special Build Tool
!ELSEIF "$(CFG)" == "debug - Win32 Internal"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Internal"
# PROP BASE Intermediate_Dir "Internal"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Internal"
# PROP Intermediate_Dir "Internal"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MD /W3 /WX /Zi /Ot /Oa /Og /Oi /Oy /Ob2 /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"_pch.h" /FD /GF /Gs /c
# ADD CPP /nologo /G6 /MD /W3 /WX /Zi /Ot /Og /Oi /Oy /Ob2 /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "_INTERNAL" /Yu"_pch.h" /FD /GF /Gs /c
# SUBTRACT CPP /Oa
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"Internal\debuginternal.lib"
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=copying
PostBuild_Cmds=copy internal\debuginternal.lib ..\..\lib
# End Special Build Tool
!ELSEIF "$(CFG)" == "debug - Win32 Profile"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Profile"
# PROP BASE Intermediate_Dir "Profile"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Profile"
# PROP Intermediate_Dir "Profile"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MD /W3 /WX /Zi /Ot /Oa /Og /Oi /Oy /Ob2 /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"_pch.h" /FD /GF /Gs /c
# ADD CPP /nologo /G6 /MD /W3 /WX /Zi /Ot /Og /Oi /Oy /Ob2 /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "_PROFILE" /Yu"_pch.h" /FD /GF /Gs /c
# SUBTRACT CPP /Oa
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"Profile\debugprofile.lib"
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=copying
PostBuild_Cmds=copy profile\debugprofile.lib ..\..\lib
# End Special Build Tool
!ENDIF
# Begin Target
# Name "debug - Win32 Release"
# Name "debug - Win32 Debug"
# Name "debug - Win32 Internal"
# Name "debug - Win32 Profile"
# Begin Group "Precompiled header"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\_pch.cpp
# ADD CPP /Yc"_pch.h"
# End Source File
# Begin Source File
SOURCE=.\_pch.h
# End Source File
# End Group
# Begin Group "Doxygen"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\compile_doxygen.bat
# End Source File
# Begin Source File
SOURCE=.\debug.dox
# End Source File
# Begin Source File
SOURCE=.\debug_priv.dox
# End Source File
# End Group
# Begin Group "IO Classes"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\debug_io.h
# End Source File
# Begin Source File
SOURCE=.\debug_io_con.cpp
# End Source File
# Begin Source File
SOURCE=.\debug_io_flat.cpp
# End Source File
# Begin Source File
SOURCE=.\debug_io_net.cpp
# End Source File
# Begin Source File
SOURCE=.\debug_io_ods.cpp
# End Source File
# Begin Source File
SOURCE=.\internal_io.h
# End Source File
# End Group
# Begin Group "Exception handler"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\debug_except.cpp
# End Source File
# Begin Source File
SOURCE=.\internal_except.h
# End Source File
# Begin Source File
SOURCE=.\rc_exception.inl
# End Source File
# End Group
# Begin Group "Stack walk"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\debug_stack.cpp
# End Source File
# Begin Source File
SOURCE=.\debug_stack.h
# End Source File
# Begin Source File
SOURCE=.\debug_stack.inl
# End Source File
# End Group
# Begin Group "Command interface"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\debug_cmd.cpp
# End Source File
# Begin Source File
SOURCE=.\debug_cmd.h
# End Source File
# Begin Source File
SOURCE=.\debug_getdefaultcommands.cpp
# End Source File
# End Group
# Begin Group "Proxy header"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Include\rts\debug.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\debug.cpp
# ADD CPP /FAcs
# End Source File
# Begin Source File
SOURCE=.\debug.h
# End Source File
# Begin Source File
SOURCE=.\debug_debug.cpp
!IF "$(CFG)" == "debug - Win32 Release"
!ELSEIF "$(CFG)" == "debug - Win32 Debug"
!ELSEIF "$(CFG)" == "debug - Win32 Internal"
# ADD CPP /FAcs
!ELSEIF "$(CFG)" == "debug - Win32 Profile"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\debug_debug.h
# End Source File
# Begin Source File
SOURCE=.\debug_doc.h
# End Source File
# Begin Source File
SOURCE=.\debug_internal.cpp
# End Source File
# Begin Source File
SOURCE=.\debug_macro.h
# End Source File
# Begin Source File
SOURCE=.\debug_purecall.cpp
# End Source File
# Begin Source File
SOURCE=.\internal.h
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,179 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "debug"=.\debug.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
debug
.
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "debug_dlg"=.\debug_dlg\debug_dlg.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
debug_dlg
.\debug_dlg
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "netserv"=.\netserv\netserv.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
netserv
.\netserv
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "test1"=.\test1\test1.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
test1
.\test1
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name debug
End Project Dependency
}}}
###############################################################################
Project: "test2"=.\test2\test2.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
test2
.\test2
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name debug
End Project Dependency
}}}
###############################################################################
Project: "test3"=.\test3\test3.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
test3
.\test3
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name debug
End Project Dependency
}}}
###############################################################################
Project: "test4"=.\test4\test4.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
test4
.\test4
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name debug
End Project Dependency
}}}
###############################################################################
Project: "test5"=.\test5\test5.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
test5
.\test5
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name debug
End Project Dependency
}}}
###############################################################################
Project: "test6"=.\test6\test6.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
test6
.\test6
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name debug
End Project Dependency
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View file

@ -0,0 +1,120 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debugging module
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef DEBUG_H // Include guard
#define DEBUG_H
/**
\page lib_var Library variants
Generally speaking there are four different library variants:
- Internal: all asserts/checks/logs, full optimizations (_INTERNAL macro defined)
- %Debug: all asserts/checks/logs, no optimizations (_DEBUG macro defined)
- Profile: all asserts/checks/logs, full optimizations, profiling active (_PROFILE macro defined)
- Release: no asserts/checks/logs, full optimizations
These variants will be broken down into separate features which
can be queried for by #ifdef(HAS_FEATURE):
<table><tr>
<td><b>Variant</b></td>
<td><b>HAS_ASSERTS</b></td>
<td><b>HAS_LOGS</b></td>
<td><b>HAS_OPT</b></td>
<td><b>HAS_PROFILE</b></td>
</tr><tr>
<td>Internal</td>
<td><center>Y</center></td>
<td><center>Y</center></td>
<td><center>Y</center></td>
<td><center></center></td>
</tr><tr>
<td>%Debug</td>
<td><center>Y</center></td>
<td><center>Y</center></td>
<td><center></center></td>
<td><center></center></td>
</tr><tr>
<td>Profile</td>
<td><center>Y</center></td>
<td><center>Y</center></td>
<td><center>Y</center></td>
<td><center>Y</center></td>
</tr><tr>
<td>Release</td>
<td><center></center></td>
<td><center></center></td>
<td><center>Y</center></td>
<td><center></center></td>
</tr></table>
Library files have a suffix appended that depends on the
library variant:
- Internal: XXXInternal.lib
- %Debug: XXXDebug.lib
- Profile: XXXProfile.lib
- Release: XXX.lib
*/
#if defined(_DEBUG) && defined(_INTERNAL)
#error "Only either _DEBUG or _INTERNAL should ever be defined"
#endif
// Define which libraries to use.
#if defined(_INTERNAL)
# pragma comment (lib,"debuginternal.lib")
# define HAS_ASSERTS
# define HAS_LOGS
# define HAS_OPT
#elif defined(_DEBUG)
# pragma comment (lib,"debugdebug.lib")
# define HAS_ASSERTS
# define HAS_LOGS
#elif defined(_PROFILE)
# pragma comment (lib,"debugprofile.lib")
# define HAS_ASSERTS
# define HAS_LOGS
# define HAS_OPT
# define HAS_PROFILE
#else
# pragma comment (lib,"debug.lib")
# define HAS_OPT
#endif
// include all our public header files (use double quotes here)
#include "debug_doc.h"
#include "debug_macro.h"
#include "debug_io.h"
#include "debug_cmd.h"
#include "debug_stack.h"
#include "debug_debug.h"
#endif // DEBUG_H

View file

@ -0,0 +1,405 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_cmd.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug command group 'debug'
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include <process.h>
bool DebugCmdInterfaceDebug::Execute(class Debug& dbg, const char *cmd,
CommandMode cmdmode, unsigned argn,
const char * const * argv)
{
// just for convenience...
bool normalMode=cmdmode==CommandMode::Normal;
if (!strcmp(cmd,"help"))
{
if (!normalMode)
return true;
if (!argn)
{
dbg << "debug group help:\n"
" list, io, alwaysflush, timestamp, exit, clear, add, view\n";
return true;
}
else if (!strcmp(argv[0],"list"))
{
dbg << "list (g|l|d|a|c) [ <pattern> ]\n"
"\n"
"Shows some or all items of a specific type.\n"
"\n"
"The following items are supported:\n"
"- g: command groups\n"
"- l: log groups (only those encountered yet)\n"
"- d: log groups with descriptions (only those that have descriptions)\n"
"- a: asserts/crashes (only those hit yet)\n"
"- c: checks (only those failed yet)\n"
"\n"
"If a pattern is specified only items matching\n"
"that pattern are shown. A pattern can contain\n"
"any character, letter, or a wildcard '*'.\n"
"\n"
"Please note that assert, crashes, and check items have\n"
"their line number appended to the current file name,\n"
"e.g. debug.cpp(13).\n";
return true;
}
else if (!strcmp(argv[0],"io"))
{
dbg << "io <I/O Class> <cmd> { <param> }]\n"
"\n"
"Issues a I/O class command. I/O class commands are used\n"
"for determining where all log output should be sent. \n"
"Please check the list of \ref debug_ioclasses for a list\n"
"of existing I/O classes.\n"
"\n"
"Each existing I/O class must accept at least the\n"
"following two commands: 'add' and 'remove'. Usually\n"
"after a class has been added it reacts to the 'help'\n"
"command as well.\n"
"\n"
"If the command is entered without any parameters a list\n"
"of active I/O classes is shown. Typing 'io ?' retrieves\n"
"a list of possible I/O classes.\n";
return true;
}
else if (!strcmp(argv[0],"alwaysflush"))
{
dbg << "alwaysflush [ (+|-) ]\n\n"
"Enables/disables flushing after each new entry in\n"
"the log file (default: off).\n";
return true;
}
else if (!strcmp(argv[0],"timestamp"))
{
dbg << "timestamp [ (+|-) ]\n\n"
"Enables/disables timestamping each log entry\n"
"(default: off).\n";
return true;
}
else if (!strcmp(argv[0],"exit"))
{
dbg << "exit\n\nExits program immediately.\n";
return true;
}
else if (!strcmp(argv[0],"clear"))
{
dbg << "clear (l|a|c)\n\n"
"Clears the given inclusion/exclusion list\n"
"(l=logs, a=asserts/crashes, c=checks).\n";
return true;
}
else if (!strcmp(argv[0],"add"))
{
dbg << "add (l|a|c) (+|-) <pattern>\n"
"\n"
"Adds a pattern to the given list (l=logs, \n"
"a=asserts/crashes, c=checks). By default all\n"
"asserts, crashes, and checks are active, all logs\n"
"inactive. Each item is then checked \n"
"against all pattern in the respective\n"
"list. If a match is found the active/inactive\n"
"state is modified accordingly (+ for active,\n"
"- for inactive). The final state is always\n"
"the last match.";
return true;
}
else if (!strcmp(argv[0],"view"))
{
dbg << "view [ (l|a|c) ]\n\n"
"Shows the active pattern for the given list\n"
"(l=logs, a=asserts/crashes, c=checks).\n";
return true;
}
return false;
}
if (!strcmp(cmd,"list"))
{
const char *pattern=argn>=2?argv[1]:"*";
switch(argn?*argv[0]:0)
{
case 'g':
{
if (normalMode)
dbg << "Command groups:\n";
for (Debug::CmdInterfaceListEntry *cur=dbg.firstCmdGroup;cur;cur=cur->next)
if (Debug::SimpleMatch(cur->group,pattern))
dbg << cur->group << "\n";
}
break;
case 'l':
case 'd':
{
if (normalMode)
dbg << "Logs:\n";
for (Debug::KnownLogGroupList *cur=dbg.firstLogGroup;cur;cur=cur->next)
if (Debug::SimpleMatch(cur->nameGroup,pattern)&&
(*argv[0]=='l'||cur->descr))
{
dbg << cur->nameGroup;
if (cur->descr)
dbg << " (" << cur->descr << ")";
dbg << "\n";
}
}
break;
case 'a':
case 'c':
{
if (normalMode)
dbg << (*argv[0]=='a'?"Asserts/Crashes:\n":"Checks:\n");
unsigned mask=*argv[0]=='a'?Debug::FrameTypeAssert:Debug::FrameTypeCheck;
for (unsigned k=0;k<Debug::FRAME_HASH_SIZE;k++)
{
for (Debug::FrameHashEntry *cur=dbg.frameHash[k];cur;cur=cur->next)
{
if (!(cur->frameType&mask))
continue;
char help[256];
wsprintf(help,"%s(%i)",cur->fileOrGroup,cur->line);
if (Debug::SimpleMatch(help,pattern))
{
dbg << help << " (" << cur->hits << " hits)";
if (cur->status==Debug::Skip)
dbg << " [off]";
dbg << "\n";
}
}
}
}
break;
default:
dbg << "Unknown item type, see help.";
}
return true;
}
if (!strcmp(cmd,"io"))
{
// cmd: io
if (!argn||!strcmp(argv[0],"?"))
{
// show active/all I/O classes
if (normalMode)
dbg << (argn?"Possible:\n":"Active:\n");
bool hadItem=false;
for (Debug::IOFactoryListEntry *cur=dbg.firstIOFactory;cur;cur=cur->next)
{
if (!argn&&!cur->io)
continue;
hadItem=true;
dbg << cur->ioID << " (" << cur->descr << ")\n";
}
if (normalMode&&!hadItem)
dbg << "(none)\n";
}
else
{
// regular I/O command
// find I/O class
for (Debug::IOFactoryListEntry *cur=dbg.firstIOFactory;cur;cur=cur->next)
if (!strcmp(argv[0],cur->ioID))
break;
if (!cur)
{
dbg << "Unknown I/O class " << argv[0];
return true; // still return true because we knew the command
}
if (argn>1)
{
// 'add' command?
if (!strcmp(argv[1],"add"))
{
if (cur->io)
{
dbg << "I/O class already added";
return true;
}
cur->io=cur->factory();
if (!cur->io)
{
dbg << "I/O class factory failed";
return true;
}
}
// 'remove' command?
if (!strcmp(argv[1],"remove"))
{
if (cur->io)
{
cur->io->Delete();
cur->io=NULL;
}
return true;
}
}
// now pass along I/O command
if (!cur->io)
{
dbg << "Add I/O class first";
return true;
}
cur->io->Execute(dbg,argn>1?argv[1]:NULL,!normalMode,argn>1?argn-2:0,argv+2);
}
return true;
}
if (!strcmp(cmd,"alwaysflush"))
{
if (argn)
{
if (*argv[0]=='+')
dbg.alwaysFlush=true;
if (*argv[0]=='-')
dbg.alwaysFlush=false;
}
if (normalMode)
dbg << "Always flush: " << (dbg.alwaysFlush?"on":"off");
else
dbg << (dbg.alwaysFlush?"1":"0");
return true;
}
if (!strcmp(cmd,"timestamp"))
{
if (argn)
{
if (*argv[0]=='+')
dbg.timeStamp=true;
if (*argv[0]=='-')
dbg.timeStamp=false;
}
if (normalMode)
dbg << "Timestamp: " << (dbg.timeStamp?"on":"off");
else
dbg << (dbg.timeStamp?"1":"0");
return true;
}
if (!strcmp(cmd,"exit"))
{
exit(1);
return true;
}
if (!strcmp(cmd,"clear")||
!strcmp(cmd,"add")||
!strcmp(cmd,"view"))
{
unsigned mask=0;
if (argn)
{
for (const char *p=argv[0];*p;p++)
{
switch(*p)
{
case 'l': mask|=Debug::FrameTypeLog; break;
case 'a': mask|=Debug::FrameTypeAssert; break;
case 'c': mask|=Debug::FrameTypeCheck; break;
}
}
}
if (!mask)
mask=0xffffffff;
bool modified=false;
if (!strcmp(cmd,"clear"))
{
// remove some (or all) pattern
const char *pattern=argn<2?"*":argv[1];
for (Debug::PatternListEntry **entryPtr=&dbg.firstPatternEntry;*entryPtr;)
{
if ( (((*entryPtr)->frameTypes&mask)!=0)
&& Debug::SimpleMatch((*entryPtr)->pattern,pattern) )
{
// remove this entry
modified=true;
Debug::PatternListEntry *cur=*entryPtr;
*entryPtr=cur->next;
DebugFreeMemory(cur->pattern);
DebugFreeMemory(cur);
}
else
entryPtr=&((*entryPtr)->next);
}
// must fixup lastPatternEntry now
if (dbg.firstPatternEntry)
{
for (Debug::PatternListEntry *cur=dbg.firstPatternEntry;cur->next;cur=cur->next);
dbg.lastPatternEntry=cur;
}
else
dbg.lastPatternEntry=NULL;
}
if (!strcmp(cmd,"add"))
{
// add a pattern
if (argn<3)
dbg << "Please specify mode and pattern";
else
{
dbg.AddPatternEntry(mask,*argv[1]=='+',argv[2]);
modified=true;
}
}
if (!strcmp(cmd,"view"))
{
// show list of defined patterns
for (Debug::PatternListEntry *cur=dbg.firstPatternEntry;cur;cur=cur->next)
{
if (!(cur->frameTypes&mask))
continue;
if (cur->frameTypes&Debug::FrameTypeLog) dbg << "l";
if (cur->frameTypes&Debug::FrameTypeAssert) dbg << "a";
if (cur->frameTypes&Debug::FrameTypeCheck) dbg << "c";
dbg << (cur->isActive?" + ":" - ") << cur->pattern << "\n";
}
}
if (modified)
{
// pattern list was modified, set all frame entries statuses to Unknown
for (unsigned k=0;k<Debug::FRAME_HASH_SIZE;k++)
for (Debug::FrameHashEntry *cur=dbg.frameHash[k];cur;cur=cur->next)
cur->status=Debug::Unknown;
}
return true;
}
// unknown command
return false;
}

View file

@ -0,0 +1,131 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_cmd.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug command interface
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef DEBUG_CMD_H // Include guard
#define DEBUG_CMD_H
/**
\interface DebugCmdInterface debug.h <rts/debug.h>
\brief Debug command group interface.
A debug command group interface implementation defines a new
command group and the commands implemented for this group.
A Debug command group interface instance must register itself
using Debug::AddCommands. Ownership is then transfered to
the Debug module unless the object is manually removed
by calling Debug::RemoveCommands.
For convenience the macro \ref DEBUG_CREATE_COMMAND_GROUP
can be used as well.
*/
class DebugCmdInterface
{
// no copy/assign op
DebugCmdInterface(const &DebugCmdInterface);
DebugCmdInterface& operator=(const DebugCmdInterface&);
protected:
// nobody can call this destructor (except child classes)
virtual ~DebugCmdInterface() {}
public:
// interface only so no functionality here
explicit DebugCmdInterface(void) {}
/// possible command modes
enum CommandMode
{
/// normal command mode
Normal,
/// structured command mode
Structured,
MAX
};
/**
\brief Execute the given command.
This function is called whenever a command has been issued for
the command group the interface implements.
\param dbg debug instance
\param cmd command issued
\param cmdmode command mode
\param argn number of additional arguments passed in
\param argv argument list
\return true if command was known, false if not
*/
virtual bool Execute(class Debug& dbg, const char *cmd, CommandMode cmdmode,
unsigned argn, const char * const * argv)=0;
/**
\brief Destroys the current command interface.
Use this function instead of just delete'ing the instance.
*/
virtual void Delete(void)=0;
};
/**
\addtogroup debug_cmd_macros Debug command interface helper macros
These macros can be used if a command interface instance should
be available right after starting the program (which is usually
the case).
*/
///@{
#ifdef DOXYGEN
/**
\brief Helper macro for creating and registering a command interface
instance the Debug module.
\param groupname name of command group this class if for
(without quotes)
\param type type name of class we're implementing
*/
#define DEBUG_CREATE_COMMAND_GROUP(groupname,type)
#else
#define DEBUG_CREATE_COMMAND_GROUP(groupname,type) \
static bool __RegisterDebugCmdGroup_##type=Debug::AddCommands(#groupname,new type);
#endif
///@}
#endif // DEBUG_CMD_H

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,209 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_dlg/debug_dlg.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug exception dialog test program
//////////////////////////////////////////////////////////////////////////////
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
// Pardon my coding here but this is for testing only...
#pragma comment (lib,"comctl32")
BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
SendDlgItemMessage(hWnd,100,WM_SETTEXT,0,(LPARAM)"EXCEPTION_TYPE");
SendDlgItemMessage(hWnd,101,WM_SETTEXT,0,(LPARAM)"Explains exception type further here...\n"
"123456789012345678901234567890123456789012345678901234567890");
SendDlgItemMessage(hWnd,102,WM_SETTEXT,0,(LPARAM)"Module/File/Line, Address");
SendDlgItemMessage(hWnd,103,WM_SETTEXT,0,(LPARAM)"File version, build type");
HWND list;
list=GetDlgItem(hWnd,104);
LVCOLUMN c;
c.mask=LVCF_TEXT|LVCF_WIDTH;
c.pszText="";
c.cx=0;
ListView_InsertColumn(list,0,&c);
c.mask=LVCF_TEXT|LVCF_WIDTH|LVCF_FMT;
c.pszText="Address";
c.cx=60;
c.fmt=LVCFMT_RIGHT;
ListView_InsertColumn(list,1,&c);
c.mask=LVCF_TEXT|LVCF_WIDTH;
c.pszText="Module";
c.cx=120;
ListView_InsertColumn(list,2,&c);
c.pszText="Symbol";
c.cx=300;
ListView_InsertColumn(list,3,&c);
c.pszText="File";
c.cx=130;
ListView_InsertColumn(list,4,&c);
c.pszText="Line";
c.cx=80;
ListView_InsertColumn(list,5,&c);
LVITEM item;
item.iItem=0;
item.iSubItem=0;
item.mask=0;
item.iItem=ListView_InsertItem(list,&item);
item.mask=LVIF_TEXT;
item.iSubItem++;
item.pszText="01234567";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="MSVCRTD.dll+0xad38";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="mainCRTStartupSuperLongSymbolOYeahThisIsCool+0xd23e0";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="reallyreallyverylongfilename.cpp";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="5748+0xad38";
ListView_SetItem(list,&item);
for (int k=1;k<30;k++)
{
item.iItem=k;
item.iSubItem=0;
item.iItem=ListView_InsertItem(list,&item);
item.mask=LVIF_TEXT;
item.iSubItem++;
item.pszText="88888888";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="MSVCRTD.dll+0xad38";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="Debug::DebugException::Symbol+0xd23e0";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="regularfilename.cpp";
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText="5748+0x38";
ListView_SetItem(list,&item);
}
HFONT hf;
hf=CreateFont(13,0,0,0,FW_NORMAL,
FALSE,FALSE,FALSE,ANSI_CHARSET,
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,FIXED_PITCH|FF_MODERN,NULL);
SendDlgItemMessage(hWnd,105,WM_SETFONT,(WPARAM)hf,MAKELPARAM(TRUE,0));
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"EAX:0x00000666 EBX:0x7ffdf000 ECX:0x00000000");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"EDX:0x00422208 ESI:0x02100210 EDI:0x0012fec4");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"EIP:0x0040103d ESP:0x0012fe78 EBP:0x0012fec4");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"Flags:%00000000000000010000001000000110");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"CS:0x001b DS:0x0023 SS:0x0023");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ES:0x0023 FS:0x0038 GS:0x0000");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"CW:%0000001001111111");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"SW:%0000000000000000");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"TW:%1111111111111111");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ErrOfs: 0x00000000 ErrSel: 0x03020000");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"DataOfs: 0x00000000 DataSel: 0xffff0000");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"Cr0NpxState: 0x00000000");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(0) 10020203100210021002 -1.#IND00");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(1) 01031002010320020103 -1.#IND00");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(2) 10021002100210021002 -1.#IND00");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(3) 02031002020320020203 -1.#IND00");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(4) 10021002100210021002 -1.#IND00");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(5) 12031002100210021002 -1.#IND00");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(6) 14021402100212031002 -1.#IND00");
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)"ST(7) 12031002100210021002 -1.#IND00");
}
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
EndDialog(hWnd,IDOK);
break;
}
return FALSE;
default:
return FALSE;
}
}
int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int)
{
// show dialog box first
InitCommonControls();
DialogBox(hInst,MAKEINTRESOURCE(100),NULL,DialogProc);
// write out resource data (if possible)
FILE *f=fopen("..\\rc_exception.inl","wt");
if (f)
{
fprintf(f,"static unsigned char rcException[]={ // program generated, do not edit\n");
HRSRC h=FindResource(hInst,MAKEINTRESOURCE(100),RT_DIALOG);
DWORD size=SizeofResource(hInst,h);
unsigned char *data=(unsigned char *)LockResource(LoadResource(hInst,h));
for (unsigned k=0;k<size;k+=8)
{
for (unsigned i=0;i<8;i++)
fprintf(f,"0x%02x,",k+i<size?data[k+i]:0);
fprintf(f,"\n");
}
fprintf(f,"0 };\n");
fclose(f);
}
return 0;
}

View file

@ -0,0 +1,97 @@
# Microsoft Developer Studio Project File - Name="debug_dlg" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=debug_dlg - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "debug_dlg.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "debug_dlg.mak" CFG="debug_dlg - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "debug_dlg - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "debug_dlg - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "debug_dlg"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "debug_dlg - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "debug_dlg - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
!ENDIF
# Begin Target
# Name "debug_dlg - Win32 Release"
# Name "debug_dlg - Win32 Debug"
# Begin Source File
SOURCE=.\debug_dlg.cpp
# End Source File
# Begin Source File
SOURCE=.\debug_dlg.rc
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,110 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_EXCEPTION DIALOGEX 0, 0, 479, 245
STYLE DS_SYSMODAL | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP |
WS_VISIBLE | WS_CAPTION
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE
CAPTION "Exception"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,422,224,50,14
CTEXT "ExType",100,7,7,265,9,SS_NOPREFIX
LTEXT "ExMsg",101,7,19,265,28,SS_NOPREFIX | SS_SUNKEN
CTEXT "ExAddr",102,7,59,265,19,SS_NOPREFIX | SS_CENTERIMAGE |
SS_SUNKEN
LTEXT "Location:",IDC_STATIC,7,50,30,8
LTEXT "Stack trace:",IDC_STATIC,7,103,40,8
CONTROL "List2",104,"SysListView32",LVS_REPORT |
LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,115,465,106
CTEXT "Ver",103,7,86,265,10,SS_NOPREFIX | SS_SUNKEN
LISTBOX 105,280,7,192,103,LBS_NOINTEGRALHEIGHT | LBS_NOSEL |
WS_VSCROLL | WS_TABSTOP
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_EXCEPTION, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 472
VERTGUIDE, 272
TOPMARGIN, 7
BOTTOMMARGIN, 238
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,35 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by debug_dlg.rc
//
#define IDD_EXCEPTION 100
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1003
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,709 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_doc.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// additional Doxygen module documentation
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef DEBUG_DOC_H // Include guard
#define DEBUG_DOC_H
// This generates a small main page for Doxygen if a module only
// documentation is built.
#ifndef DOXYGEN_GLOBAL_DOC
/**
\mainpage %Debug module
The following pages contain the most useful information:
- \ref module_debug
- \ref debug_macros
- \ref debug_stream
- \ref debug_cmd
\internal This is the internal module documentation meant only for
programmers who are working on the module internals.
*/
#endif
/**
\page module_debug Debug module overview
\section overview Overview
The Debug module contains all functions necessary to perform debugging related tasks,
e.g. checking assertions or logging.
\section logging Logging
Logging can be sent to a number of different locations:
- a flat log file
- a console window
- a debugger via OutputDebugString
- to a remote program (via a named pipe)
- to a number of separated log files
By default logging is enabled to the flat log file.
\section cmd Commands
The debug module is controlled via extendable commands. Commands are
typically put into logical groups. A command can then be executed
in a number of ways:
- group.command \<param\> (explicitly specifies which group to use)
- command \<param\> (assumes that the command resides in the same group
as the previous one)
- group. (switches the current group)
Every group has to respond to the command 'help'.
See also: \ref debug_cmd
\section dbgcmd .dbgcmd file
On startup the debug module tries to open a file called \<exe\>.dbgcmd -
if found then all lines in this module are directly interpreted as commands.
If the file is not found then default.dbgcmd is tried instead.
This allows for setting up a default environment.
*/
/**
\page debug_cmd Debug commands
Notation used:
- [ abc ] means that 'abc' may or may not be specified
- { abc } means that 'abc' may be specified any number of times (or not at all)
- (a|b|c) means that either 'a', 'b' or 'c' must be specified once
The following commands are already build in (group: debug):
<table><tr>
<td><b>Command</b></td>
<td><b>Parameters</b></td>
<td><b>Description</b></td>
</tr><tr>
<!---------------------------------->
<td valign=top>list</td>
<td valign=top>(g|l|d|a|c) [ \<pattern\> ]</td>
<td>
Shows some or all items of a specific type.
The following items are supported:
- g: command groups
- l: log groups (only those encountered yet)
- d: log groups with descriptions (only those that have descriptions)
- a: asserts/crashes (only those hit yet)
- c: checks (only those failed yet)
If a pattern is specified only items matching
that pattern are shown. A pattern can contain
any character, letter, or a wildcard '*'.
Please note that assert, crashes, and check items have
their line number appended to the current file name,
e.g. debug.cpp(13).
Example:
\code
> list g
debug
> list l test*
test
test_log2
> list d test*
test_log2: test log group w/ description
\endcode
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>help</td>
<td valign=top></td>
<td>
Shows help regarding debug group commands.
Example:
\code
> help
Help info debug group:
...
\endcode
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>io</td>
<td valign=top>[ \<I/O Class\> \<cmd\> { \<param\> }] </td>
<td>
Issues a I/O class command. I/O class commands are used
for determining where all log output should be sent.
Please check the list of \ref debug_ioclasses for a list
of existing I/O classes.
Each existing I/O class must accept at least the
following two commands: 'add' and 'remove'. Parameters
for these commands and additional commands are defined
on this page: \ref debug_ioclasses
If the command is entered without any parameters a list
of active I/O classes is shown. Typing 'io ?' retrieves
a list of possible I/O classes.
Example:
\code
> io
Active:
flat (flat log file)
ods (OutputDebugString)
> io ods remove
> io ?
Possible:
flat (flat/split log file)
con (console window)
ods (OutputDebugString)
net (Network destination via named pipe)
\endcode
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>alwaysflush</td>
<td valign=top>[ (+|-) ]</td>
<td>
Enables/disables flushing after each new entry in
the log file (default: off)
Example:
\code
> alwaysflush +
Flush: on
\endcode
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>timestamp</td>
<td valign=top>[ (+|-) ]</td>
<td>
Enables/disables timestamping each log entry
(default: off).
Example:
\code
> timestamp +
Timestamping: on
\endcode
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>exit</td>
<td valign=top></td>
<td>
Exits program immediately.
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>clear</td>
<td valign=top>(l|a|c)</td>
<td>
Clears the given inclusion/exclusion list
(l=logs, a=asserts/crashes, c=checks).
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>add</td>
<td valign=top>(l|a|c) (+|-) \<pattern\></td>
<td>
Adds a pattern to the given list (l=logs,
a=asserts/crashes, c=checks). By default all
asserts, crashes, and checks are active, all logs
inactive. Each item is then checked
against all pattern in the respective
list. If a match is found the active/inactive
state is modified accordingly (+ for active, -
for inactive). The final state is always
the last match.
Example:
\code
> clear l
> add l + test*
> add l - *45*
\endcode
This would now enable logging on all log groups
that start with 'test' but don't have '45' in
the group name.
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>view</td>
<td valign=top>[ (l|a|c) ]</td>
<td>
Shows the active pattern for the given list
(l=logs, a=asserts/crashes, c=checks).
</td>
<!-- keep this as template for new commands -->
</tr><tr>
<!---------------------------------->
<td valign=top></td>
<td valign=top></td>
<td>
</td>
</tr></table>
*/
/**
\addtogroup debug_stream Debug and Logging stream
The Debug class can act as an output stream for debugging and logging purposes.
This is used e.g. for displaying custom messages in a failed DASSERT_MSG statement
or for logging data.
There are a number of reasons why this module implements this in a stream-like
fashion instead of the 'usual' printf method:
- type safety: using a streams-like approach makes logging statements
type safe. No more crashes in an ASSERT or log statement because the
parameter specifiers in the printf format string didn't match with
the values actually given.
- extensibility: new stream operators can be implemented outside of the debug
module
Syntactically the Debug class acts almost like a ostream class:
\code
int n=1;
float f=4;
DLOG( "This is a static string and some other stuff: "
<< n << " " << f << "\n" );
\endcode
New types can be added easily, e.g.:
\code
struct Point2D { int x,y; };
inline Debug& operator<<(Debug& debug, const Point2D &pt)
{
debug << "(" << pt.x << ";" << pt.y << ")";
return debug;
}
void test(const Point2D &val)
{
DLOG( "Current point value is " << val << "\n" );
DASSERT_MSG( val.x>=0 && val.y>=0, val << " is invalid");
}
\endcode
Please note that all these operators should not be cluttered with any #ifdef _DEBUG
or similar conditional compile statements. It is not necessary to remove these
operators from the code in release builds (just don't forget to add 'inline' before
the operator though).
In addition there are a number of helper classes declared inside of Debug:
- Debug::MemDump provides functions for inserting a raw memory dump into the Debug stream
- Debug::HResult dumps out a HRESULT value plus additionally calling custom translator functions
*/
/**
\page debug_ioclasses Debug I/O classes
The %Debug module defines a number of pre-existing I/O classes. New classes can
be developed and added.
An I/O class can have additional commands and parameters. This section lists
the existing I/O classes and their additional commands and parameters. The
initial part of the command ('io \<class\>') is omitted here.
\section debug_ioc_flat flat (flat or split log file)
By default all data is written into a single flag log file. Optionally the
size of this log file may be limited (implemented by using a memory based
ring buffer).
<table><tr>
<td><b>I/O Command</b></td>
<td><b>Parameters</b></td>
<td><b>Description</b></td>
</tr><tr>
<!---------------------------------->
<td valign=top>add</td>
<td valign=top>[ \<filename\> [ \<size in kb\> ] ]</td>
<td>
Adds the flat I/O class. If a filename is
specified all output is written to that file.
Otherwise the filename \<exe\>-\<machinename\>.log
(resp. \<exe\>-\<machinename\>-\<splitname\>.log)
is automatically used. Any existing files with
that name are overwritten.
Instead of a real file name a 'magic' file name
can be used by starting the file name with a '*'
followed by any number of special characters:
- 'e': inserts EXE name
- 'm': inserts machine name
- 'u': inserts username
- 't': inserts timestamp
- 'n': inserts split name (empty if main log file)
- '-': inserts '-'
- 'E', 'M', 'U', 'T', 'N': same as above but with '-'
in front (for 'N': empty if main log file)
.log is automatically appended if using magic
file names.
So basically 'add' and 'and *eMN' are identical.
If a size is specified then all data is internally written
to a fixed size memory based ring buffer. This data is
flushed out once the program exits.
If no size is given then the size of the log file
is not limited and any log data is written out
immediately.
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>copy</td>
<td valign=top>\<directory\></td>
<td>
Copies generated log file(s) into the given
directory if the program exists or crashes.
If there is already a log file with the same
name a unique number is appended to the
current log files' name.
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>splitadd</td>
<td valign=top>\<types\> \<filter\> \<name\> [ \<size in kb\> ]</td>
<td>
Splits off part of the log data. Multiple
splits can be defined. They are written out
to the first matching split file.
'types' defines one or more
string types which should be split off:
- a: asserts/crashes
- c: checks
- l: logs
- h: crash
- x: exceptions
- r: replies from commands
- o: other messages
Next a filter is specified that determines
which items are to be filtered (only for string
types a, c and l). Items can be listed with
then 'list' command. The filter is exactly specified
as in that command.
The third parameter defines a name for this
split. If there is already a split with the same name
then both will write to the same destination file.
Note: If splits are used and the filename given
for 'add' is static then the split name is automatically
appended to the log file name (before the extension).
If a size is specified then all data is internally written
to a fixed size memory based ring buffer. This data is
flushed out once the program exits.
If no size is given then the size of the log file
is not limited and any log data is written out
immediately.
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>splitview</td>
<td valign=top></td>
<td>
Shows all existing splits in the order they are
evaluated.
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>splitremove</td>
<td valign=top>\<namepattern\></td>
<td>
Removes all active splits matching the given
name pattern.
</td>
<!-- keep this as template for new commands -->
</tr><tr>
<!---------------------------------->
<td valign=top></td>
<td valign=top></td>
<td>
</td>
</tr></table>
\section debug_ioc_con con (console window)
<table><tr>
<td><b>I/O Command</b></td>
<td><b>Parameters</b></td>
<td><b>Description</b></td>
</tr><tr>
<!---------------------------------->
<td valign=top>add</td>
<td valign=top>%</td>
<td>
Adds the console window as log output. A new
console window is created (if it doesn't
exist already).
</td>
<!-- keep this as template for new commands -->
</tr><tr>
<!---------------------------------->
<td valign=top></td>
<td valign=top></td>
<td>
</td>
</tr></table>
\section debug_ioc_ods ods (OutputDebugString, for use in debugger)
<table><tr>
<td><b>I/O Command</b></td>
<td><b>Parameters</b></td>
<td><b>Description</b></td>
</tr><tr>
<!---------------------------------->
<td valign=top>add</td>
<td valign=top>%</td>
<td>
%Debug output is sent via OutputDebugString.
</td>
<!-- keep this as template for new commands -->
</tr><tr>
<!---------------------------------->
<td valign=top></td>
<td valign=top></td>
<td>
</td>
</tr></table>
\section debug_ioc_net net (Network destination via named pipe)
<table><tr>
<td><b>I/O Command</b></td>
<td><b>Parameters</b></td>
<td><b>Description</b></td>
</tr><tr>
<!---------------------------------->
<td valign=top>add</td>
<td valign=top>\<name\></td>
<td>
Tells system which computer to connect to for
remote logging. By default this is the local
machine. The debug module tries to connect
to a named pipe \\\\\<name\>\\pipe\\ea_debug_v1.
<!-- sorry about all these backslashes but they're used for escaping... -->
</td>
<!-- keep this as template for new commands -->
</tr><tr>
<!---------------------------------->
<td valign=top></td>
<td valign=top></td>
<td>
</td>
</tr></table>
*/
/**
\page debug_structcmd Structured command reply
\section debug_structcmd_overview Overview
All commands are capable of returning replies in two differnt forms: A regular
reply or a structured reply.
A structured reply is basically like the regular reply but with three differences:
- Structured reply string type \ref DebugIOInterface::StructuredCmdReply
- There is a 1:1 mapping between command and result i.e. no matter how long a command
result is there will always be only one call to the \ref DebugIOInterface::Write method
for that result.
- The result format is fixed for any given command i.e. it must not change.
A structured reply is given if the command is invoked with a '!' as first character.
The motivation behind having structured command replies is to make it possible
to hide some of the debug command complexity behind a UI.
\section debug_structcmd_list List of structured command replies for debug command group
The reply for a structured command always consists of first repeating the
given command, a CR and then additional optional reply data.
<table><tr>
<td valign=top><b>Command</b></td>
<td><b>Reply</b></td>
</tr><tr>
<!---------------------------------->
<td valign=top>list</td>
<td>
\<item 1\> CR<br>
...<br>
\<item N\> CR
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>help</td>
<td>
regular reply format (unstructured)
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>io, io ?</td>
<td>
\<item 1\> CR<br>
...<br>
\<item N\> CR
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>io \<any parameters\></td>
<td>
'1' CR (if command ok) <br>
'0' \<error msg\> CR (if command failed)
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>alwaysflush</td>
<td>
'1' CR (if flush on) <br>
'0' CR (if flush off)
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>timestamp</td>
<td>
'1' CR (if timestamp on) <br>
'0' CR (if timestamp off)
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>exit</td>
<td>
none
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>clear</td>
<td>
none
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>add</td>
<td>
none
</td>
</tr><tr>
<!---------------------------------->
<td valign=top>view</td>
<td>
\<item 1\> CR<br>
...<br>
\<item N\> CR
</td>
<!-- keep this as template for new commands -->
</tr><tr>
<!---------------------------------->
<td valign=top></td>
<td>
</td>
</tr></table>
*/
#endif // DEBUG_DOC_H

View file

@ -0,0 +1,409 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_except.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Unhandled exception handler
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include <commctrl.h>
#pragma comment (lib,"comctl32")
DebugExceptionhandler::DebugExceptionhandler(void)
{
// don't do anything here!
}
const char *DebugExceptionhandler::GetExceptionType(struct _EXCEPTION_POINTERS *exptr, char *explanation)
{
#define EX(code,text) \
case EXCEPTION_##code: strcpy(explanation,text); return "EXCEPTION_" #code;
switch(exptr->ExceptionRecord->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
wsprintf(explanation,
"The thread tried to read from or write to a virtual\n"
"address for which it does not have the appropriate access.\n"
"Access address 0x%08x was %s.",
exptr->ExceptionRecord->ExceptionInformation[1],
exptr->ExceptionRecord->ExceptionInformation[0]?"written to":"read from");
return "EXCEPTION_ACCESS_VIOLATION";
EX(ARRAY_BOUNDS_EXCEEDED,"The thread tried to access an array element that\n"
"is out of bounds and the underlying hardware\n"
"supports bounds checking.")
EX(BREAKPOINT,"A breakpoint was encountered.")
EX(DATATYPE_MISALIGNMENT,"The thread tried to read or write data that is\n"
"misaligned on hardware that does not provide alignment.\n"
"For example, 16-bit values must be aligned on\n"
"2-byte boundaries; 32-bit values on 4-byte\n"
"boundaries, and so on.")
EX(FLT_DENORMAL_OPERAND,"One of the operands in a floating-point operation is\n"
"denormal. A denormal value is one that is too small\n"
"to represent as a standard floating-point value.")
EX(FLT_DIVIDE_BY_ZERO,"The thread tried to divide a floating-point\n"
"value by a floating-point divisor of zero.")
EX(FLT_INEXACT_RESULT,"The result of a floating-point operation\n"
"cannot be represented exactly as a decimal fraction.")
EX(FLT_INVALID_OPERATION,"Some strange unknown floating point operation was attempted.")
EX(FLT_OVERFLOW,"The exponent of a floating-point operation is greater\n"
"than the magnitude allowed by the corresponding type.")
EX(FLT_STACK_CHECK,"The stack overflowed or underflowed as the result\n"
"of a floating-point operation.")
EX(FLT_UNDERFLOW,"The exponent of a floating-point operation is less\n"
"than the magnitude allowed by the corresponding type.")
EX(GUARD_PAGE,"A guard page was accessed.")
EX(ILLEGAL_INSTRUCTION,"The thread tried to execute an invalid instruction.")
EX(IN_PAGE_ERROR,"The thread tried to access a page that was not\n"
"present, and the system was unable to load the page.\n"
"For example, this exception might occur if a network "
"connection is lost while running a program over the network.")
EX(INT_DIVIDE_BY_ZERO,"The thread tried to divide an integer value by\n"
"an integer divisor of zero.")
EX(INT_OVERFLOW,"The result of an integer operation caused a carry\n"
"out of the most significant bit of the result.")
EX(INVALID_DISPOSITION,"An exception handler returned an invalid disposition\n"
"to the exception dispatcher. Programmers using a\n"
"high-level language such as C should never encounter\n"
"this exception.")
EX(INVALID_HANDLE,"An invalid Windows handle was used.")
EX(NONCONTINUABLE_EXCEPTION,"The thread tried to continue execution after\n"
"a noncontinuable exception occurred.")
EX(PRIV_INSTRUCTION,"The thread tried to execute an instruction whose\n"
"operation is not allowed in the current machine mode.")
EX(SINGLE_STEP,"A trace trap or other single-instruction mechanism\n"
"signaled that one instruction has been executed.")
EX(STACK_OVERFLOW,"The thread used up its stack.")
case 0xE06D7363: strcpy(explanation,"Microsoft C++ Exception"); return "EXCEPTION_MS";
default:
wsprintf(explanation,"Unknown exception code 0x%08x",exptr->ExceptionRecord->ExceptionCode);
return "EXCEPTION_UNKNOWN";
}
#undef EX
}
void DebugExceptionhandler::LogExceptionLocation(Debug &dbg, struct _EXCEPTION_POINTERS *exptr)
{
struct _CONTEXT &ctx=*exptr->ContextRecord;
char buf[512];
DebugStackwalk::Signature::GetSymbol(ctx.Eip,buf,sizeof(buf));
dbg << "Exception occured at\n" << buf << ".";
}
void DebugExceptionhandler::LogRegisters(Debug &dbg, struct _EXCEPTION_POINTERS *exptr)
{
struct _CONTEXT &ctx=*exptr->ContextRecord;
dbg << Debug::FillChar('0')
<< Debug::Hex()
<< "EAX:" << Debug::Width(8) << ctx.Eax
<< " EBX:" << Debug::Width(8) << ctx.Ebx
<< " ECX:" << Debug::Width(8) << ctx.Ecx << "\n"
<< "EDX:" << Debug::Width(8) << ctx.Edx
<< " ESI:" << Debug::Width(8) << ctx.Esi
<< " EDI:" << Debug::Width(8) << ctx.Edi << "\n"
<< "EIP:" << Debug::Width(8) << ctx.Eip
<< " ESP:" << Debug::Width(8) << ctx.Esp
<< " EBP:" << Debug::Width(8) << ctx.Ebp << "\n"
<< "Flags:" << Debug::Bin() << Debug::Width(32) << ctx.EFlags << Debug::Hex() << "\n"
<< "CS:" << Debug::Width(4) << ctx.SegCs
<< " DS:" << Debug::Width(4) << ctx.SegDs
<< " SS:" << Debug::Width(4) << ctx.SegSs
<< "\nES:" << Debug::Width(4) << ctx.SegEs
<< " FS:" << Debug::Width(4) << ctx.SegFs
<< " GS:" << Debug::Width(4) << ctx.SegGs << "\n" << Debug::FillChar() << Debug::Dec();
}
void DebugExceptionhandler::LogFPURegisters(Debug &dbg, struct _EXCEPTION_POINTERS *exptr)
{
struct _CONTEXT &ctx=*exptr->ContextRecord;
if (!(ctx.ContextFlags&CONTEXT_FLOATING_POINT))
{
dbg << "FP registers not available\n";
return;
}
FLOATING_SAVE_AREA &flt=ctx.FloatSave;
dbg << Debug::Bin() << Debug::FillChar('0')
<< "CW:" << Debug::Width(16) << (flt.ControlWord&0xffff) << "\n"
<< "SW:" << Debug::Width(16) << (flt.StatusWord&0xffff) << "\n"
<< "TW:" << Debug::Width(16) << (flt.TagWord&0xffff) << "\n"
<< Debug::Hex()
<< "ErrOfs: " << Debug::Width(8) << flt.ErrorOffset
<< " ErrSel: " << Debug::Width(8) << flt.ErrorSelector << "\n"
<< "DataOfs: " << Debug::Width(8) << flt.DataOffset
<< " DataSel: " << Debug::Width(8) << flt.DataSelector << "\n"
<< "Cr0NpxState: " << Debug::Width(8) << flt.Cr0NpxState << "\n";
for (unsigned k=0;k<SIZE_OF_80387_REGISTERS/10;++k)
{
dbg << Debug::Dec() << "ST(" << k << ") ";
dbg.SetPrefixAndRadix("",16);
BYTE *value=flt.RegisterArea+k*10;
for (unsigned i=0;i<10;i++)
dbg << Debug::Width(2) << value[i];
double fpVal;
// convert from temporary real (10 byte) to double
_asm
{
mov eax,value
fld tbyte ptr [eax]
fstp qword ptr [fpVal]
}
dbg << " " << fpVal << "\n";
}
dbg << Debug::FillChar() << Debug::Dec();
}
// include exception dialog box
#include "rc_exception.inl"
// stupid dialog box function needs this
static struct _EXCEPTION_POINTERS *exPtrs;
// and this saves us from re-generating register/version info again...
static char regInfo[1024],verInfo[256];
// and this saves us from doing a stack walk twice
static DebugStackwalk::Signature sig;
static BOOL CALLBACK ExceptionDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
break;
case WM_COMMAND:
if (LOWORD(wParam)==IDOK)
EndDialog(hWnd,IDOK);
default:
return FALSE;
}
// init dialog box
// version
SendDlgItemMessage(hWnd,103,WM_SETTEXT,0,(LPARAM)verInfo);
// registers
char *p=regInfo;
for (char *q=p;;q++)
{
if (!*q||*q=='\n')
{
bool quit=!*q; *q=0;
SendDlgItemMessage(hWnd,105,LB_ADDSTRING,0,(LPARAM)p);
if (quit)
break;
p=q+1;
}
}
// yes, this generates a GDI leak but we're crashing anyway
SendDlgItemMessage(hWnd,105,WM_SETFONT,(WPARAM)CreateFont(13,0,0,0,FW_NORMAL,
FALSE,FALSE,FALSE,ANSI_CHARSET,
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,FIXED_PITCH|FF_MODERN,NULL),MAKELPARAM(TRUE,0));
// exception type
SendDlgItemMessage(hWnd,100,WM_SETTEXT,0,(LPARAM)
DebugExceptionhandler::GetExceptionType(exPtrs,regInfo));
SendDlgItemMessage(hWnd,101,WM_SETTEXT,0,(LPARAM)regInfo);
// address
struct _CONTEXT &ctx=*exPtrs->ContextRecord;
DebugStackwalk::Signature::GetSymbol(ctx.Eip,regInfo,sizeof(regInfo));
SendDlgItemMessage(hWnd,102,WM_SETTEXT,0,(LPARAM)regInfo);
// stack
// (this code is a little messy because we're dealing with a raw list control)
HWND list;
list=GetDlgItem(hWnd,104);
if (!sig.Size())
{
LVCOLUMN c;
c.mask=LVCF_TEXT|LVCF_WIDTH;
c.pszText="";
c.cx=690;
ListView_InsertColumn(list,0,&c);
LVITEM item;
item.iItem=0;
item.iSubItem=0;
item.mask=LVIF_TEXT;
item.pszText="No stack data available - check for dbghelp.dll";
item.iItem=ListView_InsertItem(list,&item);
}
else
{
// add columns first
LVCOLUMN c;
c.mask=LVCF_TEXT|LVCF_WIDTH;
c.pszText="";
c.cx=0; // first column is empty (can't right-align 1st column)
ListView_InsertColumn(list,0,&c);
c.mask=LVCF_TEXT|LVCF_WIDTH|LVCF_FMT;
c.pszText="Address";
c.cx=60;
c.fmt=LVCFMT_RIGHT;
ListView_InsertColumn(list,1,&c);
c.mask=LVCF_TEXT|LVCF_WIDTH;
c.pszText="Module";
c.cx=120;
ListView_InsertColumn(list,2,&c);
c.pszText="Symbol";
c.cx=300;
ListView_InsertColumn(list,3,&c);
c.pszText="File";
c.cx=130;
ListView_InsertColumn(list,4,&c);
c.pszText="Line";
c.cx=80;
ListView_InsertColumn(list,5,&c);
// now add stack walk lines
for (unsigned k=0;k<sig.Size();k++)
{
DebugStackwalk::Signature::GetSymbol(sig.GetAddress(k),regInfo,sizeof(regInfo));
LVITEM item;
item.iItem=k;
item.iSubItem=0;
item.mask=0;
item.iItem=ListView_InsertItem(list,&item);
item.mask=LVIF_TEXT;
item.iSubItem++;
item.pszText=strtok(regInfo," ");
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText=strtok(NULL,",");
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText=strtok(NULL,",");
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText=strtok(NULL,":");
ListView_SetItem(list,&item);
item.iSubItem++;
item.pszText=strtok(NULL,"");
ListView_SetItem(list,&item);
}
}
return TRUE;
}
#include <stdio.h>
LONG __stdcall DebugExceptionhandler::ExceptionFilter(struct _EXCEPTION_POINTERS* pExPtrs)
{
// we should not be calling ourselves!
static bool inExceptionFilter;
if (inExceptionFilter)
{
MessageBox(NULL,"Exception in exception handler","Fatal error",MB_OK);
return EXCEPTION_CONTINUE_SEARCH;
}
inExceptionFilter=true;
if (pExPtrs->ExceptionRecord->ExceptionCode==EXCEPTION_STACK_OVERFLOW)
{
// almost everything we are about to do will generate a second
// stack overflow... double fault... so give at least a little warning
OutputDebugString("EA/DEBUG: EXCEPTION_STACK_OVERFLOW\n");
}
// Let's log some info
Debug &dbg=Debug::Instance;
// we're logging an exception
++dbg.disableAssertsEtc;
if (dbg.curType!=DebugIOInterface::StringType::MAX)
dbg.FlushOutput();
dbg.StartOutput(DebugIOInterface::StringType::Exception,"");
// start off with the exception type & location
dbg << "\n" << Debug::RepeatChar('=',80) << "\n";
dbg << GetExceptionType(pExPtrs,regInfo) << ":\n" << regInfo << "\n\n";
LogExceptionLocation(dbg,pExPtrs); dbg << "\n\n";
// build info must be saved off for dialog...
unsigned curOfs=dbg.ioBuffer[DebugIOInterface::Exception].used;
dbg.WriteBuildInfo();
unsigned len=dbg.ioBuffer[DebugIOInterface::Exception].used-curOfs;
if (len>=sizeof(verInfo))
len=sizeof(verInfo)-1;
memcpy(verInfo,dbg.ioBuffer[DebugIOInterface::Exception].buffer+curOfs,len);
verInfo[len]=0;
dbg << "\n\n";
// save off register info as well...
curOfs=dbg.ioBuffer[DebugIOInterface::Exception].used;
LogRegisters(dbg,pExPtrs); dbg << "\n";
LogFPURegisters(dbg,pExPtrs); dbg << "\n";
len=dbg.ioBuffer[DebugIOInterface::Exception].used-curOfs;
if (len>=sizeof(regInfo))
len=sizeof(regInfo)-1;
memcpy(regInfo,dbg.ioBuffer[DebugIOInterface::Exception].buffer+curOfs,len);
regInfo[len]=0;
// now finally add stack & EIP dump
dbg.m_stackWalk.StackWalk(sig,pExPtrs->ContextRecord);
dbg << sig << "\n";
dbg << "Bytes around EIP:" << Debug::MemDump::Char(((char *)(pExPtrs->ContextRecord->Eip))-32,80);
dbg.FlushOutput();
// shut down real Debug module now
// (atexit code never gets called in exception case)
Debug::StaticExit();
// Show a dialog box
InitCommonControls();
exPtrs=pExPtrs;
DialogBoxIndirect(NULL,(LPDLGTEMPLATE)rcException,NULL,ExceptionDlgProc);
// Now die
return EXCEPTION_EXECUTE_HANDLER;
}

View file

@ -0,0 +1,36 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_getdefaultcommands.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// DebugGetDefaultCommands function
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
// this function has its own file so that it can be 'overridden'
// by another program using the Debug module
const char *DebugGetDefaultCommands(void)
{
return "!debug.io flat add";
}

View file

@ -0,0 +1,86 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_internal.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Implementation of internal code
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
void DebugInternalAssert(const char *file, int line, const char *expr)
{
// dangerous as well but since this function is used in this
// module only we know how long stuff can get
char buf[512];
wsprintf(buf,"File %s, line %i:\n%s",file,line,expr);
MessageBox(NULL,buf,"Internal assert failed",
MB_OK|MB_ICONSTOP|MB_TASKMODAL|MB_SETFOREGROUND);
// stop right now!
TerminateProcess(GetCurrentProcess(),666);
}
void *DebugAllocMemory(unsigned numBytes)
{
HGLOBAL h=GlobalAlloc(GMEM_FIXED,numBytes);
if (!h)
DCRASH_RELEASE("Debug mem alloc failed");
return (void *)h;
}
void *DebugReAllocMemory(void *oldPtr, unsigned newSize)
{
// Windows doesn't like ReAlloc with NULL handle/ptr...
if (!oldPtr)
return newSize?DebugAllocMemory(newSize):0;
// Shrinking to 0 size is basically freeing memory
if (!newSize)
{
GlobalFree((HGLOBAL)oldPtr);
return 0;
}
// now try GlobalReAlloc first
HGLOBAL h=GlobalReAlloc((HGLOBAL)oldPtr,newSize,0);
if (!h)
{
// this failed (Windows doesn't like ReAlloc'ing larger
// fixed memory blocks) - go with Alloc/Free instead
h=GlobalAlloc(GMEM_FIXED,newSize);
if (!h)
DCRASH_RELEASE("Debug mem realloc failed");
unsigned oldSize=GlobalSize((HGLOBAL)oldPtr);
memcpy((void *)h,oldPtr,oldSize<newSize?oldSize:newSize);
GlobalFree((HGLOBAL)oldPtr);
}
return (void *)h;
}
void DebugFreeMemory(void *ptr)
{
if (ptr)
GlobalFree((HGLOBAL)ptr);
}

View file

@ -0,0 +1,202 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_io.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug I/O interface
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef DEBUG_IO_H // Include guard
#define DEBUG_IO_H
/**
\interface DebugIOInterface debug.h <rts/debug.h>
\brief Debug I/O interface.
A Debug I/O interface implementation must register itself
using Debug::AddIOFactory. Typically this is done
by using the \ref DEBUG_DECLARE_IO_INTERFACE and
\ref DEBUG_IMPLEMENT_IO_INTERFACE macros (recommended, but
not mandatory.)
*/
class DebugIOInterface
{
// no copy/assign op
DebugIOInterface(const &DebugIOInterface);
DebugIOInterface& operator=(const DebugIOInterface&);
protected:
/**
\brief I/O class destructor.
The destructor must always be protected. Destruction is
done by calling the Delete member function.
*/
virtual ~DebugIOInterface() {}
public:
// interface only so no functionality here
explicit DebugIOInterface(void) {}
/// List of possible log string types
enum StringType
{
/// DASSERT etc
Assert = 0,
/// DCHECK etc
Check,
/// DLOG etc
Log,
/// DCRASH etc
Crash,
/// Exception
Exception,
/// Regular command reply
CmdReply,
/// Structured command reply, see \ref debug_structcmd
StructuredCmdReply,
/// some other message
Other,
MAX
};
/**
\brief Retrieves up to the given number of characters from a command input source.
This source can be e.g. keyboard or a network pipe. This function must
not block.
\param buf buffer to place read characters in
\param maxchar maximum number of characters to return
\return numbers of characters written to buffer
\note There is no terminating NUL char written to the buffer
*/
virtual int Read(char *buf, int maxchar)=0;
/**
\brief Write out some characters differentiated by the log string type.
\param type possible string type
\param src string source, may be NULL, content depends on type:
<table><tr>
<td><b>type</b></td><td><b>src</b></td></tr><tr>
<td>Assert</td><td>file(line)</td></tr><tr>
<td>Check</td><td>file(line)</td></tr><tr>
<td>Log</td><td>log group</td></tr><tr>
<td>Crash</td><td>file(line)</td></tr><tr>
<td>Exception</td><td>NULL</td></tr><tr>
<td>CmdReply</td><td>group.command</td></tr><tr>
<td>StructuredCmdReply</td><td>group.command</td></tr><tr>
<td>Other</td><td>NULL</td>
</tr></table>
\param str string to output, NUL delimited, if NULL then simply flush
output (if applicable)
*/
virtual void Write(StringType type, const char *src, const char *str)=0;
/**
\brief Emergency shutdown function.
This function gets called during an exception and should perform the
absolute bare minimum (e.g. just flushing and closing the output file).
*/
virtual void EmergencyFlush(void)=0;
/**
\brief I/O class specific command.
All io \<class\> commands are passed into this function, with the
exception of remove which results in simply calling the class
destructor.
\param dbg debug instance
\param cmd command issued
\param structuredCmd true if structured command reply, false if not
\param argn number of additional arguments passed in
\param argv argument list
*/
virtual void Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv)=0;
/**
\brief Destroys the current I/O class instance.
Use this function instead of just delete'ing the instance.
*/
virtual void Delete(void)=0;
};
/**
\addtogroup debug_io_macros Debug I/O interface helper macros
*/
///@{
#ifdef DOXYGEN
/**
\brief Helper macro used in I/O class declaration to declare
a factory function.
\param type type name of class we're implementing
\note This macro changes the access method to private.
*/
#define DEBUG_DECLARE_IO_INTERFACE(type)
/**
\brief Helper macro for registering I/O class factory with
the Debug module.
\param io_id name of I/O class as it should be registered with Debug module
(without quotes)
\param descr short I/O class description
\param type type name of class we're implementing
*/
#define DEBUG_IMPLEMENT_IO_INTERFACE(io_id,descr,type)
#else
#define DEBUG_DECLARE_IO_INTERFACE(type) \
public: \
static bool __RegisterClassFactory; \
static DebugIOInterface *__ClassFactory(void) { return new type; }
#define DEBUG_IMPLEMENT_IO_INTERFACE(io_id,descr,type) \
static bool type::__RegisterClassFactory=Debug::AddIOFactory(#io_id,descr,type::__ClassFactory);
#endif
///@}
#endif // DEBUG_IO_H

View file

@ -0,0 +1,230 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_io_con.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug I/O class con (console window)
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include <stdlib.h>
#include <new> // needed for placement new prototype
DebugIOCon::DebugIOCon(void):
m_inputUsed(0), m_inputRead(0)
{
// check: is there already a console window open?
m_allocatedConsole=AllocConsole()!=0;
if (m_allocatedConsole)
{
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(h,0);
// make screen buffer same size as currently displayed area
// (prevents that our input line gets scrolled out of view)
h=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(h,&info);
COORD newSize;
newSize.X=info.srWindow.Right+1;
newSize.Y=info.srWindow.Bottom+1;
SetConsoleScreenBufferSize(h,newSize);
// hide cursor
CONSOLE_CURSOR_INFO ci;
ci.dwSize=1;
ci.bVisible=FALSE;
SetConsoleCursorInfo(h,&ci);
Write(StringType::Other,NULL,"\n\nEA/Debug console open\n\n");
}
}
DebugIOCon::~DebugIOCon()
{
// close console if we allocated it
if (m_allocatedConsole)
FreeConsole();
}
int DebugIOCon::Read(char *buf, int maxchar)
{
// We are not supporting reading from the console
// unless we allocated that console ourselves.
// The reason for that is that if we didn't allocate
// the console ourselves we're running as a console
// process and if we'd be reading data from the console
// we would probably be snatching away keyboard data
// for the process that is using that console.
if (!m_allocatedConsole)
return 0;
// are we doing a continuous read?
if (m_inputRead)
{
int numRead;
if (maxchar>m_inputUsed-m_inputRead)
{
// return all
numRead=m_inputUsed-m_inputRead;
memcpy(buf,m_input+m_inputRead,numRead);
m_inputRead=m_inputUsed=0;
}
else
{
// return partially
numRead=maxchar;
memcpy(buf,m_input+m_inputRead,numRead);
m_inputRead+=maxchar;
}
return numRead;
}
// update our input buffer
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
bool returnChars=false;
for (;;)
{
DWORD dwRecords;
if (!GetNumberOfConsoleInputEvents(h,&dwRecords))
break;
if (!dwRecords)
break;
INPUT_RECORD record;
ReadConsoleInput(h,&record,1,&dwRecords);
if (record.EventType!=KEY_EVENT)
continue;
KEY_EVENT_RECORD &key=record.Event.KeyEvent;
if (!key.bKeyDown||!key.uChar.AsciiChar)
continue;
if (key.uChar.AsciiChar=='\r'||
key.uChar.AsciiChar=='\n')
{
m_input[m_inputUsed++]='\n';
returnChars=true;
break;
}
/// @todo_opt if somebody wants this can be improved by adding support for cursor keys, history, etc
if (key.uChar.AsciiChar=='\b')
{
if (m_inputUsed)
m_inputUsed--;
}
else if (((unsigned char)key.uChar.AsciiChar)>=' ')
{
if (m_inputUsed<sizeof(m_input)-1)
m_input[m_inputUsed++]=key.uChar.AsciiChar;
}
}
// update screen
h=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(h,&info);
CHAR_INFO ci[sizeof(m_input)+1];
for (unsigned k=0;k<=sizeof(m_input);k++)
{
ci[k].Char.AsciiChar=k<m_inputUsed?m_input[k]:' ';
ci[k].Attributes=BACKGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_GREEN
|FOREGROUND_RED|FOREGROUND_INTENSITY;
}
// fake another cursor
if (GetTickCount()&512)
ci[m_inputUsed].Attributes=BACKGROUND_BLUE|BACKGROUND_GREEN
|BACKGROUND_RED|BACKGROUND_INTENSITY|FOREGROUND_GREEN;
COORD srcSize,srcCoord;
srcSize.X=sizeof(m_input); srcSize.Y=1;
srcCoord.X=srcCoord.Y=0;
SMALL_RECT r;
r.Left=r.Top=r.Bottom=0; r.Right=info.dwSize.X-1;
WriteConsoleOutput(h,ci+(m_inputUsed<=info.dwSize.X?0:m_inputUsed-info.dwSize.X),
srcSize,srcCoord,&r);
// return data now?
if (returnChars&&m_inputUsed>1)
{
*buf=*m_input;
m_inputRead=1;
return 1;
}
return 0;
}
void DebugIOCon::Write(StringType type, const char *src, const char *str)
{
if (type==StringType::StructuredCmdReply||!str)
return;
DWORD dwDummy;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),str,strlen(str),&dwDummy,NULL);
}
void DebugIOCon::Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv)
{
if (!cmd||!strcmp(cmd,"help"))
{
dbg << "con I/O help:\n"
" add [ <width> [ <height> ] ]\n"
" create con I/O (optionally specifying the window size)\n";
}
else if (!strcmp(cmd,"add"))
{
if (argn>0&&m_allocatedConsole)
{
// resize our console area
HANDLE h=GetStdHandle(STD_OUTPUT_HANDLE);
COORD newSize;
newSize.X=atoi(argv[0]);
newSize.Y=argn>1?atoi(argv[1]):25;
SMALL_RECT sr;
sr.Left=sr.Top=0;
sr.Right=newSize.X-1;
sr.Bottom=newSize.Y-1;
SetConsoleWindowInfo(h,TRUE,&sr);
SetConsoleScreenBufferSize(h,newSize);
SetConsoleWindowInfo(h,TRUE,&sr);
}
}
}
DebugIOInterface *DebugIOCon::Create(void)
{
return new (DebugAllocMemory(sizeof(DebugIOCon))) DebugIOCon();
}
void DebugIOCon::Delete(void)
{
this->~DebugIOCon();
DebugFreeMemory(this);
}

View file

@ -0,0 +1,546 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_io_flat.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug I/O class flat (flat or split log file)
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include <stdlib.h>
#include <new> // needed for placement new prototype
DebugIOFlat::OutputStream::OutputStream(const char *filename, unsigned maxSize):
m_bufferUsed(0), m_nextChar(0)
{
m_fileName=(char *)DebugAllocMemory(strlen(filename)+1);
strcpy(m_fileName,filename);
m_limitedFileSize=maxSize>0;
m_bufferSize=m_limitedFileSize?maxSize:0x10000;
m_buffer=(char *)DebugAllocMemory(m_bufferSize);
if (!m_limitedFileSize)
m_fileHandle=CreateFile(m_fileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
NULL);
}
DebugIOFlat::OutputStream::~OutputStream()
{
}
DebugIOFlat::OutputStream *DebugIOFlat::OutputStream::Create(const char *filename, unsigned maxSize)
{
return new (DebugAllocMemory(sizeof(OutputStream))) OutputStream(filename,maxSize);
}
void DebugIOFlat::OutputStream::Delete(const char *path)
{
Flush();
if (!m_limitedFileSize)
CloseHandle(m_fileHandle);
if (path&&*path)
{
// copy file to given path
int run=-1;
char *ext=strrchr(m_fileName,'.');
if (!ext)
ext=m_fileName+strlen(m_fileName);
char *fileNameOnly=strrchr(m_fileName,'\\');
fileNameOnly=fileNameOnly?fileNameOnly+1:m_fileName;
unsigned pathLen=strlen(path);
for (;;)
{
// absolute path?
char help[512];
if (path[0]&&(path[1]==':'||(path[0]=='\\'&&path[1]=='\\')))
{
strcpy(help,path);
strcpy(help+pathLen,fileNameOnly);
help[ext-fileNameOnly+pathLen]=0;
}
else
{
// no, relative path given
strcpy(help,m_fileName);
strcpy(help+(fileNameOnly-m_fileName),path);
strcpy(help+(fileNameOnly-m_fileName)+pathLen,fileNameOnly);
help[ext-fileNameOnly+pathLen+(fileNameOnly-m_fileName)]=0;
}
if (++run)
wsprintf(help+strlen(help),"(%i)%s",run,ext);
else
strcat(help,ext);
if (CopyFile(m_fileName,help,TRUE))
break;
if (GetLastError()!=ERROR_FILE_EXISTS)
break;
}
}
DebugFreeMemory(m_buffer);
DebugFreeMemory(m_fileName);
this->~OutputStream();
DebugFreeMemory(this);
}
void DebugIOFlat::OutputStream::Write(const char *src)
{
if (!src)
{
// flush request, flush only if unlimited file size
if (!m_limitedFileSize)
Flush();
}
else
{
unsigned len=strlen(src);
while (len>m_bufferSize)
{
InternalWrite(src,m_bufferSize);
src+=m_bufferSize;
len-=m_bufferSize;
}
InternalWrite(src,len);
}
}
void DebugIOFlat::OutputStream::InternalWrite(const char *src, unsigned len)
{
__ASSERT(len<=m_bufferSize);
// unlimited log file length?
if (!m_limitedFileSize)
{
if (m_bufferUsed+len>m_bufferSize)
Flush();
memcpy(m_buffer+m_bufferUsed,src,len);
m_bufferUsed+=len;
}
else
{
// just write to ring buffer
if ((m_bufferUsed+=len)>m_bufferSize)
m_bufferUsed=m_bufferSize;
while (len)
{
unsigned toWrite;
if (m_nextChar+len>m_bufferSize)
toWrite=m_bufferSize-m_nextChar;
else
toWrite=len;
memcpy(m_buffer+m_nextChar,src,toWrite);
if ((m_nextChar+=toWrite)>=m_bufferSize)
m_nextChar=0;
src+=toWrite;
len-=toWrite;
}
}
}
void DebugIOFlat::OutputStream::Flush(void)
{
if (!m_limitedFileSize)
{
// simple flush to file
DWORD written;
WriteFile(m_fileHandle,m_buffer,m_bufferUsed,&written,NULL);
m_bufferUsed=0;
}
else
{
// create file, write ring buffer
m_fileHandle=CreateFile(m_fileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
NULL);
DWORD written;
if (m_bufferUsed<m_bufferSize)
WriteFile(m_fileHandle,m_buffer,m_bufferUsed,&written,NULL);
else
{
WriteFile(m_fileHandle,m_buffer+m_nextChar,m_bufferUsed-m_nextChar,&written,NULL);
WriteFile(m_fileHandle,m_buffer,m_nextChar,&written,NULL);
}
CloseHandle(m_fileHandle);
}
}
//////////////////////////////////////////////////////////////////////////////
void DebugIOFlat::ExpandMagic(const char *src, const char *splitName, char *buf)
{
// barf if too long
if (strlen(src)>250)
src="*eMN";
// non-magic name?
if (*src!='*')
{
// just return input name
if (splitName)
{
// must jam in split name before extension
const char *p=strrchr(src,'.');
if (!p)
p=src+strlen(src);
strncpy(buf,src,p-src);
buf[p-src]='-';
strcpy(buf+(p-src)+1,splitName);
strcat(buf,p);
}
else
strcpy(buf,src);
return;
}
// translate magic name
src++;
char *dst=buf;
while (*src)
{
if (dst-buf>250)
break;
if (*src>='A'&&*src<='Z'&&(*src!='N'||splitName))
*dst++='-';
char help[256];
DWORD size=sizeof(help);
*help=0;
switch(*src++)
{
case 'e':
case 'E':
GetModuleFileName(NULL,help,sizeof(help));
break;
case 'm':
case 'M':
GetComputerName(help,&size);
break;
case 'u':
case 'U':
GetUserName(help,&size);
break;
case 't':
case 'T':
{
SYSTEMTIME systime;
GetLocalTime(&systime);
wsprintf(help,"%04i%02i%02i-%02i%02i-%02i",
systime.wYear,systime.wMonth,systime.wDay,
systime.wHour,systime.wMinute,systime.wSecond);
}
break;
case 'n':
case 'N':
if (splitName&&strlen(splitName)<250)
strcpy(help,splitName);
break;
default:
*dst++=src[-1];
}
unsigned len=strlen(help);
if (dst-buf+len>250)
break;
strcpy(dst,help);
dst+=len;
}
strcpy(dst,".log");
}
DebugIOFlat::DebugIOFlat(void):
m_firstStream(NULL), m_firstSplit(NULL),
m_lastStreamPtr(&m_firstStream), m_lastSplitPtr(&m_firstSplit)
{
*m_copyDir=0;
}
DebugIOFlat::~DebugIOFlat()
{
for (SplitListEntry *cur=m_firstSplit;cur;)
{
SplitListEntry *kill=cur;
cur=cur->next;
DebugFreeMemory(kill);
}
m_firstSplit=NULL;
for (StreamListEntry *stream=m_firstStream;stream;)
{
StreamListEntry *kill=stream;
stream=stream->next;
kill->stream->Delete(m_copyDir);
DebugFreeMemory(kill);
}
}
void DebugIOFlat::Write(StringType type, const char *src, const char *str)
{
for (SplitListEntry *cur=m_firstSplit;cur;cur=cur->next)
{
if (!(cur->stringTypes&(1<<type)))
continue;
if (src&&*src&&!Debug::SimpleMatch(src,cur->items))
continue;
cur->stream->Write(str);
break;
}
if (!cur)
m_firstStream->stream->Write(str);
}
void DebugIOFlat::EmergencyFlush(void)
{
for (StreamListEntry *cur=m_firstStream;cur;cur=cur->next)
cur->stream->Flush();
}
void DebugIOFlat::Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv)
{
if (!cmd||!strcmp(cmd,"help"))
{
if (!argn)
dbg << "flat I/O help:\n"
"The following I/O commands are defined:\n"
" add, copy, splitadd, splitview, splitremove\n"
"Type in debug.io flat help <cmd> for a detailed command help.\n";
else if (!strcmp(argv[0],"add"))
dbg <<
"add [ <filename> [ <size in kb> ] ]\n\n"
"Create flat file I/O (optionally specifying file name and file size).\n"
"If a filename is specified all output is written to that file. Otherwise\n"
"the magic filename '*eMN' is automatically used. Any existing files with\n"
"that name are overwritten.\n"
"\n"
"Instead of a real file name a 'magic' file name can be used by starting\n"
"the file name with a '*' followed by any number of special characters:\n"
"- 'e': inserts EXE name\n"
"- 'm': inserts machine name\n"
"- 'u': inserts username\n"
"- 't': inserts timestamp\n"
"- 'n': inserts split name (empty if main log file)\n"
"- '-': inserts '-'\n"
"- 'E', 'M', 'U', 'T', 'N': same as above but with '-' in front \n"
" (for 'N': empty if main log file)\n"
".log is automatically appended if using magic file names.\n"
"\n"
"If a size is specified then all data is internally written to a fixed \n"
"size memory based ring buffer. This data is flushed out once the \n"
"program exits. If no size is given then the size of the log file is not \n"
"limited and any log data is written out immediately.\n";
else if (!strcmp(argv[0],"copy"))
dbg <<
"copy <directory>\n\n"
"Copies generated log file(s) into the given directory if the program\n"
"exists or crashes. If there is already a log file with the same\n"
"name a unique number is appended to the current log files' name.\n";
else if (!strcmp(argv[0],"splitadd"))
dbg <<
"splitadd <types> <filter> <name> [ <size in kb> ]\n\n"
"Splits off part of the log data. Multiple splits can be defined. They \n"
"are written out to the first matching split file.\n"
"\n"
"'types' defines one or more string types which should be split off:\n"
"- a: asserts\n"
"- c: checks\n"
"- l: logs\n"
"- h: crash\n"
"- x: exceptions\n"
"- r: replies from commands\n"
"- o: other messages \n"
"\n"
"Next a filter is specified that determines which items are to be \n"
"filtered (only for string types a, c and l). Items can be listed with\n"
"then 'list' command. The filter is exactly specified as in that command.\n"
"\n"
"The third parameter defines a name for this split. If there is \n"
"already a split with the same name then both will write to the same \n"
"destination file.\n"
"\n"
"Note: If splits are used and the filename given for 'add' is static \n"
"or does not contain 'n' or 'N' then the split name is automatically \n"
"appended to the log file name (before the extension).\n"
"\n"
"If a size is specified then all data is internally written to a \n"
"fixed size memory based ring buffer. This data is flushed out once \n"
"the program exits.\n"
"\n"
"If no size is given then the size of the log file is not limited and \n"
"any log data is written out immediately.\n";
else if (!strcmp(argv[0],"splitview"))
dbg << "splitview\n\n"
"Shows all existing splits in the order they are evaluated.";
else if (!strcmp(argv[0],"splitremove"))
dbg << "splitremove <namepattern>\n\n"
"Removes all active splits matching the given name pattern.";
else
dbg << "Unknown flat I/O command";
}
else if (!strcmp(cmd,"add"))
{
// add [ <filename> [ <size in kb> ] ]
__ASSERT(m_firstStream==NULL);
strcpy(m_baseFilename,argn?argv[0]:"*eMN");
char fn[256];
ExpandMagic(m_baseFilename,NULL,fn);
m_firstStream=(StreamListEntry *)DebugAllocMemory(sizeof(StreamListEntry));
m_firstStream->next=NULL;
m_firstStream->stream=OutputStream::Create(fn,argn>1?atoi(argv[1])*1024:0);
m_lastStreamPtr=&m_firstStream->next;
}
else if (!strcmp(cmd,"copy"))
{
// copy <directory>
if (argn)
{
strncpy(m_copyDir,argv[0],sizeof(m_copyDir)-1);
m_copyDir[sizeof(m_copyDir)-1]=0;
}
}
else if (!strcmp(cmd,"splitadd"))
{
// splitadd <types> <filter> <name> [ <size in kb> ]
if (argn>=3)
{
// add entry
SplitListEntry *cur=(SplitListEntry *)DebugAllocMemory(sizeof(SplitListEntry));
cur->next=*m_lastSplitPtr;
m_lastSplitPtr=&cur->next;
if (!m_firstSplit)
m_firstSplit=cur;
cur->stringTypes=0;
for (const char *p=argv[0];*p;++p)
{
switch(*p)
{
case 'a': cur->stringTypes|=1<<Assert; break;
case 'c': cur->stringTypes|=1<<Check; break;
case 'l': cur->stringTypes|=1<<Log; break;
case 'h': cur->stringTypes|=1<<Crash; break;
case 'x': cur->stringTypes|=1<<Exception; break;
case 'r': cur->stringTypes|=1<<CmdReply; break;
case 'o': cur->stringTypes|=1<<Other; break;
}
}
if (!cur->stringTypes)
cur->stringTypes=0xffffffff;
strncpy(cur->items,argv[1],sizeof(cur->items)-1);
cur->items[sizeof(cur->items)-1]=0;
strncpy(cur->name,argv[2],sizeof(cur->name)-1);
cur->name[sizeof(cur->name)-1]=0;
// create our filename, search for stream with same filename
char fn[256];
ExpandMagic(m_baseFilename,cur->name,fn);
for (StreamListEntry *stream=m_firstStream;stream;stream=stream->next)
if (!strcmp(stream->stream->GetFilename(),fn))
break;
if (!stream)
{
// must create new stream
stream=(StreamListEntry *)DebugAllocMemory(sizeof(StreamListEntry));
stream->next=NULL;
*m_lastStreamPtr=stream;
m_lastStreamPtr=&stream->next;
stream->stream=OutputStream::Create(fn,argn>3?atoi(argv[3])*1024:0);
}
cur->stream=stream->stream;
}
}
else if (!strcmp(cmd,"splitview"))
{
// splitview
for (SplitListEntry *cur=m_firstSplit;cur;cur=cur->next)
{
for (StringType t=Assert;t<MAX;t=(StringType)(t+1))
{
if (t==StructuredCmdReply||!(cur->stringTypes&(1<<t)))
continue;
switch(t)
{
case Assert: dbg << "a"; break;
case Check: dbg << "c"; break;
case Log: dbg << "l"; break;
case Crash: dbg << "h"; break;
case Exception: dbg << "x"; break;
case CmdReply: dbg << "r"; break;
case Other: dbg << "o"; break;
}
}
dbg << " " << cur->items << " " << cur->name << "\n";
}
}
else if (!strcmp(cmd,"splitremove"))
{
// splitremove <namepattern>
const char *pattern=argn<1?"*":argv[0];
for (SplitListEntry **entryPtr=&m_firstSplit;*entryPtr;)
{
if ( Debug::SimpleMatch((*entryPtr)->name,pattern) )
{
// remove this entry
SplitListEntry *cur=*entryPtr;
*entryPtr=cur->next;
DebugFreeMemory(cur);
}
else
entryPtr=&((*entryPtr)->next);
}
// must fixup m_lastSplitPtr now
if (m_firstSplit)
{
for (SplitListEntry *cur=m_firstSplit;cur->next;cur=cur->next);
m_firstSplit=cur;
}
else
m_firstSplit=NULL;
}
}
DebugIOInterface *DebugIOFlat::Create(void)
{
return new (DebugAllocMemory(sizeof(DebugIOFlat))) DebugIOFlat();
}
void DebugIOFlat::Delete(void)
{
this->~DebugIOFlat();
DebugFreeMemory(this);
}

View file

@ -0,0 +1,128 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_io_net.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug I/O class net (Network destination via named pipe)
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include <new> // needed for placement new prototype
DebugIONet::DebugIONet(void)
{
}
DebugIONet::~DebugIONet()
{
if (m_pipe!=INVALID_HANDLE_VALUE)
CloseHandle(m_pipe);
}
int DebugIONet::Read(char *buf, int maxchar)
{
if (m_pipe==INVALID_HANDLE_VALUE)
return 0;
DWORD mode=PIPE_READMODE_MESSAGE|PIPE_NOWAIT;
SetNamedPipeHandleState(m_pipe,&mode,NULL,NULL);
DWORD read;
if (!ReadFile(m_pipe,buf,maxchar-1,&read,NULL))
read=0;
mode=PIPE_READMODE_MESSAGE|PIPE_WAIT;
SetNamedPipeHandleState(m_pipe,&mode,NULL,NULL);
return read;
}
void DebugIONet::Write(StringType type, const char *src, const char *str)
{
if (m_pipe==INVALID_HANDLE_VALUE)
return;
DWORD dummy;
WriteFile(m_pipe,&type,1,&dummy,NULL);
unsigned len;
len=src?strlen(src):0;
WriteFile(m_pipe,&len,4,&dummy,NULL);
if (len)
WriteFile(m_pipe,src,len,&dummy,NULL);
len=strlen(str);
WriteFile(m_pipe,&len,4,&dummy,NULL);
if (len)
WriteFile(m_pipe,str,len,&dummy,NULL);
}
void DebugIONet::EmergencyFlush(void)
{
}
void DebugIONet::Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv)
{
if (!cmd||!strcmp(cmd,"help"))
{
dbg << "net I/O help:\n"
" add [ <machine> ]\n"
" create net I/O (optionally specifying the machine to connect to)\n";
}
else if (!strcmp(cmd,"add"))
{
const char *machine=argn?argv[0]:".";
char buf[256];
wsprintf(buf,"\\\\%s\\pipe\\ea_debug_v1",machine);
m_pipe=CreateFile(buf,GENERIC_READ|GENERIC_WRITE,
0,NULL,OPEN_EXISTING,0,NULL);
if (m_pipe==INVALID_HANDLE_VALUE)
{
dbg << "Could not connect to given machine.\n";
return;
}
// we're reading messages
DWORD mode=PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(m_pipe,&mode,NULL,NULL);
// write welcome message
char comp[128];
mode=sizeof(comp);
GetComputerName(comp,&mode);
wsprintf(buf,"Client at %s\n",comp);
Write(Other,NULL,buf);
}
}
DebugIOInterface *DebugIONet::Create(void)
{
return new (DebugAllocMemory(sizeof(DebugIONet))) DebugIONet();
}
void DebugIONet::Delete(void)
{
this->~DebugIONet();
DebugFreeMemory(this);
}

View file

@ -0,0 +1,47 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_io_ods.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug I/O class ods (OutputDebugString, for use in debugger)
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include <new> // needed for placement new prototype
void DebugIOOds::Write(StringType type, const char *src, const char *str)
{
if (type!=StringType::StructuredCmdReply&&str)
OutputDebugString(str);
}
DebugIOInterface *DebugIOOds::Create(void)
{
return new (DebugAllocMemory(sizeof(DebugIOOds))) DebugIOOds();
}
void DebugIOOds::Delete(void)
{
this->~DebugIOOds();
DebugFreeMemory(this);
}

View file

@ -0,0 +1,394 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_macro.h $
// $Author: mhoffe $
// $Revision: #2 $
// $DateTime: 2003/07/09 10:57:23 $
//
// ©2003 Electronic Arts
//
// Debugging macros
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef DEBUG_MACRO_H // Include guard
#define DEBUG_MACRO_H
// I'm putting the documentation for the following macros
// here because Doxygen otherwise includes the values of each macro
// in the documentation. I don't want that (it would expose some
// internals) so I'm putting all comments for the following macros
// here...
#ifdef DOXYGEN // defined if Doxygen is running
/**
\addtogroup debug_macros Debugging and logging macros
This module defines a number of macros. Usually only these macros should be
used to access any debug functionality.
All these macros are defined if either _DEBUG or _INTERNAL is defined. Otherwise
all of them (with the exception of DCHECK and DCHECK_MSG) will be removed.
*/
///@{
/**
\brief Regular assert macro.
This macro will generate an error message on screen if the evaluated expression
returns false. The user will then have the choice of aborting the program,
continuing once or continuing with completely ignoring that specific assertion.
Assertions are completely removed if neither _DEBUG nor _INTERNAL are defined.
\param expr expression, trigger assert window if false
*/
#define DASSERT(expr)
/**
\brief Assert macro with custom message.
Like \ref DASSERT but a custom message will be given in addition to the expression.
The message can be specified in a stream-like notation, e.g.
\code
DASSERT_MSG( n>=0 && n<MAX_N, "n:" << n << ", max " << MAX_N);
\endcode
For more information see the \ref debug_stream page.
Assertions are completely removed if neither _DEBUG nor _INTERNAL are defined.
\param expr expression, trigger assert window if false
\param msg custom message stream, see \ref debug_stream
*/
#define DASSERT_MSG(expr,msg)
/**
\brief Compile time assertion.
This assertion will fail during compile time. It can be used anywhere and will
(of course) remain in release compiles as well. No code is generated in any case.
If a compile time assertion fails the compiler will give an error message like
this:
\code
debug.cpp(14) : error C2027: use of undefined type 'StaticAssertionFailed<0>'
\endcode
If the expression given can't be evaluated at compile time the error message
looks like this:
\code
debug.cpp(15) : error C2027: use of undefined type 'StaticAssertionFailed< ?? >'
\endcode
\param expr expression which can be evaluated at compile time
*/
#define DCTASSERT(expr)
/**
\brief Function macro, checks if the given expression is true, returns false if not.
Additionally a message is written to the log file. This macro is usually used
like this:
\code
if ( !DCHECK( n>=0 && n<MAX_N ) ) return;
\endcode
\note Checks will remain in place even in release builds!
\param expr expression which will always be checked
*/
#define DCHECK(expr)
/**
\brief Function macro, \ref DCHECK with additional message on failure.
For more information see the \ref debug_stream page.
\note Even though the expression check will remain in place in release builds the
\a msg part is completely removed.
\param expr expression which will always be checked
\param msg custom message stream, see \ref debug_stream
*/
#define DCHECK_MSG(expr,msg)
/**
\brief Macro for precondition-checks.
Internally expands to
\code
if (!DCHECK(!(cond)))
\endcode
so it can be used e.g. like this:
\code
DFAIL_IF(!ptrval) return;
\endcode
\param cond condition which is checked for failure
*/
#define DFAIL_IF(cond)
/**
\brief Convenience macro, \ref DFAIL_IF with additional message on failure.
Internally expands to
\code
if (!DCHECK_MSG(!(cond),msg))
\endcode
so it can be used e.g. like this:
\code
DFAIL_IF_MSG(!ptrval,"pointer must not be NULL") return;
\endcode
\param cond condition which is checked for failure
\param msg custom message stream, see \ref debug_stream
*/
#define DFAIL_IF_MSG(cond,msg)
/**
\brief Writes a message to the log file.
It also generates a logging group with the name of the current file (but without
path or extension), e.g. if DLOG("hello world") is written in here a logging group
called 'debug' would be created.
Logs can be turned on and off based on individual logging groups.
\param what message, see \ref debug_stream
*/
#define DLOG(what)
/**
\brief Adds a description for the current file if used for logging.
\note This macro must be used in a CPP file in file scope only.
\param descr a short static description of what gets logged in the current file
*/
#define DLOG_DESCR(descr)
/**
\brief Writes a message to the log file using a custom log group.
Works just like \ref DLOG but instead of using the current file as a logging group
the logging group is explicitly specified.
\note Specifiy the group directly without quotes, e.g.
\code
DLOG_GROUP(my_log_group,"hello world")
\endcode
\param group logging group, without quotes
\param what message, see \ref debug_stream
*/
#define DLOG_GROUP(group,what)
/**
\brief Adds a description for a custom log group
\note This macro must be used in a CPP file in file scope only.
\param group logging group, without quotes
\param descr a short static description of what gets logged in the specified log group
*/
#define DLOG_GROUP_DESCR(group,descr)
/**
\brief Unconditionally aborts the program in debug/internal builds.
A DCRASH can not be disabled by the user.
\param msg custom message stream, see \ref debug_stream
*/
#define DCRASH(msg)
/**
\brief Unconditional program exit that is active in release builds as well.
\note In a release build the crash message will not include the file name or
line number where the DCRASH_RELEASE was specified.
\param msg custom message stream, see \ref debug_stream
*/
#define DCRASH_RELEASE(msg)
/**
\brief Unconditional assert.
Basically makes sense only as default clause in switch statements to make
sure that no case is missed, e.g.
\code
switch(n)
{
case MY_DEF_VAL_A:
// ...
break;
case MY_DEF_VAL_B:
// ...
break;
default:
DFAIL();
}
\endcode
Gets removed in release builds.
*/
#define DFAIL()
/**
\brief Function macro, determines if logging is active for current file or not.
This function macro can be safely used without any #ifdefs:
\code
if (D_ISLOG())
{
// do some computationally expensive logging here...
}
\endcode
In release builds this macro expands to \a false effectively removing
the whole section.
\return true if logging is active, false if not
*/
#define D_ISLOG()
/**
\brief Function macro, determines if logging is active for the specified log group or not.
Works just like \ref D_ISLOG but instead of using the current file as a logging group
the logging group is explicitly specified.
\param group logging group, without quotes
\return true if logging is active, false if not
*/
#define D_ISLOG_GROUP(group)
///@}
#elif defined(_DEBUG) || defined(_INTERNAL)
#define DASSERT(expr) \
((void)( Debug::SkipNext() || \
(expr) || \
Debug::AssertBegin(__FILE__,__LINE__,#expr).AssertDone() ))
#define DASSERT_MSG(expr,msg) \
((void)( Debug::SkipNext() || \
(expr) || \
( Debug::AssertBegin(__FILE__,__LINE__,#expr) << ": " << msg ).AssertDone() ))
#define DCHECK(expr) \
( (expr) || \
Debug::SkipNext() || \
Debug::CheckBegin(__FILE__,__LINE__,#expr).CheckDone() )
#define DCHECK_MSG(expr,msg) \
( (expr) || \
Debug::SkipNext() || \
( Debug::CheckBegin(__FILE__,__LINE__,#expr) << ": " << msg ).CheckDone() )
#define DFAIL_IF(cond) \
if (!DCHECK(!(cond)))
#define DFAIL_IF_MSG(cond,msg) \
if (!DCHECK_MSG(!(cond),msg))
#define DLOG(what) \
((void)( Debug::SkipNext() || \
( Debug::LogBegin(__FILE__) << what ).LogDone() ))
#define DLOG_DESCR(descr) \
static Debug::LogDescription _LogDescr_FILE(__FILE__,descr);
#define DLOG_GROUP(group,what) \
((void)( Debug::SkipNext() || \
( Debug::LogBegin(#group) << what ).LogDone() ))
#define DLOG_GROUP_DESCR(group,descr) \
static Debug::LogDescription(#group,descr) _LogDescr_Grp_##group
#define DCRASH(msg) \
(Debug::SkipNext() || (Debug::CrashBegin(__FILE__,__LINE__) << msg).CrashDone(false))
#define DCRASH_RELEASE(msg) \
(Debug::SkipNext(),(Debug::CrashBegin(__FILE__,__LINE__) << msg).CrashDone(true))
#define DFAIL() \
Debug::AssertBegin(__FILE__,__LINE__,NULL).AssertDone()
#define D_ISLOG() \
Debug::IsLogEnabled(__FILE__)
#define D_ISLOG_GROUP(group) \
Debug::IsLogEnabled(#group)
#else
#define DASSERT(expr) ((void)0)
#define DASSERT_MSG(expr,msg) ((void)0)
#define DCHECK(expr) (expr)
#define DCHECK_MSG(expr,msg) (expr)
#define DFAIL_IF(cond) if (cond)
#define DFAIL_IF_MSG(cond,msg) if (cond)
#define DLOG(what) ((void)0)
#define DLOG_DESCR(descr)
#define DLOG_GROUP(group,what) ((void)0)
#define DLOG_GROUP_DESCR(g,d)
#define DCRASH(msg) ((void)0)
#define DCRASH_RELEASE(msg) (Debug::SkipNext(),(Debug::CrashBegin(NULL,0) << msg).CrashDone(true))
#define DFAIL() ((void)0)
#define D_ISLOG() false
#define D_ISLOG_GROUP(group) false
#endif
// put these helper templates in a namespace...
namespace _Debug
{
template<bool> struct StaticAssertionFailed;
template<> struct StaticAssertionFailed<true> {};
template<int x> struct StaticAssertionTest {};
#define DCTASSERT(expr) typedef ::_Debug::StaticAssertionTest< \
sizeof(::_Debug::StaticAssertionFailed< (bool)(expr) >) \
> DebugStaticAssertTypedef__;
};
// These are stolen from the WW3D Debug file. REALLY useful. :-)
#define STRING_IT(a) #a
#define TOKEN_IT(a) STRING_IT(,##a)
/**
The macro MESSAGE allows user to put:
\code
#pragma MESSAGE("Hello world")
\endcode
anywhere in a source file. The message:
\code
sourcefname.cpp (123) : Hello world
\endcode
would be printed if put in sourcefname.cpp on line 123 in compile window like an error.
You can then use next/prev error hot keys to see where comment is. It is not an error and
will be printed everytime it is compiled. Very useful to put comments in code that cannot
be forgotten.
*/
#define MESSAGE(a) message (__FILE__ "(" TOKEN_IT(__LINE__) ") : " a)
#endif // DEBUG_MACRO_H

View file

@ -0,0 +1,36 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_purecall.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Replacement for MSVCRT _purecall
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
// Pure virtual function called
int __cdecl _purecall(void)
{
DCRASH_RELEASE("Pure virtual function called.");
return 0;
}

View file

@ -0,0 +1,391 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_stack.cpp $
// $Author: KMorness $
// $Revision: #2 $
// $DateTime: 2005/01/19 15:02:33 $
//
// ©2003 Electronic Arts
//
// Stack walker
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include "dbghelp.h"
// Definitions to allow run-time linking to the dbghelp.dll functions.
#define DBGHELP(name,ret,par) typedef ret (WINAPI *name##Type) par;
#include "debug_stack.inl"
#undef DBGHELP
#define DBGHELP(name,ret,par) name##Type _##name;
static union
{
struct
{
#include "debug_stack.inl"
};
unsigned funcPtr[1];
} gDbg;
#undef DBGHELP
#define DBGHELP(name,ret,par) #name,
static char const *DebughelpFunctionNames[] =
{
#include "debug_stack.inl"
NULL
};
#undef DBGHELP
// local dbghelp.dll module handle
static HMODULE g_dbghelp;
// local flag that is true if we're using an old dbghelp.dll version
static bool g_oldDbghelp;
static void InitDbghelp(void)
{
// already called?
if (g_dbghelp)
return;
// firstly check for dbghelp.dll in the EXE directory
char dbgHelpPath[256];
if (GetModuleFileName(NULL,dbgHelpPath,sizeof(dbgHelpPath)))
{
char *slash=strrchr(dbgHelpPath,'\\');
if (slash)
{
strcpy(slash+1,"DBGHELP.DLL");
g_dbghelp=::LoadLibrary(dbgHelpPath);
}
}
if (!g_dbghelp)
// load any version we can
g_dbghelp=::LoadLibrary("DBGHELP.DLL");
if (!g_dbghelp)
return;
// Get function addresses
unsigned *funcptr=gDbg.funcPtr;
for (unsigned k=0;DebughelpFunctionNames[k];++k,++funcptr)
{
*funcptr=(unsigned)GetProcAddress(g_dbghelp,DebughelpFunctionNames[k]);
if (!*funcptr)
break;
}
if (DebughelpFunctionNames[k])
{
// not all functions found -> clear them all
while (funcptr!=gDbg.funcPtr)
*--funcptr=NULL;
}
else
{
// Set options
gDbg._SymSetOptions(gDbg._SymGetOptions()|SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES);
// Init module
gDbg._SymInitialize((HANDLE)GetCurrentProcessId(),NULL,TRUE);
// Check: are we using a newer version of dbghelp.dll?
// (older versions have some serious issues.. err... bugs)
if (!GetProcAddress(g_dbghelp,"SymEnumSymbolsForAddr"))
g_oldDbghelp=true;
}
}
//////////////////////////////////////////////////////////////////////////////
DebugStackwalk::Signature::Signature(const Signature &src)
{
*this=src;
}
DebugStackwalk::Signature& DebugStackwalk::Signature::operator=(const Signature& src)
{
if (&src!=this)
{
m_numAddr=src.m_numAddr;
memcpy(m_addr,src.m_addr,m_numAddr*sizeof(*m_addr));
}
return *this;
}
unsigned DebugStackwalk::Signature::GetAddress(int n) const
{
DFAIL_IF_MSG(n<0||n>=MAX_ADDR,n << "/" << MAX_ADDR) return 0;
return m_addr[n];
}
void DebugStackwalk::Signature::GetSymbol(unsigned addr, char *buf, unsigned bufSize)
{
DFAIL_IF(!buf) return;
DFAIL_IF(bufSize<64||bufSize>=0x80000000) return;
InitDbghelp();
char *bufEnd=buf+bufSize;
*buf=0;
buf+=wsprintf(buf,"%08x",addr);
// determine module
unsigned modBase=gDbg._SymGetModuleBase((HANDLE)GetCurrentProcessId(),addr);
if (!modBase)
{
strcpy(buf," (unknown module)");
return;
}
// illegal code ptr?
if (IsBadReadPtr((void *)addr,4)||IsBadCodePtr((FARPROC)addr))
{
strcpy(buf," (invalid code addr)");
return;
}
char symbolBuffer[512];
GetModuleFileName((HMODULE)modBase,symbolBuffer,sizeof(symbolBuffer));
char *p=strrchr(symbolBuffer,'\\'); // use filename only, strip off path
p=p?p+1:symbolBuffer;
*buf++=' ';
strcpy(buf,p);
buf+=strlen(buf);
if (bufEnd-buf<32)
return;
buf+=wsprintf(buf,"+0x%x",addr-modBase);
// determine symbol
PIMAGEHLP_SYMBOL symPtr=(PIMAGEHLP_SYMBOL)symbolBuffer;
memset(symPtr,0,sizeof(symbolBuffer));
symPtr->SizeOfStruct=sizeof(IMAGEHLP_SYMBOL);
symPtr->MaxNameLength=sizeof(symbolBuffer)-sizeof(IMAGEHLP_SYMBOL);
DWORD displacement;
if (!gDbg._SymGetSymFromAddr((HANDLE)GetCurrentProcessId(),addr,&displacement,symPtr))
return;
if ((unsigned int)(bufEnd-buf)<strlen(symPtr->Name)+16)
return;
buf+=wsprintf(buf,", %s+0x%x",symPtr->Name,displacement);
// and line number
IMAGEHLP_LINE line;
memset(&line,0,sizeof(line));
line.SizeOfStruct=sizeof(line);
if (!gDbg._SymGetLineFromAddr((HANDLE)GetCurrentProcessId(),addr,&displacement,&line))
return;
p=strrchr(line.FileName,'\\'); // use filename only, strip off path
p=p?p+1:line.FileName;
if ((unsigned int)(bufEnd-buf)<strlen(p)+16)
return;
buf+=wsprintf(buf,", %s:%i+0x%x",p,line.LineNumber,displacement);
}
void DebugStackwalk::Signature::GetSymbol(unsigned addr,
char *bufMod, unsigned sizeMod, unsigned *relMod,
char *bufSym, unsigned sizeSym, unsigned *relSym,
char *bufFile, unsigned sizeFile, unsigned *linePtr, unsigned *relLine)
{
InitDbghelp();
if (bufMod) *bufMod=0;
if (relMod) *relMod=0;
if (bufSym) *bufSym=0;
if (relSym) *relSym=0;
if (bufFile) *bufFile=0;
if (linePtr) *linePtr=0;
if (relLine) *relLine=0;
DFAIL_IF(bufMod&&sizeMod<16) return;
DFAIL_IF(bufSym&&sizeSym<16) return;
DFAIL_IF(bufFile&&sizeFile<16) return;
// determine module
unsigned modBase=gDbg._SymGetModuleBase((HANDLE)GetCurrentProcessId(),addr);
if (!modBase)
{
if (bufMod)
strcpy(bufMod,"(unknown mod)");
if (bufSym)
strcpy(bufSym,"(unknown)");
return;
}
// illegal code ptr?
if (IsBadReadPtr((void *)addr,4)||IsBadCodePtr((FARPROC)addr))
{
if (bufMod)
strcpy(bufMod,"(inv code addr)");
if (bufSym)
strcpy(bufSym,"(unknown)");
return;
}
char symbolBuffer[512];
if (bufMod)
{
GetModuleFileName((HMODULE)modBase,symbolBuffer,sizeof(symbolBuffer));
char *p=strrchr(symbolBuffer,'\\'); // use filename only, strip off path
p=p?p+1:symbolBuffer;
strncpy(bufMod,p,sizeMod);
bufMod[sizeMod-1]=0;
}
if (relMod)
*relMod=addr-modBase;
// determine symbol
if (bufSym)
{
PIMAGEHLP_SYMBOL symPtr=(PIMAGEHLP_SYMBOL)symbolBuffer;
memset(symPtr,0,sizeof(symbolBuffer));
symPtr->SizeOfStruct=sizeof(IMAGEHLP_SYMBOL);
symPtr->MaxNameLength=sizeof(symbolBuffer)-sizeof(IMAGEHLP_SYMBOL);
DWORD displacement;
if (gDbg._SymGetSymFromAddr((HANDLE)GetCurrentProcessId(),addr,&displacement,symPtr))
{
strncpy(bufSym,symPtr->Name,sizeSym);
bufSym[sizeSym-1]=0;
if (relSym)
*relSym=displacement;
}
else
strcpy(bufSym,"(unknown)");
}
// and line number
if (bufFile)
{
IMAGEHLP_LINE line;
memset(&line,0,sizeof(line));
line.SizeOfStruct=sizeof(line);
DWORD displacement;
if (!gDbg._SymGetLineFromAddr((HANDLE)GetCurrentProcessId(),addr,&displacement,&line))
strcpy(bufFile,"(unknown)");
else
{
char *p=strrchr(line.FileName,'\\'); // use filename only, strip off path
p=p?p+1:line.FileName;
strncpy(bufFile,p,sizeFile);
bufFile[sizeFile-1]=0;
if (linePtr)
*linePtr=line.LineNumber;
if (relLine)
*relLine=displacement;
}
}
}
Debug& operator<<(Debug &dbg, const DebugStackwalk::Signature &sig)
{
dbg << sig.Size() << " addresses:\n";
for (unsigned k=0;k<sig.Size();k++)
{
char buf[512];
sig.GetSymbol(sig.GetAddress(k),buf,sizeof(buf));
dbg << buf << "\n";
}
return dbg;
}
//////////////////////////////////////////////////////////////////////////////
DebugStackwalk::DebugStackwalk(void)
{
// it doesn't harm to do this here
InitDbghelp();
}
DebugStackwalk::~DebugStackwalk()
{
}
void *DebugStackwalk::GetDbghelpHandle(void)
{
return g_dbghelp;
}
bool DebugStackwalk::IsOldDbghelp(void)
{
return g_oldDbghelp;
}
int DebugStackwalk::StackWalk(Signature &sig, struct _CONTEXT *ctx)
{
InitDbghelp();
sig.m_numAddr=0;
// bail out if no stack walk available
if (!gDbg._StackWalk)
return 0;
// Set up the stack frame structure for the start point of the stack walk (i.e. here).
STACKFRAME stackFrame;
memset(&stackFrame,0,sizeof(stackFrame));
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrStack.Mode = AddrModeFlat;
stackFrame.AddrFrame.Mode = AddrModeFlat;
// Use the context struct if it was provided.
if (ctx)
{
stackFrame.AddrPC.Offset = ctx->Eip;
stackFrame.AddrStack.Offset = ctx->Esp;
stackFrame.AddrFrame.Offset = ctx->Ebp;
}
else
{
// walk stack back using current call chain
unsigned long reg_eip, reg_ebp, reg_esp;
__asm
{
here:
lea eax,here
mov reg_eip,eax
mov reg_ebp,ebp
mov reg_esp,esp
};
stackFrame.AddrPC.Offset = reg_eip;
stackFrame.AddrStack.Offset = reg_esp;
stackFrame.AddrFrame.Offset = reg_ebp;
}
// Walk the stack by the requested number of return address iterations.
bool skipFirst=!ctx;
while (sig.m_numAddr<Signature::MAX_ADDR&&
gDbg._StackWalk(IMAGE_FILE_MACHINE_I386,GetCurrentProcess(),GetCurrentThread(),
&stackFrame,NULL,NULL,gDbg._SymFunctionTableAccess,gDbg._SymGetModuleBase,NULL))
{
if (skipFirst)
skipFirst=false;
else
sig.m_addr[sig.m_numAddr++]=stackFrame.AddrPC.Offset;
}
return sig.m_numAddr;
}

View file

@ -0,0 +1,172 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_stack.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Stack walker
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef DEBUG_STACK_H // Include guard
#define DEBUG_STACK_H
/// \brief stack walker class (singleton)
class DebugStackwalk
{
friend class Debug;
DebugStackwalk(const DebugStackwalk&);
DebugStackwalk& operator=(DebugStackwalk&);
// private so that only Debug can create and destroy us
DebugStackwalk(void);
~DebugStackwalk();
public:
/// \brief a stack trace signature
class Signature
{
// makes life easier :)
friend class DebugStackwalk;
/// max # of possible addresses
enum { MAX_ADDR = 256 };
/// number of addresses
unsigned m_numAddr;
/// addresses
unsigned m_addr[MAX_ADDR];
public:
explicit Signature(void): m_numAddr(0) {}
Signature(const Signature &src);
Signature& operator=(const Signature& src);
/**
\brief Determine the number of addresses in this signature.
\return number of addresses in this signature
*/
unsigned Size(void) const { return m_numAddr; }
/**
\brief Get a single address from the signature.
The address at index 0 is always on top of the stack.
\param n index, 0..Size()-1
\return signature address
*/
unsigned GetAddress(int n) const;
/**
\brief Strong ordering operator.
Signatures are ordered by looking at the bottom of the stack
first. Implemented inline so that STL algorithms using this
operator can be compiled more efficiently.
*/
bool operator<(const Signature &other) const
{
unsigned m=m_numAddr<other.m_numAddr?m_numAddr:other.m_numAddr;
for (unsigned k=0;k<m;k++)
{
if (m_addr[m_numAddr-k-1]<other.m_addr[other.m_numAddr-k-1])
return true;
if (m_addr[m_numAddr-k-1]>other.m_addr[other.m_numAddr-k-1])
return false;
}
return m_numAddr<other.m_numAddr;
}
/**
\brief Determines symbol for given address.
The data is returned in the form
\<addr\> \<module\>+NN, \<sym\>+NN, \<file\>:\<line\>+NN
\param addr function address
\param buf return buffer
\param bufSize size of return buffer, minimum is 64 bytes (256 recommended)
*/
static void GetSymbol(unsigned addr, char *buf, unsigned bufSize);
/**
\brief Determines symbol for given address.
\param addr function address
\param bufMod module buffer, may be NULL
\param sizeMod size of buffer, including NUL, minimum 16 if given
\param relMod relative address within module, may be NULL
\param bufSym symbol buffer, may be NULL
\param sizeSym size of buffer, including NUL
\param relSym relative address within symbol, may be NULL
\param bufFile file name buffer, may be NULL
\param sizeFile size of buffer, including NUL
\param line line number, may be NULL
\param relLine relative address within line, may be NULL
*/
static void GetSymbol(unsigned addr,
char *bufMod, unsigned sizeMod, unsigned *relMod,
char *bufSym, unsigned sizeSym, unsigned *relSym,
char *bufFile, unsigned sizeFile, unsigned *line, unsigned *relLine);
};
/** \internal
\brief Returns dbghelp.dll DLL handle.
\return dbghelp.dll DLL handle
*/
static void *GetDbghelpHandle(void);
/** \internal
\brief Checks if dbghelp.dll version is old.
\return true if old version, false if not
*/
static bool IsOldDbghelp(void);
/**
\brief Walks the stack from the given address.
\param sig stack signature to return
\param ctx processor context, if NULL then use current address
\return number of addresses found
*/
static int StackWalk(Signature &sig, struct _CONTEXT *ctx=0);
};
/**
\brief Dumps a complete signature with symbols.
\param dbg debug instance
\param sig signature
\return debug instance
*/
Debug& operator<<(Debug &dbg, const DebugStackwalk::Signature &sig);
#endif // DEBUG_STACK_H

View file

@ -0,0 +1,63 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
// Used for dynamically linking to dbghelp.dll functions.
// keep this always as first entry
DBGHELP(SymInitialize,
BOOL,
(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess))
DBGHELP(SymGetOptions,
DWORD,
(void))
DBGHELP(SymSetOptions,
DWORD,
(DWORD SymOptions))
DBGHELP(StackWalk,
BOOL,
(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame,
LPVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE TranslateAddress))
DBGHELP(SymFunctionTableAccess,
LPVOID,
(HANDLE hProcess, DWORD AddrBase))
DBGHELP(SymGetModuleBase,
DWORD,
(HANDLE hProcess, DWORD dwAddr))
DBGHELP(SymGetSymFromAddr,
BOOL,
(HANDLE hProcess, DWORD Address, LPDWORD Displacement,
PIMAGEHLP_SYMBOL Symbol))
DBGHELP(SymGetLineFromAddr,
BOOL,
(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement,
PIMAGEHLP_LINE Line))
// keep this always as last entry
DBGHELP(SymCleanup,
BOOL,
(HANDLE hProcess))

View file

@ -0,0 +1,101 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/internal.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Internal header
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef INTERNAL_H // Include guard
#define INTERNAL_H
// make sure we're not omitting the frame pointer
#pragma optimize("y",off)
// We're doing our own little internal asserts for full debug
// builds (until this library is proven & stable)
#ifdef _DEBUG
# define __ASSERT(x) do { if (!(x)) DebugInternalAssert(__FILE__,__LINE__,#x); } while (0)
#else
# define __ASSERT(x) do { } while(0)
#endif
/** \internal
Internal assert function for module internal assertions.
\param file file name
\param line line number
\param expr expression which failed
*/
void DebugInternalAssert(const char *file, int line, const char *expr);
/** \internal
Allocate the given number of bytes from the Windows heap.
This function performs a controlled crash on failure.
\param numBytes number of bytes to allocate
\return pointer to allocated memory
*/
void *DebugAllocMemory(unsigned numBytes);
/** \internal
Allocates/reallocates the given memory block to the new
given size.
This function performs a controlled crash on failure.
\param oldPtr pointer to old memory block, may be NULL
\param newSize new size of block
\return pointer to reallocated memory
*/
void *DebugReAllocMemory(void *oldPtr, unsigned newSize);
/** \internal
Frees the allocated memory block.
This function never fails.
\param ptr memory block to free
*/
void DebugFreeMemory(void *ptr);
/// \internal Command group: 'debug'
class DebugCmdInterfaceDebug: public DebugCmdInterface
{
public:
virtual bool Execute(class Debug& dbg, const char *cmd, CommandMode cmdmode,
unsigned argn, const char * const * argv);
virtual void Delete(void)
{
this->~DebugCmdInterfaceDebug();
DebugFreeMemory(this);
}
};
#endif // INTERNAL_H

View file

@ -0,0 +1,90 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/internal_except.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Unhandled exception handler
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef INTERNAL_EXCEPT_H // Include guard
#define INTERNAL_EXCEPT_H
/// \internal exception handler
class DebugExceptionhandler
{
DebugExceptionhandler(const DebugExceptionhandler&);
DebugExceptionhandler& operator=(const DebugExceptionhandler&);
// nobody can instantiate us
DebugExceptionhandler(void);
/** \internal
\brief Log exception location.
\param dbg debug instance
\param exptr exception pointers
*/
static void LogExceptionLocation(Debug &dbg, struct _EXCEPTION_POINTERS *exptr);
/** \internal
\brief Log regular registers.
\param dbg debug instance
\param exptr exception pointers
*/
static void LogRegisters(Debug &dbg, struct _EXCEPTION_POINTERS *exptr);
/** \internal
\brief Log FPU registers.
\param dbg debug instance
\param exptr exception pointers
*/
static void LogFPURegisters(Debug &dbg, struct _EXCEPTION_POINTERS *exptr);
public:
/** \internal
\brief Determine exception type.
\param exptr exception pointers
\param explanation exception explanation, buffer must be 512 chars
\return exception type as string
*/
static const char *GetExceptionType(struct _EXCEPTION_POINTERS *exptr, char *explanation);
/** \internal
\brief System exception filter
*/
static long __stdcall ExceptionFilter(struct _EXCEPTION_POINTERS* pExPtrs);
};
#endif // INTERNAL_EXCEPT_H

View file

@ -0,0 +1,256 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/internal_io.h $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Internal header: I/O classes
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma once
#endif
#ifndef INTERNAL_IO_H // Include guard
#define INTERNAL_IO_H
/// \internal \brief con debug I/O class
class DebugIOCon: public DebugIOInterface
{
/**
true if we allocated the console, false if there has already
been a console
*/
bool m_allocatedConsole;
/**
internal input buffer
*/
char m_input[256];
/**
number of bytes in input buffer
*/
unsigned m_inputUsed;
/**
Current read position. This variable is 0 while data is
composed into m_input and >0 while multiple Read calls are
received.
*/
unsigned m_inputRead;
public:
explicit DebugIOCon(void);
virtual ~DebugIOCon();
virtual int Read(char *buf, int maxchar);
virtual void Write(StringType type, const char *src, const char *str);
virtual void EmergencyFlush(void) {}
virtual void Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv);
static DebugIOInterface *Create(void);
virtual void Delete(void);
};
/// \internal \brief con flat I/O class
class DebugIOFlat: public DebugIOInterface
{
/// \brief single output stream
class OutputStream
{
OutputStream(const OutputStream&);
OutputStream& operator=(const OutputStream&);
/// output file name (dynamically allocated)
char *m_fileName;
/// output file handle (only if unlimited output buffer size)
HANDLE m_fileHandle;
/// file size limited?
bool m_limitedFileSize;
/// output buffer
char *m_buffer;
/// number of bytes in buffer
unsigned m_bufferUsed;
/// size of buffer (if m_limitedFileSize then m_bufferSize==m_maxSize)
unsigned m_bufferSize;
/// position of next free char in ring buffer (used if m_limitedFileSize)
unsigned m_nextChar;
// these are private so that we are forced to use Create/Destroy
OutputStream(const char *filename, unsigned maxSize);
~OutputStream();
/**
\brief Writes some data to output stream.
\param src string to write
\param len number of bytes to write
*/
void InternalWrite(const char *src, unsigned len);
public:
/**
\brief Creates a new output stream instance.
\param filename name of output file (will be overwritten if it exists)
\param maxSize maximum size of output file, unlimited if 0
*/
static OutputStream *Create(const char *filename, unsigned maxSize);
/**
\brief Destroys this object.
If a path is given the file is copied to that path as well. If there
is already a file with that name in the destination directory the
current file is copied under a new unique name.
\param path optional path to a destination directory
*/
void Delete(const char *path=NULL);
/**
\brief Determines name of output stream.
\return name of output stream
*/
const char *GetFilename(void) { return m_fileName; }
/**
\brief Writes data to the output stream.
\param src NUL delimited string to write
*/
void Write(const char *src);
/**
\brief Flushes all buffered data.
*/
void Flush(void);
};
/// \brief a single split structure
struct SplitListEntry
{
/// next split
SplitListEntry *next;
/// for which string types?
unsigned stringTypes;
/// for which items?
char items[256];
/// split name
char name[256];
/// into which stream? (note: pointer not owned by this!)
OutputStream *stream;
};
/// \brief List of output streams
struct StreamListEntry
{
/// next entry
StreamListEntry *next;
/// which stream?
OutputStream *stream;
};
/// first split
SplitListEntry *m_firstSplit;
/// end of split list pointer
SplitListEntry **m_lastSplitPtr;
/// first output stream (first is always the default output stream)
StreamListEntry *m_firstStream;
/// end of stream list pointer
StreamListEntry **m_lastStreamPtr;
/// base filename
char m_baseFilename[256];
/// copy location
char m_copyDir[256];
/**
\brief Expands a magic filename into a real filename.
\param src magic filename or real filename
\param splitName split name, NULL for default stream
\param buf output buffer, must have a size of at least 256 char's
*/
static void ExpandMagic(const char *src, const char *splitName, char *buf);
public:
explicit DebugIOFlat(void);
virtual ~DebugIOFlat();
virtual int Read(char *buf, int maxchar) { return 0; }
virtual void Write(StringType type, const char *src, const char *str);
virtual void EmergencyFlush(void);
virtual void Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv);
static DebugIOInterface *Create(void);
virtual void Delete(void);
};
/// \internal \brief net debug I/O class
class DebugIONet: public DebugIOInterface
{
/// our pipe handle
HANDLE m_pipe;
public:
explicit DebugIONet(void);
virtual ~DebugIONet();
virtual int Read(char *buf, int maxchar);
virtual void Write(StringType type, const char *src, const char *str);
virtual void EmergencyFlush(void);
virtual void Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv);
static DebugIOInterface *Create(void);
virtual void Delete(void);
};
/// \internal \brief ods debug I/O class
class DebugIOOds: public DebugIOInterface
{
public:
explicit DebugIOOds(void) {}
virtual int Read(char *buf, int maxchar) { return 0; }
virtual void Write(StringType type, const char *src, const char *str);
virtual void EmergencyFlush(void) {}
virtual void Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv) {}
static DebugIOInterface *Create(void);
virtual void Delete(void);
};
#endif // INTERNAL_IO_H

View file

@ -0,0 +1,328 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/netserv/netserv.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Simple console based server for NET I/O connections
//////////////////////////////////////////////////////////////////////////////
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <malloc.h>
// Note: This implementation is quick'n'ugly. I've developed this
// program basically just for testing the net I/O class.
static char m_input[256];
static unsigned m_inputUsed;
static void InitConsole(void)
{
AllocConsole();
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(h,0);
// make screen buffer same size as currently displayed area
// (prevents that our input line gets scrolled out of view)
h=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(h,&info);
COORD newSize;
newSize.X=info.srWindow.Right+1;
newSize.Y=info.srWindow.Bottom+1;
SetConsoleScreenBufferSize(h,newSize);
// hide cursor
CONSOLE_CURSOR_INFO ci;
ci.dwSize=1;
ci.bVisible=FALSE;
SetConsoleCursorInfo(h,&ci);
}
static char *InputConsole(void)
{
// update our input buffer
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
bool returnChars=false;
for (;;)
{
DWORD dwRecords;
if (!GetNumberOfConsoleInputEvents(h,&dwRecords))
break;
if (!dwRecords)
break;
INPUT_RECORD record;
ReadConsoleInput(h,&record,1,&dwRecords);
if (record.EventType!=KEY_EVENT)
continue;
KEY_EVENT_RECORD &key=record.Event.KeyEvent;
if (!key.bKeyDown||!key.uChar.AsciiChar)
continue;
if (key.uChar.AsciiChar=='\r'||
key.uChar.AsciiChar=='\n')
{
m_input[m_inputUsed++]='\n';
returnChars=true;
break;
}
/// @todo_opt if somebody wants this can be improved by adding support for cursor keys, history, etc
if (key.uChar.AsciiChar=='\b')
{
if (m_inputUsed)
m_inputUsed--;
}
else if (((unsigned char)key.uChar.AsciiChar)>=' ')
{
if (m_inputUsed<sizeof(m_input)-1)
m_input[m_inputUsed++]=key.uChar.AsciiChar;
}
}
// update screen
h=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(h,&info);
CHAR_INFO ci[sizeof(m_input)+1];
for (unsigned k=0;k<=sizeof(m_input);k++)
{
ci[k].Char.AsciiChar=k<m_inputUsed?m_input[k]:' ';
ci[k].Attributes=BACKGROUND_BLUE|FOREGROUND_BLUE|FOREGROUND_GREEN
|FOREGROUND_RED|FOREGROUND_INTENSITY;
}
// fake another cursor
if (GetTickCount()&512)
ci[m_inputUsed].Attributes=BACKGROUND_BLUE|BACKGROUND_GREEN
|BACKGROUND_RED|BACKGROUND_INTENSITY|FOREGROUND_BLUE;
COORD srcSize,srcCoord;
srcSize.X=sizeof(m_input); srcSize.Y=1;
srcCoord.X=srcCoord.Y=0;
SMALL_RECT r;
r.Left=r.Top=r.Bottom=0; r.Right=info.dwSize.X-1;
WriteConsoleOutput(h,ci+(m_inputUsed<=info.dwSize.X?0:m_inputUsed-info.dwSize.X),
srcSize,srcCoord,&r);
// return data now?
if (returnChars&&m_inputUsed>1)
{
m_input[--m_inputUsed]=0;
m_inputUsed=0;
return m_input;
}
return 0;
}
class Pipe
{
Pipe(const Pipe&);
Pipe& operator=(const Pipe&);
HANDLE m_pipe;
bool m_connected;
int m_state;
int m_stringType;
int m_len;
char *m_src;
char *m_str;
public:
Pipe(void):
m_pipe(INVALID_HANDLE_VALUE),
m_src(NULL), m_str(NULL), m_stringType(0)
{
}
~Pipe()
{
if (m_pipe!=INVALID_HANDLE_VALUE)
{
DisconnectNamedPipe(m_pipe);
CloseHandle(m_pipe);
free(m_src);
free(m_str);
}
}
bool Create(const char *name)
{
m_pipe=CreateNamedPipe(name,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_NOWAIT,
PIPE_UNLIMITED_INSTANCES,1024,1024,0,NULL);
m_connected=false;
return m_pipe!=INVALID_HANDLE_VALUE;
}
bool Connected(void)
{
if (!m_connected)
{
ConnectNamedPipe(m_pipe,NULL);
if (GetLastError()==ERROR_PIPE_CONNECTED)
{
DWORD dwDummy;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"\n<connect>\n",11,&dwDummy,NULL);
m_connected=true;
m_state=0;
}
}
return m_connected;
}
void Write(char msg)
{
DWORD dummy;
if (!WriteFile(m_pipe,&msg,1,&dummy,NULL)||!dummy)
{
char sp[30];
wsprintf(sp,"%c:%i/%i\n",msg,dummy,GetLastError());
DWORD dwDummy;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),sp,strlen(sp),&dwDummy,NULL);
}
}
const char *Read(void)
{
DWORD read;
switch(m_state)
{
case 0:
if (!ReadFile(m_pipe,&m_stringType,1,&read,NULL))
break;
if (read==1)
m_state++;
return NULL;
case 1:
case 3:
if (!ReadFile(m_pipe,&m_len,4,&read,NULL))
break;
if (read==4)
{
if (m_state==1)
m_src=(char *)realloc(m_src,m_len+1);
else
m_str=(char *)realloc(m_str,m_len+1);
m_state++;
}
return NULL;
case 2:
if (!ReadFile(m_pipe,m_src,m_len,&read,NULL))
break;
if (read==m_len)
{
m_src[m_len]=0;
m_state++;
}
return NULL;
case 4:
if (!ReadFile(m_pipe,m_str,m_len,&read,NULL))
break;
if (read==m_len)
{
m_str[m_len]=0;
m_state=0;
return m_str;
}
return NULL;
}
if (GetLastError()==ERROR_BROKEN_PIPE)
{
DisconnectNamedPipe(m_pipe);
DWORD dwDummy;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"\n<disconnect>\n",14,&dwDummy,NULL);
m_connected=false;
}
return NULL;
}
};
int CALLBACK WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
InitConsole();
char buf1[200],buf2[400];
DWORD dwDummy=sizeof(buf1);
GetComputerName(buf1,&dwDummy);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),buf2,
wsprintf(buf2,"\n\nSimple debug.net Server ready. Enter 'quit' to exit.\n\nLocal machine: %s\n\n",buf1),
&dwDummy,NULL);
Pipe p[10];
for (int k=0;k<10;k++)
if (!p[k].Create("\\\\.\\pipe\\ea_debug_v1"))
{
char msg[200];
wsprintf(msg,"Can't create named pipe (Code %i).",GetLastError());
MessageBox(NULL,msg,"Error",MB_OK);
return 1;
}
for (;;)
{
char *input=InputConsole();
if (input)
{
if (!strcmp(input,"quit"))
break;
}
for (int k=0;k<10;k++)
{
if (!p[k].Connected())
continue;
const char *msg=p[k].Read();
if (msg)
{
DWORD dwDummy;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg,strlen(msg),&dwDummy,NULL);
}
if (input)
{
for (unsigned i=0;input[i];i++)
p[k].Write(input[i]);
p[k].Write('\n');
}
}
Sleep(10);
}
return 0;
}

View file

@ -0,0 +1,93 @@
# Microsoft Developer Studio Project File - Name="netserv" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=netserv - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "netserv.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "netserv.mak" CFG="netserv - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "netserv - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "netserv - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "netserv"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "netserv - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "netserv - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
!ENDIF
# Begin Target
# Name "netserv - Win32 Release"
# Name "netserv - Win32 Debug"
# Begin Source File
SOURCE=.\netserv.cpp
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,83 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
static unsigned char rcException[]={ // program generated, do not edit
0x01,0x00,0xff,0xff,0x00,0x00,0x00,0x00,
0x80,0x02,0x00,0x00,0xc2,0x0a,0xc0,0x90,
0x09,0x00,0x00,0x00,0x00,0x00,0xdf,0x01,
0xf5,0x00,0x00,0x00,0x00,0x00,0x45,0x00,
0x78,0x00,0x63,0x00,0x65,0x00,0x70,0x00,
0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,
0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x01,
0x4d,0x00,0x53,0x00,0x20,0x00,0x53,0x00,
0x61,0x00,0x6e,0x00,0x73,0x00,0x20,0x00,
0x53,0x00,0x65,0x00,0x72,0x00,0x69,0x00,
0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x50,
0xa6,0x01,0xe0,0x00,0x32,0x00,0x0e,0x00,
0x01,0x00,0x00,0x00,0xff,0xff,0x80,0x00,
0x4f,0x00,0x4b,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x81,0x00,0x02,0x50,0x07,0x00,0x07,0x00,
0x09,0x01,0x09,0x00,0x64,0x00,0x00,0x00,
0xff,0xff,0x82,0x00,0x45,0x00,0x78,0x00,
0x54,0x00,0x79,0x00,0x70,0x00,0x65,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x10,0x02,0x50,
0x07,0x00,0x13,0x00,0x09,0x01,0x1c,0x00,
0x65,0x00,0x00,0x00,0xff,0xff,0x82,0x00,
0x45,0x00,0x78,0x00,0x4d,0x00,0x73,0x00,
0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x81,0x12,0x02,0x50,0x07,0x00,0x3b,0x00,
0x09,0x01,0x13,0x00,0x66,0x00,0x00,0x00,
0xff,0xff,0x82,0x00,0x45,0x00,0x78,0x00,
0x41,0x00,0x64,0x00,0x64,0x00,0x72,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x50,
0x07,0x00,0x32,0x00,0x1e,0x00,0x08,0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0x82,0x00,
0x4c,0x00,0x6f,0x00,0x63,0x00,0x61,0x00,
0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,
0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x50,0x07,0x00,0x67,0x00,
0x28,0x00,0x08,0x00,0xff,0xff,0xff,0xff,
0xff,0xff,0x82,0x00,0x53,0x00,0x74,0x00,
0x61,0x00,0x63,0x00,0x6b,0x00,0x20,0x00,
0x74,0x00,0x72,0x00,0x61,0x00,0x63,0x00,
0x65,0x00,0x3a,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x80,0x81,0x50,0x07,0x00,0x73,0x00,
0xd1,0x01,0x6a,0x00,0x68,0x00,0x00,0x00,
0x53,0x00,0x79,0x00,0x73,0x00,0x4c,0x00,
0x69,0x00,0x73,0x00,0x74,0x00,0x56,0x00,
0x69,0x00,0x65,0x00,0x77,0x00,0x33,0x00,
0x32,0x00,0x00,0x00,0x4c,0x00,0x69,0x00,
0x73,0x00,0x74,0x00,0x32,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x81,0x10,0x02,0x50,
0x07,0x00,0x56,0x00,0x09,0x01,0x0a,0x00,
0x67,0x00,0x00,0x00,0xff,0xff,0x82,0x00,
0x56,0x00,0x65,0x00,0x72,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x41,0xa1,0x50,
0x18,0x01,0x07,0x00,0xc0,0x00,0x67,0x00,
0x69,0x00,0x00,0x00,0xff,0xff,0x83,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0 };

View file

@ -0,0 +1,49 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/test1/test1.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug module - Test 1 (Checking early exceptions)
//////////////////////////////////////////////////////////////////////////////
#include "../debug.h"
const char *DebugGetDefaultCommands(void)
{
return "!debug.io con add";
}
int divByNull;
unsigned *invalidPtr=(unsigned *)0x666;
bool crash(void)
{
*invalidPtr/=divByNull;
return true;
}
bool thisWillCrash=crash();
void main(void)
{
}

View file

@ -0,0 +1,89 @@
# Microsoft Developer Studio Project File - Name="test1" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=test1 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "test1.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "test1.mak" CFG="test1 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "test1 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "test1 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "test1"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "test1 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ELSEIF "$(CFG)" == "test1 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ENDIF
# Begin Target
# Name "test1 - Win32 Release"
# Name "test1 - Win32 Debug"
# Begin Source File
SOURCE=.\test1.cpp
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,26 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
// stdafx.cpp : source file that includes just the standard includes
// test2.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View file

@ -0,0 +1,50 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
// Local Header Files
// TODO: reference additional headers your program requires here
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)

View file

@ -0,0 +1,3 @@
; test dbgcmd file
debug.io con add ; send output to CON I/O window

View file

@ -0,0 +1,45 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by TEST2.RC
//
#define IDR_MAINFRAME 128
#define IDD_TEST2_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDS_APP_TITLE 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDS_HELLO 106
#define IDI_TEST2 107
#define IDI_SMALL 108
#define IDC_TEST2 109
#define IDC_MYICON 2
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif

View file

@ -0,0 +1,246 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/test2/test2.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug module - Test 2 (Checking commands, CON I/O, cmddbg file)
//////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include "..\debug.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
class TestCmdInterface: public DebugCmdInterface
{
public:
virtual bool Execute(class Debug& dbg, const char *cmd, CommandMode cmdmode,
unsigned argn, const char * const * argv)
{
if (strcmp(cmd,"box"))
return false;
MessageBox(NULL,"Hello world!","Command",MB_OK);
return true;
}
virtual void Delete(void) { delete this; }
};
DEBUG_CREATE_COMMAND_GROUP(test,TestCmdInterface)
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TEST2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TEST2);
// Send a command to Debug interface
Debug::Command("debug.io ; send via EXE, try test.box!");
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_TEST2);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_TEST2;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
// create a timer for calling Debug::Update
SetTimer(hWnd,1,100,NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_TIMER:
Debug::Update();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}

View file

@ -0,0 +1,118 @@
# Microsoft Developer Studio Project File - Name="test2" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=test2 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "test2.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "test2.mak" CFG="test2 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "test2 - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "test2 - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "test2"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "test2 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "test2 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
!ENDIF
# Begin Target
# Name "test2 - Win32 Release"
# Name "test2 - Win32 Debug"
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\resource.h
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# ADD CPP /Yc"stdafx.h"
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# Begin Source File
SOURCE=.\test2.rc
# End Source File
# End Group
# Begin Source File
SOURCE=.\default.dbgcmd
# End Source File
# Begin Source File
SOURCE=.\test2.cpp
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,132 @@
//Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDC_TEST2 MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About ...", IDM_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDC_TEST2 ACCELERATORS MOVEABLE PURE
BEGIN
"?", IDM_ABOUT, ASCII, ALT
"/", IDM_ABOUT, ASCII, ALT
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "System"
BEGIN
ICON IDI_TEST2,IDC_MYICON,14,9,16,16
LTEXT "test2 Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX
LTEXT "Copyright (C) 2003",IDC_STATIC,49,20,119,8
DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""resource.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDC_TEST2 "TEST2"
IDS_APP_TITLE "test2"
IDS_HELLO "Hello World!"
END
#endif
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,65 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/test3/test3.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug module - Test 3 (Checking FLAT I/O, logging)
//////////////////////////////////////////////////////////////////////////////
#ifdef NDEBUG
# define _INTERNAL
# pragma comment(linker,"/nodefaultlib:debuginternal.lib")
#endif
#include "../debug.h"
unsigned divByNull;
void main(void)
{
// switch to debug group
Debug::Command("debug.");
Debug::Command("alwaysflush +");
// we want our files copied
Debug::Command("io flat copy ..\\");
// split 'split_me' log group to separate file (with size limit)
Debug::Command("io flat splitadd l split_me splitted 1");
// turn all logs on
Debug::Command("add l + *");
// disable no_log log
Debug::Command("add l - no_log");
// now log something...
DLOG("This should be visible.\n");
DLOG_GROUP(no_log,"This should *NOT* be visible.\n");
for (int k=0;k<200;k++)
DLOG_GROUP(split_me,"Log line " << k << "\n");
DLOG_GROUP(split_me,"Final line in separate log file.\n");
// and now let's crash!
divByNull/=divByNull;
}

View file

@ -0,0 +1,88 @@
# Microsoft Developer Studio Project File - Name="test3" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=test3 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "test3.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "test3.mak" CFG="test3 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "test3 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "test3 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "test3"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "test3 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "test3 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ENDIF
# Begin Target
# Name "test3 - Win32 Release"
# Name "test3 - Win32 Debug"
# Begin Source File
SOURCE=.\test3.cpp
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,42 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/test4/test4.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug module - Test 4 (Multiple DASSERTs, high-count DCHECKs)
//////////////////////////////////////////////////////////////////////////////
#include "../debug.h"
void main(void)
{
for (int i=0;i<30;i++)
DCHECK_MSG(i>100,"run#" << i);
Debug::Command("list c");
for (int k=0;k<3;k++)
{
DASSERT(k>4);
DASSERT_MSG(k<1,"k must be less than 1...");
Debug::Command("list a");
}
}

View file

@ -0,0 +1,88 @@
# Microsoft Developer Studio Project File - Name="test4" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=test4 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "test4.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "test4.mak" CFG="test4 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "test4 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "test4 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "test4"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "test4 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "test4 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ENDIF
# Begin Target
# Name "test4 - Win32 Release"
# Name "test4 - Win32 Debug"
# Begin Source File
SOURCE=.\test4.cpp
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,43 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/test5/test5.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug module - Test 5 (printf style formatting)
//////////////////////////////////////////////////////////////////////////////
#include "../debug.h"
const char *DebugGetDefaultCommands(void)
{
return "!debug.io con add";
}
void main(void)
{
// turn on all logs
Debug::Command("add l + *");
for (int k=0;k<16;k++)
DLOG("Testing: " << Debug::Format("0x%04x (%c)",k,'A'+k) << "\n");
}

View file

@ -0,0 +1,88 @@
# Microsoft Developer Studio Project File - Name="test5" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=test5 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "test5.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "test5.mak" CFG="test5 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "test5 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "test5 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "test5"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "test5 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "test5 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ENDIF
# Begin Target
# Name "test5 - Win32 Release"
# Name "test5 - Win32 Debug"
# Begin Source File
SOURCE=.\test5.cpp
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,59 @@
/*
** Command & Conquer Generals Zero Hour(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/>.
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/test6/test6.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug module - Test 6 (SEH, FPO test)
//////////////////////////////////////////////////////////////////////////////
#include "../debug.h"
#include <stdio.h>
int test,divByZero;
void func1(void)
{
test/=divByZero;
}
void func2(void)
{
func1();
}
void func3(void)
{
func2();
}
void main(void)
{
try
{
func3();
}
catch (...)
{
printf("This catch clause should not be executed.\n");
}
}

View file

@ -0,0 +1,89 @@
# Microsoft Developer Studio Project File - Name="test6" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=test6 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "test6.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "test6.mak" CFG="test6 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "test6 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "test6 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "test6"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "test6 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ELSEIF "$(CFG)" == "test6 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ENDIF
# Begin Target
# Name "test6 - Win32 Release"
# Name "test6 - Win32 Debug"
# Begin Source File
SOURCE=.\test6.cpp
# End Source File
# End Target
# End Project