194 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*
 | 
						|
 * _DEBUG.H
 | 
						|
 *
 | 
						|
 *  Header file for ArchiveLib 1.0
 | 
						|
 *
 | 
						|
 *  Copyright (c) 1994 Greenleaf Software, Inc.
 | 
						|
 *  All Rights Reserved
 | 
						|
 *
 | 
						|
 * DESCRIPTION
 | 
						|
 *
 | 
						|
 *  These macros and types are all used in the debug versions of the
 | 
						|
 *  ArchiveLib.
 | 
						|
 * 
 | 
						|
 * MACROS
 | 
						|
 *
 | 
						|
 *   _ALAssertFailure()
 | 
						|
 *   AL_ASSERT()
 | 
						|
 *   AL_ASSERT_OBJECT()
 | 
						|
 *   AL_CLASS_TAG()
 | 
						|
 * 
 | 
						|
 * PROTOTYPES:
 | 
						|
 *
 | 
						|
 *   IsBadWritePtr()
 | 
						|
 *
 | 
						|
 * ENUMERATED TYPES:
 | 
						|
 *
 | 
						|
 *   _ALClassTags
 | 
						|
 *
 | 
						|
 * REVISION HISTORY
 | 
						|
 *
 | 
						|
 *  May 26, 1994  1.0A  : First release
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef __DEBUG_H
 | 
						|
#define __DEBUG_H
 | 
						|
/*
 | 
						|
 * _ALAssertFailure is the function called by AL_ASSERT() and
 | 
						|
 * AL_ASSERT_OBJECT() when their assertion fails.
 | 
						|
 */
 | 
						|
void AL_CFUNCTION _ALAssertFailure( const char AL_DLL_FAR *condition,
 | 
						|
                                    const char AL_DLL_FAR *filename,
 | 
						|
                                    int line,
 | 
						|
                                    const char AL_DLL_FAR *message,
 | 
						|
                                    ... );
 | 
						|
#ifdef NDEBUG
 | 
						|
/*
 | 
						|
 * In the non-debug versions, both of these macros basically go away.
 | 
						|
 * The only difficulty is trying to avoid having the compilers generate
 | 
						|
 * error messages when they see this code.  Maybe in NDEBUG mode I could
 | 
						|
 * change these to inline functions that do nothing?
 | 
						|
 */
 | 
						|
 | 
						|
#define AL_ASSERT( condition, message ) ((void) 0)
 | 
						|
#define AL_ASSERT_OBJECT( pointer, class, message ) ((void) 0)
 | 
						|
 | 
						|
#else
 | 
						|
/*
 | 
						|
 * In debug mode, AL_ASSERT() tests the condition, and generates
 | 
						|
 * an abort with an error message when the condition fails.
 | 
						|
 */
 | 
						|
#define AL_ASSERT( condition, message )             \
 | 
						|
            ( ( condition ) ?                       \
 | 
						|
                   (void) 0 :                       \
 | 
						|
                   _ALAssertFailure( #condition,    \
 | 
						|
                                     __FILE__,      \
 | 
						|
                                     __LINE__,      \
 | 
						|
                                     message ) )    \
 | 
						|
/*
 | 
						|
 * I can only call IsBadWritePtr() if TOOLHELP.DLL is available.  As far
 | 
						|
 * as I know, it won't be available with any of the DOS Extenders
 | 
						|
 * The only way we have access to TOOLHELP.DLL is if we are *really*
 | 
						|
 * running under Windows, not some bogus imitation.
 | 
						|
 */
 | 
						|
#if !defined( AL_WINDOWS_GUI ) 
 | 
						|
  #define IsBadWritePtr( p, s ) 0
 | 
						|
#endif
 | 
						|
/*
 | 
						|
 * AL_ASSERT_OBJECT() is a great macro.  It is used to test the 
 | 
						|
 * validity of an object.  This is a two step process.  First,
 | 
						|
 * we make sure we are dealing with a good pointer.  If not, an
 | 
						|
 * asserting error is triggered.  This is much better than the
 | 
						|
 * GPF you would normally get from a bad pointer.  Next, we
 | 
						|
 * test the GoodTag() macro, which verifies that this is
 | 
						|
 * a properly constructed object from the specified class.  Of
 | 
						|
 * course, in NDEBUG mode this all goes away.
 | 
						|
 *
 | 
						|
 */ 
 | 
						|
