Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
wdebug.h
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/*****************************************************************************\
20wdebug Neal Kettler
21
22MT-LEVEL
23 MT-Safe
24
25The debugging module is pretty good for debugging and it has some message
26printing stuff as well. The basic idea is that you write a class that
27inherits from OutputDevice (several are provided) and assign that output
28device to a stream. There are seperate streams for debugging, information,
29warning, and error messages. Each one can have a seperate output device,
30or they can all have the same one. Debugging messages only get compiled
31in if your module defines 'DEBUG'. If you don't define debug, then not even
32the text of the debugging message gets into the binary. All the other
33output streams get printed regardless of whether DEBUG is defined.
34
35Sample usage:
36FileD debug_device("gameres.debug"); // create a file device
37MsgManager::setDebugStream(&debug_device);
38DBGMSG("This debug message #" << 1 << " you use C++ streams");
39
40Note that since these are defines you really don't need to put a semicolon
41at the end, and it can be bad in situations like this:
42
43if (x)
44 DBGMSG("Stuff is broken");
45else
46 DBGMSG("Stuff is NOT broken");
47
48This won't compile, read the code until you figure it out. Only then
49will you be ready to leave grasshopper.
50
51\*****************************************************************************/
52
53#ifndef WDEBUG_HEADER
54#define WDEBUG_HEADER
55
56#define USE_DEBUG_SEM
57
58#include "wstypes.h"
59
60#ifdef _WINDOWS
61#include <iostream.h>
62#include <strstrea.h>
63#else
64#include <iostream>
65
66// Windows headers have a tendency to redefine IN
67#ifdef IN
68#undef IN
69#endif
70#define IN const
71
72#endif
73
74#ifdef USE_DEBUG_SEM
75#include "sem4.h"
76#else
77#include "critsec.h"
78#endif
79#include "odevice.h"
80#include "streamer.h"
81#include "xtime.h"
82#include "timezone.h" // MDC
83#include "filed.h"
84
85// This is needed because the streams return a pointer. Every time you
86// change the output device the old stream is deleted, and a new one
87// is created.
88// MDC: Added a macro to switch between semaphores & critsecs to debug a
89// problem in Win32.
90
91#ifdef USE_DEBUG_SEM
93#define DEBUGLOCK DebugLibSemaphore.Wait()
94#define DEBUGUNLOCK DebugLibSemaphore.Post()
95#else
97#define DEBUGLOCK DebugLibSemaphore.lock()
98#define DEBUGUNLOCK DebugLibSemaphore.unlock()
99#endif
100
101// Print an information message
102#define INFMSG(X)\
103{\
104 char timebuf[40]; \
105 Xtime now; \
106 now -= TimezoneOffset(); \
107 now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
108 DEBUGLOCK; \
109 if (MsgManager::infoStream()) \
110 (*(MsgManager::infoStream())) << "INF " << timebuf << " [" << \
111 __FILE__ << " " << __LINE__ << "] " << X << endl; \
112 DEBUGUNLOCK; \
113}
114
115// Print a warning message
116#define WRNMSG(X)\
117{\
118 char timebuf[40]; \
119 Xtime now; \
120 now -= TimezoneOffset(); \
121 now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
122 DEBUGLOCK; \
123 if (MsgManager::warnStream()) \
124 (*(MsgManager::warnStream())) << "WRN " << timebuf << " [" << \
125 __FILE__ << " " << __LINE__ << "] " << X << endl; \
126 DEBUGUNLOCK; \
127}
128
129// Print an error message
130#define ERRMSG(X)\
131{\
132 char timebuf[40]; \
133 Xtime now; \
134 now -= TimezoneOffset(); \
135 now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
136 DEBUGLOCK; \
137 if (MsgManager::errorStream()) \
138 (*(MsgManager::errorStream())) << "ERR " << timebuf << " [" << \
139 __FILE__ << " " << __LINE__ << "] " << X << endl; \
140 DEBUGUNLOCK; \
141}
142
143
144// Just get a stream to the information device, no extra junk
145#define INFSTREAM(X)\
146{\
147 DEBUGLOCK; \
148 if (MsgManager::infoStream()) \
149 (*(MsgManager::infoStream())) << X;\
150 DEBUGUNLOCK; \
151}
152
153// Just get a stream to the warning device, no extra junk
154#define WRNSTREAM(X)\
155{\
156 DEBUGLOCK; \
157 if (MsgManager::warnStream()) \
158 (*(MsgManager::warnStream())) << X;\
159 DEBUGUNLOCK; \
160}
161
162// Just get a stream to the error device, no extra junk
163#define ERRSTREAM(X)\
164{\
165 DEBUGLOCK; \
166 if (MsgManager::errorStream()) \
167 (*(MsgManager::errorStream())) << X;\
168 DEBUGUNLOCK; \
169}
170
171#ifndef DEBUG
172
173// No debugging, no debug messages.
174// Note that anything enclosed in "DBG()" will NOT get executed
175// unless DEBUG is defined.
176// They are defined to {} for consistency when DEBUG is defined
177
178#define DBG(X)
179#define DBGSTREAM(X) {}
180#define PVAR(v) {}
181#define DBGMSG(X) {}
182#define VERBOSE(X) {}
183
184#else // DEBUG _is_ defined
185
186// Execute only if in debugging mode
187#define DBG(X) X
188
189// In Windows, send a copy to the debugger window
190#ifdef _WINDOWS
191
192// Print a variable
193#define PVAR(v) \
194{ \
195 DEBUGLOCK; \
196 if (MsgManager::debugStream()) \
197 (*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
198 "]: " << ##V << " = " << V << endl; \
199 strstream __s;\
200 __s << __FILE__ << "[" << __LINE__ << \
201 "]: " << ##V << " = " << V << '\n' << '\0';\
202 OutputDebugString(__s.str());\
203 DEBUGUNLOCK; \
204}
205
206
207#define DBGMSG(X)\
208{\
209 DEBUGLOCK; \
210 if (MsgManager::debugStream()) \
211 (*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
212 " " << __LINE__ << "] " << X << endl;\
213 strstream __s;\
214 __s << "DBG [" << __FILE__ << \
215 " " << __LINE__ << "] " << X << '\n' << '\0';\
216 OutputDebugString(__s.str());\
217 DEBUGUNLOCK; \
218}
219
220// Just get a stream to the debugging device, no extra junk
221#define DBGSTREAM(X)\
222{\
223 DEBUGLOCK; \
224 if (MsgManager::debugStream()) \
225 (*(MsgManager::debugStream())) << X;\
226 strstream __s;\
227 __s << X << '\0';\
228 OutputDebugString(__s.str());\
229 DEBUGUNLOCK; \
230}
231
232// Verbosely execute a statement
233#define VERBOSE(X)\
234{ \
235 DEBUGLOCK; \
236 if (MsgManager::debugStream()) \
237 (*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
238 "]: " << ##X << endl; X \
239 strstream __s;\
240 __s << __FILE__ << "[" << __LINE__ << \
241 "]: " << ##X << '\n' << '\0';\
242 OutputDebugString(__s.str());\
243 DEBUGUNLOCK; \
244}
245
246#else // _WINDOWS
247
248// Print a variable
249#define PVAR(v) \
250{ \
251 DEBUGLOCK; \
252 if (MsgManager::debugStream()) \
253 (*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
254 "]: " << ##V << " = " << V << endl; \
255 DEBUGUNLOCK; \
256}
257
258
259#define DBGMSG(X)\
260{\
261 DEBUGLOCK; \
262 if (MsgManager::debugStream()) \
263 (*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
264 " " << __LINE__ << "] " << X << endl;\
265 DEBUGUNLOCK; \
266}
267
268// Just get a stream to the debugging device, no extra junk
269#define DBGSTREAM(X)\
270{\
271 DEBUGLOCK; \
272 if (MsgManager::debugStream()) \
273 (*(MsgManager::debugStream())) << X;\
274 DEBUGUNLOCK; \
275}
276
277// Verbosely execute a statement
278#define VERBOSE(X)\
279{ \
280 DEBUGLOCK; \
281 if (MsgManager::debugStream()) \
282 (*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
283 "]: " << ##X << endl; X \
284 DEBUGUNLOCK; \
285}
286#endif // _WINDOWS
287
288#endif // DEBUG
289
290//#undef DEBUGLOCK
291//#undef DEBUGUNLOCK
292
293class MsgManager
294{
295 protected:
297
298 public:
299 static int setAllStreams(OutputDevice *device);
300 static int ReplaceAllStreams(FileD *output_device, IN char *device_filename, IN char *copy_filename);
301 static int setDebugStream(OutputDevice *device);
302 static int setInfoStream(OutputDevice *device);
303 static int setWarnStream(OutputDevice *device);
304 static int setErrorStream(OutputDevice *device);
305
306 static void enableDebug(int flag);
307 static void enableInfo(int flag);
308 static void enableWarn(int flag);
309 static void enableError(int flag);
310
311 static ostream *debugStream(void);
312 static ostream *infoStream(void);
313 static ostream *warnStream(void);
314 static ostream *errorStream(void);
315};
316
317#endif
Definition filed.h:25
static void enableInfo(int flag)
static ostream * errorStream(void)
static ostream * warnStream(void)
static int setDebugStream(OutputDevice *device)
static void enableDebug(int flag)
static void enableWarn(int flag)
static int ReplaceAllStreams(FileD *output_device, IN char *device_filename, IN char *copy_filename)
Definition wdebug.cpp:80
static int setErrorStream(OutputDevice *device)
static int setWarnStream(OutputDevice *device)
static ostream * debugStream(void)
static int setAllStreams(OutputDevice *device)
static int setInfoStream(OutputDevice *device)
static void enableError(int flag)
static ostream * infoStream(void)
Definition sem4.h:43
Sem4 DebugLibSemaphore
Definition wdebug.cpp:46
OutputDevice * output_device
Definition main.cpp:59
#define IN
Definition wdebug.h:70
unsigned char flag
Definition vchannel.cpp:273