//-----------------------------------------------------------------------------
// GSDebug.h
//
// Copyright 1995-1998 Graphsoft, Inc.
// All Rights Reserved.
//
// This header file contains all prototypes and related information for all
// debugging functions and variables.  It is completely cross-platform and
// can be included in 100% Mac, 100% Windows and hybrid files.
//
// Started August 3, 1995 by David Bowman
//
// SourceSafe information for this version:
//    $Revision: 6 $
//    $Date: 2/9/01 9:35 AM $
//    $Author: Lyndsey $
//-----------------------------------------------------------------------------

#ifndef _GSDEBUG_H_
#define _GSDEBUG_H_ 1

#pragma once

///////////////////////////////////////////////////////////////////////////////
// _GSDEBUG_DLL_
//
// To use the DLL version of GSDebug, define _GSDEBUG_DLL_ to be non-zero in
// the project settings. If you do not define it, the default will be to use
// the object file version.

#if !defined(_GSDEBUG_DLL_)
	#define _GSDEBUG_DLL_ 0
#endif


///////////////////////////////////////////////////////////////////////////////
// _GSDEBUG_LIB_
//
// To use the LIB version of GSDebug, define _GSDEBUG_LIB_ to be non-zero in
// the project settings. If you do not define it, the default will be to use
// the object file version.

#if !defined(_GSDEBUG_LIB_)
	#define _GSDEBUG_LIB_ 0
#endif


///////////////////////////////////////////////////////////////////////////////
// GS_USE_ONLY_MODERN
//
// Define GS_USE_ONLY_MODERN to be non-zero to force more modern behavior.
// Modern behavior includes requiring a TProgrammer attached to all debug
// calls. If you do not define it, the default will be to not use it.

#if !defined(GS_USE_ONLY_MODERN)
	#define GS_USE_ONLY_MODERN 1
#endif


///////////////////////////////////////////////////////////////////////////////
// GS_HWND_CHECK
//
// Define GS_HWND_CHECK to non-zero if you want to include Windows HWND
// validation functions.

#if !defined(GS_HWND_CHECK)
	#if defined(_INC_WINDOWS) || defined(_GSWIN_)
		#define GS_HWND_CHECK 1
	#else
		#define GS_HWND_CHECK 0
	#endif
#endif


///////////////////////////////////////////////////////////////////////////////
// GS_USE_OBSOLETE
//
// Define GS_USE_OBSOLETE to be non-zero to include very old debugging
// functions. You really don't want to do this unless you have to.
#if !defined(GS_USE_OBSOLETE)
	#if !_MINICAD_EXTERNAL_ && !_GSWINSDK_ && !_MAGICFOLDER_ && !_GSESDK_ && !GS_SHELL_BUILD && !GS_COMP_BUILD && !GS_PROTECTION_BUILD && !GS_GSDEBUG_BUILD
		#define GS_USE_OBSOLETE 1
	#else
		#define GS_USE_OBSOLETE 0
	#endif
#endif


///////////////////////////////////////////////////////////////////////////////
// GS_USE_CLASS_DEBUGGING
//
// Define GS_USE_CLASS_DEBUGGING to be non-zero to enable class debugging.

#if !defined(GS_USE_CLASS_DEBUGGING)
	#if !_MINICAD_EXTERNAL_
		#define GS_USE_CLASS_DEBUGGING	1
	#else
		#define GS_USE_CLASS_DEBUGGING	0
	#endif
#endif


/////////////////////////////////////////////////////////////////////////////////////////
// _GSDEBUG_
//
// When building the GSDebug.dll or GSDebug.lib, you must define _GSDEBUG_ in the
// compiler preprocessor flags settings.

#if _GSDEBUG_ && !_GSDEBUG_DLL_ && !_GSDEBUG_LIB_
	#error if _GSDEBUG_ is defined, _GSDEBUG_DLL_ or _GSDEBUG_LIB_ must also be defined
#endif


/////////////////////////////////////////////////////////////////////////////////////////
// Not allowed to use the DLL and LIB versions at the same time.

#if _GSDEBUG_DLL_ && _GSDEBUG_LIB_
	#error Not allowed to define both _GSDEBUG_DLL_ and _GSDEBUG_LIB_
#endif
#if !_GSDEBUG_DLL_ && !_GSDEBUG_LIB_
	#define _GSDEBUG_OBJ_	1
#endif


///////////////////////////////////////////////////////////////////////////////
// GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_n
//
// With CodeWarrior 8.3 we exceeded a symbol table limit in the Mac debug build.
// The code that is enabled by the preprocessor variables below represents successive
// successful efforts to work around the problem.  [MAF 5/3/05]  

#define GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_1		0	// Turn off DMSGs
#define GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_2		0	// Turn off ASSERTs for various handle, pointer, and string checks
#define GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_3		0	// Turn off DSTOPs
#define GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_4		0	// Turn off ASSERTN
#define GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_5		0	// Turn off VERIFYN

#if GS_MAC
	//  Turn off effect of DEBUG_DO_NOTHING applied to GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_n
	//	Set GS_DSTOP_ALWAYS for MAC environment that DOES NOT skip Debugging stops.
	#define GS_DSTOP_ALWAYS SteveJ	// Turn off effect of DEBUG_DO_NOTHING applied to GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_n
#endif


///////////////////////////////////////////////////////////////////////////////
// Implementation Starts Here
///////////////////////////////////////////////////////////////////////////////


/* Includes */
/* -------- */

// Debugging library is only useful under C++. This allows it to be globally included in externals.
#ifdef __cplusplus

#include <StdLib.h>
#include <StdIO.h>
#include <String.h>
#if !_WINDOWS
	#include <StdArg.h>
#endif


///////////////////////////////////////////////////////////////////////////////
// AS OF 8/20/98 -
//		On Windows, GSESDK code is called without special calling conventions

#if _WINDOWS && _GSDEBUG_DLL_
	#if _GSDEBUG_
		// Building GSDebug.dll
		#define GSDEBUG_EXPORT			__declspec(dllexport)

	#else
		// Building a module that uses GSDebug.dll
		#define GSDEBUG_EXPORT			__declspec(dllimport)
	#endif
#else
	// Building a module that compiles GSDebug.cpp directly (no GSDebug.dll).
	#define GSDEBUG_EXPORT
#endif


/////////////////////////////////////////////////////////////////////////////////////////

#include "GSTypes.h"

/* End of Includes */


/* Basic Types */
/* ----------- */

typedef GSStringPtr BugStringPtr;

#if _WINDOWS
	#if _MAGICFOLDER_
		#define Boolean	Bool8
		#define Byte	Uint8
	#endif
#endif


/* Private Variables */
/* ----------------- */
#if GS_GSDEBUG_BUILD || (APPBUILD && !GS_INTERFACE_FACTORING)
extern char		gDebugAppName[32];
#endif


///////////////////////////////////////////////////////////////////////////////
// Timers
//
//	Use like this:
//		...code....
//		START_TIMER(NameOfTimer);
//		...code.to.time...
//		END_TIMER(kProgrammer, NameOfTimer);
//		...code...

#if _WINDOWS && BUG

	class GSDEBUG_EXPORT TProgrammer;
	class GSDEBUG_EXPORT TDebugTimer
	{
		public:
			TDebugTimer();
			void Stop(const TProgrammer &who, ConstGSCStrPtr name, bool bWindow);

		private:
			#if _WINDOWS
				Uint64 fStartTime;
			#else
			#endif
	};

	#define START_TIMER(name)		TDebugTimer timer_##name
	#define END_TIMER(who, name)	timer_##name##.Stop(who, #name, false)

#else
	#define START_TIMER(name)
	#define END_TIMER(who, name)
#endif

#if _WINDOWS && _MAGICFOLDER_
	#define START_TIMER_RELEASE(name)	const Uint32 timer_##name = ::GetTickCount()
	#define END_TIMER_RELEASE(name) do { \
		const Uint32 elapsed = ::GetTickCount() - timer_##name; \
		Uint32 seconds = elapsed / 1000; \
		Uint32 tenths = (elapsed - seconds*1000 + 50) / 100; \
		if (tenths > 9) { tenths = 0; ++seconds; } \
		char szMessage[60]; \
		::sprintf(szMessage, "Timer '" #name "' took %d.%d seconds.", seconds, tenths); \
		::AfxMessageBox(szMessage); \
	} while (0)
#else
	#define START_TIMER_RELEASE(name)
	#define END_TIMER_RELEASE(name)
#endif


/////////////////////////////////////////////////////////////////////////////////////////
// Compiler messages
//
//	Use like this:
//		#pragma CMSG(kProgrammer, "Your message")

#define CMSG_makeString1(x)	#x
#define CMSG_makeString(x)	CMSG_makeString1(x)
#define CMSG(who, desc)		message(__FILE__ "(" CMSG_makeString(__LINE__) ") : " #who ": " desc)


/////////////////////////////////////////////////////////////////////////////////////////
// Print preprocessor definition
//
// use this is see what something has been defined to be. For example:
//    #pragma PRINTDEFINE(kDave, BUG)
// Will, when compiling, generate a line in the compiler output window telling you what
// "BUG" is currently defined to.

#define PRINTDEFINE(who, what)		message(__FILE__ "(" CMSG_makeString(__LINE__) ") : " #who ": " #what " = " CMSG_makeString(what))


/////////////////////////////////////////////////////////////////////////////////////////
// Macro to mark something as un-implemented.
//
// For example:
//
//   void TMyClass::CalulateComplexNumber()
//   {
//      NOT_IMPLEMENTED(kDave, TMyClass::CalulateComplexNumber);
//   }

#define NOT_IMPLEMENTED(who, func)	DSTOP((who, "Not implemented: " #func))


/////////////////////////////////////////////////////////////////////////////////////////

