/*
     File:       AssertMacros.h
 
     Contains:   This file defines structured error handling and assertion macros for
                 programming in C. Originally used in QuickDraw GX and later enhanced.
                 These macros are used throughout Apple's software.

                 See "Living In an Exceptional World" by Sean Parent
                 (develop, The Apple Technical Journal, Issue 11, August/September 1992)
                 <http://developer.apple.com/dev/techsupport/develop/issue11toc.shtml>
                 for the methodology behind these error handling and assertion macros.

     Copyright:  © 2002 by Apple Computer, Inc., all rights reserved.
  
     Bugs?:      For bug reports, consult the following page on
                 the World Wide Web:
 
                     http://developer.apple.com/bugreporter/ 
*/
#ifndef __ASSERTMACROS__
#define __ASSERTMACROS__


/*
 *  Macro overview:
 *  
 *      check(assertion)
 *         In production builds, pre-processed away  
 *         In debug builds, if assertion evaluates to false, calls DEBUG_ASSERT_MESSAGE
 *  
 *      verify(assertion)
 *         In production builds, evaluates assertion and does nothing
 *         In debug builds, if assertion evaluates to false, calls DEBUG_ASSERT_MESSAGE
 *  
 *      require(assertion, exceptionLabel)
 *         In production builds, if the assertion expression evaluates to false, goto exceptionLabel
 *         In debug builds, if the assertion expression evaluates to false, calls DEBUG_ASSERT_MESSAGE
 *                          and jumps to exceptionLabel
 *  
 *      In addition the following suffixes are available:
 * 
 *         _noerr     Adds "!= 0" to assertion.  Useful for asserting and OSStatus or OSErr is noErr (zero)
 *         _action    Adds statement to be executued if assertion fails
 *         _quiet     Suppress call to DEBUG_ASSERT_MESSAGE
 *         _string    Allows you to add explanitory message to DEBUG_ASSERT_MESSAGE
 *  
 *        For instance, require_noerr_string(resultCode, label, msg) will do nothing if 
 *        resultCode is zero, otherwise it will call DEBUG_ASSERT_MESSAGE with msg
 *        and jump to label.
 *
 *  Configuration:
 *
 *      By default all macros generate "production code" (i.e non-debug).  If  
 *      DEBUG_ASSERT_PRODUCTION_CODE is defined to zero or DEBUG is defined to non-zero
 *      while this header is included, the macros will generated debug code.
 *
 *      If DEBUG_ASSERT_COMPONENT_NAME_STRING is defined, all debug messages will
 *      be prefixed with it.
 *
 *      By default, all messages write to stderr.  If you would like to write a custom
 *      error message formater, defined DEBUG_ASSERT_MESSAGE to your function name.
 *
 */


/*
 *  Before including this file, #define DEBUG_ASSERT_COMPONENT_NAME_STRING to
 *  a C-string containing the name of your client. This string will be passed to
 *  the DEBUG_ASSERT_MESSAGE macro for inclusion in any assertion messages.
 *
 *  If you do not define DEBUG_ASSERT_COMPONENT_NAME_STRING, the default
 *  DEBUG_ASSERT_COMPONENT_NAME_STRING value, an empty string, will be used by
 *  the assertion macros.
 */
#ifndef DEBUG_ASSERT_COMPONENT_NAME_STRING
    #define DEBUG_ASSERT_COMPONENT_NAME_STRING ""
#endif


/*
 *  To activate the additional assertion code and messages for non-production builds,
 *  #define DEBUG_ASSERT_PRODUCTION_CODE to zero before including this file.
 *
 *  If you do not define DEBUG_ASSERT_PRODUCTION_CODE, the default value 1 will be used
 *  (production code = no assertion code and no messages).
 */
#ifndef DEBUG_ASSERT_PRODUCTION_CODE
   #define DEBUG_ASSERT_PRODUCTION_CODE !DEBUG
#endif