#define AL_ASSERT_OBJECT( pointer, class, message )                    \
 | 
						|
    ( pointer == 0 || IsBadWritePtr( pointer, sizeof( class ) ) ) ?    \
 | 
						|
        _ALAssertFailure( "IsBadWritePtr()",                           \
 | 
						|
                          __FILE__,                                    \
 | 
						|
                          __LINE__,                                    \
 | 
						|
                          "%s: Bad pointer to object of class %s",     \
 | 
						|
                          message,                                     \
 | 
						|
                          #class )                                     \
 | 
						|
     :                                                                 \
 | 
						|
        ( ( (class *)pointer)->GoodTag() ?                             \
 | 
						|
            (void) 0                                                   \
 | 
						|
    :                                                                  \
 | 
						|
            _ALAssertFailure( #pointer "->GoodTag()",                  \
 | 
						|
            __FILE__,                                                  \
 | 
						|
            __LINE__,                                                  \
 | 
						|
            "%s: %s is not an object of class %s",                     \
 | 
						|
            message,                                                   \
 | 
						|
            #pointer,                                                  \
 | 
						|
            #class ) )
 | 
						|
#endif
 | 
						|
/*
 | 
						|
 * The AL_CLASS_TAG() macro assigns a new debug class and data
 | 
						|
 * member to each of the classes in ArchiveLib.  Each of these
 | 
						|
 * debug classes uses a special integer tag (stored in the data member)
 | 
						|
 * to uniquely identify itself.  These are the integer values of
 | 
						|
 * these integers.
 | 
						|
 */
 | 
						|
 | 
						|
enum _ALClassTags {
 | 
						|
    _ALDeletedObjectTag = 0,
 | 
						|
    _ALStorageTag,
 | 
						|
    _ALFileTag,
 | 
						|
    _ALMemoryTag,
 | 
						|
    _ALEntryTag,
 | 
						|
    _ALEntryListTag,
 | 
						|
    _ALArchiveBaseTag,
 | 
						|
    _ALArchiveTag,
 | 
						|
    _ALMonitorTag,
 | 
						|
    _ALBarGraphTag,
 | 
						|
    _ALSpinnerTag,
 | 
						|
    _ALWindowsMessageTag,
 | 
						|
    _ALCompressionEngineTag,
 | 
						|
    _ALCopyEngineTag,
 | 
						|
    _ALGreenleafEngineTag,
 | 
						|
    _ALCompressedObjectTag,
 | 
						|
    _ALNameTag,
 | 
						|
    _ALWildCardExpanderTag,
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * AL_CLASS_TAG( x ) is a macro that is used to help debug
 | 
						|
 * ArchiveLib.  The insertion of this macro in a class definition
 | 
						|
 * adds a new data member and member function to the class.  The
 | 
						|
 * data member is an object of a class uniquely created by the
 | 
						|
 * macro.  The reason the data member is a class object instead
 | 
						|
 * of a simple integer or character tag is this: By making it a 
 | 
						|
 * class object, we can automatically assign it a valid value
 | 
						|
 * when constructed, and an invalid value when destroyed.
 | 
						|
 *
 | 
						|
 * The member function added to the class is called GoodTag().
 | 
						|
 * Once you have added AL_CLASS_TAG( x ) to your class definition,
 | 
						|
 * you can call object.GoodTag() anytime you want.  It will return
 | 
						|
 * a true value only if the data member has the correct value,
 | 
						|
 *
 | 
						|
 * We make use of this function in AL_ASSERT_OBJECT().  It
 | 
						|
 * checks the value of this object frequently in member functions
 | 
						|
 * and destructors, generating an assertion failure if the object
 | 
						|
 * doesn't look like the correct type.
 | 
						|
 *
 | 
						|
 * Note that the ASSERT_OBJECT() statements generate no code when the 
 | 
						|
 * library is compiled with NDEBUG, so this class will not be 
 | 
						|
 * generating much low overhead.  However, the data member will
 | 
						|
 * still be taking up a single byte in each instance.
 | 
						|
 *
 | 
						|
 * If you want to eliminate class tags, this line in will do it
 | 
						|
 * You will save one byte per instance.  The best way to accomplish this
 | 
						|
 * is to define the macro in ALCUSTOM.H, then rebuild the library with
 | 
						|
 * macro AL_CUSTOM defined in your project.  After you build this new
 | 
						|
 * version of the library, you must absolutely, positively, be sure
 | 
						|
 * that you continue to use AL_CUSTOM and ALCUSTOM.H when working
 | 
						|
 * with the library.  If you don't, your library and your application
 | 
						|
 * will think that most classes in ArchiveLib are different sizes, and
 | 
						|
 * *nothing* will work.
 | 
						|
 *
 | 
						|
 *#define AL_CLASS_TAG( x ) int GoodTag(){ return 1; }
 | 
						|
 */
 | 
						|
 | 
						|
#if defined( NDEBUG ) && !defined( AL_CLASS_TAG )
 | 
						|
  #define AL_CLASS_TAG( x ) class AL_CLASS_TYPE _ALTag##x {                   \
 | 
						|
               public :                                                       \
 | 
						|
                   unsigned char mucTagVal;                                   \
 | 
						|
              } mMyTag;                                                       \
 | 
						|
              int AL_PROTO GoodTag(){ return 1; }
 | 
						|
#endif  /* #if defined( NDEBUG ) && !defined( AL_CLASS_TAG ) */
 | 
						|
 | 
						|
#if !defined( NDEBUG ) && !defined( AL_CLASS_TAG )
 | 
						|
  #define AL_CLASS_TAG( x ) class AL_CLASS_TYPE _ALTag##x {                   \
 | 
						|
               public :                                                       \
 | 
						|
                   AL_PROTO _ALTag##x(){ mucTagVal = x; }                     \
 | 
						|
                   AL_PROTO ~_ALTag##x(){ mucTagVal = _ALDeletedObjectTag; }  \
 | 
						|
                   unsigned char mucTagVal;                                   \
 | 
						|
              } mMyTag;                                                       \
 | 
						|
              int AL_PROTO GoodTag(){ return mMyTag.mucTagVal == x; }
 | 
						|
#endif /* #if !defined( NDEBUG ) && !defined( AL_CLASS_TAG ) */
 | 
						|
#endif /* #ifndef __DEBUG_H      */
 |