#if (_WINDOWS && _MINICAD_ && !defined(_INC_WINDOWS)) || !_WINDOWS

	// if Windows.h has not been included, then we may need to use
	// the standard library implementations even under Windows

	//this must follow: #include "GSWin.h"

	#ifndef _INC_STRING

		#if _WINDOWS
		__declspec(dllimport)
		#endif
		int stricmp(const char *a, const char *b);
	#endif

	#ifndef _WINBASE_
		#define lstrcat			strcat
		#define lstrlen			strlen
		#define lstrcpy			strcpy
		#define lstrcpyn		strncpy
		#define lstrcmp			strcmp
		#define lstrcmpi		stricmp
		#if !_WINDOWS
			#define strcmpi		stricmp
		#endif
	#endif // !_WINBASE_

#endif


#if !_WINDOWS
	// use the Debug window externally
	#if defined(_MINICAD_EXTERNAL_)
		#define OutputDebugString	Debug
	#else
		#define OutputDebugString(msg)	printf("%s", msg)
	#endif
#else
	extern "C" __declspec(dllimport) void _stdcall DebugBreak(void);
#endif



////////////////////////////////////////////////////////////////////////////////
// Setup for "THIS_FILE" macro.  Use THIS_FILE instead of __FILE__ to reduce
// the size of the executable. [DMB]

#if TEST
	#define DECLARE_THIS_FILE	static const char THIS_FILE[] = __FILE__;
#else
	#define DECLARE_THIS_FILE
#endif
#ifndef THIS_FILE
	#define THIS_FILE __FILE__
#endif



////////////////////////////////////////////////////////////////////////////////
// Use the following macro to print Pascal strings or Rect's in a printf type
// format string.  For example:
//
//		DMSG((dlAlways, "File name: %.*s\n", PASCALPRINT(filename)));
//		DMSG((dlAlways, "myRect: (%d,%d)-(%d,%d)\n", RECTPRINT(myRect)));

#define PASCALPRINT(pascal_string)	\
	((ConstGSStringPtr)(pascal_string))[0], &((ConstGSStringPtr)(pascal_string))[1]

#define RECTPRINT(r)	\
	(r).Left(), (r).Top(), (r).Right(), (r).Bottom()


//---------------------------------------------------------------------------------------
// --- Debugging
//
// TEST is true if either BUG or NETBUG are true.
// Most general testing code should be in "#ifdef TEST" blocks.
//
// Anything which causes a break or writes to the debug window
// should be in "#ifdef BUG" blocks.

#define	DEBUG_DO_NOTHING	((void) 0)


// Debug levels.
enum EDebugLevel { dlAlways, brief, verbose, mongo, dlNever };


// Include all obsolete functions and macros. DO NOT USE them anymore.
#if GS_USE_OBSOLETE
	#include "GSDebug.obsolete.h"
#endif


/////////////////////////////////////////////////////////////////////////////////////////
#if !_WINDOWS
	// this is really ugly - but it allows our DSTOPs to land us at the right
	// line even if they take place in an ANSI cross platform file - PCP

	#if !defined(__MACTYPES__)
		extern "C" void Debugger(void);
	#endif

	#define	GSBreakToLowLevelDebugger_()		::Debugger()
	#define	GSBreakStrToLowLevelDebugger_(s)	::DebugStr(s)
	#define	GSBreakToSourceDebugger_()			::SysBreak()
	#define	GSBreakStrToSourceDebugger_(s)		::SysBreakStr(s)
#endif



/////////////////////////////////////////////////////////////////////////////////////////
// This hack allows the Mac to build until this code moves back into GSDebug.h for good

#if !_WINDOWS
	#define ASSERTNOFPEXCEPTION() 	DEBUG_DO_NOTHING
	#define ASSERTFPSTACKVALID()	DEBUG_DO_NOTHING
#endif


/////////////////////////////////////////////////////////////////////////////////////////
// The following structure defs are used by externals to communicate back to UCallBacks.cp
// so that they can assert valid handles and pointers. This structure must be compiled
// into the same byte offsets by every compiler we use, so beware of tricky changes. - PCP
//
// If these are changed, then the current crop of externals built with BUG or TEST
// will not work with the new MiniCad, so be careful.

#if !_MAGICFOLDER_
	const short kKludgeSendAssert			= 2001;
	const short kKludgeSendLog				= 2002;
	const short kKludgeValidatePointer		= 2003;
	const short kKludgeValidateHandle		= 2004;
	const short kKludgeCheckHeap			= 2005;
	const short kKludgeCheckPorts			= 2006;
	const short kKludgeValidateString		= 2007;
	const short kKludgeValidatePString		= 2008;
#endif


/////////////////////////////////////////////////////////////////////////////////////////
// kCrashTrapConstant
//
// kCrashTrapConstant is defined to a value which will likely cause an immediate crash
// (of some variety) on any platform. It is used in the TEST and BUG versions to flag
// pointers which are dangerous to use. These pointers should typically be set to nil in
// the release version, but that decision must be made on a case by case basis, so
// kCrashTrapConstant is not defined for the release version

#if TEST
	const unsigned long kCrashTrapConstant = 0x50ff8001;
#endif


/////////////////////////////////////////////////////////////////////////////////////////
#if TEST
	struct AssertParameters {
		char*	toWhom;
		char*	description;
	};

	struct ValidateParameters {
		Bool8	isAssert;
		char*	toWhom;
		char*	file;
		long	line;
		char*	itemName;
		void*	thePointerOrHandle;
		long	expectedSize;
		long	expectedSize2;
	};

	// flag values for ValidatePortParameters
	const long kAllowWMgrPort = 1L;

	struct ValidatePortParameters {
		char*	message;
		char*	file;
		long	line;
		long	flags;
	};
#endif // TEST


/////////////////////////////////////////////////////////////////////////////////////////
// PORT testing functions

// XXX_JDW_ALTURA CLEANUP [2003-05-28]
//#if TEST && !_MAGICFOLDER_ && (!_WINDOWS || !defined(_INC_WINDOWS)) && !_GSESDK_ && !GS_INTERFACE_FACTORING  && !_WIN_EXTERNAL_
//#if TEST && !_MAGICFOLDER_ && !_GSESDK_ && !_WIN_EXTERNAL_ && defined(_WINDOWS)
#if 0
	// Only do port checking when doing a TEST or BUG build and only when compiling
	// a Mac/Altura module.
	// Don't check the ports if GS_INTERFACE_FACTORING because the core shouldn't know
	// anything about the port in that case.
	#include <QuickDraw.h>
	#define DO_PORT_CHECKING	1
#else 
	#define DO_PORT_CHECKING	0
#endif

#if DO_PORT_CHECKING

	Bool8 IsValidMacPort(GrafPtr port);
	#define __ASSERTPORT(toWhom, msg, port)			DSTOP((!::IsValidMacPort((GrafPtr)(port)), toWhom, "%s: Invalid port (0x%08x)", (const char*)(msg), (GrafPtr)(port)))
	#if _WINDOWS
		#define __ASSERTCURRENTPORT(toWhom, msg)	do { GrafPtr curPort; ::GetPort(&curPort); __ASSERTPORT(toWhom, msg, curPort); } while (0)
	#else
		#define __ASSERTCURRENTPORT(toWhom, msg)	ASSERTLEGALPORTM(msg)
	#endif

	// The LL versions allow the port to be set to the window manager port without
	// complaining. They still check to make sure all handles in the window manager
	// port are in the system heap so we won't crash the system later on. - PCP

	#if _WINDOWS
		#define ASSERTLEGALPORTM(message)			__ASSERTCURRENTPORT(kGrafPortCheck, (message) ? (message) : "ASSERTLEGALPORTM")
		#define LLASSERTLEGALPORTM(message)			__ASSERTCURRENTPORT(kGrafPortCheck, (message) ? (message) : "LLASSERTLEGALPORTM")
	#else
		int _AssertLegalPort(char *message, const char* file, int line, Bool8 allowWMgrPort);
		
		#define ASSERTLEGALPORTM(message)			((void)_AssertLegalPort(message, THIS_FILE, __LINE__, false))
		#define LLASSERTLEGALPORTM(message)			((void)_AssertLegalPort(message, THIS_FILE, __LINE__, true))
	#endif
#else
	#if !_MAGICFOLDER_
		#define __ASSERTPORT(toWhom, msg, port)		DEBUG_DO_NOTHING
		#define __ASSERTCURRENTPORT(toWhom, msg)	DEBUG_DO_NOTHING
		#define ASSERTLEGALPORTM(message)			DEBUG_DO_NOTHING
		#define LLASSERTLEGALPORTM(message)			DEBUG_DO_NOTHING
	#endif
#endif // DO_PORT_CHECKING

#if !_MAGICFOLDER_
	// New port checking functions. [DMB 12/13/96]
	#define ASSERTPORT(toWhom, port)				__ASSERTPORT(toWhom, "ASSERTPORT", port)
	#define ASSERTCURRENTPORT(toWhom)				__ASSERTCURRENTPORT(toWhom, "ASSERTCURRENTPORT")

	// Old port checking functions. DO NOT USE THESE.
	#define ASSERTLEGALPORT()						ASSERTLEGALPORTM(NULL)
	#define LLASSERTLEGALPORT()						LLASSERTLEGALPORTM(NULL)
#endif


/////////////////////////////////////////////////////////////////////////////////////////
// Functions and macros to stop the application.  Defines STOP().

#if BUG
	// Define the method used to break into the debugger,
	#if _WINDOWS
		#define DO_STOP()			__asm {int 3}
	#else
		#define DO_STOP()			GSBreakToLowLevelDebugger_()
	#endif
	#define STOP()					do { if (GSDebug::WantToBreak()) DO_STOP(); } while(0)
#else
	#define STOP()					DEBUG_DO_NOTHING
#endif // BUG


/////////////////////////////////////////////////////////////////////////////////////////
// Functions to change debug library behavior.