/*
 *  DEBUG_ASSERT_MESSAGE(component, assertion, label, error, file, line, errorCode)
 *
 *  Summary:
 *    All assertion messages are routed through this macro. If you wish to use your
 *    own routine to display assertion messages, you can override DEBUG_ASSERT_MESSAGE
 *    by #defining DEBUG_ASSERT_MESSAGE before including this file.
 *
 *  Parameters:
 *
 *    componentNameString:
 *      A pointer to a string constant containing the name of the
 *      component this code is part of. This must be a string constant
 *      (and not a string variable or NULL) because the preprocessor
 *      concatenates it with other string constants.
 *
 *    assertionString:
 *      A pointer to a string constant containing the assertion.
 *      This must be a string constant (and not a string variable or
 *      NULL) because the Preprocessor concatenates it with other
 *      string constants.
 *    
 *    exceptionLabelString:
 *      A pointer to a string containing the exceptionLabel, or NULL.
 *    
 *    errorString:
 *      A pointer to the error string, or NULL. DEBUG_ASSERT_MESSAGE macros
 *      must not attempt to concatenate this string with constant
 *      character strings.
 *    
 *    fileName:
 *      A pointer to the fileName or pathname (generated by the
 *      preprocessor __FILE__ identifier), or NULL.
 *    
 *    lineNumber:
 *      The line number in the file (generated by the preprocessor
 *      __LINE__ identifier), or 0 (zero).
 *    
 *    errorCode:
 *      A value associated with the assertion, or 0.
 *
 *  Here is an example of a DEBUG_ASSERT_MESSAGE macro and a routine which displays
 *  assertion messsages:
 *
 *      #define DEBUG_ASSERT_COMPONENT_NAME_STRING "MyCoolProgram"
 *
 *      #define DEBUG_ASSERT_MESSAGE(componentNameString, assertionString,                           \
 *                                   exceptionLabelString, errorString, fileName, lineNumber, errorCode) \
 *              MyProgramDebugAssert(componentNameString, assertionString,                           \
 *                                   exceptionLabelString, errorString, fileName, lineNumber, errorCode)
 *
 *      static void
 *      MyProgramDebugAssert(const char *componentNameString, const char *assertionString, 
 *                           const char *exceptionLabelString, const char *errorString, 
 *                           const char *fileName, long lineNumber, int errorCode)
 *      {
 *          if ( (assertionString != NULL) && (*assertionString != '\0') )
 *              fprintf(stderr, "Assertion failed: %s: %s\n", componentNameString, assertionString);
 *          else
 *              fprintf(stderr, "Check failed: %s:\n", componentNameString);
 *          if ( exceptionLabelString != NULL )
 *              fprintf(stderr, "    %s\n", exceptionLabelString);
 *          if ( errorString != NULL )
 *              fprintf(stderr, "    %s\n", errorString);
 *          if ( fileName != NULL )
 *              fprintf(stderr, "    file: %s\n", fileName);
 *          if ( lineNumber != 0 )
 *              fprintf(stderr, "    line: %ld\n", lineNumber);
 *          if ( errorCode != 0 )
 *              fprintf(stderr, "    error: %d\n", errorCode);
 *      }
 *
 *  If you do not define DEBUG_ASSERT_MESSAGE, a simple printf to stderr will be used.
 */
#ifndef DEBUG_ASSERT_MESSAGE
   #ifdef KERNEL
      #include <syslog.h>
      #define DEBUG_ASSERT_MESSAGE(name, assertion, label, message, file, line, value) \
                                  syslog(LOG_ERR, "AssertMacros: %s, %s file: %s, line: %d\n", assertion, (message!=0) ? message : "", file, line);
   #else
      #include <stdio.h>
      #define DEBUG_ASSERT_MESSAGE(name, assertion, label, message, file, line, value) \
                                  fprintf(stderr, "AssertMacros: %s, %s file: %s, line: %d\n", assertion, (message!=0) ? message : "", file, line);
   #endif
#endif





