222 lines
8.8 KiB
C
Executable File
222 lines
8.8 KiB
C
Executable File
/*
|
|
* _DEBUG.H
|
|
*
|
|
* Header file for ArchiveLib 2.0
|
|
*
|
|
* Copyright (c) 1994-1996 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
|
|
*
|
|
* August 10, 1994 1.0B : A few changes to help out UNIX.
|
|
*
|
|
* February 14, 1996 2.0A : New release
|
|
*/
|
|
|
|
#ifndef __DEBUG_H
|
|
#define __DEBUG_H
|
|
/*
|
|
* _ALAssertFailure is the function called by AL_ASSERT() and
|
|
* AL_ASSERT_OBJECT() when their assertion fails.
|
|
*/
|
|
AL_LINKAGE 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) /* Tag debug macro */
|
|
#define AL_ASSERT_OBJECT( pointer, class, message ) ((void) 0) /* Tag debug macro */
|
|
|
|
#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 ) /* Tag debug macro */ \
|
|
( ( 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 )
|
|
# 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* I had to change the name of the arguments to this macro in order
|
|
* to avoid a Sun CC warning message. The arguments were originally
|
|
* named "pointer" and "class". I got a couple of warning messages
|
|
* telling me that "macro substitutions not performed in strings", like
|
|
* anyone is going to think that...
|
|
*/
|
|
|
|
#define AL_ASSERT_OBJECT( ptr, cls, message ) /* Tag debug macro */ \
|
|
( ptr == 0 || IsBadWritePtr( ptr, sizeof( cls ) ) ) ? \
|
|
_ALAssertFailure( "IsBadWritePtr()", \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
"%s: Bad pointer to object of class %s", \
|
|
message, \
|
|
#cls ) \
|
|
: \
|
|
( ( (cls *)ptr)->GoodTag() ? \
|
|
(void) 0 \
|
|
: \
|
|
_ALAssertFailure( #ptr "->GoodTag()", \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
"%s: %s is not an object of class %s", \
|
|
message, \
|
|
#ptr, \
|
|
#cls ) )
|
|
#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 { /* Tag debug type */
|
|
_ALDeletedObjectTag = 0,
|
|
_ALStorageTag,
|
|
_ALFileTag,
|
|
_ALMemoryBaseTag,
|
|
_ALMemoryTag,
|
|
_ALHugeMemoryTag,
|
|
_ALWinMemoryTag,
|
|
_ALEntryTag,
|
|
_ALEntryListTag,
|
|
_ALArchiveTag,
|
|
_ALGlArchiveTag,
|
|
_ALPkArchiveTag,
|
|
_ALMonitorTag,
|
|
_ALBarGraphTag,
|
|
_ALSpinnerTag,
|
|
_ALWindowsMessageTag,
|
|
_ALEngineTag,
|
|
_ALCompressorTag,
|
|
_ALDecompressorTag,
|
|
_ALCopyCompressorTag,
|
|
_ALCopyDecompressorTag,
|
|
_ALGlCompressorTag,
|
|
_ALGlDecompressorTag,
|
|
_ALPkCompressorTag,
|
|
_ALPkDecompressorTag,
|
|
_ALBadEngineTag,
|
|
_ALCompressedObjectTag,
|
|
_ALNameTag,
|
|
_ALWildCardExpanderTag,
|
|
_ALOs2MessageTag,
|
|
_ALToolKitTag,
|
|
_ALSimpleMonitorTag
|
|
};
|
|
|
|
/*
|
|
* 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 { /* Tag debug macro */ \
|
|
public : \
|
|
unsigned char mucTagVal; \
|
|
} mMyTag; \
|
|
int AL_INLINE_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 { /* Tag debug macro */ \
|
|
public : \
|
|
AL_INLINE_PROTO _ALTag##x(){ mucTagVal = x; } \
|
|
AL_INLINE_PROTO ~_ALTag##x(){ mucTagVal = _ALDeletedObjectTag; } \
|
|
unsigned char mucTagVal; \
|
|
} mMyTag; \
|
|
int AL_INLINE_PROTO GoodTag(){ return mMyTag.mucTagVal == x; }
|
|
#endif /* #if !defined( NDEBUG ) && !defined( AL_CLASS_TAG ) */
|
|
#endif /* #ifndef __DEBUG_H */
|