#if TEST

	#if _WINDOWS
		extern "C" Bool8 GSDebug_IsInDebugMessage();
		// Description:
		//   Determine if a debug dialog is currently being displayed.
		//
		// Returns:
		//   BOOL - 'TRUE' if a debug dialog is currently being displayed. 'FALSE' if
		//     no debug dialogs are being displayed.
	#endif

	namespace GSDebug {

		// Replaces 'iWantToDebug'.
		bool GSDEBUG_EXPORT WantToDebug();
		bool GSDEBUG_EXPORT WantToDebug(bool bWantToDebug);

		// Replaces 'debugLevel'.
		EDebugLevel GSDEBUG_EXPORT DebugLevel();
		EDebugLevel GSDEBUG_EXPORT DebugLevel(EDebugLevel newDebuglevel);

		// Replaces 'useSourceDebugger'.
		bool GSDEBUG_EXPORT UseSourceDebugger();
		bool GSDEBUG_EXPORT UseSourceDebugger(bool bUseSourceDebugger);

		// Replaces 'drawToScreen'.
		// Choosing drawToScreen disables GWorlds
		bool GSDEBUG_EXPORT DrawToScreen();
		bool GSDEBUG_EXPORT DrawToScreen(bool bDrawToScreen);

		// Replaces 'iWantToStop'.
		// 'true' to stop application on a STOP(), 'false' to keep going.
		bool GSDEBUG_EXPORT WantToBreak();
		bool GSDEBUG_EXPORT WantToBreak(bool bWantToBreak);

		// Replace the debug flags.
		Uint32 GSDEBUG_EXPORT Flags();
		Uint32 GSDEBUG_EXPORT Flags(Uint32 inNewFlags);


		// Flags for TProgrammer IDs.
		const Uint64 kNoNetDebugFlag		= 0x8000000000000000ULL;
		const Uint64 kNoDebuggerBreakFlag	= 0x4000000000000000ULL;
		const Uint64 kNoDebugWindowFlag		= 0x2000000000000000ULL;
		const Uint64 kNoStackCrawlFlag		= 0x1000000000000000ULL;
		const Uint64 kOnlyIfActiveUserFlag	= 0x0800000000000000ULL;

		// Flags for GS_DebugInit( )
		const Uint32 kNoFlags				= 0x00000000UL;
		const Uint32 kNeverUseDebugWindows	= 0x00000001UL;

	} // namespace GSDebug
#endif	// TEST


/////////////////////////////////////////////////////////////////////////////////////////
// Functions used by DSTOP implementation. Do not use these.

#if TEST
	namespace GSDebug {
		void GSDEBUG_EXPORT SetDStopFileName(ConstGSCStrPtr szFileName);
		void GSDEBUG_EXPORT SetDStopLineNumber(int nLineNumber);
	} // namespace GSDebug
#endif


/////////////////////////////////////////////////////////////////////////////////////////
// Remote logging / Local logging

#if GS_LOCALLOGFLAG

	// as of 2009, local logging is a service which is always available in the release build
	// we will retire the GS_LOCALLOGFLAG


	// gRemoteLogLevel is a runtime global which controls how much data we log to the local
	// VW User Log file and send to NNA. It is controlled by NNA if the user turns on their preference
	// expressing willingness to send data to NNA

	// gRemoteLogLevel 1 - minimal logging of application crashes
	// gRemoteLogLevel 2 - include lauch and quit times
	// gRemoteLogLevel 5 - include one or two lines per user action
	// gRemoteLogLevel 8 - include timings for user actions and side effects
	// gRemoteLogLevel 10 - include timings for significant user activity

	// under no curcumstances should REMOTELOG be called in a tight loop where it could affect performance
	// It should be assumed that REMOTELOG may take up to 1/1000 of a sec to execute, so it should not
	// be called more than a few times within ant given second of runtime and then only rarely.

	// These are the macros you should use to log messages to the debug server.
	// They have almost no runtime overhead except in the tightest loops when running in the release application
	// in the debug application, they incur the overhead of writing to (and often scrolling) the debug window
	// which can be significant.
	//
	// use the "TIGHT" variant to log to the usage log file but avoid the higher overhead of writing to the debug window

	// use the TIMING variant to log standard timing format (note that this does not work with classic network logging)


	extern Uint16 gRemoteLogLevel;

	void GSDEBUG_EXPORT LocalLogStrTight(Uint16 level, const char *description);
	int  GSDEBUG_EXPORT LocalLogTight(Uint16 level, const char *format, ...);
	int  GSDEBUG_EXPORT LocalLogTiming(Uint16 level, double timing, const char *format, ...);

	void GSDEBUG_EXPORT LocalLogStr(Uint16 level, const char *description);
	int  GSDEBUG_EXPORT LocalLog(Uint16 level, const char *format, ...);
#endif

// GS_BETA_PROGRAM_SUPPORT is a flag used to build a release app with some functionality
// which is too sensitive for general release. It can include log messages as well as
// beta serial number support - PCP

#if NETBUG
	// Implementation functions. Do not call these directly.
	#if !_MINICAD_EXTERNAL_
		void InitRemoteDebug(void);
		void KillRemoteDebug(void);
		void LogVersionStamp(void);
	#endif
	class GSDEBUG_EXPORT TProgrammer;
	void GSDEBUG_EXPORT RemoteDebug(const TProgrammer& toWhom, const char *description);
	void GSDEBUG_EXPORT RemoteDebug(const char *toWhom, const char *description, Bool8 doStackCrawl=true);
	void GSDEBUG_EXPORT RemoteLog(Uint16 level, const char *description);
	int  GSDEBUG_EXPORT _Log(Uint16 level, const char *format, ...); // For internal use by LOG macro.


	#if GS_LOCALLOGFLAG
		//#define REMOTELOG(l,s)			::RemoteLog(l,s); LocalLogStr(l,s);
		//#define REMOTELOGTIGHT(l,s)		::RemoteLog(l,s); LocalLogStrTight(l,s);
		#define REMOTELOGF(parms)			_Log parms; LocalLog parms;
		#define REMOTELOGTIGHTF(parms)		_Log parms; LocalLogTight parms;
		#define REMOTELOGTIMINGF(parms)		LocalLogTiming parms;
		#if GS_BETA_PROGRAM_SUPPORT
			#define REMOTELOGBETAF(parms)	_Log parms; LocalLogTight parms;
		#else
			#define REMOTELOGBETAF(parms)	DEBUG_DO_NOTHING
		#endif
	#else
		//#define REMOTELOG(l,s)			::RemoteLog(l,s)
		//#define REMOTELOGTIGHT(l,s)		::RemoteLog(l,s)
		#define REMOTELOGF(parms)			_Log parms
		#define REMOTELOGTIGHTF(parms)		_Log parms
		#define REMOTELOGTIMINGF(parms)		DEBUG_DO_NOTHING
		#if GS_BETA_PROGRAM_SUPPORT
			#define REMOTELOGBETAF(parms)	_Log parms;
		#else
			#define REMOTELOGBETAF(parms)	DEBUG_DO_NOTHING
		#endif
	#endif

#else
	#if GS_LOCALLOGFLAG
		//#define REMOTELOG(l,s)			LocalLogStr(l,s);
		//#define REMOTELOGTIGHT(l,s)		LocalLogStrTight(l,s);
		#define REMOTELOGF(parms)			LocalLog parms;
		#define REMOTELOGTIGHTF(parms)		LocalLogTight parms;
		#define REMOTELOGTIMINGF(parms)		LocalLogTiming parms;
		#if GS_BETA_PROGRAM_SUPPORT
			#define REMOTELOGBETAF(parms)	LocalLogTight parms;
		#else
			#define REMOTELOGBETAF(parms)	DEBUG_DO_NOTHING
		#endif
	#else
		//#define REMOTELOG(l,s)			DEBUG_DO_NOTHING
		//#define REMOTELOGTIGHT(l,s)		DEBUG_DO_NOTHING
		#define REMOTELOGF(parms)			DEBUG_DO_NOTHING
		#define REMOTELOGTIGHTF(parms)		DEBUG_DO_NOTHING
		#define REMOTELOGTIMINGF(parms)		DEBUG_DO_NOTHING
		#define REMOTELOGBETAF(parms)		DEBUG_DO_NOTHING
	#endif
#endif




////////////////////////////////////////////////////////////////////////////////
// TProgrammer class

#if TEST

const short kDebugStringLength = 50;

#define kEveryoneConst	0x0FFFFFFFFFFFFFFFULL
#define kProgrammerMask	0x0FFFFFFFFFFFFFFFULL
#define kOptionBitsMask	(~kProgrammerMask)

class GSDEBUG_EXPORT TProgrammer
{
	public:
		TProgrammer()											{ Set("Unnamed", 0, true); }
		TProgrammer(const char *name, Uint64 id, bool sendOwn=true) { Register(name, id); Set(name, id, sendOwn); }
		TProgrammer(const TProgrammer& a)						{ Set(a.fName, a.fID, a.fSendOnOwn); }
	
		const char *GetName() const 							{ return fName; }
		Uint64 GetID(bool filter=false) const					{ return filter ? (fID & kEveryoneConst) : fID; }

		bool IsEveryone() const									{ return (fID & kEveryoneConst) == kEveryoneConst; }
		bool IsActLikeRelease() const							{ return (fID & kProgrammerMask) == 0; }

		bool LogOnOwn() const;
		bool ShouldBreak() const								{ return !IsActLikeRelease() && !IsNoBreakBitSet(); }
		bool ShouldNetDebug() const								{ return !IsActLikeRelease() && !IsNoNetDebugBitSet(); }
		bool ShouldShowWindow() const							{ return !IsActLikeRelease() && !IsNoWindowBitSet(); }
		bool ShouldDoStackCrawl() const							{ return !IsNoStackCrawlBitSet(); }
	
		TProgrammer operator &(const TProgrammer& a) const;
		TProgrammer operator |(const TProgrammer& a) const		{ return this->operator &(a); }
		Uint64 operator &(Uint64 dw) const						{ return fID & dw; }
	
		operator const char *() const							{ return GetName(); }
	
		bool operator ==(const TProgrammer& a) const			{ return MatchExact(a); }
		bool operator !=(const TProgrammer& a) const			{ return !MatchExact(a); }
		bool operator ==(const char *sz) const					{ return _strcmpi(sz, fName)!=0; }
		bool MatchExact(const TProgrammer& a) const				{ return fID == a.fID; }
		bool IsIn(const TProgrammer& a) const					{ return IsIn(a.fID); }
		bool IsIn(Uint64 id) const								{ return (GetID(true) & (id & kEveryoneConst)) == GetID(true); }
		bool LooseIsIn(const TProgrammer& a) const				{ return (fID & a.fID) != 0; }
		bool ContainsCurrentUser() const;

