NS/dev/tankefugl/source/util/ZassertTemplate.cpp

195 lines
5.6 KiB
C++

// ZASSERT AND STACKTRACE are an improved assertion system which augments
// the WIN32 assert.h standard _assert.
// (c) 1999 Zachary B. Simpson
// Code may be used and distributed freely as long as all
// changes are noted appropriately.
//
// This is a simple program which test the ZASSERT
// and STACKTRACE funtctions with some arbitrary calls.
//
// This supplies LEVEL 2 "Template" Code for implementing
// the assert and emailToBugDatabase functions
#ifdef WIN32
#include "windows.h"
// Only needed for message box
#include "winbase.h"
#include <process.h>
#endif
#include "stdio.h"
#include "stacktrace.h"
#include "zassert.h"
// LEVEL 2 CODE
// The following is template code which can be cut, pasted,
// and modified appropriately for your application.
//-------------------------------------------------------------------
HWND hRunAssertBox;
int breakpointOnAssert = 0;
// If this flag is set and it is a debug build then
// it will issue an int 3 causing a breakpoint in the
// debugger. This is very handy for ensuring that
// the programmer can exmaine memory, etc.
// default is 0.
int getBreakpointOnAssert()
{
return breakpointOnAssert;
}
void setBreakpointOnAssert(int inValue)
{
breakpointOnAssert = inValue;
}
// The following is a template for the function
// which gets called by the runAssertBox
// in the case that the user hits the "email" button
// This is LEVEL 2 "Template" Code
#ifdef WIN32
void emailToBugDatabase( char *msg ) {
int success = emailMsgTo( msg, "bugs@overmind.org" );
// Note that you MUST specify the full name of the computer
// since emailMsgTo does NOT use the MX record. In other
// words, you can't specify "zsimpson@eden.com"
if( !success ) {
MessageBox(
NULL,
"Email to bug database failed.\r\n"
"Please \"Copy\" the message and send it to the appropriate database.",
"E-Mail Failed",
MB_APPLMODAL|MB_ICONEXCLAMATION
);
}
}
#endif
// This is LEVEL 2 "Template" Code
// The following is a template for the function
// which ultimately gets called by the assert macros
// NOTE the use of the ASSERTFUNC macro which makes this PORTABLE
// The declaration is:
// void _assert( void *msg, void *file, unsigned line )
ASSERTFUNC {
// Just in case, prevent recursion
static int recurse = 0;
if( recurse ) {
// Under GNU C you may get a warning concerning this
// return since ASSERTFUNC is declared noreturn.
// Ignore the warning.
return;
}
recurse = 1;
// Run a stack trace, skip the assert call (passing 1)
char *stackMsg = stackTrace(1);
// Setup and application specific information
// You should put all code that you want to add to the
// assert message here. For example, you might want
// to include:
// * version numbers
// * computer name
// * user name
// * date, time, etc.
// * relevant state information (direct draw, CD/HD, etc)
// * debug staus, heap check, etc.
char *appMsg = "ASSERT TEST VERSION 1.0";
//
char buffer[4096]={0,};
strcpy( buffer, "The system has failed an assertion:\r\nAssert: \"" );
strcpy( buffer+strlen(buffer), (char *)msg );
sprintf( buffer+strlen(buffer), "\" @ %s:%d\r\n", file, line );
if( appMsg && *appMsg ) {
sprintf( buffer+strlen(buffer), "%s\r\n", appMsg );
}
sprintf( buffer+strlen(buffer), "%s\r\n", stackMsg );
// Trace the assert out to a file just for good measure.
FILE *f = fopen( "assert.txt", "w+b" );
if( f ) {
fprintf( f, buffer );
fclose( f );
}
// Trace the assert to STDOUT. Especially important
// for UNIX since this is the only message you'll see.
printf( buffer );
// breakpointOnAssert is true this will force a debugger
// to stop. Ideally, it would be possible to determine
// if we are currently running in a debugger so that this
// flag would not be necessary, but I have been unable
// to figure out how to do this.
// If you hit this breakpoint and you want to keep
// running, don't forget that you can simply skip over the
// exit call by changing the debugger change EIP command.
#ifdef _DEBUG
//#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
#ifdef WIN32
if( breakpointOnAssert )
//if(IsDebuggerPresent())
{
__asm int 3;
}
#endif
//#endif
#endif
// Create the assert box. Note that a real implementation
// should translate all of the stock messages.
#ifdef WIN32
hRunAssertBox = (HWND)createAssertBox( buffer, emailToBugDatabase );
//unsigned long theRC = _beginthread(runAssertBox, 0, hAssertBox);
//runAssertBox( hAssertBox );
int theRC = atexit(theExitRunAssertBox);
//ASSERT(theRC == 0);
#else
// Under UNIX, send the email immediately.
emailMsgTo( buffer, "bugs@overmind.org" );
#endif
// And finally, shut down.
exit(1);
}
//---------------------------------------------------------------------
// The following code is all testing code for
// REGRESSION PURPOSES.
// DO NOT COPY into your application
void freeFunc( int a, char *string ) {
assert( 0 == 1 );
// assert now, we should get a stack trace
// indicting freeFunc( 0xDEADBEEF, PTR() )
// and a hex dump of the pointer
}
//struct Boink {
// int a;
// int b;
//
// void method1( int _a, int _b ) {
// method2( _a+1, _b, "This is a test" );
// }
// void method2( int _a, int _b, char *msg ) {
// freeFunc( 0xDEADBEEF, msg );
// }
//};
//
//void main( int argc, char **argv ) {
// // Setup breakpoint to make debugging easier when in debugger
// breakpointOnAssert = 1;
//
// // Call method which is assert...
// Boink b;
// b.method1(10,20);
//}