requireToDebuggerOrNote.c from redshed at Krugle
Show requireToDebuggerOrNote.c syntax highlighted
/****************************************************************************************
requireToDebuggerOrNote.c $Revision: 3 $
<http://rentzsch.com/require>
Copyright © 1997-2002 Red Shed Software. All rights reserved.
by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
Reports requirement failures via DebugStr() if a debugger is installed. Otherwise the
failure is reported via the Notification Manager.
When compiling for Carbon, requires C++ (see below).
When reporting via the Notification Manager, a failure will not halt the caller.
When reporting via the Notification Manager, if the program hits another requirement
failure and there is an outstanding failure notification, the second WILL NOT BE
REPORTED.
************************************************************************************/
#include "requireImplementation.c"
#ifndef __NOTIFICATION__
#include "Notification.h"
#endif // __NOTIFICATION__
typedef struct {
NMRec nm;
Str255 str;
} NMStr;
pascal
void
NMDisplayProc(
NMRecPtr nmReqPtr );
NMStr gNote;
Boolean gNoteShowing = false;
// When compiling for Carbon, C++ needs to be turned on. We need to allocate a
// routine descriptor for the notification manager's callback.
//
// Under Classic 68K, routine descriptors aren't used and no allocation is
// necessary.
//
// Under CFM (either CFM-68K or CFM-PPC), we can use the BUILD_ROUTINE_DESCRIPTOR
// macro, which builds the routine descriptor at compile time and it loaded with
// the rest of the code, automatically.
//
// The Carbon engineers, in their infinite wisdom, REQUIRES we call a function that
// in turn (under Mac OS 9) WILL CALL NEWROUTINEDESCRIPTOR, WHICH WILL CALL NEWPTR!
// This can't be done at interrupt time, and the requirements package WILL be
// called at interrupt time. The work-around is to give gProc an initial value of a
// function, which can only be done using C++. The C++ support runtime will execute
// the function before entering main(), at system task time.
#if TARGET_API_MAC_CARBON
NMUPP gProc = NewNMUPP( NMDisplayProc );
#else
#if TARGET_RT_MAC_CFM
RoutineDescriptor gRD = BUILD_ROUTINE_DESCRIPTOR( uppNMProcInfo, NMDisplayProc );
NMUPP gProc = &gRD;
#else
NMUPP gProc = &NMDisplayProc;
#endif
#endif
Boolean
IsDebuggerCallable();
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, Jul 21, 1997 Created.
************************************************************************************/
void
RequireNotice(
const char *msg,
const char *code,
const char *note,
long nmbr,
const char *file,
long line,
long errn )
{
Str255 outStr = "\p";
#define out outStr, sizeof( Str255 ) - 1
// Message line.
if( msg )
RAppendCStringToPString( msg, out );
else
RAppendPStringToPString( "\pGeneric Require Failure", out );
// Note line.
if( note ) {
RAppendPStringToPString( "\p\r note: ", out );
RAppendCStringToPString( note, out );
}
// File line.
if( file ) {
RAppendPStringToPString( "\p\r file: ", out );
RAppendCStringToPString( file, out );
}
// Line line.
if( line ) {
RAppendPStringToPString( "\p\r line: ", out );
RAppendLongToPString( line, out );
}
// Errn line.
if( errn ) {
RAppendPStringToPString( "\p\r errn: ", out );
RAppendLongToPString( errn, out );
}
// Nmbr line.
if( nmbr ) {
RAppendPStringToPString( "\p\r nmbr: ", out );
RAppendLongToPString( nmbr, out );
}
// Code line.
if( code ) {
RAppendPStringToPString( "\p\r code: ", out );
RAppendCStringToPString( code, out );
}
#undef out
if( IsDebuggerCallable() ) {
DebugStr( outStr );
} else if( !gNoteShowing ) {
gNoteShowing = true;
BlockMoveData( outStr, gNote.str, outStr[ 0 ] + 1 );
gNote.nm.qType = nmType;
gNote.nm.nmMark = 0;
gNote.nm.nmIcon = nil;
gNote.nm.nmSound = nil;
gNote.nm.nmStr = gNote.str;
gNote.nm.nmResp = gProc;
gNote.nm.nmRefCon = SetCurrentA5();
NMInstall( &gNote.nm );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sun, Jan 30, 2000 Created.
Stolen from Debugging.h:
"Tech Q&A PLAT-30 says to check bit 5 of the byte at 0xbff to
determine whether Macsbug ( or any other low level debugger )
is installed; I also check that MacJmp ( which points to the
entry point for the debugger ) is not nil and not -1.
MacJmpFlag:
Bit 5 should be set to indicate the debugger is installed.
Bit 6 should be set to indicate the debugger is initialized.
Bit 7 should be clear to indicate that the debugger is NOT busy
Dr. Macsbug says to also check that the byte at 0xBFF isn't 0xFF."
This probably isn't kosher under Mac OS X...
************************************************************************************/
Boolean
IsDebuggerCallable()
{
UInt32 macJmp = *(UInt32*)0x0120;
UInt8 macJmpFlag = *(UInt8*)0x0BFF;
return( macJmpFlag != 0xFF
&& (macJmpFlag & 0xE0) == 0x60
&& macJmp != 0
&& macJmp != 0xFFFFFFFF );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Jan 29, 2000 Created.
************************************************************************************/
pascal
void
NMDisplayProc(
NMRecPtr nmReqPtr )
{
long oldA5;
OSErr err = NMRemove( nmReqPtr );
oldA5 = SetA5( nmReqPtr->nmRefCon );
gNoteShowing = false;
SetA5( oldA5 );
}
See more files for this project here