		static bool GetProgrammerName(Uint64 id, char *name);
		static bool ExtractProgrammer(TProgrammer &who, TProgrammer &one);
	
		bool IsNoNetDebugBitSet() const							{ return (fID & GSDebug::kNoNetDebugFlag) != 0; }
		bool IsNoBreakBitSet() const							{ return (fID & GSDebug::kNoDebuggerBreakFlag) != 0; }
		bool IsNoWindowBitSet() const							{ return (fID & GSDebug::kNoDebugWindowFlag) != 0; }
		bool IsNoStackCrawlBitSet() const						{ return (fID & GSDebug::kNoStackCrawlFlag) != 0; }
		bool IsOnlyIfActiveUserBitSet() const					{ return (fID & GSDebug::kOnlyIfActiveUserFlag) != 0; }

	protected:
		void Set(const char *name, Uint64 id, bool sendOwn)		{ strncpy(fName, name, kDebugStringLength-1); fID = id; fSendOnOwn = sendOwn; }

	private:

		class GSDEBUG_EXPORT TRegistered
		{
			public:
				TRegistered()									{ fID = 0; fName[0] = 0; }
				char fName[kDebugStringLength];
				Uint64 fID;
		};
		static void Register(const char *name, Uint64 id);
		static const int fMaxProgrammers;
		static TRegistered fRegistered[];

		char fName[kDebugStringLength];
		Uint64 fID;
		bool fSendOnOwn;
	};

#else

	#define TProgrammer int

#endif // TEST


#if BUG && !defined(_MINICAD_EXTERNAL_)
void InitBugMem();
#endif


/////////////////////////////////////////////////////////////////////////////////////////
#if TEST && !defined(_MINICAD_EXTERNAL_)
	// Implementation functions. Do not call these directly, use the macros.
	GSDEBUG_EXPORT void GDB_DebugInit (const char* appName, Uint32 flags);
	GSDEBUG_EXPORT void GDB_DebugTerminate();
	#if defined(_INC_WINDOWS)
		extern "C" GSDEBUG_EXPORT void GDB_DebugSetExeHandle(HINSTANCE hInst);
		extern "C" GSDEBUG_EXPORT void GDB_SetDebugMessageParentWindow(HWND hParentWnd);
	#endif

	void PerformLaunchAsserts(void);

	// Call DEBUG_INIT() to initialize the GSDebug library. For flags, see GSDebug namespace.
	#define DEBUG_INIT(appName, flags)	::GDB_DebugInit(appName, flags)

	#if defined(_INC_WINDOWS)
		// Set the handle of the executable being run.
		#define DEBUG_SETEXE(hInst)		::GDB_DebugSetExeHandle(hInst)

		// Set the parent window for the next dialog that the debug system displays.
		#define DEBUG_SETPARENTWINDOW(hParentWnd) ::GDB_SetDebugMessageParentWindow(hParentWnd)
	#else
		#define DEBUG_SETEXE(hInst)		DEBUG_DO_NOTHING
	#endif

	// Call DEBUG_TERMINATE to shut down the GSDebug library.
	#define DEBUG_TERMINATE()			::GDB_DebugTerminate()

#endif


/////////////////////////////////////////////////////////////////////////////////////////
#if TEST
	#define MAKEWHO(name)			TProgrammer(name, kEveryoneConst, true)
	#define DECLAREWHO(var, name)	TProgrammer var(name, kEveryoneConst, true)
	#define TEST_ONLY(x)			x
#else
	#define MAKEWHO(name)			0
	#define DECLAREWHO(var, name)	TProgrammer var
	#define TEST_ONLY(x)
#endif // TEST

#if BUG
	#define BUG_ONLY(x)				x
#else
	#define BUG_ONLY(x)
#endif
	

/////////////////////////////////////////////////////////////////////////////////////////
// Routing objects for network asserts

#if TEST

// Active Engineers

	#define		kRichFile				"Rich"
	#define		kSeanFile				"Sean"
	#define		kSteveFile				"Steve Johnson"
	#define		kPaulFile				"Paul"
	#define		kDaveFile				"Dave"
	#define		kDaveDFile				"DaveD"
	#define		kJeffFile				"Jeff"
	#define		kDarickFile				"Darick"
	#define		kAndrewFile				"AndrewB"
	#define		kShirleyFile			"Shirley"
	#define		kMarkFile				"MFarnan"
#if GS_WIN
	#define		kMikeFile				"MikeH"
#else
	#define		kMikeFile				"mhartman"
#endif
	#define		kBruceFile				"Bruce"
	#define		kAyoFile				"Ayodeji"
	#define		kMaoFile				"Charlene"
	#define		kChaoFile				"Chao"
	#define		kEJKerrFile				"EJKerr"
	#define		kJGeraciFile			"JGeraci"
	#define		kVictorFile				"Victor"
	#define     kAbdelFile              "Abdel"
	#define		kKarimFile				"Karim"
	#define		kAlexFile				"Alex"
	#define		kBiplabFile				"Biplab"
	#define		kLyndseyFile			"Lyndsey"
	#define		kNIvanovaFile			"nivanova"
	#define		kVStanevFile			"vstanev"
	#define		kMRizovFile				"MRizov"
	#define		kVKitanovFile			"VKitanov"
	#define		kIRovelovFile			"IRovelov"
	#define		kYSimeonovFile			"YSimeonov"
	#define		kANikolovaFile			"ANikolova"
	#define		kDonneFile				"Donne"
	#define     kPKameoFile             "PKameo"
	#define		kNHenkelFile			"NHenkel"
	#define		kToluFile				"Tolu"
	#define	    kAbouzarFile			"Abouzar"
	#define 	kRFosterFile			"RFoster"
	#define 	kAStantonFile			"AStanton"
	#define 	kJHutchisonFile			"JHutchison"
	#define		kBWilliamsFile			"BWilliams"
	#define 	kILaneFile				"ILane"
	#define 	kCGrayeFile 			"CGraye"
	#define 	kHTsafakFile			"HTsafak"
	#define		kRLevinFile				"RLevin"
	#define		kJLoyFile				"JLoy"
	#define		kTYokoyamaFile			"TYokoyama"
	#define		kEveryoneFile			"Everyone"
	#define		kCarrieFile				"Carrie"
	#define		kMikeDFile				"MikeD"
	#define		kEGorrFile				"Eric"
	#define		kJWarshawFile			"JWarshaw"
	#define		kBAtwoodFile			"BAtwood"
	#define		kTArdoinFile			"TArdoin"
	#define		kCStulbergerFile		"CStulberger"
	#define		kPFletcherFile			"PFletcher"
	#define		kZPageFile				"ZPage"
	
	
