/********************************************************************* FILENAME Exceptions.h DESCRIPTION A collection of routines and macros to handle assertions and exceptions. COPYRIGHT Copyright © Apple Computer, Inc. 1989-1991 All rights reserved. ROUTINES EXTERNALS dprintf check_dprintf checkpos_dprintf MACROS EXTERNALS check ncheck check_action ncheck_action require nrequire require_action nrequire_action resume MODIFICATION HISTORY Nov 12 95 BKJ Moved to MetroWerks environment & the NSPR NOTE To keep code size down, use these routines and macros with the C compiler option -b2 or -b3. This will eliminate duplicate strings within a procedure. *********************************************************************/ #ifndef __MACERRORHANDLING__ #define __MACERRORHANDLING__ /********************************************************************* INCLUDES *********************************************************************/ #include /**/ /********************************************************************* CONSTANTS AND CONTROL *********************************************************************/ /* These defines are used to control the amount of information displayed when an assertion fails. DEBUGOFF and WARN will run silently. MIN will simply break into the debugger. ON will break and display the assertion that failed and the exception (for require statements). FULL will also display the source file name and line number. SYM does a SysBreak and is usefull when using a symbolic debugger like SourceBug or SADE. They should be set into DEBUGLEVEL. The default LEVEL is OFF. */ #define DEBUGOFF 0 #define DEBUGWARN 1 #define DEBUGMIN 2 #define DEBUGON 3 #define DEBUGFULL 4 #define DEBUGSYM 6 #ifndef DEBUGLEVEL #define DEBUGLEVEL DEBUGOFF #endif DEBUGLEVEL /* resumeLabel is used to control the insertion of labels for use with the resume macro. If you do not use the resume macro and you wish to have multible exceptions per label then you can add the following define to you source code. */ #define resumeLabel(exception) // Multiple exceptions per label // #define resumeLabel(exception) resume_ ## exception: // Single exception per label /* traceon and debugon are used to test for options */ #define traceon ((DEBUGLEVEL > DEBUGWARN) && defined(TRACEON)) #define debugon (DEBUGLEVEL > DEBUGWARN) /* Add some macros for DEBUGMIN and DEBUGSYM to keep the size down. */ #define __DEBUGSMALL ((DEBUGLEVEL == DEBUGMIN) || \ (DEBUGLEVEL == DEBUGSYM)) #if DEBUGLEVEL == DEBUGMIN #define __DebuggerBreak Debugger() #elif DEBUGLEVEL == DEBUGSYM #define __DebuggerBreak SysBreak() #endif /**/ /********************************************************************* MACRO check(assertion) DESCRIPTION If debugging is on then check will test assertion and if it fails break into the debugger. Otherwise check does nothing. *********************************************************************/ #if __DEBUGSMALL #define check(assertion) \ do { \ if (assertion) ; \ else __DebuggerBreak; \ } while (false) #elif DEBUGLEVEL == DEBUGON #define check(assertion) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define check(assertion) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed\n" \ "File: %s\n" \ "Line: %d", \ #assertion, __FILE__, __LINE__); \ } \ } while (false) #else #define check(assertion) #endif /**/ /********************************************************************* MACRO ncheck(assertion) DESCRIPTION If debugging is on then ncheck will test !assertion and if it fails break into the debugger. Otherwise ncheck does nothing. *********************************************************************/ #if __DEBUGSMALL #define ncheck(assertion) \ do { \ if (assertion) __DebuggerBreak; \ } while (false) #elif DEBUGLEVEL == DEBUGON #define ncheck(assertion) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \ #assertion, __privateAssertion); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define ncheck(assertion) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ "File: %s\n" \ "Line: %d", \ #assertion, __privateAssertion, __FILE__, __LINE__); \ } \ } while (false) #else #define ncheck(assertion) #endif /**/ /********************************************************************* MACRO check_action(assertion, action) DESCRIPTION If debugging is on then check_action will test assertion and if it fails break into the debugger then execute action. Otherwise check_action does nothing. *********************************************************************/ #if __DEBUGSMALL #define check_action(assertion, action) \ do { \ if (assertion) ; \ else { \ __DebuggerBreak; \ { action } \ } while (false) #elif DEBUGLEVEL == DEBUGON #define check_action(assertion, action) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed", #assertion); \ { action } \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define check_action(assertion, action) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed\n" \ "File: %s\n" \ "Line: %d", \ #assertion, __FILE__, __LINE__); \ { action } \ } \ } while (false) #else #define check_action(assertion, action) #endif /**/ /************************************************************************************** MACRO ncheck_action(assertion, action) DESCRIPTION If debugging is on then ncheck_action will test !assertion and if it fails break into the debugger then execute action. Otherwise ncheck_action does nothing. *********************************************************************/ #if __DEBUGSMALL #define ncheck_action(assertion, action) \ do { \ if (assertion) { \ __DebuggerBreak; \ { action } \ } \ } while (false) #elif DEBUGLEVEL == DEBUGON #define ncheck_action(assertion, action) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed", \ #assertion, __privateAssertion); \ { action } \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define ncheck_action(assertion, action) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ "File: %s\n" \ "Line: %d", \ #assertion, __privateAssertion, __FILE__, __LINE__); \ { action } \ } \ } while (false) #else #define ncheck_action(assertion, action) #endif /**/ /********************************************************************* MACRO require(assertion, exception) DESCRIPTION require will test assertion and if it fails: break into the debugger if debugging is on. goto exception. *********************************************************************/ #if __DEBUGSMALL #define require(assertion, exception) \ do { \ if (assertion) ; \ else { \ __DebuggerBreak; \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGON #define require(assertion, exception) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed\n" \ "Exception \"%s\" Raised", \ #assertion, #exception); \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define require(assertion, exception) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed\n" \ "Exception \"%s\" Raised\n" \ "File: %s\n" \ "Line: %d", \ #assertion, #exception, __FILE__, __LINE__); \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #else #define require(assertion, exception) \ do { \ if (assertion) ; \ else { \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #endif /**/ /********************************************************************* MACRO nrequire(assertion, exception) DESCRIPTION nrequire will test !assertion and if it fails: break into the debugger if debugging is on. goto exception. *********************************************************************/ #if __DEBUGSMALL #define nrequire(assertion, exception) \ do { \ if (assertion) { \ DebugStr(); \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGON #define nrequire(assertion, exception) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ "Exception \"%s\" Raised", \ #assertion, __privateAssertion, #exception); \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define nrequire(assertion, exception) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ "Exception \"%s\" Raised\n" \ "File: %s\n" \ "Line: %d", \ #assertion, __privateAssertion, #exception, __FILE__, \ __LINE__); \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #else #define nrequire(assertion, exception) \ do { \ if (assertion) { \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #endif /**/ /********************************************************************* MACRO require_action(assertion, exception, action) DESCRIPTION require_action will test assertion and if it fails: break into the debugger if debugging is on. execute action. goto exception. *********************************************************************/ #if __DEBUGSMALL #define require_action(assertion, exception, action) \ do { \ if (assertion) ; \ else { \ __DebuggerBreak; \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGON #define require_action(assertion, exception, action) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed\n" \ "Exception \"%s\" Raised", \ #assertion, #exception); \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define require_action(assertion, exception, action) \ do { \ if (assertion) ; \ else { \ dprintf(notrace, "Assertion \"%s\" Failed\n" \ "Exception \"%s\" Raised\n" \ "File: %s\n" \ "Line: %d", \ #assertion, #exception, __FILE__, __LINE__); \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #else #define require_action(assertion, exception, action) \ do { \ if (assertion) ; \ else { \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #endif /**/ /********************************************************************* MACRO nrequire_action(assertion, exception, action) DESCRIPTION nrequire_action will test !assertion and if it fails: break into the debugger if debugging is on. execute action. goto exception. *********************************************************************/ #if __DEBUGSMALL #define nrequire_action(assertion, exception, action) \ do { \ if (assertion) { \ __DebuggerBreak; \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGON #define nrequire_action(assertion, exception, action) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ "Exception \"%s\" Raised", \ #assertion, __privateAssertion, #exception); \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #elif DEBUGLEVEL == DEBUGFULL #define nrequire_action(assertion, exception, action) \ do { \ void* __privateAssertion = (void*)(assertion); \ \ if (__privateAssertion) { \ dprintf(notrace, "Assertion \"!(%s [= %#08X])\" Failed\n" \ "Exception \"%s\" Raised\n" \ "File: %s\n" \ "Line: %d", \ #assertion, __privateAssertion, #exception, __FILE__, \ __LINE__); \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #else #define nrequire_action(assertion, exception, action) \ do { \ if (assertion) { \ { action } \ goto exception; \ resumeLabel(exception); \ } \ } while (false) #endif /**/ /********************************************************************* MACRO resume(exception) DESCRIPTION resume will resume execution after the n/require/_action statement specified by exception. Resume lables must be on (the default) in order to use resume. If an action form of require was used then the action will not be re-executed. *********************************************************************/ #define resume(exception) \ do { \ goto resume_ ## exception; \ } while (false) /**/ /********************************************************************/ #endif