/*
 *  debug_string(message)
 *
 *  Summary:
 *    Production builds: does nothing and produces no code.
 *
 *    Non-production builds: call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    message:
 *      The C string to display.
 *
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define debug_string(message)
#else
   #define debug_string(message)                                              \
      do                                                                      \
      {                                                                       \
          DEBUG_ASSERT_MESSAGE(                                               \
              DEBUG_ASSERT_COMPONENT_NAME_STRING,                             \
              "",                                                             \
              0,                                                              \
              message,                                                        \
              __FILE__,                                                       \
              __LINE__,                                                       \
              0);                                                             \
      } while ( 0 )
#endif


/*
 *  check(assertion)
 *
 *  Summary:
 *    Production builds: does nothing and produces no code.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define check(assertion)
#else
   #define check(assertion)                                                   \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  0,                                                          \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
          }                                                                   \
      } while ( 0 )
#endif

#define ncheck(assertion)                                                     \
  check(!(assertion))


/*
 *  check_string(assertion, message)
 *
 *  Summary:
 *    Production builds: does nothing and produces no code.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define check_string(assertion, message)
#else
   #define check_string(assertion, message)                                   \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  0,                                                          \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
          }                                                                   \
      } while ( 0 )
#endif

#define ncheck_string(assertion, message)                                     \
  check_string(!(assertion), message)


/*
 *  check_noerr(errorCode)
 *
 *  Summary:
 *    Production builds: does nothing and produces no code.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The errorCode expression to compare with 0.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define check_noerr(errorCode)
#else
   #define check_noerr(errorCode)                                             \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  0,                                                          \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
          }                                                                   \
      } while ( 0 )
#endif


/*
 *  check_noerr_string(errorCode, message)
 *
 *  Summary:
 *    Production builds: check_noerr_string() does nothing and produces
 *    no code.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The errorCode expression to compare to 0.
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define check_noerr_string(errorCode, message)
#else
   #define check_noerr_string(errorCode, message)                             \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  0,                                                          \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
          }                                                                   \
      } while ( 0 )
#endif


/*
 *  verify(assertion)
 *
 *  Summary:
 *    Production builds: evaluate the assertion expression, but ignore
 *    the result.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define verify(assertion)                                                  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
          }                                                                   \
      } while ( 0 )
#else
   #define verify(assertion)                                                  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  0,                                                          \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
          }                                                                   \
      } while ( 0 )
#endif

#define nverify(assertion)                                                    \
  verify(!(assertion))


/*
 *  verify_string(assertion, message)
 *
 *  Summary:
 *    Production builds: evaluate the assertion expression, but ignore
 *    the result.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define verify_string(assertion, message)                                  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
          }                                                                   \
      } while ( 0 )
#else
   #define verify_string(assertion, message)                                  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  0,                                                          \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
          }                                                                   \
      } while ( 0 )
#endif

#define nverify_string(assertion, message)                                    \
  verify_string(!(assertion), message)


/*
 *  verify_noerr(errorCode)
 *
 *  Summary:
 *    Production builds: evaluate the errorCode expression, but ignore
 *    the result.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define verify_noerr(errorCode)                                            \
      do                                                                      \
      {                                                                       \
          if ( 0 != (errorCode) )                                             \
          {                                                                   \
          }                                                                   \
      } while ( 0 )
#else
   #define verify_noerr(errorCode)                                            \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  0,                                                          \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
          }                                                                   \
      } while ( 0 )
#endif


/*
 *  verify_noerr_string(errorCode, message)
 *
 *  Summary:
 *    Production builds: evaluate the errorCode expression, but ignore
 *    the result.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define verify_noerr_string(errorCode, message)                            \
      do                                                                      \
      {                                                                       \
          if ( 0 != (errorCode) )                                             \
          {                                                                   \
          }                                                                   \
      } while ( 0 )
#else
   #define verify_noerr_string(errorCode, message)                            \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  0,                                                          \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
          }                                                                   \
      } while ( 0 )
#endif


/*
 *  verify_action(assertion, action)
 *
 *  Summary:
 *    Production builds: if the assertion expression evaluates to false,
 *    then execute the action statement or compound statement (block).
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE and then execute the action statement or compound
 *    statement (block).
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    action:
 *      The statement or compound statement (block).
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define verify_action(assertion, action)                                   \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              action;                                                         \
          }                                                                   \
      } while ( 0 )
#else
   #define verify_action(assertion, action)                                  \
     do                                                                      \
      {                                                                      \
          if ( !(assertion) )                                                \
          {                                                                  \
             DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                        \
                  #assertion,                                                \
                  0,                                                         \
                  0,                                                         \
                  __FILE__,                                                  \
                  __LINE__,                                                  \
                  0);                                                        \
             { action; }                                                     \
         }                                                                   \
     } while ( 0 )
#endif


/*
 *  require(assertion, exceptionLabel)
 *
 *  Summary:
 *    Production builds: if the assertion expression evaluates to false,
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    exceptionLabel:
 *      The label.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require(assertion, exceptionLabel)                                 \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require(assertion, exceptionLabel)                                 \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  #exceptionLabel,                                            \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif

#define nrequire(assertion, exceptionLabel)                                   \
  require(!(assertion), exceptionLabel)


/*
 *  require_action(assertion, exceptionLabel, action)
 *
 *  Summary:
 *    Production builds: if the assertion expression evaluates to false,
 *    execute the action statement or compound statement (block) and then
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE, execute the action statement or compound
 *    statement (block), and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    action:
 *      The statement or compound statement (block).
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require_action(assertion, exceptionLabel, action)                  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require_action(assertion, exceptionLabel, action)                  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  #exceptionLabel,                                            \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif

#define nrequire_action(assertion, exceptionLabel, action)                    \
  require_action(!(assertion), exceptionLabel, action)


/*
 *  require_quiet(assertion, exceptionLabel)
 *
 *  Summary:
 *    If the assertion expression evaluates to false, goto exceptionLabel.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    exceptionLabel:
 *      The label.
 */