// Departed Engineers whose ASSERTs have not been transferred to another category yet

	#define		kChrisFile				"Chris"
	#define		kLewisFile				"Lewis"
	#define		kRamseyFile				"Ramsey"
	#define		kTroyFile				"Troy"
	#define		kCalebFile				"Caleb"
	#define		kJimGFile				"JimG"
	#define		kRichnFile				"RichN"
	#define		kGeorgeFile				"George"
	#define		kJimFile				"Jim"
	#define		kRobertFile				"Robert"



	#if !_MAGICFOLDER_
		#define		kDialogClassFile		"Dialog Class"
		#define		kOverflowsFile			"Overflows"
		#define		kNewMemoryTimingFile	"New Memory Timing"
		#define		kPointerCheckFile		"Pointer Check"
		#define		kHandleCheckFile		"Handle Check"
		#define		kArrayOverflowFile		"Static Array Overflow"
		#define		kMCCoordTypesFile		"MCCoordTypes"
		#define		kMiniPascalFile			"MiniPascal"
	#endif

	#define kRich				TProgrammer(kRichFile,   		0x0000000000000001ULL, true)
	#define kSean				TProgrammer(kSeanFile,   		0x0000000000000002ULL, false)
	#define kChris				TProgrammer(kChrisFile,  		0x0000000000000004ULL, true)
	#define kSteve				TProgrammer(kSteveFile,  		0x0000000000000008ULL, true)
	#define kJim				TProgrammer(kJimFile,    		0x0000000000000010ULL, true)
	#define kPaul				TProgrammer(kPaulFile,   		0x0000000000000020ULL, true)
	#define kJimG				TProgrammer(kJimGFile,   		0x0000000000000040ULL, false)
	#define kDave				TProgrammer(kDaveFile,   		0x0000000000000080ULL, false)
	#define kDaveD				TProgrammer(kDaveDFile,  		0x0000000000000100ULL, true)
	#define kRamsey				TProgrammer(kRamseyFile, 		0x0000000000000200ULL, true)
	#define kJeff				TProgrammer(kJeffFile,   		0x0000000000000400ULL, true)
	#define kDarick				TProgrammer(kDarickFile, 		0x0000000000000800ULL, false)
	#define kAndrewB			TProgrammer(kAndrewFile, 		0x0000000000001000ULL | GSDebug::kNoDebugWindowFlag, false)
	#define kShirley			TProgrammer(kShirleyFile,		0x0000000000002000ULL, true)
	#define kMark				TProgrammer(kMarkFile,   		0x0000000000004000ULL, false)
	#define kMike				TProgrammer(kMikeFile,   		0x0000000000008000ULL, true)
	#define kBruce				TProgrammer(kBruceFile,  		0x0000000000010000ULL, false)
	#define kAyo				TProgrammer(kAyoFile,    		0x0000000000020000ULL, true)
	#define kRobert				TProgrammer(kRobertFile, 		0x0000000000040000ULL, false)
	#define kRichn				TProgrammer(kRichnFile,  		0x0000000000080000ULL, false)
	#define kMao				TProgrammer(kMaoFile,	 		0x0000000000100000ULL, false)
	#define kChao				TProgrammer(kChaoFile,	 		0x0000000000200000ULL, false)
	#define kTroy				TProgrammer(kTroyFile,	 		0x0000000000400000ULL, true)
	#define kEJKerr				TProgrammer(kEJKerrFile, 		0x0000000000800000ULL, true)
	#define kJGeraci			TProgrammer(kJGeraciFile,		0x0000000001000000ULL, true)
	#define kCaleb				TProgrammer(kCalebFile,	 		0x0000000002000000ULL, true)
	#define kLewis				TProgrammer(kLewisFile,	 		0x0000000004000000ULL, true)
	#define kGeorge				TProgrammer(kGeorgeFile, 		0x0000000008000000ULL, true)
	#define kVictor				TProgrammer(kVictorFile, 		0x0000000010000000ULL, true)
	#define kAbdel				TProgrammer(kAbdelFile,  		0x0000000020000000ULL, true)
	#define kKarim				TProgrammer(kKarimFile,  		0x0000000040000000ULL, true)
	#define kAlex				TProgrammer(kAlexFile,	 		0x0000000080000000ULL, true)
	#define kBiplab				TProgrammer(kBiplabFile, 		0x0000000100000000ULL, true)
	#define kLyndsey			TProgrammer(kLyndseyFile,		0x0000000200000000ULL, true)
	#define kNIvanova			TProgrammer(kNIvanovaFile,		0x0000000400000000ULL, true)
	#define kVStanev			TProgrammer(kVStanevFile,		0x0000000800000000ULL, true)
	#define kMRizov				TProgrammer(kMRizovFile, 		0x0000001000000000ULL, true)
	#define kDonne				TProgrammer(kDonneFile,	 		0x0000002000000000ULL, true)
	#define kPKameo				TProgrammer(kPKameoFile, 		0x0000004000000000ULL, true)
	#define kNHenkel			TProgrammer(kNHenkelFile,		0x0000008000000000ULL, true)
	#define kTolu				TProgrammer(kToluFile,	 		0x0000010000000000ULL, true)
	#define kAbouzar			TProgrammer(kAbouzarFile,		0x0000020000000000ULL, true)
	#define kRFoster			TProgrammer(kRFosterFile,		0x0000040000000000ULL, true)
	#define kAStanton			TProgrammer(kAStantonFile,		0x0000080000000000ULL, true)
	#define kJHutchison			TProgrammer(kJHutchisonFile,	0x0000100000000000ULL, true)
	#define kCGraye				TProgrammer(kCGrayeFile,		0x0000200000000000ULL, true)
	#define kILane 				TProgrammer(kILaneFile,			0x0000400000000000ULL, true)
	#define kBWilliams			TProgrammer(kBWilliamsFile, 	0x0000800000000000ULL, true)
	#define kHTsafak			TProgrammer(kHTsafakFile,		0x0001000000000000ULL, true)
	#define kJLoy				TProgrammer(kJLoyFile,			0x0002000000000000ULL, true)
	#define kRLevin				TProgrammer(kRLevinFile,		0x0004000000000000ULL, true)
	#define kTYokoyama			TProgrammer(kTYokoyamaFile, 	0x0008000000000000ULL, true)
	#define kCarrie				TProgrammer(kCarrieFile,		0x0010000000000000ULL, true)
	#define kEGorr				TProgrammer(kEGorrFile,			0x0010000000000000ULL, true)
	#define kMikeD				TProgrammer(kMikeDFile,			0x0020000000000000ULL, true)
	#define kJWarshaw			TProgrammer(kJWarshawFile,		0x0040000000000000ULL, true)
	#define kBAtwood			TProgrammer(kBAtwoodFile,		0x0080000000000000ULL, true)
	#define kTArdoin			TProgrammer(kTArdoinFile,		0x0100000000000000ULL, true)
	#define kCStulberger		TProgrammer(kCStulbergerFile,	0x0200000000000000ULL, true)
	#define kPFletcher			TProgrammer(kPFletcherFile,		0x0400000000000000ULL, true)
	#define kVKitanov			TProgrammer(kVKitanovFile,		0x0800000000000000ULL, true)
	#define kZPage				TProgrammer(kZPageFile,			0x1000000000000000ULL, true)
	#define kIRovelov			TProgrammer(kIRovelovFile,		0x2000000000000000ULL, true)
	#define kYSimeonov			TProgrammer(kYSimeonovFile,		0x4000000000000000ULL, true)
	#define kANikolova			TProgrammer(kANikolovaFile,		0x8000000000000000ULL, true)



	#define kActLikeRelease		TProgrammer("No One (null)",		0x00000000,						false)
	#define kNoNetDebug			TProgrammer("No Net Debug",			GSDebug::kNoNetDebugFlag,		false)
	#define kNoBreak			TProgrammer("No Debugger Break",	GSDebug::kNoDebuggerBreakFlag,	false)
	#define kNoWindow			TProgrammer("No Window",			GSDebug::kNoDebugWindowFlag,	false)
	#define kNoStackCrawl		TProgrammer("No Stack Crawl",		GSDebug::kNoStackCrawlFlag,		false)
	#define kOnlyIfActiveUser	TProgrammer("Only If Active user",	GSDebug::kOnlyIfActiveUserFlag,	false)


// Departed Engineers whose ASSERTs have been transferred to some-one/thing else

	#define	kMatt				kRichn


	#define kEveryone			MAKEWHO(kEveryoneFile)

	#if _MAGICFOLDER_
		#define kOpenLog			MAKEWHO("MFOpenLog")
	#else
		#define	kAbortLowMem		MAKEWHO("AbortLowMem")
		#define	kDialogError		MAKEWHO(kDialogClassFile)
		#define	kFastMul			MAKEWHO("FastMul")
		#define	kFastMulInterim		MAKEWHO("FastMul")
		#define	kGrafPortCheck		MAKEWHO("GrafPortCheck")
		#define	kHandleCheck		MAKEWHO(kHandleCheckFile)
		#define	kListFailure		MAKEWHO("ListFailure")
		#define kMCCoordTypes		MAKEWHO("MCCoordTypes")
		#define	kMemTiming			MAKEWHO(kNewMemoryTimingFile)
		#define	kMiniPascal			MAKEWHO(kMiniPascalFile)
		#define	kOverflows			MAKEWHO(kOverflowsFile)
		#define	kPointerCheck		MAKEWHO(kPointerCheckFile)
		#define	kRefListFailure		MAKEWHO("RefListFailure")
		#define	kStaticArrayToWhom	MAKEWHO(kArrayOverflowFile)
		#define	kUnlabled			MAKEWHO("Unlabled Breaks")
		#define	kWorksheetFailure	MAKEWHO("WorksheetFailure")
		#define	kTextFailure		MAKEWHO("TextFailure")
	#endif

	Bool8 GSDEBUG_EXPORT _IsUser(const char *szUser);
	Bool8 GSDEBUG_EXPORT _IsUser(const TProgrammer& who);
	#define ONUSER(user, func)	do { if (::_IsUser(user)) { func; } } while(0)

#else // TEST
// Release version definitions:

	#define __ignore_programmer int(0)

	#define kRich				__ignore_programmer
	#define kSean				__ignore_programmer
	#define kChris				__ignore_programmer
	#define kSteve				__ignore_programmer
	#define kJim				__ignore_programmer
	#define kPaul				__ignore_programmer
	#define kJimG				__ignore_programmer
	#define kDave				__ignore_programmer
	#define kDaveD				__ignore_programmer
	#define kRamsey				__ignore_programmer
	#define kShirley			__ignore_programmer
	#define kMatt				__ignore_programmer
	#define kJeff				__ignore_programmer
	#define kDarick				__ignore_programmer
	#define kAndrewB			__ignore_programmer
	#define	kMark				__ignore_programmer
	#define	kMike				__ignore_programmer
	#define kBruce				__ignore_programmer
	#define kKarim				__ignore_programmer
	#define kRobert				__ignore_programmer
	#define kRichn				__ignore_programmer
	#define kMao				__ignore_programmer
	#define kChao				__ignore_programmer
	#define kNIvanova			__ignore_programmer
	#define kVStanev			__ignore_programmer
	#define kMRizov				__ignore_programmer
    #define kTroy				__ignore_programmer
    #define kEJKerr				__ignore_programmer
    #define kJGeraci			__ignore_programmer
	#define kCaleb				__ignore_programmer
	#define kLewis				__ignore_programmer
	#define kAyo				__ignore_programmer
	#define kGeorge				__ignore_programmer
	#define kVictor				__ignore_programmer
	#define kAbdel				__ignore_programmer
	#define kAlex				__ignore_programmer
	#define kBiplab				__ignore_programmer
	#define kLyndsey			__ignore_programmer
	#define	kDonne				__ignore_programmer
	#define kPKameo				__ignore_programmer
	#define kNHenkel			__ignore_programmer
	#define	kTolu				__ignore_programmer
	#define kAbouzar			__ignore_programmer
	#define kRFoster			__ignore_programmer
	#define kAStanton			__ignore_programmer
	#define kJHutchison			__ignore_programmer
	#define kCGraye				__ignore_programmer
	#define kILane				__ignore_programmer
	#define kBWilliams			__ignore_programmer
	#define kHTsafak			__ignore_programmer
	#define kJLoy				__ignore_programmer
	#define kRLevin				__ignore_programmer
	#define kTYokoyama			__ignore_programmer
	#define kEGorr				__ignore_programmer
	#define JWarshaw			__ignore_programmer
	#define kBAtwood			__ignore_programmer
	#define kEveryone			__ignore_programmer

	#define kActLikeRelease		__ignore_programmer
	#define kNoNetDebug			__ignore_programmer
	#define kNoBreak			__ignore_programmer
	#define kNoWindow			__ignore_programmer
	#define kNoStackCrawl		__ignore_programmer
	#define kOnlyIfActiveUser	__ignore_programmer
	#define	kCarrie				__ignore_programmer
	#define	kTArdoin			__ignore_programmer
	#define	kCStulberger		__ignore_programmer
	#define	kPFletcher			__ignore_programmer
	#define	kVKitanov			__ignore_programmer
	#define kZPage				__ignore_programmer
	#define	kIRovelov			__ignore_programmer
	#define	kYSimeonov			__ignore_programmer
	#define	kANikolova			__ignore_programmer

