wdebug.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. wdebug Neal Kettler
  20. MT-LEVEL
  21. MT-Safe
  22. The debugging module is pretty good for debugging and it has some message
  23. printing stuff as well. The basic idea is that you write a class that
  24. inherits from OutputDevice (several are provided) and assign that output
  25. device to a stream. There are seperate streams for debugging, information,
  26. warning, and error messages. Each one can have a seperate output device,
  27. or they can all have the same one. Debugging messages only get compiled
  28. in if your module defines 'DEBUG'. If you don't define debug, then not even
  29. the text of the debugging message gets into the binary. All the other
  30. output streams get printed regardless of whether DEBUG is defined.
  31. Sample usage:
  32. FileD debug_device("gameres.debug"); // create a file device
  33. MsgManager::setDebugStream(&debug_device);
  34. DBGMSG("This debug message #" << 1 << " you use C++ streams");
  35. Note that since these are defines you really don't need to put a semicolon
  36. at the end, and it can be bad in situations like this:
  37. if (x)
  38. DBGMSG("Stuff is broken");
  39. else
  40. DBGMSG("Stuff is NOT broken");
  41. This won't compile, read the code until you figure it out. Only then
  42. will you be ready to leave grasshopper.
  43. \*****************************************************************************/
  44. #ifndef WDEBUG_HEADER
  45. #define WDEBUG_HEADER
  46. #define USE_DEBUG_SEM
  47. #include "wstypes.h"
  48. #ifdef _WINDOWS
  49. #include <iostream.h>
  50. #include <strstrea.h>
  51. #else
  52. #include <iostream>
  53. // Windows headers have a tendency to redefine IN
  54. #ifdef IN
  55. #undef IN
  56. #endif
  57. #define IN const
  58. #endif
  59. #ifdef USE_DEBUG_SEM
  60. #include "sem4.h"
  61. #else
  62. #include "critsec.h"
  63. #endif
  64. #include "odevice.h"
  65. #include "streamer.h"
  66. #include "xtime.h"
  67. #include "timezone.h" // MDC
  68. #include "filed.h"
  69. // This is needed because the streams return a pointer. Every time you
  70. // change the output device the old stream is deleted, and a new one
  71. // is created.
  72. // MDC: Added a macro to switch between semaphores & critsecs to debug a
  73. // problem in Win32.
  74. #ifdef USE_DEBUG_SEM
  75. extern Sem4 DebugLibSemaphore;
  76. #define DEBUGLOCK DebugLibSemaphore.Wait()
  77. #define DEBUGUNLOCK DebugLibSemaphore.Post()
  78. #else
  79. extern CritSec DebugLibSemaphore;
  80. #define DEBUGLOCK DebugLibSemaphore.lock()
  81. #define DEBUGUNLOCK DebugLibSemaphore.unlock()
  82. #endif
  83. // Print an information message
  84. #define INFMSG(X)\
  85. {\
  86. char timebuf[40]; \
  87. Xtime now; \
  88. now -= TimezoneOffset(); \
  89. now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
  90. DEBUGLOCK; \
  91. if (MsgManager::infoStream()) \
  92. (*(MsgManager::infoStream())) << "INF " << timebuf << " [" << \
  93. __FILE__ << " " << __LINE__ << "] " << X << endl; \
  94. DEBUGUNLOCK; \
  95. }
  96. // Print a warning message
  97. #define WRNMSG(X)\
  98. {\
  99. char timebuf[40]; \
  100. Xtime now; \
  101. now -= TimezoneOffset(); \
  102. now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
  103. DEBUGLOCK; \
  104. if (MsgManager::warnStream()) \
  105. (*(MsgManager::warnStream())) << "WRN " << timebuf << " [" << \
  106. __FILE__ << " " << __LINE__ << "] " << X << endl; \
  107. DEBUGUNLOCK; \
  108. }
  109. // Print an error message
  110. #define ERRMSG(X)\
  111. {\
  112. char timebuf[40]; \
  113. Xtime now; \
  114. now -= TimezoneOffset(); \
  115. now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
  116. DEBUGLOCK; \
  117. if (MsgManager::errorStream()) \
  118. (*(MsgManager::errorStream())) << "ERR " << timebuf << " [" << \
  119. __FILE__ << " " << __LINE__ << "] " << X << endl; \
  120. DEBUGUNLOCK; \
  121. }
  122. // Just get a stream to the information device, no extra junk
  123. #define INFSTREAM(X)\
  124. {\
  125. DEBUGLOCK; \
  126. if (MsgManager::infoStream()) \
  127. (*(MsgManager::infoStream())) << X;\
  128. DEBUGUNLOCK; \
  129. }
  130. // Just get a stream to the warning device, no extra junk
  131. #define WRNSTREAM(X)\
  132. {\
  133. DEBUGLOCK; \
  134. if (MsgManager::warnStream()) \
  135. (*(MsgManager::warnStream())) << X;\
  136. DEBUGUNLOCK; \
  137. }
  138. // Just get a stream to the error device, no extra junk
  139. #define ERRSTREAM(X)\
  140. {\
  141. DEBUGLOCK; \
  142. if (MsgManager::errorStream()) \
  143. (*(MsgManager::errorStream())) << X;\
  144. DEBUGUNLOCK; \
  145. }
  146. #ifndef DEBUG
  147. // No debugging, no debug messages.
  148. // Note that anything enclosed in "DBG()" will NOT get executed
  149. // unless DEBUG is defined.
  150. // They are defined to {} for consistency when DEBUG is defined
  151. #define DBG(X)
  152. #define DBGSTREAM(X) {}
  153. #define PVAR(v) {}
  154. #define DBGMSG(X) {}
  155. #define VERBOSE(X) {}
  156. #else // DEBUG _is_ defined
  157. // Execute only if in debugging mode
  158. #define DBG(X) X
  159. // In Windows, send a copy to the debugger window
  160. #ifdef _WINDOWS
  161. // Print a variable
  162. #define PVAR(v) \
  163. { \
  164. DEBUGLOCK; \
  165. if (MsgManager::debugStream()) \
  166. (*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
  167. "]: " << ##V << " = " << V << endl; \
  168. strstream __s;\
  169. __s << __FILE__ << "[" << __LINE__ << \
  170. "]: " << ##V << " = " << V << '\n' << '\0';\
  171. OutputDebugString(__s.str());\
  172. DEBUGUNLOCK; \
  173. }
  174. #define DBGMSG(X)\
  175. {\
  176. DEBUGLOCK; \
  177. if (MsgManager::debugStream()) \
  178. (*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
  179. " " << __LINE__ << "] " << X << endl;\
  180. strstream __s;\
  181. __s << "DBG [" << __FILE__ << \
  182. " " << __LINE__ << "] " << X << '\n' << '\0';\
  183. OutputDebugString(__s.str());\
  184. DEBUGUNLOCK; \
  185. }
  186. // Just get a stream to the debugging device, no extra junk
  187. #define DBGSTREAM(X)\
  188. {\
  189. DEBUGLOCK; \
  190. if (MsgManager::debugStream()) \
  191. (*(MsgManager::debugStream())) << X;\
  192. strstream __s;\
  193. __s << X << '\0';\
  194. OutputDebugString(__s.str());\
  195. DEBUGUNLOCK; \
  196. }
  197. // Verbosely execute a statement
  198. #define VERBOSE(X)\
  199. { \
  200. DEBUGLOCK; \
  201. if (MsgManager::debugStream()) \
  202. (*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
  203. "]: " << ##X << endl; X \
  204. strstream __s;\
  205. __s << __FILE__ << "[" << __LINE__ << \
  206. "]: " << ##X << '\n' << '\0';\
  207. OutputDebugString(__s.str());\
  208. DEBUGUNLOCK; \
  209. }
  210. #else // _WINDOWS
  211. // Print a variable
  212. #define PVAR(v) \
  213. { \
  214. DEBUGLOCK; \
  215. if (MsgManager::debugStream()) \
  216. (*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
  217. "]: " << ##V << " = " << V << endl; \
  218. DEBUGUNLOCK; \
  219. }
  220. #define DBGMSG(X)\
  221. {\
  222. DEBUGLOCK; \
  223. if (MsgManager::debugStream()) \
  224. (*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
  225. " " << __LINE__ << "] " << X << endl;\
  226. DEBUGUNLOCK; \
  227. }
  228. // Just get a stream to the debugging device, no extra junk
  229. #define DBGSTREAM(X)\
  230. {\
  231. DEBUGLOCK; \
  232. if (MsgManager::debugStream()) \
  233. (*(MsgManager::debugStream())) << X;\
  234. DEBUGUNLOCK; \
  235. }
  236. // Verbosely execute a statement
  237. #define VERBOSE(X)\
  238. { \
  239. DEBUGLOCK; \
  240. if (MsgManager::debugStream()) \
  241. (*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
  242. "]: " << ##X << endl; X \
  243. DEBUGUNLOCK; \
  244. }
  245. #endif // _WINDOWS
  246. #endif // DEBUG
  247. //#undef DEBUGLOCK
  248. //#undef DEBUGUNLOCK
  249. class MsgManager
  250. {
  251. protected:
  252. MsgManager();
  253. public:
  254. static int setAllStreams(OutputDevice *device);
  255. static int ReplaceAllStreams(FileD *output_device, IN char *device_filename, IN char *copy_filename);
  256. static int setDebugStream(OutputDevice *device);
  257. static int setInfoStream(OutputDevice *device);
  258. static int setWarnStream(OutputDevice *device);
  259. static int setErrorStream(OutputDevice *device);
  260. static void enableDebug(int flag);
  261. static void enableInfo(int flag);
  262. static void enableWarn(int flag);
  263. static void enableError(int flag);
  264. static ostream *debugStream(void);
  265. static ostream *infoStream(void);
  266. static ostream *warnStream(void);
  267. static ostream *errorStream(void);
  268. };
  269. #endif