#define require_quiet(assertion, exceptionLabel)                              \
  do                                                                          \
  {                                                                           \
      if ( !(assertion) )                                                     \
      {                                                                       \
          goto exceptionLabel;                                                \
      }                                                                       \
  } while ( 0 )

#define nrequire_quiet(assertion, exceptionLabel)                             \
  require_quiet(!(assertion), exceptionLabel)


/*
 *  require_action_quiet(assertion, exceptionLabel, action)
 *
 *  Summary:
 *    If the assertion expression evaluates to false, execute the action
 *    statement or compound statement (block), and goto exceptionLabel.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    action:
 *      The statement or compound statement (block).
 */
#define require_action_quiet(assertion, exceptionLabel, action)               \
  do                                                                          \
  {                                                                           \
      if ( !(assertion) )                                                     \
      {                                                                       \
          {                                                                   \
              action;                                                         \
          }                                                                   \
          goto exceptionLabel;                                                \
      }                                                                       \
  } while ( 0 )

#define nrequire_action_quiet(assertion, exceptionLabel, action)              \
  require_action_quiet(!(assertion), exceptionLabel, action)


/*
 *  require_string(assertion, exceptionLabel, message)
 *
 *  Summary:
 *    Production builds: if the assertion expression evaluates to false,
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE, and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require_string(assertion, exceptionLabel, message)                 \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require_string(assertion, exceptionLabel, message)                 \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  #exceptionLabel,                                            \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif

#define nrequire_string(assertion, exceptionLabel, string)                    \
  require_string(!(assertion), exceptionLabel, string)


/*
 *  require_action_string(assertion, exceptionLabel, action, message)
 *
 *  Summary:
 *    Production builds: if the assertion expression evaluates to false,
 *    execute the action statement or compound statement (block), and then
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the assertion expression evaluates to false,
 *    call DEBUG_ASSERT_MESSAGE, execute the action statement or compound
 *    statement (block), and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    assertion:
 *      The assertion expression.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    action:
 *      The statement or compound statement (block).
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require_action_string(assertion, exceptionLabel, action, message)  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require_action_string(assertion, exceptionLabel, action, message)  \
      do                                                                      \
      {                                                                       \
          if ( !(assertion) )                                                 \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #assertion,                                                 \
                  #exceptionLabel,                                            \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  0);                                                         \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif

#define nrequire_action_string(assertion, exceptionLabel, action, message)    \
  require_action_string(!(assertion), exceptionLabel, action, message)


/*
 *  require_noerr(errorCode, exceptionLabel)
 *
 *  Summary:
 *    Production builds: if the errorCode expression does not equal 0 (noErr),
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 *
 *    exceptionLabel:
 *      The label.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require_noerr(errorCode, exceptionLabel)                           \
      do                                                                      \
      {                                                                       \
          if ( 0 != (errorCode) )                                             \
          {                                                                   \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require_noerr(errorCode, exceptionLabel)                           \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  #exceptionLabel,                                            \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif

/*
 *  require_noerr_action(errorCode, exceptionLabel, action)
 *
 *  Summary:
 *    Production builds: if the errorCode expression does not equal 0 (noErr),
 *    execute the action statement or compound statement (block) and
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE, execute the action statement or
 *    compound statement (block), and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    action:
 *      The statement or compound statement (block).
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require_noerr_action(errorCode, exceptionLabel, action)            \
      do                                                                      \
      {                                                                       \
          if ( 0 != (errorCode) )                                             \
          {                                                                   \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require_noerr_action(errorCode, exceptionLabel, action)            \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  #exceptionLabel,                                            \
                  0,                                                          \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif


/*
 *  require_noerr_quiet(errorCode, exceptionLabel)
 *
 *  Summary:
 *    If the errorCode expression does not equal 0 (noErr),
 *    goto exceptionLabel.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 *
 *    exceptionLabel:
 *      The label.
 */