#endif // TEST

#define kWinOnly				( kJimG | kDave )
#define kDXFers					( kChao | kNIvanova | kVStanev | kVKitanov )


#if TEST

#if BUG
	#if 1 || _MINICAD_EXTERNAL_ || _MAGICFOLDER_ || _GSESDK_ || _GSWINSDK_
		inline void LIMITMESSAGES(const TProgrammer &)								{ }
		inline void LIMITMESSAGES(const EDebugLevel &)								{ }
		inline void LIMITMESSAGES(const TProgrammer &, const EDebugLevel &)			{ }
		inline void LIMITMESSAGES(const EDebugLevel &, const TProgrammer &)			{ }
		inline void LIMITMESSAGES()													{ }
	#else
		extern TProgrammer gProgrammerFilter;
		
		inline void LIMITMESSAGES(const TProgrammer &who)							{ gProgrammerFilter = who; }
		inline void LIMITMESSAGES(const EDebugLevel &level)							{ debugLevel = level; }
		inline void LIMITMESSAGES(const TProgrammer &who, const EDebugLevel &level)	{ LIMITMESSAGES(who); LIMITMESSAGES(level); }
		inline void LIMITMESSAGES(const EDebugLevel &level, const TProgrammer &who)	{ LIMITMESSAGES(who, level); }
		inline void LIMITMESSAGES()													{ LIMITMESSAGES(kEveryone, brief); }
	#endif
#endif // BUG


/*
The following routines and macros are hooked into the network debugging system. You will receive a file
describing when these breaks occur on any Graphsoft Macintosh machine (Engineering, Tech Support, etc.).
*/

int GSDEBUG_EXPORT _FileDebugMessage(const TProgrammer& toWhom, const char *file, int line, const char *message);
int GSDEBUG_EXPORT _Assert(const TProgrammer& toWhom, const char *file, int line, const char *expr);
	// For internal use by ASSERT macro only.

#if !_WINDOWS

	enum {
		kNoBlock = 0,
		kHandle = 1,
		kPointer = 2,
		kFree = 3
	};

	short _FindContainingBlock(const TProgrammer& toWhom, void* ptr, long& result);

	int _AssertNotVolatile(const TProgrammer& toWhom, const char* file, int line, const char* ptrName, void* ptr);
		// For internal use by ASSERTNOTVOLATILE macro only.

#endif // !_WINDOWS

void GSDEBUG_EXPORT CheckHeap(const TProgrammer &toWhom = kEveryone);
	// checks the heap for a number of problems - hooked into the new memory system - checks fragmentation
	// this may be called at any time memory operations are legal - it can take a while with full heaps
	// this is primarily called from the main event loop - you should probably not need to call it



int GSDEBUG_EXPORT _AssertValidPointer(const TProgrammer& toWhom, const char* file, int line, const char* itemName, const void *ptr, long lByteCount=1, Bool8 bReadOnly=false);
Bool8 GSDEBUG_EXPORT _VerifyValidPointer(const TProgrammer& toWhom, const char* file, int line, const char* itemName, const void *ptr, long lCount=1, Bool8 bReadOnly=false);
int GSDEBUG_EXPORT _AssertValidString(Bool8 isAssert, const TProgrammer& toWhom, const char* file, int line, const char* itemName, const char *psz, long cbMin=0, long cbMax=0);
int GSDEBUG_EXPORT _AssertValidHandle(const TProgrammer& toWhom, const char* file, int line, const char* itemName, GSHandle h, long lCount=1);
int GSDEBUG_EXPORT _AssertValidMenuHandle(const TProgrammer& toWhom, const char* file, int line, const char* itemName, GSHandle h);
Bool8 GSDEBUG_EXPORT _VerifyValidHandle(const TProgrammer& toWhom, const char* file, int line, const char* itemName, GSHandle h, long lCount=1);
int GSDEBUG_EXPORT _AssertValidPString(Bool8 isAssert, const TProgrammer& toWhom, const char* file, int line, const char* itemName, ConstGSStringPtr ps, int cbMin=0, int cbMax=0);



#if defined(_INC_WINDOWS) || defined(_GSWIN_) || GS_HWND_CHECK
	extern "C" {
		bool GSDEBUG_EXPORT _ValidateHWND(const TProgrammer& toWhom, bool bAssert, const char* file, int line, const char* itemName, void *hWnd);
		bool GSDEBUG_EXPORT _ValidateHDC(const TProgrammer& toWhom, bool bAssert, const char* file, int line, const char* itemName, void *hdc);

		// *PCP* - we may want to move this back from the structured exceptions file
		//void GSDEBUG_EXPORT ForceFPException_( void );
	}
#endif



/* Debugging macros.  All of these may be used without #ifdef BUG...#endif. */

//
//	ASSERTs
//

