libMVRgdtf 40bc00a
A library for GDTF and MVR
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GSDebug.h
Go to the documentation of this file.
1//
2// Copyright Nemetschek Vectorworks, Inc.
3// Use of this file is governed by the Nemetschek Vectorworks SDK License Agreement
4// http://developer.vectorworks.net/index.php?title=Vectorworks_SDK_License
5//
6//
7// This header file contains all prototypes and related information for all
8// debugging functions and variables. It is completely cross-platform and
9// can be included in 100% Mac, 100% Windows and hybrid files.
10//
11// ------------------------------------------------------------------
12// TProgrammer Addition and Removal Process:
13// ------------------------------------------------------------------
14// Adding a new Engineer:
15// 1) Search for @1. Add a new entry, finding an empty slot or appending.
16// 2) Search for @3. Add a new entry at the same relative position as you added for step 1 (to keep things in sync).
17// 3) Search for @5. Add a new entry at the same relative position.
18
19// Removing a departed Engineer:
20// 1) Search for @1. Remove from this table. Just comment the whole line, change the name/constant to XXXXX, and leave a space with a comment that says // Empty. We no longer add "kNoOne" placeholders.
21// 2) Search for @2. Append an entry for this engineer.
22// 3) Search for @3. Remove the entry for this engineer (cut it).
23// 4) Search for @4. Append an entry for this engineer (paste from previous)
24// 5) Search for @5. Remove the entry for this engineer.
25// ------------------------------------------------------------------
26
27
28
29#ifndef _GSDEBUG_H_
30#define _GSDEBUG_H_ 1
31
32#pragma once
33
35// _GSDEBUG_DLL_
36//
37// To use the DLL version of GSDebug, define _GSDEBUG_DLL_ to be non-zero in
38// the project settings. If you do not define it, the default will be to use
39// the object file version.
40
41#if !defined(_GSDEBUG_DLL_)
42 #define _GSDEBUG_DLL_ 0
43#endif
44
45
47// _GSDEBUG_LIB_
48//
49// To use the LIB version of GSDebug, define _GSDEBUG_LIB_ to be non-zero in
50// the project settings. If you do not define it, the default will be to use
51// the object file version.
52
53#if !defined(_GSDEBUG_LIB_)
54 #define _GSDEBUG_LIB_ 0
55#endif
56
57
59// GS_USE_ONLY_MODERN
60//
61// Define GS_USE_ONLY_MODERN to be non-zero to force more modern behavior.
62// Modern behavior includes requiring a TProgrammer attached to all debug
63// calls. If you do not define it, the default will be to not use it.
64
65#if !defined(GS_USE_ONLY_MODERN)
66 #define GS_USE_ONLY_MODERN 1
67#endif
68
69
71// GS_HWND_CHECK
72//
73// Define GS_HWND_CHECK to non-zero if you want to include Windows HWND
74// validation functions.
75
76#if !defined(GS_HWND_CHECK)
77 #if defined(_INC_WINDOWS) || defined(_GSWIN_)
78 #define GS_HWND_CHECK 1
79 #else
80 #define GS_HWND_CHECK 0
81 #endif
82#endif
83
84
86// GS_USE_OBSOLETE
87//
88// Define GS_USE_OBSOLETE to be non-zero to include very old debugging
89// functions. You really don't want to do this unless you have to.
90#if !defined(GS_USE_OBSOLETE)
91 #if !_MINICAD_EXTERNAL_ && !_GSWINSDK_ && !_MAGICFOLDER_ && !_GSESDK_ && !GS_SHELL_BUILD && !GS_COMP_BUILD && !GS_PROTECTION_BUILD && !GS_GSDEBUG_BUILD
92 #define GS_USE_OBSOLETE 1
93 #else
94 #define GS_USE_OBSOLETE 0
95 #endif
96#endif
97
98
100// GS_USE_CLASS_DEBUGGING
101//
102// Define GS_USE_CLASS_DEBUGGING to be non-zero to enable class debugging.
103
104#if !defined(GS_USE_CLASS_DEBUGGING)
105 #if !_MINICAD_EXTERNAL_
106 #define GS_USE_CLASS_DEBUGGING 1
107 #else
108 #define GS_USE_CLASS_DEBUGGING 0
109 #endif
110#endif
111
112
114// _GSDEBUG_
115//
116// When building the GSDebug.dll or GSDebug.lib, you must define _GSDEBUG_ in the
117// compiler preprocessor flags settings.
118
119#if _GSDEBUG_ && !_GSDEBUG_DLL_ && !_GSDEBUG_LIB_
120 #error if _GSDEBUG_ is defined, _GSDEBUG_DLL_ or _GSDEBUG_LIB_ must also be defined
121#endif
122
123
125// Not allowed to use the DLL and LIB versions at the same time.
126
127#if _GSDEBUG_DLL_ && _GSDEBUG_LIB_
128 #error Not allowed to define both _GSDEBUG_DLL_ and _GSDEBUG_LIB_
129#endif
130#if !_GSDEBUG_DLL_ && !_GSDEBUG_LIB_
131 #define _GSDEBUG_OBJ_ 1
132#endif
133
134
135#if GS_MAC
136 // Turn off effect of DEBUG_DO_NOTHING applied to GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_n
137 // Set GS_DSTOP_ALWAYS for MAC environment that DOES NOT skip Debugging stops.
138 #define GS_DSTOP_ALWAYS SteveJ // Turn off effect of DEBUG_DO_NOTHING applied to GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_n
139#endif
140
141
143// Implementation Starts Here
145
146
147/* Includes */
148/* -------- */
149
150// Debugging library is only useful under C++. This allows it to be globally included in externals.
151#ifdef __cplusplus
152
153#include <stdlib.h>
154#include <stdio.h>
155#include <string.h>
156#include <string>
157#include <map>
158#include <chrono>
159#include <ctime>
160#include <fstream>
161#include <functional>
162#include <thread>
163#include <mutex>
164#include <atomic>
165
166#if !_WINDOWS
167 #include <stdarg.h>
168#endif
169
170
172// AS OF 8/20/98 -
173// On Windows, GSESDK code is called without special calling conventions
174
175#if _WINDOWS && _GSDEBUG_DLL_
176 #if _GSDEBUG_
177 // Building GSDebug.dll
178 #define GSDEBUG_EXPORT __declspec(dllexport)
179
180 #else
181 // Building a module that uses GSDebug.dll
182 #define GSDEBUG_EXPORT __declspec(dllimport)
183 #endif
184#else
185 // Building a module that compiles GSDebug.cpp directly (no GSDebug.dll).
186 #define GSDEBUG_EXPORT
187#endif
188
189
191
192#include "GSTypes.h"
193
194
195/* End of Includes */
196
197
198/* Basic Types */
199/* ----------- */
200
201#if _WINDOWS
202 #if _MAGICFOLDER_
203 #define Boolean Bool8
204 #define Byte Uint8
205 #endif
206#endif
207
208
209/* Private Variables */
210/* ----------------- */
211#if GS_GSDEBUG_BUILD || (APPBUILD && !GS_INTERFACE_FACTORING)
212extern char gDebugAppName[32];
213#endif
214
215
217// Timers
218//
219// Use like this:
220// ...code....
221// START_TIMER(NameOfTimer);
222// ...code.to.time...
223// END_TIMER(kProgrammer, NameOfTimer);
224// ...code...
225
226#if _WINDOWS && BUG
227
228 class GSDEBUG_EXPORT TProgrammer;
229 class GSDEBUG_EXPORT TDebugTimer
230 {
231 public:
232 TDebugTimer();
233 void Stop(const TProgrammer &who, ConstGSCStrPtr name, bool bWindow);
234
235 private:
236 #if _WINDOWS
237 Uint64 fStartTime;
238 #else
239 #endif
240 };
241
242 #define START_TIMER(name) TDebugTimer timer_##name
243 #define END_TIMER(who, name) timer_##name##.Stop(who, #name, false)
244
245#else
246 #define START_TIMER(name)
247 #define END_TIMER(who, name)
248#endif
249
250#if _WINDOWS && _MAGICFOLDER_
251 #define START_TIMER_RELEASE(name) const Uint32 timer_##name = ::GetTickCount()
252 #define END_TIMER_RELEASE(name) do { \
253 const Uint32 elapsed = ::GetTickCount() - timer_##name; \
254 Uint32 seconds = elapsed / 1000; \
255 Uint32 tenths = (elapsed - seconds*1000 + 50) / 100; \
256 if (tenths > 9) { tenths = 0; ++seconds; } \
257 char szMessage[60]; \
258 ::sprintf(szMessage, "Timer '" #name "' took %d.%d seconds.", seconds, tenths); \
259 ::AfxMessageBox(szMessage); \
260 } while (0)
261#else
262 #define START_TIMER_RELEASE(name)
263 #define END_TIMER_RELEASE(name)
264#endif
265
266
268// Compiler messages
269//
270// Use like this:
271// #pragma CMSG(kProgrammer, "Your message")
272
273#define CMSG_makeString1(x) #x
274#define CMSG_makeString(x) CMSG_makeString1(x)
275#define CMSG(who, desc) message(__FILE__ "(" CMSG_makeString(__LINE__) ") : " #who ": " desc)
276
277
279// Print preprocessor definition
280//
281// use this is see what something has been defined to be. For example:
282// #pragma PRINTDEFINE(kDave, BUG)
283// Will, when compiling, generate a line in the compiler output window telling you what
284// "BUG" is currently defined to.
285
286#define PRINTDEFINE(who, what) message(__FILE__ "(" CMSG_makeString(__LINE__) ") : " #who ": " #what " = " CMSG_makeString(what))
287
288
290// Macro to mark something as un-implemented.
291//
292// For example:
293//
294// void TMyClass::CalulateComplexNumber()
295// {
296// NOT_IMPLEMENTED(kDave, TMyClass::CalulateComplexNumber);
297// }
298
299#define NOT_IMPLEMENTED(who, func) DSTOP((who, "Not implemented: " #func))
300
301
303
304#if (_WINDOWS && _MINICAD_ && !defined(_INC_WINDOWS)) || !_WINDOWS
305
306 // if Windows.h has not been included, then we may need to use
307 // the standard library implementations even under Windows
308
309 //this must follow: #include "GSWin.h"
310
311 #ifndef _INC_STRING
312
313 #if _WINDOWS
314 __declspec(dllimport)
315 #endif
316 Sint32 stricmp(const char *a, const char *b);
317 #endif
318
319 #if !_WINDOWS
320 #define strcmpi stricmp
321 #endif
322
323#endif
324
325
326#if !_WINDOWS
327 // use the Debug window externally
328 #if defined(_MINICAD_EXTERNAL_)
329 #define OutputDebugString Debug
330 #else
331 #define OutputDebugString(msg) printf("%s", msg)
332 #endif
333#else
334 extern "C" __declspec(dllimport) void _stdcall DebugBreak(void);
335#endif
336
337
338
340// Setup for "THIS_FILE" macro. Use THIS_FILE instead of __FILE__ to reduce
341// the size of the executable. [DMB]
342
343#if TEST
344 #define DECLARE_THIS_FILE static const char THIS_FILE[] = __FILE__;
345#else
346 #define DECLARE_THIS_FILE
347#endif
348#ifndef THIS_FILE
349 #define THIS_FILE __FILE__
350#endif
351
352
353
355// Use the following macro to print Pascal strings or Rect's in a printf type
356// format string. For example:
357//
358// DMSG((dlAlways, "File name: %.*s\n", PASCALPRINT(filename)));
359// DMSG((dlAlways, "myRect: (%d,%d)-(%d,%d)\n", RECTPRINT(myRect)));
360
361#define PASCALPRINT(pascal_string) \
362 ((ConstGSStringPtr)(pascal_string))[0], &((ConstGSStringPtr)(pascal_string))[1]
363
364#define RECTPRINT(r) \
365 (r).Left(), (r).Top(), (r).Right(), (r).Bottom()
366
367#define TXSTRINGPRINT(txstring) \
368 (const char*)txstring
369
370//---------------------------------------------------------------------------------------
371// --- Debugging
372//
373// TEST is true if either BUG or NETBUG are true.
374// Most general testing code should be in "#ifdef TEST" blocks.
375//
376// Anything which causes a break or writes to the debug window
377// should be in "#ifdef BUG" blocks.
378
379#define DEBUG_DO_NOTHING ((void) 0)
380
381
382// Debug levels.
383enum EDebugLevel { dlAlways, brief, verbose, mongo, dlNever };
384
385
387#if !_WINDOWS
388 // this is really ugly - but it allows our DSTOPs to land us at the right
389 // line even if they take place in an ANSI cross platform file - PCP
390
391 #if !defined(__MACTYPES__)
392 extern "C" void Debugger(void);
393 #endif
394
395 #define Int13BreakMacro { __asm__("int $3\n" : : ); }
396 #define GSBreakToLowLevelDebugger_() Int13BreakMacro
397 #define GSBreakStrToLowLevelDebugger_(s) ::DebugStr(s)
398 #define GSBreakToSourceDebugger_() ::SysBreak()
399 #define GSBreakStrToSourceDebugger_(s) ::SysBreakStr(s)
400#endif
401
402
403
405// This hack allows the Mac to build until this code moves back into GSDebug.h for good
406
407#if !_WINDOWS
408 #define ASSERTNOFPEXCEPTION() DEBUG_DO_NOTHING
409 #define ASSERTFPSTACKVALID() DEBUG_DO_NOTHING
410#endif
411
412
414// The following structure defs are used by externals to communicate back to UCallBacks.cp
415// so that they can assert valid handles and pointers. This structure must be compiled
416// into the same byte offsets by every compiler we use, so beware of tricky changes. - PCP
417//
418// If these are changed, then the current crop of externals built with BUG or TEST
419// will not work with the new MiniCad, so be careful.
420
421#if !_MAGICFOLDER_
422 const short kKludgeSendAssert = 2001;
423 const short kKludgeSendLog = 2002;
424 const short kKludgeValidatePointer = 2003;
425 const short kKludgeValidateHandle = 2004;
426 const short kKludgeCheckHeap = 2005;
427 const short kKludgeCheckPorts = 2006;
428 const short kKludgeValidateString = 2007;
429 const short kKludgeValidatePString = 2008;
430#endif
431
432
434// kCrashTrapConstant
435//
436// kCrashTrapConstant is defined to a value which will likely cause an immediate crash
437// (of some variety) on any platform. It is used in the TEST and BUG versions to flag
438// pointers which are dangerous to use. These pointers should typically be set to nil in
439// the release version, but that decision must be made on a case by case basis, so
440// kCrashTrapConstant is not defined for the release version
441
442// The above statement is no longer true. We should stop using it this pointer value as a trap. [Hugues 11/21/13] X64PRJ_REVISIT
443#if TEST
444 const void* const kCrashTrapConstant = (void*) 0x50ff8001;
445#endif
446
447
449#if TEST
450 struct AssertParameters {
451 char* toWhom;
452 char* description;
453 };
454
455 struct ValidateParameters {
456 Bool8 isAssert;
457 char* toWhom;
458 char* file;
459 Sint32 line;
460 char* itemName;
461 void* thePointerOrHandle;
462 Sint32 expectedSize;
463 Sint32 expectedSize2;
464 };
465
466 // flag values for ValidatePortParameters
467 const Sint32 kAllowWMgrPort = 1L;
468
469 struct ValidatePortParameters {
470 char* message;
471 char* file;
472 Sint32 line;
473 Sint32 flags;
474 };
475#endif // TEST
476
477
479// PORT testing functions
480
481// XXX_JDW_ALTURA CLEANUP [2003-05-28]
482//#if TEST && !_MAGICFOLDER_ && (!_WINDOWS || !defined(_INC_WINDOWS)) && !_GSESDK_ && !GS_INTERFACE_FACTORING && !_WIN_EXTERNAL_
483//#if TEST && !_MAGICFOLDER_ && !_GSESDK_ && !_WIN_EXTERNAL_ && defined(_WINDOWS)
484#if 0
485 // Only do port checking when doing a TEST or BUG build and only when compiling
486 // a Mac/Altura module.
487 // Don't check the ports if GS_INTERFACE_FACTORING because the core shouldn't know
488 // anything about the port in that case.
489 #include <QuickDraw.h>
490 #define DO_PORT_CHECKING 1
491#else
492 #define DO_PORT_CHECKING 0
493#endif
494
495#if DO_PORT_CHECKING
496
497 Bool8 IsValidMacPort(GrafPtr port);
498 #define __ASSERTPORT(toWhom, msg, port) DSTOP((!::IsValidMacPort((GrafPtr)(port)), toWhom, "%s: Invalid port (0x%08x)", (const char*)(msg), (GrafPtr)(port)))
499 #if _WINDOWS
500 #define __ASSERTCURRENTPORT(toWhom, msg) do { GrafPtr curPort; ::GetPort(&curPort); __ASSERTPORT(toWhom, msg, curPort); } while (0)
501 #else
502 #define __ASSERTCURRENTPORT(toWhom, msg) ASSERTLEGALPORTM(msg)
503 #endif
504
505 // The LL versions allow the port to be set to the window manager port without
506 // complaining. They still check to make sure all handles in the window manager
507 // port are in the system heap so we won't crash the system later on. - PCP
508
509 #if _WINDOWS
510 #define ASSERTLEGALPORTM(message) __ASSERTCURRENTPORT(kGrafPortCheck, (message) ? (message) : "ASSERTLEGALPORTM")
511 #define LLASSERTLEGALPORTM(message) __ASSERTCURRENTPORT(kGrafPortCheck, (message) ? (message) : "LLASSERTLEGALPORTM")
512 #else
513 Sint32 _AssertLegalPort(char *message, const char* file, Sint32 line, Bool8 allowWMgrPort);
514
515 #define ASSERTLEGALPORTM(message) ((void)_AssertLegalPort(message, THIS_FILE, __LINE__, false))
516 #define LLASSERTLEGALPORTM(message) ((void)_AssertLegalPort(message, THIS_FILE, __LINE__, true))
517 #endif
518#else
519 #if !_MAGICFOLDER_
520 #define __ASSERTPORT(toWhom, msg, port) DEBUG_DO_NOTHING
521 #define __ASSERTCURRENTPORT(toWhom, msg) DEBUG_DO_NOTHING
522 #define ASSERTLEGALPORTM(message) DEBUG_DO_NOTHING
523 #define LLASSERTLEGALPORTM(message) DEBUG_DO_NOTHING
524 #endif
525#endif // DO_PORT_CHECKING
526
527#if !_MAGICFOLDER_
528 // New port checking functions. [DMB 12/13/96]
529 #define ASSERTPORT(toWhom, port) __ASSERTPORT(toWhom, "ASSERTPORT", port)
530 #define ASSERTCURRENTPORT(toWhom) __ASSERTCURRENTPORT(toWhom, "ASSERTCURRENTPORT")
531
532 // Old port checking functions. DO NOT USE THESE.
533 #define ASSERTLEGALPORT() ASSERTLEGALPORTM(NULL)
534 #define LLASSERTLEGALPORT() LLASSERTLEGALPORTM(NULL)
535#endif
536
537
539// Functions and macros to stop the application. Defines STOP().
540
541#if BUG
542 // Define the method used to break into the debugger,
543 #if _WINDOWS
544 #define DO_STOP() __debugbreak()
545 #else
546 #define DO_STOP() GSBreakToLowLevelDebugger_()
547 #endif
548 #define STOP() do { if (GSDebug::WantToBreak()) DO_STOP(); } while(0)
549#else
550 #define STOP() DEBUG_DO_NOTHING
551#endif // BUG
552
553
555// Functions to change debug library behavior.
556
557#if TEST
558
559 #if _WINDOWS
560 extern "C" Bool8 GSDebug_IsInDebugMessage();
561 // Description:
562 // Determine if a debug dialog is currently being displayed.
563 //
564 // Returns:
565 // BOOL - 'TRUE' if a debug dialog is currently being displayed. 'FALSE' if
566 // no debug dialogs are being displayed.
567 #endif
568
569 namespace GSDebug {
570
571 // Replaces 'iWantToDebug'.
572 bool GSDEBUG_EXPORT WantToDebug();
573 bool GSDEBUG_EXPORT WantToDebug(bool bWantToDebug);
574
575 // Replaces 'debugLevel'.
576 EDebugLevel GSDEBUG_EXPORT DebugLevel();
577 EDebugLevel GSDEBUG_EXPORT DebugLevel(EDebugLevel newDebuglevel);
578
579 // Replaces 'useSourceDebugger'.
580 bool GSDEBUG_EXPORT UseSourceDebugger();
581 bool GSDEBUG_EXPORT UseSourceDebugger(bool bUseSourceDebugger);
582
583 // Replaces 'drawToScreen'.
584 // Choosing drawToScreen disables GWorlds
585 bool GSDEBUG_EXPORT DrawToScreen();
586 bool GSDEBUG_EXPORT DrawToScreen(bool bDrawToScreen);
587
588 // Replaces 'iWantToStop'.
589 // 'true' to stop application on a STOP(), 'false' to keep going.
590 bool GSDEBUG_EXPORT WantToBreak();
591 bool GSDEBUG_EXPORT WantToBreak(bool bWantToBreak);
592
593 // Replace the debug flags.
594 Uint32 GSDEBUG_EXPORT Flags();
595 Uint32 GSDEBUG_EXPORT Flags(Uint32 inNewFlags);
596
597
598 // Flags for TProgrammer IDs.
599 const Uint64 kNoNetDebugFlag = 0x8000000000000000ULL;
600 const Uint64 kNoDebuggerBreakFlag = 0x4000000000000000ULL;
601 const Uint64 kNoDebugWindowFlag = 0x2000000000000000ULL;
602 const Uint64 kNoStackCrawlFlag = 0x1000000000000000ULL;
603 const Uint64 kOnlyIfActiveUserFlag = 0x0800000000000000ULL;
604
605 // Flags for GS_DebugInit( )
606 const Uint32 kNoFlags = 0x00000000UL;
607 const Uint32 kNeverUseDebugWindows = 0x00000001UL;
608
609 } // namespace GSDebug
610#endif // TEST
611
612
614// Functions used by DSTOP implementation. Do not use these.
615
616#if TEST
617 namespace GSDebug {
618 void GSDEBUG_EXPORT SetDStopFileName(ConstGSCStrPtr szFileName);
619 void GSDEBUG_EXPORT SetDStopLineNumber(Sint32 nLineNumber);
620 } // namespace GSDebug
621#endif
622
623#if NETBUG
624 // Implementation functions. Do not call these directly.
625 #if !_MINICAD_EXTERNAL_
626 void InitRemoteDebug(void);
627 void KillRemoteDebug(void);
628 void LogVersionStamp(void);
629 #endif
630 class GSDEBUG_EXPORT TProgrammer;
631 void GSDEBUG_EXPORT RemoteDebug(const TProgrammer& toWhom, const char *description);
632 void GSDEBUG_EXPORT RemoteDebug(const char *toWhom, const char *description, Bool8 doStackCrawl=true);
633 void GSDEBUG_EXPORT RemoteLog(Uint16 level, const char *description);
634 Sint32 GSDEBUG_EXPORT _Log(Uint16 level, const char *format, ...); // For internal use by LOG macro.
635#endif
636
638// TProgrammer class
639
640#if TEST
641
642const short kDebugStringLength = 50;
643
644#define kEveryoneConst 0x0FFFFFFFFFFFFFFFULL // This filters the most significant bits
645#define kEveryoneConstLSB 0xFFFFFFFFFFFFFFFFULL // This filters the lesser significant bits
646#define kProgrammerMask 0x0FFFFFFFFFFFFFFFULL // this filters the most significant bits
647#define kProgrammerMask 0x0FFFFFFFFFFFFFFFULL // this filters the most significant bits
648#define kProgrammerMaskLSB 0xFFFFFFFFFFFFFFFFULL // this filters the most significant bits
649#define kOptionBitsMask (~kProgrammerMask)
650
651class GSDEBUG_EXPORT TProgrammer
652{
653 public:
654 TProgrammer() { Set("Unnamed", 0, 0, true); }
655
656 TProgrammer(const char *name, Uint64 id2, Uint64 id1, bool sendOwn=true) { Register(name, id2, id1); Set(name, id2, id1, sendOwn); }
657 TProgrammer(const TProgrammer& a) { Set(a.fName, a.fID2, a.fID1, a.fSendOnOwn); }
658
659 const char *GetName() const { return fName; }
660 Uint64 GetID2(bool filter=false) const { return filter ? (fID2 & kEveryoneConst) : fID2; }
661 Uint64 GetID1() const { return fID1; }
662
663 bool IsEveryone() const { return (fID1 & kEveryoneConstLSB) == kEveryoneConstLSB && (fID2 & kEveryoneConst) == kEveryoneConst; }
664 bool IsActLikeRelease() const { return (fID1 & kProgrammerMaskLSB) == 0 && (fID2 & kProgrammerMask) == 0;}
665
666 bool LogOnOwn() const;
667 bool ShouldBreak() const { return !IsActLikeRelease() && !IsNoBreakBitSet(); }
668 bool ShouldNetDebug() const { return !IsActLikeRelease() && !IsNoNetDebugBitSet(); }
669 bool ShouldShowWindow() const { return !IsActLikeRelease() && !IsNoWindowBitSet(); }
670 bool ShouldDoStackCrawl() const { return !IsNoStackCrawlBitSet(); }
671
672 TProgrammer operator &(const TProgrammer& a) const;
673 TProgrammer operator |(const TProgrammer& a) const { return this->operator &(a); }
674
675 operator const char *() const { return GetName(); }
676
677 bool operator ==(const TProgrammer& a) const { return MatchExact(a); }
678 bool operator !=(const TProgrammer& a) const { return !MatchExact(a); }
679 bool operator ==(const char *sz) const { return _strcmpi(sz, fName)!=0; }
680 bool MatchExact(const TProgrammer& a) const { return fID2 == a.fID2 && fID1 == a.fID1; }
681 bool IsIn(const TProgrammer& a) const { return IsIn(a.fID2, a.fID1); }
682
683 // Return true if this "is in" the passed id pair -- which could be a single programmer or a group.
684 bool IsIn(Uint64 id2, Uint64 id1) const;
685
686 bool ContainsCurrentUser() const;
687
688 static bool GetProgrammerName(Uint64 id2, Uint64 id1, char *name);
689 static bool ExtractProgrammer(TProgrammer &who, TProgrammer &one);
690
691 bool IsNoNetDebugBitSet() const { return (fID2 & GSDebug::kNoNetDebugFlag) != 0; }
692 bool IsNoBreakBitSet() const { return (fID2 & GSDebug::kNoDebuggerBreakFlag) != 0; }
693 bool IsNoWindowBitSet() const { return (fID2 & GSDebug::kNoDebugWindowFlag) != 0; }
694 bool IsNoStackCrawlBitSet() const { return (fID2 & GSDebug::kNoStackCrawlFlag) != 0; }
695 bool IsOnlyIfActiveUserBitSet() const { return (fID2 & GSDebug::kOnlyIfActiveUserFlag) != 0; }
696
697 protected:
698 void Set(const char *name, Uint64 id2, Uint64 id1, bool sendOwn) { strncpy(fName, name, kDebugStringLength-1); fID2 = id2; fID1 = id1; fSendOnOwn = sendOwn; }
699
700 private:
701
702 class GSDEBUG_EXPORT TRegistered
703 {
704 public:
705 TRegistered() { fID2 = 0; fID1 = 0; fName[0] = 0; }
706 char fName[kDebugStringLength];
707 Uint64 fID2, fID1;
708 };
709 static void Register(const char *name, Uint64 id2, Uint64 id1);
710 static const Sint32 fMaxProgrammers;
711 static TRegistered fRegistered[];
712
713 char fName[kDebugStringLength];
714 Uint64 fID2, fID1; // Values in significance - so fID2 is higher significant bits than fID1.
715 bool fSendOnOwn;
716 };
717
718#else
719
720 #define TProgrammer Sint32
721
722#endif // TEST
723
724
725#if BUG && !defined(_MINICAD_EXTERNAL_)
726void InitBugMem();
727#endif
728
729
731#if TEST && !defined(_MINICAD_EXTERNAL_)
732 // Implementation functions. Do not call these directly, use the macros.
733 GSDEBUG_EXPORT void GDB_DebugInit (const char* appName, Uint32 flags);
734 GSDEBUG_EXPORT void GDB_DebugTerminate();
735 #if defined(_INC_WINDOWS)
736 extern "C" GSDEBUG_EXPORT void GDB_DebugSetExeHandle(HINSTANCE hInst);
737 extern "C" GSDEBUG_EXPORT void GDB_SetDebugMessageParentWindow(HWND hParentWnd);
738 #endif
739
740 void PerformLaunchAsserts(void);
741
742 // Call DEBUG_INIT() to initialize the GSDebug library. For flags, see GSDebug namespace.
743 #define DEBUG_INIT(appName, flags) ::GDB_DebugInit(appName, flags)
744
745 #if defined(_INC_WINDOWS)
746 // Set the handle of the executable being run.
747 #define DEBUG_SETEXE(hInst) ::GDB_DebugSetExeHandle(hInst)
748
749 // Set the parent window for the next dialog that the debug system displays.
750 #define DEBUG_SETPARENTWINDOW(hParentWnd) ::GDB_SetDebugMessageParentWindow(hParentWnd)
751 #else
752 #define DEBUG_SETEXE(hInst) DEBUG_DO_NOTHING
753 #endif
754
755 // Call DEBUG_TERMINATE to shut down the GSDebug library.
756 #define DEBUG_TERMINATE() ::GDB_DebugTerminate()
757
758#endif
759
760
762#if TEST
763 #define MAKEWHO(name) TProgrammer(name, kEveryoneConst, kEveryoneConstLSB, true)
764 #define DECLAREWHO(var, name) TProgrammer var(name, kEveryoneConst, kEveryoneConstLSB, true)
765 #define TEST_ONLY(x) x
766#else
767 #define MAKEWHO(name) 0
768 #define DECLAREWHO(var, name) TProgrammer var
769 #define TEST_ONLY(x)
770#endif // TEST
771
772#if BUG
773 #define BUG_ONLY(x) x
774#else
775 #define BUG_ONLY(x)
776#endif
777
778#if TEST
779
780#if BUG
781 #if 1 || _MINICAD_EXTERNAL_ || _MAGICFOLDER_ || _GSESDK_ || _GSWINSDK_
782 inline void LIMITMESSAGES(const TProgrammer &) { }
783 inline void LIMITMESSAGES(const EDebugLevel &) { }
784 inline void LIMITMESSAGES(const TProgrammer &, const EDebugLevel &) { }
785 inline void LIMITMESSAGES(const EDebugLevel &, const TProgrammer &) { }
786 inline void LIMITMESSAGES() { }
787 #else
788 extern TProgrammer gProgrammerFilter;
789
790 inline void LIMITMESSAGES(const TProgrammer &who) { gProgrammerFilter = who; }
791 inline void LIMITMESSAGES(const EDebugLevel &level) { debugLevel = level; }
792 inline void LIMITMESSAGES(const TProgrammer &who, const EDebugLevel &level) { LIMITMESSAGES(who); LIMITMESSAGES(level); }
793 inline void LIMITMESSAGES(const EDebugLevel &level, const TProgrammer &who) { LIMITMESSAGES(who, level); }
794 inline void LIMITMESSAGES() { LIMITMESSAGES(kEveryone, brief); }
795 #endif
796#endif // BUG
797
798
799/*
800The following routines and macros are hooked into the network debugging system. You will receive a file
801describing when these breaks occur on any Graphsoft Macintosh machine (Engineering, Tech Support, etc.).
802*/
803
804Sint32 GSDEBUG_EXPORT _FileDebugMessage(const TProgrammer& toWhom, const char *file, Sint32 line, const char *message);
805Sint32 GSDEBUG_EXPORT _Assert(const TProgrammer& toWhom, const char *file, Sint32 line, const char *expr);
806Sint32 GSDEBUG_EXPORT _AssertEx(const TProgrammer & inProgrammer, const char * inAssertFile, Sint32 inAssertLine, const char * inMessage, ...);
807
808 // For internal use by ASSERT macro only.
809
810#if !_WINDOWS
811
812 enum {
813 kNoBlock = 0,
814 kHandle = 1,
815 kPointer = 2,
816 kFree = 3
817 };
818
819 short _FindContainingBlock(const TProgrammer& toWhom, void* ptr, Sint32& result);
820
821 Sint32 _AssertNotVolatile(const TProgrammer& toWhom, const char* file, Sint32 line, const char* ptrName, void* ptr);
822 // For internal use by ASSERTNOTVOLATILE macro only.
823
824#endif // !_WINDOWS
825
826void GSDEBUG_EXPORT CheckHeap(const TProgrammer &toWhom = kEveryone);
827 // checks the heap for a number of problems - hooked into the new memory system - checks fragmentation
828 // this may be called at any time memory operations are legal - it can take a while with full heaps
829 // this is primarily called from the main event loop - you should probably not need to call it
830
831
832
833Sint32 GSDEBUG_EXPORT _AssertValidPointer(const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, const void *ptr, size_t lByteCount=1, Bool8 bReadOnly=false);
834Bool8 GSDEBUG_EXPORT _VerifyValidPointer(const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, const void *ptr, size_t lCount=1, Bool8 bReadOnly=false);
835Sint32 GSDEBUG_EXPORT _AssertValidString(Bool8 isAssert, const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, const char *psz, Sint32 cbMin=0, Sint32 cbMax=0);
836Sint32 GSDEBUG_EXPORT _AssertValidHandle(const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, GSHandle h, size_t lCount=1);
837Sint32 GSDEBUG_EXPORT _AssertValidMenuHandle(const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, GSHandle h);
838Bool8 GSDEBUG_EXPORT _VerifyValidHandle(const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, GSHandle h, size_t lCount=1);
839Sint32 GSDEBUG_EXPORT _AssertValidPString(Bool8 isAssert, const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, ConstGSStringPtr ps, Sint32 cbMin=0, Sint32 cbMax=0);
840
841
842
843#if defined(_INC_WINDOWS) || defined(_GSWIN_) || GS_HWND_CHECK
844 extern "C" {
845 bool GSDEBUG_EXPORT _ValidateHWND(const TProgrammer& toWhom, bool bAssert, const char* file, Sint32 line, const char* itemName, void *hWnd);
846 bool GSDEBUG_EXPORT _ValidateHDC(const TProgrammer& toWhom, bool bAssert, const char* file, Sint32 line, const char* itemName, void *hdc);
847
848 // *PCP* - we may want to move this back from the structured exceptions file
849 //void GSDEBUG_EXPORT ForceFPException_( void );
850 }
851#endif
852
853
854
855/* Debugging macros. All of these may be used without #ifdef BUG...#endif. */
856
857//
858// ASSERTs
859//
860
861inline Bool8 VerifyStop(Bool8 b) { STOP(); return b; } // Special function since one can not put an "_asm" instruction in the middle of a "?:" expression. [DMB, 11/30/94]
862#if _WINDOWS
863// These are the Windows ASSERT macros.
864 #define ASSERTN(toWhom, exp) \
865 do { \
866 if (!(exp) && _Assert(toWhom, THIS_FILE, __LINE__, #exp)) STOP(); \
867 } while (0)
868
869 #define ASSERTLOCKED(toWhom, h) do {;} while (0)
870 #define ASSERTUNLOCKED(toWhom, h) do {;} while (0)
871 #define ASSERTNOTVOLATILE(toWhom, p) do {;} while (0)
872 #define ASSERTHANDLE(toWhom, h, bytes) do {;} while (0)
873 #define ASSERTPSTRING(toWhom, ps, min, max) do {;} while (0)
874 #define VERIFYN(toWhom, exp) \
875 ((Bool8)( (exp) ? true : (_Assert(toWhom, THIS_FILE, __LINE__, #exp) ? VerifyStop(false) : false ) ))
876
877 #define VERIFYMSG(toWhom, exp, failMsg, ...) \
878 ((Bool8)( (exp) ? true : (_AssertEx(toWhom, THIS_FILE, __LINE__, failMsg, __VA_ARGS__) ? VerifyStop(false) : false ) ))
879
880 #define ASSERTPOINTER_READONLY(toWhom, ptr, bytes) do {;} while (0)
881 #define ASSERTPOINTER(toWhom, ptr, bytes) do {;} while (0)
882 #define ASSERTSTRING(toWhom, psz, min, max) \
883 do { \
884 if (_AssertValidString(true,toWhom,THIS_FILE,__LINE__,#psz,(const char *)psz,min,max)) STOP(); \
885 } while (0)
886
887 #if GS_HWND_CHECK
888
889 #define ASSERTHWND(toWhom, hWnd) \
890 do { \
891 if (!_ValidateHWND(toWhom,true,THIS_FILE,__LINE__,#hWnd,hWnd)) STOP(); \
892 } while (0)
893 #define VERIFYHWND(toWhom, hWnd) \
894 ( _ValidateHWND(toWhom,FALSE,THIS_FILE,__LINE__,#hWnd,hWnd) ? true : false )
895 #define ASSERTHDC(toWhom, hdc) \
896 do { \
897 if (!_ValidateHDC(toWhom,true,THIS_FILE,__LINE__,#hdc,hdc)) STOP(); \
898 } while (0)
899 #define VERIFYHDC(toWhom, hdc) \
900 ( _ValidateHDC(toWhom,FALSE,THIS_FILE,__LINE__,#hdc,hdc) ? true : false )
901 #endif
902
903
904#if 0
905 #define ASSERTNOFPEXCEPTION() \
906 ForceFPException_()
907#endif
908
909#else // !_WINDOWS
910
911// These are the Mac ASSERT macros.
912
913 #define ASSERTN(toWhom, expression) \
914 do { \
915 if (!(expression) && _Assert(toWhom, THIS_FILE, __LINE__, #expression)) STOP(); \
916 } while (0)
917
918
919 #define VERIFYN(toWhom, exp) \
920 ((Bool8)( (exp) ? true : (_Assert(toWhom, THIS_FILE, __LINE__, #exp) ? VerifyStop(false) : false ) ))
921
922 #define VERIFYMSG(toWhom, exp, failMsg, ...) \
923 ((Bool8)( (exp) ? true : (_AssertEx(toWhom, THIS_FILE, __LINE__, failMsg, ##__VA_ARGS__) ? VerifyStop(false) : false ) ))
924
925 #define ASSERTSTRING(toWhom, psz, min, max) \
926 ((void)_AssertValidString(true,toWhom,THIS_FILE,__LINE__,#psz,(const char *)psz,min,max))
927
928 #define ASSERTPOINTER(toWhom, ptr, bytes) \
929 ((void)_AssertValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes))
930
931 #define ASSERTPOINTER_READONLY(toWhom, ptr, bytes) ASSERTPOINTER(toWhom, ptr, bytes)
932
933 Bool8 __IsHandleLocked(GSHandle h);
934
935// #define ASSERTLOCKED(toWhom,h)
936// ( h?(__IsHandleLocked((GSHandle)h) ? (void)0 : (void)_Assert(toWhom,THIS_FILE,__LINE__,"\"" #h " locked\"")) : (void)0 )
937// #define ASSERTUNLOCKED(toWhom,h)
938// ( h?(__IsHandleLocked((GSHandle)h) ? (void)_Assert(toWhom,THIS_FILE,__LINE__,"\"" #h " unlocked\"") : (void)0) : (void)0 )
939
940 // The concept of locked/unlocked handles no longer exists
941 #define ASSERTLOCKED(toWhom,h) ((void) 0)
942 #define ASSERTUNLOCKED(toWhom,h) ((void) 0)
943
944 #define ASSERTNOTVOLATILE(toWhom, p) \
945 ( ((void)_AssertNotVolatile(toWhom, THIS_FILE, __LINE__, #p, p)) )
946 #define ASSERTHANDLE(toWhom, h, bytes) \
947 ((void)_AssertValidHandle(toWhom,THIS_FILE,__LINE__,#h,(GSHandle)h,bytes))
948
949 #define ASSERTPSTRING(toWhom, ps, min, max) \
950 ((void)_AssertValidPString(true,toWhom,THIS_FILE,__LINE__,#ps,(const BugStringPtr)ps,min,max))
951
952 #if GS_HWND_CHECK
953 #define ASSERTHWND(toWho, hWnd) \
954 DEBUG_DO_NOTHING
955 #define VERIFYHWND(toWho, hWnd) \
956 (FALSE)
957 #endif
958
959#if 0
960 #define ASSERTNOFPEXCEPTION() \
961 DEBUG_DO_NOTHING
962#endif
963
964#endif // _WINDOWS
965
966
967// these apply to both Mac and Win versions
968
969
970#define VERIFYHANDLE(toWhom, h, bytes) \
971 ::_VerifyValidHandle(toWhom,THIS_FILE,__LINE__,#h,(GSHandle)h,bytes)
972
973#define ASSERTHEAP(toWhom) \
974 ::CheckHeap(toWhom)
975
976#define VERIFYPOINTER(toWhom, ptr, bytes) \
977 ::_VerifyValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes,false)
978
979#define VERIFYPOINTER_READONLY(toWhom, ptr, bytes) \
980 ::_VerifyValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes,true)
981
982#define VERIFYSTRING(toWhom, psz, min, max) \
983 ::_AssertValidString(false,toWhom,THIS_FILE,__LINE__,#psz,(const char*)psz,min,max)
984
985#define VERIFYPSTRING(toWhom, ps, min, max) \
986 ::_AssertValidPString(false,toWhom,THIS_FILE,__LINE__,#ps,(const BugStringPtr)ps,min,max)
987
988#define ASSERTMENUHANDLE(toWhom, menu) \
989 ::_AssertValidMenuHandle(toWhom,THIS_FILE,__LINE__,#menu,(GSHandle)menu)
990
991
993// DSTOP
994extern std::atomic_flag gDSTOPLock;
995
996#define DSTOP(params) do { \
997 if ( ! gDSTOPLock.test_and_set()) { \
998 GSDebug::SetDStopFileName(THIS_FILE); \
999 GSDebug::SetDStopLineNumber(__LINE__); \
1000 if (::__DebugMessageStop params) STOP(); \
1001 GSDebug::SetDStopLineNumber(-1); \
1002 gDSTOPLock.clear(); \
1003 } \
1004 } while(0)
1005
1006
1007
1008#define GS_REMOVE_CONDITIONAL_DebugMessageStop 1
1009
1010#if GS_REMOVE_CONDITIONAL_DebugMessageStop
1011#define DSTOPIF(condition, params) if (condition) DSTOP(params);
1012#else
1013#define DSTOPIF(condition, params) DEBUG_DO_NOTHING
1014#endif
1015
1016// DSTOP implementation functions.
1017Bool8 GSDEBUG_EXPORT __DebugMessageStop(const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
1018Bool8 GSDEBUG_EXPORT __DebugMessageStop(EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
1019Bool8 GSDEBUG_EXPORT __DebugMessageStop(EDebugLevel level, const char *szFmt, ...);
1020Bool8 GSDEBUG_EXPORT __DebugMessageStop(const TProgrammer& toWhom, const char *szFmt, ...);
1021//
1022#if ! GS_REMOVE_CONDITIONAL_DebugMessageStop
1023Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
1024Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
1025Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, EDebugLevel level, const char *szFmt, ...);
1026Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, const TProgrammer& toWhom, const char *szFmt, ...);
1027Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, const char *szFmt, ...);
1028#endif
1030
1031#define INLINE
1032
1033
1034#endif // TEST
1035
1036
1037#ifdef BUG
1038
1039//
1040// DMSG
1041//
1042#define DMSG(params) ::__DebugMessage params
1043//
1044
1045
1046#define DMSGIF(condition, params) if (condition) DMSG(params);
1047
1048// the modern behavior is to require a TProgrammer attached to all debug calls
1049#if !GS_USE_ONLY_MODERN || GS_GSDEBUG_BUILD
1050void GSDEBUG_EXPORT __DebugMessage(EDebugLevel level, const char *szFmt, ...);
1051void GSDEBUG_EXPORT __DebugMessage(const char *szFmt, ...);
1052#if ! GS_REMOVE_CONDITIONAL_DebugMessageStop
1053void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, EDebugLevel level, const char *szFmt, ...);
1054void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, const char *szFmt, ...);
1055#endif
1056#endif
1057void GSDEBUG_EXPORT __DebugMessage(const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
1058void GSDEBUG_EXPORT __DebugMessage(EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
1059void GSDEBUG_EXPORT __DebugMessage(const TProgrammer& toWhom, const char *szFmt, ...);
1060#if ! GS_REMOVE_CONDITIONAL_DebugMessageStop
1061void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
1062void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
1063void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, const TProgrammer& toWhom, const char *szFmt, ...);
1064#endif
1065#endif // ifdef BUG
1066
1067// New class debugging stuff.
1068
1069#if GS_USE_CLASS_DEBUGGING
1070#ifdef BUG
1071 class GSDEBUG_EXPORT TDumpDevice
1072 {
1073 public:
1074 TDumpDevice();
1075
1076
1077 virtual ~TDumpDevice() {}
1078
1079 Sint32 printf(const TProgrammer &toWhom, Sint32 indent, const char *fmt, ...) const;
1080 Sint32 printf(const char *fmt, ...) const;
1081
1082 void SetIndent(Sint32 indent) { fIndent = indent; }
1083 void SetWho(const TProgrammer &toWhom) { fWho = toWhom; }
1084
1085 protected:
1086 virtual Sint32 vprintf(const TProgrammer &toWhom, Sint32 indent, const char *fmt, va_list &params) const = 0;
1087
1088 Sint32 fIndent;
1089 TProgrammer fWho;
1090 };
1091
1092 class GSDEBUG_EXPORT TTextDumpDevice : public TDumpDevice
1093 {
1094 public:
1095 virtual ~TTextDumpDevice() {}
1096 protected:
1097 Sint32 vprintf(const TProgrammer &toWhom, Sint32 indent, const char *fmt, va_list &params) const;
1098 };
1099
1100 extern TTextDumpDevice gl_stdDumpDevice;
1101
1102 #define DUMPCLASS(toWhom, ptr) (ptr)->Dump(toWhom, gl_stdDumpDevice, 0)
1103#else
1104 #define DUMPCLASS(toWhom, ptr) DEBUG_DO_NOTHING
1105#endif
1106#define DUMPCLASSH(toWhom, hType, h) DUMPCLASS(toWhom, *(hType)(h))
1107#define DUMPCLASSHANDLE(toWhom, h) DUMPCLASS(toWhom, *(h))
1108#define DUMPTHISCLASS(toWhom) DUMPCLASS(toWhom, this)
1109
1110#ifdef TEST
1111 #define ASSERTCLASS(toWhom, ptr) (ptr)->AssertValid(toWhom, true)
1112 #define VERIFYCLASS(toWhom, ptr) ( (ptr) ? ((ptr)->AssertValid(toWhom, true), true) : VerifyStop(false))
1113#else
1114 #define ASSERTCLASS(toWhom, ptr) DEBUG_DO_NOTHING
1115 #define VERIFYCLASS(toWhom, ptr) ((ptr) != nil)
1116#endif
1117#define ASSERTCLASSH(toWhom, type, h) ASSERTCLASSHANDLE(toWhom, (type)(h))
1118#define ASSERTCLASSHANDLE(toWhom, h) do { if (VERIFYHANDLE(toWhom, h, 0)) ASSERTCLASS(toWhom, *(h)); } while (0)
1119#define ASSERTTHISCLASS(toWhom) ASSERTCLASS(toWhom, this)
1120#define VERIFYCLASSH(toWhom, type, h) VERIFYCLASSHANDLE(toWhom, (type)(h))
1121#define VERIFYCLASSHANDLE(toWhom, h) (VERIFYHANDLE(toWhom, h, 0) ? VERIFYCLASS(toWhom, *(h)) : 0)
1122#define VERIFYTHISCLASS(toWhom) VERIFYCLASS(toWhom, this)
1123
1124#ifdef TEST
1125 #define DECLARE_ASSERTVALID \
1126 void AssertValid(const TProgrammer &toWhom, Bool8 bCheckMem) const;
1127 #define DECLARE_VIRTUAL_ASSERTVALID \
1128 virtual DECLARE_ASSERTVALID
1129 #define IMPLEMENT_ASSERTVALID(av_classname, av_parentclass, av_checks) \
1130 void av_classname::AssertValid(const TProgrammer &toWhom, Bool8 bCheckMem) const \
1131 { \
1132 if (bCheckMem) ASSERTPOINTER(toWhom, this, sizeof(av_classname)); \
1133 av_parentclass::AssertValid(toWhom, false); \
1134 av_checks \
1135 }
1136#else
1137 #define DECLARE_ASSERTVALID
1138 #define DECLARE_VIRTUAL_ASSERTVALID
1139 #define IMPLEMENT_ASSERTVALID(av_classname, av_parentclass, av_checks)
1140#endif
1141
1142#if BUG
1143 #define DECLARE_DUMP \
1144 void Dump(const TProgrammer &toWhom, TDumpDevice &dd, Sint32 indent) const;
1145 #define DECLARE_VIRTUAL_DUMP \
1146 virtual DECLARE_DUMP
1147 #define IMPLEMENT_DUMP(d_classname, d_parentclass, d_checks) \
1148 void d_classname::Dump(const TProgrammer &toWhom, TDumpDevice &dd, Sint32 indent) const \
1149 { \
1150 if (_IsUser(toWhom)) { \
1151 d_parentclass::Dump(toWhom, dd, indent); \
1152 dd.printf(toWhom, indent, #d_classname " class:\n"); \
1153 ++indent; \
1154 d_checks \
1155 } \
1156 }
1157#else
1158 #define DECLARE_DUMP
1159 #define DECLARE_VIRTUAL_DUMP
1160 #define IMPLEMENT_DUMP(d_classname, d_parentclass, d_checks)
1161#endif
1162
1163#if 1
1164// Use the following macros to dump individual class members.
1165#define DUMP_BOOL(dp) \
1166 dd.printf(toWhom, indent, #dp " = %s (%d)\n", (dp) ? "true" : "false", (Sint32)(dp))
1167#define DUMP_CHAR(dp) \
1168 DUMP_ITEM("%c", dp)
1169#define DUMP_CLASS(dp) \
1170 do { \
1171 dd.printf(toWhom, indent, #dp " =\n"); \
1172 (dp).Dump(toWhom, dd, indent+1); \
1173 } while (0)
1174#define DUMP_CLASSHANDLE(dp) \
1175 do { \
1176 if (dp) DUMP_CLASSPTR(*dp); \
1177 else DUMP_NULL(dp); \
1178 } while (0)
1179#define DUMP_CLASSPTR(dp) \
1180 do { \
1181 if (dp) DUMP_CLASS(*dp); \
1182 else DUMP_NULL(dp); \
1183 } while (0)
1184#define DUMP_DOUBLE(dp) \
1185 DUMP_ITEM("%f", dp)
1186#define DUMP_HANDLE(dp) \
1187 do { \
1188 if (dp && *dp) dd.printf(toWhom, indent, #dp " = 0x%p, *" #dp " = 0x%p\n", dp, *dp); \
1189 else if (dp) dd.printf(toWhom, indent, #dp " = 0x%p, *" #dp " = NULL\n", dp); \
1190 else DUMP_NULL(dp); \
1191 } while (0)
1192#define DUMP_INT(dp) \
1193 DUMP_ITEM("%d", dp)
1194#define DUMP_ITEM(fmt, dp) \
1195 dd.printf(toWhom, indent, #dp " = " fmt "\n", dp)
1196#define DUMP_MSG(msg) \
1197 do { \
1198 dd.SetIndent(indent); \
1199 dd.SetWho(toWhom); \
1200 dd.printf msg; \
1201 } while (0)
1202#define DUMP_NULL(dp) \
1203 dd.printf(toWhom, indent, #dp " = NULL\n")
1204#define DUMP_PSTR(dp) \
1205 do { \
1206 if ((const unsigned char*)(dp)) dd.printf(toWhom, indent, #dp " = len:%d, \"%s\"\n", strlen(dp), TXSTRINGPRINT(dp)); \
1207 else DUMP_NULL(dp); \
1208 } while (0)
1209#define DUMP_PTR(dp) \
1210 do { \
1211 if (dp) DUMP_ITEM("0x%p", dp); \
1212 else DUMP_NULL(dp); \
1213 } while (0)
1214#define DUMP_RECT(dp) \
1215 dd.printf(toWhom, indent, #dp " = (%d,%d)-(%d,%d)\n", RECTPRINT(dp))
1216#define DUMP_STR(dp) \
1217 do { \
1218 if ((const char*)(dp)) dd.printf(toWhom, indent, #dp " = len:%d, \"%s\"\n", strlen(dp), TXSTRINGPRINT(dp)); \
1219 else DUMP_NULL(dp); \
1220 } while (0)
1221#endif // !_MINICAD_EXTERNAL_
1222
1223
1224#define DECLARE_SIZEOF \
1225 size_t SizeOf() const;
1226#define IMPLEMENT_SIZEOF(classname) \
1227 size_t classname::SizeOf() const
1228#define DECLIMP_SIZEOF(classname) \
1229 size_t SizeOf() const { return sizeof(classname); }
1230
1231
1232#else
1233
1234#define DECLARE_ASSERTVALID
1235#define DECLARE_VIRTUAL_ASSERTVALID
1236#define IMPLEMENT_ASSERTVALID(av_classname, av_parentclass, av_checks)
1237
1238#define DECLARE_DUMP
1239#define DECLARE_VIRTUAL_DUMP
1240#define IMPLEMENT_DUMP(d_classname, d_parentclass, d_checks)
1241
1242
1243#endif // GS_USE_CLASS_DEBUGGING
1244
1245
1246#define DECLARE_CLASS_DEBUGGING \
1247 DECLARE_ASSERTVALID \
1248 DECLARE_DUMP
1249
1250#define DECLARE_VIRTUAL_CLASS_DEBUGGING \
1251 DECLARE_VIRTUAL_ASSERTVALID \
1252 DECLARE_VIRTUAL_DUMP
1253
1254//---------------------------------------------------------------------------------------
1255class GSDEBUG_EXPORT TDebugObject
1256// This object is not allowed to have ANY member variables. sizeof(TDebugObject) == 0
1257{
1258 public:
1259 #if TEST
1260 void AssertValid(const TProgrammer &toWhom, Bool8 bCheckMem) const;
1261 #endif
1262 DECLARE_DUMP
1263};
1264
1265//---------------------------------------------------------------------------------------
1266class GSDEBUG_EXPORT TVirtualDebugObject
1267{
1268 public:
1269 virtual ~TVirtualDebugObject() {}
1270 DECLARE_VIRTUAL_CLASS_DEBUGGING
1271};
1272
1273
1274#if _WINDOWS
1276// Use the following class to get the message for GetLastError() return code.
1277// Created by Lewis Kapell on 10/30/98.
1278
1279class GSDEBUG_EXPORT TWinErrorCode
1280{
1281 public:
1282 TWinErrorCode();
1283 ~TWinErrorCode();
1284
1285 operator const char *() const { return (const char *)fMessageBuffer; }
1286
1287 private:
1288 void *fMessageBuffer;
1289};
1290#endif // _WINDOWS
1291
1292
1294#if _WINDOWS && TEST
1295
1296 Sint32 GSDEBUG_EXPORT _AssertValidFilePath(Bool8 isAssert, const TProgrammer& toWhom, const char* file, Sint32 line, const char* itemName, const char* fullPath);
1297
1298 #define ASSERTPATH(who, fullPath) \
1299 do { \
1300 if (::_AssertValidFilePath(true, who, THIS_FILE, __LINE__, #fullPath, fullPath)) STOP(); \
1301 } while (0)
1302
1303 #define VERIFYPATH(who, fullPath) \
1304 ::_AssertValidFilePath(false, who, THIS_FILE, __LINE__, #fullPath, fullPath)
1305
1306#else
1307
1308 #define ASSERTPATH(who, fullPath) DEBUG_DO_NOTHING
1309 #define VERIFYPATH(who, fullPath) ((BOOL)( (fullPath) != 0 ))
1310
1311#endif // _MAGICFOLDER_ && TEST
1312
1313
1314// Put anything in this block which should not be defined in the test version,
1315// or the final version, but is defined in the bug version
1316
1317#if !defined(BUG)
1318 #define DMSG(params) DEBUG_DO_NOTHING
1319
1320 inline void LIMITMESSAGES(const TProgrammer &) {}
1321 inline void LIMITMESSAGES(const EDebugLevel &) {}
1322 inline void LIMITMESSAGES(const TProgrammer &, const EDebugLevel &) {}
1323 inline void LIMITMESSAGES(const EDebugLevel &, const TProgrammer &) {}
1324 inline void LIMITMESSAGES() {}
1325
1326#endif // !BUG
1327
1328// Common expression shorthand
1329#define for_i(size) for( size_t i=0; i<size; i++ )
1330#define for_j(size) for( size_t j=0; j<size; j++ )
1331#define for_k(size) for( size_t k=0; k<size; k++ )
1332#define for_m(size) for( size_t m=0; m<size; m++ )
1333
1334#define for_it( container ) for( auto it = (container).begin(); it != (container).end(); ++it )
1335#define for_jt( container ) for( auto jt = (container).begin(); jt != (container).end(); ++jt )
1336#define for_kt( container ) for( auto kt = (container).begin(); kt != (container).end(); ++kt )
1337#define for_mt( container ) for( auto mt = (container).begin(); mt != (container).end(); ++mt )
1338
1339// TDebugFile is used to aid in debugging. The possibilities are endless...
1340// Example
1341// original code:
1342// void f(int i)
1343// {
1344// if( g() )
1345// DoStuff(i);
1346// }
1347//
1348// debugging enhanced code:
1349// void f()
1350// {
1351// if( TDebugFile::GetBool("AlwaysCallDoStuff") )
1352// DoStuff( (TDebugFile::GetBool("use_i") ? i : TDebugFile::GetInt("i"));
1353// else if( g() )
1354// DoStuff(i);
1355// }
1356//
1357// with /a/debug.txt having the following contents:
1358// AlwaysCallDoStuff = true
1359// use_i = true
1360// i = 4
1361//
1362class TDebugFile
1363{
1364public:
1365
1366 TDebugFile()
1367 {
1368 }
1369
1370 static std::string GetString(const std::string & inKey)
1371 {
1372 TDebugFile & db = GetInstance();
1373
1374 db.Reload();
1375 return db.fData[inKey];
1376 }
1377
1378 static int GetInt(const std::string & inKey)
1379 {
1380 TDebugFile & db = GetInstance();
1381
1382 db.Reload();
1383 try
1384 {
1385 auto it = db.fData.find(inKey);
1386 if( it != db.fData.end() )
1387 return std::stoi(it->second);
1388 }
1389 catch( ... )
1390 {
1391 }
1392
1393 return 0;
1394 }
1395
1396 static float GetFloat(const std::string & inKey)
1397 {
1398 TDebugFile & db = GetInstance();
1399
1400 db.Reload();
1401 try
1402 {
1403 auto it = db.fData.find(inKey);
1404 if( it != db.fData.end() )
1405 return std::stof(it->second);
1406 }
1407 catch( ... )
1408 {
1409 }
1410
1411 return 0.0f;
1412 }
1413
1414 static double GetDouble(const std::string & inKey)
1415 {
1416 TDebugFile & db = GetInstance();
1417
1418 db.Reload();
1419 try
1420 {
1421 auto it = db.fData.find(inKey);
1422 if( it != db.fData.end() )
1423 return std::stod(it->second);
1424 }
1425 catch( ... )
1426 {
1427 }
1428
1429 return 0.0;
1430 }
1431
1432 static bool GetBool(const std::string & inKey)
1433 {
1434 TDebugFile & db = GetInstance();
1435
1436 db.Reload();
1437
1438 try
1439 {
1440#if _WINDOWS
1441#pragma warning(disable:4996) // stricmp deprecated
1442#endif
1443 auto it = db.fData.find(inKey);
1444 if( it != db.fData.end() )
1445 {
1446 if( stricmp(it->second.c_str(), "true") == 0 )
1447 return true;
1448 else if( stricmp(it->second.c_str(), "false") == 0 )
1449 return false;
1450 }
1451 return false;
1452
1453 }
1454 catch( ... )
1455 {
1456 }
1457
1458 return false;
1459
1460 }
1461
1462 static std::ostream & GetOutputStream()
1463 {
1464 std::ofstream & outStream = GetInstance().fOutputStream;
1465
1466 if( !outStream.is_open() )
1467 outStream.open("c:\\a\\debugOutput.txt");
1468 else
1469 outStream.flush();
1470
1471 return outStream;
1472 }
1473
1474private:
1475
1476 void Reload()
1477 {
1478 static bool first = true;
1479 static auto lastTick = std::chrono::high_resolution_clock::now();
1480 auto tick = std::chrono::high_resolution_clock::now();
1481
1482 if( first || std::chrono::duration_cast<std::chrono::milliseconds>(tick-lastTick).count() > 1000 ) // reload every 1 second
1483 {
1484 first = false;
1485 lastTick = tick;
1486
1487#if _WINDOWS
1488 std::ifstream dbgFile("c:\\a\\debug.txt");
1489#else
1490 std::ifstream dbgFile("/a/debug.txt");
1491#endif
1492 if( dbgFile.is_open() )
1493 {
1494 fData.clear();
1495
1496 dbgFile.seekg(0, std::ios::end);
1497 size_t size = size_t(dbgFile.tellg());
1498 dbgFile.seekg(0, std::ios::beg);
1499
1500 std::string contents;
1501 contents.resize(size+1);
1502 dbgFile.read(&contents[0], size);
1503 contents[size] = 0;
1504
1505 dbgFile.close();
1506
1507 size_t offset = 0;
1508
1509#define CheckEOF(index) if( index >= contents.size() ) break
1510
1511 while( offset < contents.size() )
1512 {
1513 std::string key;
1514 std::string value;
1515
1516
1517 offset = contents.find_first_not_of(" \t\n\r", offset);
1518 CheckEOF(offset);
1519
1520 size_t endOffset = offset;
1521
1522 if( contents[offset] == '"' )
1523 endOffset = contents.find_first_of("\"", ++offset);
1524 else
1525 endOffset = contents.find_first_of(" \t\n\r=", offset);
1526
1527 if( offset == endOffset )
1528 endOffset++;
1529 CheckEOF(endOffset);
1530
1531 key = contents.substr(offset, endOffset-offset);
1532 offset = endOffset;
1533
1534 offset = contents.find_first_of("=", offset);
1535 offset++;
1536 CheckEOF(offset);
1537
1538 offset = contents.find_first_not_of(" \t\n\r", offset);
1539 CheckEOF(offset);
1540
1541
1542 endOffset = offset;
1543
1544 if( contents[endOffset] == '"' )
1545 endOffset = contents.find_first_of("\"", ++offset);
1546 else
1547 endOffset = contents.find_first_of(" \t\n\r", endOffset);
1548
1549 CheckEOF(endOffset);
1550
1551 value = contents.substr(offset, endOffset-offset);
1552 fData[key] = value;
1553
1554 offset = endOffset;
1555
1556 offset = contents.find_first_of("\n\r", offset);
1557 offset++;
1558 CheckEOF(endOffset);
1559
1560#undef CheckEOF
1561 }
1562 }
1563 }
1564 }
1565
1566 // The one and only
1567 static TDebugFile & GetInstance()
1568 {
1569 static TDebugFile gDebugFile;
1570 return gDebugFile;
1571 }
1572
1573 std::map<std::string, std::string> fData; // key-value table of data read from disk
1574 std::ofstream fOutputStream;
1575
1576};
1577
1578
1579#endif // __cplusplus
1580
1581#endif // _GSDEBUG_H_
unsigned char Bool8
Definition GSTypes.h:79
uint16_t Uint16
Definition GSTypes.h:26
int32_t Sint32
Definition GSTypes.h:36
uint64_t Uint64
Definition GSTypes.h:28
uint32_t Uint32
Definition GSTypes.h:27
#define kEveryone
Definition StdAfx.h:43