#define require_noerr_quiet(errorCode, exceptionLabel)                        \
  do                                                                          \
  {                                                                           \
      if ( 0 != (errorCode) )                                                 \
      {                                                                       \
          goto exceptionLabel;                                                \
      }                                                                       \
  } while ( 0 )


/*
 *  require_noerr_action_quiet(errorCode, exceptionLabel, action)
 *
 *  Summary:
 *    If the errorCode expression does not equal 0 (noErr),
 *    execute the action statement or compound statement (block) and
 *    goto exceptionLabel.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    action:
 *      The statement or compound statement (block).
 */
#define require_noerr_action_quiet(errorCode, exceptionLabel, action)         \
  do                                                                          \
  {                                                                           \
      if ( 0 != (errorCode) )                                                 \
      {                                                                       \
          {                                                                   \
              action;                                                         \
          }                                                                   \
          goto exceptionLabel;                                                \
      }                                                                       \
  } while ( 0 )


/*
 *  require_noerr_string(errorCode, exceptionLabel, message)
 *
 *  Summary:
 *    Production builds: if the errorCode expression does not equal 0 (noErr),
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE, and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require_noerr_string(errorCode, exceptionLabel, message)           \
      do                                                                      \
      {                                                                       \
          if ( 0 != (errorCode) )                                             \
          {                                                                   \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require_noerr_string(errorCode, exceptionLabel, message)           \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  #exceptionLabel,                                            \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif


/*
 *  require_noerr_action_string(errorCode, exceptionLabel, action, message)
 *
 *  Summary:
 *    Production builds: if the errorCode expression does not equal 0 (noErr),
 *    execute the action statement or compound statement (block) and
 *    goto exceptionLabel.
 *
 *    Non-production builds: if the errorCode expression does not equal 0 (noErr),
 *    call DEBUG_ASSERT_MESSAGE, execute the action statement or compound
 *    statement (block), and then goto exceptionLabel.
 *
 *  Parameters:
 *
 *    errorCode:
 *      The expression to compare to 0.
 *
 *    exceptionLabel:
 *      The label.
 *
 *    action:
 *      The statement or compound statement (block).
 *
 *    message:
 *      The C string to display.
 */
#if DEBUG_ASSERT_PRODUCTION_CODE
   #define require_noerr_action_string(errorCode, exceptionLabel, action, message)\
      do                                                                      \
      {                                                                       \
          if ( 0 != (errorCode) )                                             \
          {                                                                   \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#else
   #define require_noerr_action_string(errorCode, exceptionLabel, action, message) \
      do                                                                      \
      {                                                                       \
          int evalOnceErrorCode = (errorCode);                                \
          if ( 0 != evalOnceErrorCode )                                       \
          {                                                                   \
              DEBUG_ASSERT_MESSAGE(                                           \
                  DEBUG_ASSERT_COMPONENT_NAME_STRING,                         \
                  #errorCode " == 0 ",                                        \
                  #exceptionLabel,                                            \
                  message,                                                    \
                  __FILE__,                                                   \
                  __LINE__,                                                   \
                  evalOnceErrorCode);                                         \
              {                                                               \
                  action;                                                     \
              }                                                               \
              goto exceptionLabel;                                            \
          }                                                                   \
      } while ( 0 )
#endif


#endif /* __ASSERTMACROS__ */