inline 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]
#if _WINDOWS
// These are the Windows ASSERT macros.
	#define ASSERTN(toWhom, exp) \
				do { \
					if (!(exp) && _Assert(toWhom, THIS_FILE, __LINE__, #exp)) STOP(); \
				} while (0)

	#define ASSERTLOCKED(toWhom, h) \
			ASSERTHANDLE(toWhom, h, 0);
	#define ASSERTUNLOCKED(toWhom, h) \
			ASSERTHANDLE(toWhom, h, 0);
	#define ASSERTNOTVOLATILE(toWhom, p) \
			ASSERTPOINTER(toWhom, p, 1)
	#define ASSERTHANDLE(toWhom, h, bytes)  \
			do { \
				if (_AssertValidHandle(toWhom,THIS_FILE,__LINE__,#h,(GSHandle)h,bytes)) STOP(); \
			} while (0)

	#define ASSERTPSTRING(toWhom, ps, min, max)  \
			do { \
				if (_AssertValidPString(true,toWhom,THIS_FILE,__LINE__,#ps,(const BugStringPtr)ps,min,max)) STOP(); \
			} while (0)

	#define VERIFYN(toWhom, exp)	\
				((Bool8)( (exp) ? true : (_Assert(toWhom, THIS_FILE, __LINE__, #exp) ? VerifyStop(false) : false ) ))
	#define ASSERTPOINTER_READONLY(toWhom, ptr, bytes) \
				do { \
					if (_AssertValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes,true)) STOP(); \
				} while (0)
	#define ASSERTPOINTER(toWhom, ptr, bytes) \
				do { \
					if (_AssertValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes,false)) STOP(); \
				} while (0)
	#define ASSERTSTRING(toWhom, psz, min, max)  \
				do { \
					if (_AssertValidString(true,toWhom,THIS_FILE,__LINE__,#psz,(const char *)psz,min,max)) STOP(); \
				} while (0)

	#if GS_HWND_CHECK

		#define ASSERTHWND(toWhom, hWnd) \
					do { \
						if (!_ValidateHWND(toWhom,true,THIS_FILE,__LINE__,#hWnd,hWnd)) STOP(); \
					} while (0)
		#define VERIFYHWND(toWhom, hWnd) \
					( _ValidateHWND(toWhom,FALSE,THIS_FILE,__LINE__,#hWnd,hWnd) ? true : false )
		#define ASSERTHDC(toWhom, hdc) \
					do { \
						if (!_ValidateHDC(toWhom,true,THIS_FILE,__LINE__,#hdc,hdc)) STOP(); \
					} while (0)
		#define VERIFYHDC(toWhom, hdc) \
					( _ValidateHDC(toWhom,FALSE,THIS_FILE,__LINE__,#hdc,hdc) ? true : false )
	#endif

//	#define ASSERTNOFPEXCEPTION() \
//				ForceFPException_()

#else	// !_WINDOWS

// These are the Mac ASSERT macros.

#if GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_4
	#define ASSERTN(toWhom, expression)                 DEBUG_DO_NOTHING
#else
	#define ASSERTN(toWhom, expression) \
				do { \
					if (!(expression) && _Assert(toWhom, THIS_FILE, __LINE__, #expression)) STOP(); \
				} while (0)

#endif

#if GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_5
	#define VERIFYN(toWhhom, expression)				((Bool8)( (exp) ? true : false ))
#else
	#define VERIFYN(toWhom, exp)	\
				((Bool8)( (exp) ? true : (_Assert(toWhom, THIS_FILE, __LINE__, #exp) ? VerifyStop(false) : false ) ))
#endif

	#define ASSERTSTRING(toWhom, psz, min, max) \
					((void)_AssertValidString(true,toWhom,THIS_FILE,__LINE__,#psz,(const char *)psz,min,max))

	#define ASSERTPOINTER(toWhom, ptr, bytes) \
					((void)_AssertValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes))

	#define ASSERTPOINTER_READONLY(toWhom, ptr, bytes) ASSERTPOINTER(toWhom, ptr, bytes)

	Bool8 __IsHandleLocked(GSHandle h);

#if GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_2
	#define ASSERTLOCKED(toWhom, h)						DEBUG_DO_NOTHING
	#define ASSERTUNLOCKED(toWhom, h)					DEBUG_DO_NOTHING
#else
	#define ASSERTLOCKED(toWhom,h) \
				( h?(__IsHandleLocked((GSHandle)h) ? (void)0 : (void)_Assert(toWhom,THIS_FILE,__LINE__,"\"" #h " locked\"")) : (void)0 )
	#define ASSERTUNLOCKED(toWhom,h) \
				( h?(__IsHandleLocked((GSHandle)h) ? (void)_Assert(toWhom,THIS_FILE,__LINE__,"\"" #h " unlocked\"") : (void)0) : (void)0 )
#endif

	#define ASSERTNOTVOLATILE(toWhom, p) \
				( ((void)_AssertNotVolatile(toWhom, THIS_FILE, __LINE__, #p, p)) )
	#define ASSERTHANDLE(toWhom, h, bytes) \
				((void)_AssertValidHandle(toWhom,THIS_FILE,__LINE__,#h,(GSHandle)h,bytes))

	#define ASSERTPSTRING(toWhom, ps, min, max) \
				((void)_AssertValidPString(true,toWhom,THIS_FILE,__LINE__,#ps,(const BugStringPtr)ps,min,max))

	#if GS_HWND_CHECK
		#define ASSERTHWND(toWho, hWnd) \
						DEBUG_DO_NOTHING
		#define VERIFYHWND(toWho, hWnd) \
						(FALSE)
	#endif

//	#define ASSERTNOFPEXCEPTION() \
//						DEBUG_DO_NOTHING

#endif // _WINDOWS


// these apply to both Mac and Win versions

#if GS_MAC && GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_2
	#define VERIFYHANDLE(toWhom, h, bytes)				((Bool8)( (h) != 0 ))
	#define ASSERTHEAP(who)								DEBUG_DO_NOTHING
	#define VERIFYPOINTER(toWhom, ptr, bytes)			((Bool8)( (ptr) != 0 ))
	#define VERIFYPOINTER_READONLY(toWhom, ptr, bytes)	((Bool8)( (ptr) != 0 ))
	#define VERIFYSTRING(toWhom, psz, min, max)			((Bool8)( (psz) != 0 ))
	#define VERIFYPSTRING(toWhom, ps, min, max)			((Bool8)( (ps) != 0 ))
	#define ASSERTMENUHANDLE(toWhom, menu)				DEBUG_DO_NOTHING
#else
	
#define VERIFYHANDLE(toWhom, h, bytes)	\
			::_VerifyValidHandle(toWhom,THIS_FILE,__LINE__,#h,(GSHandle)h,bytes)

#define ASSERTHEAP(toWhom) \
			::CheckHeap(toWhom)

#define VERIFYPOINTER(toWhom, ptr, bytes)	\
			::_VerifyValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes,false)

#define VERIFYPOINTER_READONLY(toWhom, ptr, bytes)	\
			::_VerifyValidPointer(toWhom,THIS_FILE,__LINE__,#ptr,ptr,bytes,true)

#define VERIFYSTRING(toWhom, psz, min, max)  \
			::_AssertValidString(false,toWhom,THIS_FILE,__LINE__,#psz,(const char*)psz,min,max)

#define VERIFYPSTRING(toWhom, ps, min, max)  \
			::_AssertValidPString(false,toWhom,THIS_FILE,__LINE__,#ps,(const BugStringPtr)ps,min,max)

#define ASSERTMENUHANDLE(toWhom, menu) \
			::_AssertValidMenuHandle(toWhom,THIS_FILE,__LINE__,#menu,(GSHandle)menu)

#endif   // #if GS_MAC && GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_2


/////////////////////////////////////////////////////////////////////////////////////////
//	DSTOP
#if GS_MAC && GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_3
	#define DSTOP(params)	DEBUG_DO_NOTHING
#else
		#define DSTOP(params)	do { GSDebug::SetDStopFileName(THIS_FILE); \
									 GSDebug::SetDStopLineNumber(__LINE__); \
									 if (::__DebugMessageStop params) STOP(); \
									 GSDebug::SetDStopLineNumber(-1); \
								   } while (0)


#endif

#define GS_REMOVE_CONDITIONAL_DebugMessageStop 1

#if GS_REMOVE_CONDITIONAL_DebugMessageStop
#define DSTOPIF(condition, params) if (condition) DSTOP(params);
#else
#define DSTOPIF(condition, params) DEBUG_DO_NOTHING
#endif

// DSTOP implementation functions.
Bool8 GSDEBUG_EXPORT __DebugMessageStop(const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
Bool8 GSDEBUG_EXPORT __DebugMessageStop(EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
Bool8 GSDEBUG_EXPORT __DebugMessageStop(EDebugLevel level, const char *szFmt, ...);
Bool8 GSDEBUG_EXPORT __DebugMessageStop(const TProgrammer& toWhom, const char *szFmt, ...);
//
#if ! GS_REMOVE_CONDITIONAL_DebugMessageStop
Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, EDebugLevel level, const char *szFmt, ...);
Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, const TProgrammer& toWhom, const char *szFmt, ...);
Bool8 GSDEBUG_EXPORT __DebugMessageStop(Bool8 exp, const char *szFmt, ...);
#endif
/////////////////////////////////////////////////////////////////////////////////////////

#define INLINE


#endif	// TEST


#ifdef BUG

//
//	DMSG
//
#if GS_MAC && GS_MAC_SYMBOL_TABLE_BUG_FIX_LEVEL_1
	#define DMSG(params)
#else
	#define DMSG(params)					::__DebugMessage params
#endif
//


#define DMSGIF(condition, params) if (condition) DMSG(params);

// the modern behavior is to require a TProgrammer attached to all debug calls
#if !GS_USE_ONLY_MODERN || GS_GSDEBUG_BUILD
void GSDEBUG_EXPORT __DebugMessage(EDebugLevel level, const char *szFmt, ...);
void GSDEBUG_EXPORT __DebugMessage(const char *szFmt, ...);
#if ! GS_REMOVE_CONDITIONAL_DebugMessageStop
void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, EDebugLevel level, const char *szFmt, ...);
void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, const char *szFmt, ...);
#endif
#endif
void GSDEBUG_EXPORT __DebugMessage(const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
void GSDEBUG_EXPORT __DebugMessage(EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
void GSDEBUG_EXPORT __DebugMessage(const TProgrammer& toWhom, const char *szFmt, ...);
#if ! GS_REMOVE_CONDITIONAL_DebugMessageStop
void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, const TProgrammer& toWhom, EDebugLevel level, const char *szFmt, ...);
void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, EDebugLevel level, const TProgrammer& toWhom, const char *szFmt, ...);
void GSDEBUG_EXPORT __DebugMessage(Bool8 exp, const TProgrammer& toWhom, const char *szFmt, ...);
#endif
#endif	// ifdef BUG

// New class debugging stuff.

#if GS_USE_CLASS_DEBUGGING
#ifdef BUG
	class GSDEBUG_EXPORT TDumpDevice
	{
	public:
		TDumpDevice();


		virtual ~TDumpDevice() {}
		
		int printf(const TProgrammer &toWhom, int indent, const char *fmt, ...) const;
		int printf(const char *fmt, ...) const;

		void SetIndent(int indent)				{ fIndent = indent; }
		void SetWho(const TProgrammer &toWhom)	{ fWho = toWhom; }

	protected:
		virtual int vprintf(const TProgrammer &toWhom, int indent, const char *fmt, va_list &params) const = 0;

		int fIndent;
		TProgrammer fWho;
	};

	class GSDEBUG_EXPORT TTextDumpDevice : public TDumpDevice
	{
	public:
		virtual ~TTextDumpDevice() {}
	protected:
		int vprintf(const TProgrammer &toWhom, int indent, const char *fmt, va_list &params) const;
	};

	extern TTextDumpDevice gl_stdDumpDevice;

	#define DUMPCLASS(toWhom, ptr)				(ptr)->Dump(toWhom, gl_stdDumpDevice, 0)
#else
	#define DUMPCLASS(toWhom, ptr)				DEBUG_DO_NOTHING
#endif
#define DUMPCLASSH(toWhom, hType, h)			DUMPCLASS(toWhom, *(hType)(h))
#define DUMPCLASSHANDLE(toWhom, h)				DUMPCLASS(toWhom, *(h))
#define DUMPTHISCLASS(toWhom)					DUMPCLASS(toWhom, this)

#ifdef TEST
	#define ASSERTCLASS(toWhom, ptr)			(ptr)->AssertValid(toWhom, true)
	#define VERIFYCLASS(toWhom, ptr)			( (ptr) ? ((ptr)->AssertValid(toWhom, true), true) : VerifyStop(false))
#else
	#define ASSERTCLASS(toWhom, ptr)			DEBUG_DO_NOTHING
	#define VERIFYCLASS(toWhom, ptr)			((ptr) != nil)
#endif
#define ASSERTCLASSH(toWhom, type, h)			ASSERTCLASSHANDLE(toWhom, (type)(h))
#define ASSERTCLASSHANDLE(toWhom, h)			do { if (VERIFYHANDLE(toWhom, h, 0)) ASSERTCLASS(toWhom, *(h)); } while (0)
#define ASSERTTHISCLASS(toWhom)					ASSERTCLASS(toWhom, this)
#define VERIFYCLASSH(toWhom, type, h)			VERIFYCLASSHANDLE(toWhom, (type)(h))
#define VERIFYCLASSHANDLE(toWhom, h)			(VERIFYHANDLE(toWhom, h, 0) ? VERIFYCLASS(toWhom, *(h)) : 0)
#define VERIFYTHISCLASS(toWhom)					VERIFYCLASS(toWhom, this)

#ifdef TEST
	#define DECLARE_ASSERTVALID \
			void AssertValid(const TProgrammer &toWhom, Bool8 bCheckMem) const;
	#define DECLARE_VIRTUAL_ASSERTVALID \
			virtual DECLARE_ASSERTVALID
	#define IMPLEMENT_ASSERTVALID(av_classname, av_parentclass, av_checks) \
			void av_classname::AssertValid(const TProgrammer &toWhom, Bool8 bCheckMem) const \
			{ \
				if (bCheckMem) ASSERTPOINTER(toWhom, this, sizeof(av_classname)); \
				av_parentclass::AssertValid(toWhom, false); \
				av_checks \
			}
#else
	#define DECLARE_ASSERTVALID
	#define DECLARE_VIRTUAL_ASSERTVALID
	#define IMPLEMENT_ASSERTVALID(av_classname, av_parentclass, av_checks)
#endif

#if BUG
	#define DECLARE_DUMP \
			void Dump(const TProgrammer &toWhom, TDumpDevice &dd, int indent) const;
	#define DECLARE_VIRTUAL_DUMP \
			virtual DECLARE_DUMP
	#define IMPLEMENT_DUMP(d_classname, d_parentclass, d_checks) \
			void d_classname::Dump(const TProgrammer &toWhom, TDumpDevice &dd, int indent) const \
			{ \
				if (_IsUser(toWhom)) { \
					d_parentclass::Dump(toWhom, dd, indent); \
					dd.printf(toWhom, indent, #d_classname " class:\n"); \
					++indent; \
					d_checks \
				} \
			}
#else
	#define DECLARE_DUMP
	#define DECLARE_VIRTUAL_DUMP
	#define IMPLEMENT_DUMP(d_classname, d_parentclass, d_checks)
#endif

#if 1 //!_MINICAD_EXTERNAL_
// Use the following macros to dump individual class members.
#define DUMP_BOOL(dp) \
			dd.printf(toWhom, indent, #dp " = %s (%d)\n", (dp) ? "true" : "false", (int)(dp))
#define DUMP_CHAR(dp) \
			DUMP_ITEM("%c", dp)
#define DUMP_CLASS(dp) \
			do { \
				dd.printf(toWhom, indent, #dp " =\n"); \
				(dp).Dump(toWhom, dd, indent+1); \
			} while (0)
#define DUMP_CLASSHANDLE(dp) \
			do { \
				if (dp) DUMP_CLASSPTR(*dp); \
				else DUMP_NULL(dp); \
			} while (0)
#define DUMP_CLASSPTR(dp) \
			do { \
				if (dp) DUMP_CLASS(*dp); \
				else DUMP_NULL(dp); \
			} while (0)
#define DUMP_DOUBLE(dp) \
			DUMP_ITEM("%f", dp)
#define DUMP_HANDLE(dp) \
			do { \
				if (dp && *dp) dd.printf(toWhom, indent, #dp " = %0x08x, *" #dp " = %0x08x\n", dp, *dp); \
				else if (dp) dd.printf(toWhom, indent, #dp " = %0x08x, *" #dp " = NULL\n", dp); \
				else DUMP_NULL(dp); \
			} while (0)
#define DUMP_INT(dp) \
			DUMP_ITEM("%d", dp)
#define DUMP_ITEM(fmt, dp) \
			dd.printf(toWhom, indent, #dp " = " fmt "\n", dp)
#define DUMP_MSG(msg) \
			do { \
				dd.SetIndent(indent); \
				dd.SetWho(toWhom); \
				dd.printf msg; \
			} while (0)
#define DUMP_NULL(dp) \
			dd.printf(toWhom, indent, #dp " = NULL\n")
#define DUMP_PSTR(dp) \
			do { \
				if ((const unsigned char*)(dp)) dd.printf(toWhom, indent, #dp " = len:%d, \"%.*s\"\n", lstrlen(dp), (dp)[0], PASCALPRINT(dp)); \
				else DUMP_NULL(dp); \
			} while (0)
#define DUMP_PTR(dp) \
			do { \
				if (dp) DUMP_ITEM("0x%08x", dp); \
				else DUMP_NULL(dp); \
			} while (0)
#define DUMP_RECT(dp) \
			dd.printf(toWhom, indent, #dp " = (%d,%d)-(%d,%d)\n", RECTPRINT(dp))
#define DUMP_STR(dp) \
			do { \
				if ((const char*)(dp)) dd.printf(toWhom, indent, #dp " = len:%d, \"%s\"\n", lstrlen(dp), (const char*)(dp)); \
				else DUMP_NULL(dp); \
			} while (0)
#endif // !_MINICAD_EXTERNAL_


#define DECLARE_SIZEOF \
	size_t SizeOf() const;
#define IMPLEMENT_SIZEOF(classname) \
	size_t classname::SizeOf() const
#define DECLIMP_SIZEOF(classname) \
	size_t SizeOf() const	{ return sizeof(classname); }


#else

#define DECLARE_ASSERTVALID
#define DECLARE_VIRTUAL_ASSERTVALID
#define IMPLEMENT_ASSERTVALID(av_classname, av_parentclass, av_checks)

#define DECLARE_DUMP
#define DECLARE_VIRTUAL_DUMP
#define IMPLEMENT_DUMP(d_classname, d_parentclass, d_checks)


#endif // GS_USE_CLASS_DEBUGGING


#define DECLARE_CLASS_DEBUGGING \
			DECLARE_ASSERTVALID \
			DECLARE_DUMP

#define DECLARE_VIRTUAL_CLASS_DEBUGGING \
			DECLARE_VIRTUAL_ASSERTVALID \
			DECLARE_VIRTUAL_DUMP

//---------------------------------------------------------------------------------------
class GSDEBUG_EXPORT TDebugObject
// This object is not allowed to have ANY member variables.  sizeof(TDebugObject) == 0
{
	public:
		#if TEST
			void AssertValid(const TProgrammer &toWhom, Bool8 bCheckMem) const;
		#endif
		DECLARE_DUMP
};

//---------------------------------------------------------------------------------------
class GSDEBUG_EXPORT TVirtualDebugObject
{
	public:
		virtual ~TVirtualDebugObject() {}
		DECLARE_VIRTUAL_CLASS_DEBUGGING
};


#if _WINDOWS
////////////////////////////////////////////////////////////////////////////////
// Use the following class to get the message for GetLastError() return code.
// Created by Lewis Kapell on 10/30/98.

class GSDEBUG_EXPORT TWinErrorCode
{
	public:
		TWinErrorCode();
		~TWinErrorCode();

		operator const char *() const		{ return (const char *)fMessageBuffer; }

	private:
		void *fMessageBuffer;
};
#endif	// _WINDOWS


///////////////////////////////////////////////////////////////////////////////
#if _WINDOWS && TEST

	int GSDEBUG_EXPORT _AssertValidFilePath(Bool8 isAssert, const TProgrammer& toWhom, const char* file, int line, const char* itemName, const char* fullPath);

	#define ASSERTPATH(who, fullPath) \
			do { \
				if (::_AssertValidFilePath(true, who, THIS_FILE, __LINE__, #fullPath, fullPath)) STOP(); \
			} while (0)

	#define VERIFYPATH(who, fullPath) \
				::_AssertValidFilePath(false, who, THIS_FILE, __LINE__, #fullPath, fullPath)

#else

	#define ASSERTPATH(who, fullPath)				DEBUG_DO_NOTHING
	#define VERIFYPATH(who, fullPath)				((BOOL)( (fullPath) != 0 ))

#endif // _MAGICFOLDER_ && TEST


// Put anything in this block which should not be defined in the final version,
// but is defined in the bug version & test version.

#if !defined(TEST)
	// These macros do nothing in release code.

	#if !defined(_MINICAD_EXTERNAL_)
		#define DEBUG_INIT(appName, flags)				DEBUG_DO_NOTHING
		#define DEBUG_SETEXE(hInst)						DEBUG_DO_NOTHING
		#define DEBUG_TERMINATE()						DEBUG_DO_NOTHING
		#define DEBUG_SETPARENTWINDOW(h)				DEBUG_DO_NOTHING
	#endif

	#define ASSERTN(toWhom, goodval)					DEBUG_DO_NOTHING
	#define ASSERTSTRING(toWhom, psz, min, max)			DEBUG_DO_NOTHING
	#define ASSERTPOINTER(toWhom, h, bytes)				DEBUG_DO_NOTHING
	#define ASSERTPOINTER_READONLY(toWhom, h, bytes)	DEBUG_DO_NOTHING

	#define ASSERTLOCKED(toWhom, h)						DEBUG_DO_NOTHING
	#define ASSERTUNLOCKED(toWhom, h)					DEBUG_DO_NOTHING
	#define ASSERTHANDLE(toWhom, ptr, bytes)			DEBUG_DO_NOTHING
	#define ASSERTMENUHANDLE(toWhom, menu)				DEBUG_DO_NOTHING
	#define ASSERTNOTVOLATILE(toWhom, p)				DEBUG_DO_NOTHING
	#define ASSERTHEAP(who)								DEBUG_DO_NOTHING

	#define ASSERTPSTRING(toWhom, ps, min, max)			DEBUG_DO_NOTHING

	#define ONUSER(user, func)							DEBUG_DO_NOTHING
	#define DSTOP(params)								DEBUG_DO_NOTHING
	#define DMSGIF(condition, params) 					DEBUG_DO_NOTHING
	#define DSTOPIF(condition, params) 					DEBUG_DO_NOTHING
	#define DSTOPIF(condition, params) 					DEBUG_DO_NOTHING

//	#define ASSERTNOFPEXCEPTION()						DEBUG_DO_NOTHING

	#if GS_HWND_CHECK
		#define ASSERTHWND(toWho, hWnd)					DEBUG_DO_NOTHING
		#define ASSERTHDC(toWhom, hdc)					DEBUG_DO_NOTHING
	#endif


	// These macros still do something in release code.
	#define INLINE										inline
	#define VERIFYSTRING(toWhom, psz, min, max)			((Bool8)( (psz) != 0 ))
	#define VERIFYN(toWhom, exp)						((Bool8)( (exp) ? true : false ))
	#define VERIFYPOINTER(toWhom, ptr, bytes)			((Bool8)( (ptr) != 0 ))
	#define VERIFYPOINTER_READONLY(toWhom, ptr, bytes)	((Bool8)( (ptr) != 0 ))
	#define VERIFYHANDLE(toWhom, h, bytes)				((Bool8)( (h) != 0 ))
	#define VERIFYPSTRING(toWhom, ps, min, max)			((Bool8)( (ps) != 0 ))

	#if GS_HWND_CHECK
		#define VERIFYHDC(toWhom, hdc)					((Bool8)( (hdc) != NULL ))
		#define VERIFYHWND(toWhom, hwnd)				((Bool8)( (hwnd) != NULL ))
	#endif
	
#endif	// !TEST

// Put anything in this block which should not be defined in the test version,
// or the final version, but is defined in the bug version

#if !defined(BUG)
	#define DMSG(params)	DEBUG_DO_NOTHING

	inline void LIMITMESSAGES(const TProgrammer &)							{}
	inline void LIMITMESSAGES(const EDebugLevel &)							{}
	inline void LIMITMESSAGES(const TProgrammer &, const EDebugLevel &)		{}
	inline void LIMITMESSAGES(const EDebugLevel &, const TProgrammer &)		{}
	inline void LIMITMESSAGES()												{}

#endif	// !BUG

#endif  // __cplusplus

#endif // _GSDEBUG_H_
