requireImplementation.c from redshed at Krugle
Show requireImplementation.c syntax highlighted
/****************************************************************************************
requireImplementation.c $Revision: 30 $
<http://rentzsch.com/require>
Copyright © 1997-2002 Red Shed Software. All rights reserved.
by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
************************************************************************************/
#include "requireDefinitions.h"
/**************************
*
* Funky Protos
*
**************************/
#pragma mark (Funky Protos)
void
RequireNotice(
const char *msg,
const char *code,
const char *note,
long nmbr,
const char *file,
long line,
long errn );
void
MemoryDummy(
short value );
UInt32
RAppendStringToString(
const void *source,
UInt32 sourceSize,
void *target,
UInt32 targetSize,
UInt32 maxSize );
void
RAppendStringToPString(
const void *source,
UInt32 sourceSize,
StringPtr target,
UInt32 maxSize );
void
RAppendPStringToPString(
const StringPtr source,
StringPtr target,
UInt32 maxSize );
void
RAppendCStringToPString(
const char *source,
StringPtr target,
UInt32 maxSize );
void
RAppendLongToPString(
long number,
StringPtr to,
UInt32 maxSize );
UInt8
RLongToString(
long number,
void *string,
UInt32 maxSize );
UInt32
RGetCStringLength(
const char *string );
char*
RPToCString(
StringPtr string );
/****************************************************************************************
*
* Interfaces
*
****************************************************************************************/
#pragma mark -
#pragma mark (Interfaces)
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, Jul 21, 1997 Created.
************************************************************************************/
void
_Require(
const char *code, // The code that broke the requirement.
const char *note, // Programmer's note (often nil).
const char *file, // File that contains the code that broke the requirement.
long line ) // Line of the file of the code that broke the requirement.
{
RequireNotice( "Require Failed", code, note, 0, file, line, 0 );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 30, 1999 Created.
wolf Sat, Jan 29, 2000 Carbonized.
wolf Mon, Jun 12, 2000 Wrapped test for possible deferenced nil pointer
in a TARGET_API_MAC_CARBON block.
************************************************************************************/
void
_RequireMacPtr(
const void *ptr,
const char *name,
const char *file,
long line )
{
OSErr err;
if( ptr ) {
if( (long) ptr % 4 )
RequireNotice( "Mac Ptr is misaligned", name, nil, 0, file, line, 0 );
#if !TARGET_API_MAC_CARBON
if( ptr == *(void**) 0 )
RequireNotice( "Mac Ptr is possibly a dereferenced nil ptr", name, nil,
0, file, line, 0 );
#endif // TARGET_API_MAC_CARBON
if( (long) ptr < 256 )
RequireNotice( "Mac Ptr is below 256 bytes", name, nil, 0, file, line, 0 );
// Force a dereference to cause a crash if the ptr is bogus
MemoryDummy( *(short*) ptr );
// Call a couple Toolbox routines to make sure the pointer is Toolbox-okay.
#if TARGET_API_MAC_CARBON
err = !IsPointerValid( (Ptr) ptr );
if( err )
RequireNotice( "IsPointerValid returned false", name, nil, 0, file, line, 0 );
#else // TARGET_API_MAC_CARBON
(void) PtrZone( (Ptr) ptr );
err = MemError();
if( err )
RequireNotice( "PtrZone got an error", name, nil, 0, file, line, err );
#endif // TARGET_API_MAC_CARBON
if( !err ) {
(void) GetPtrSize( (Ptr) ptr );
err = MemError();
if( err )
RequireNotice( "GetPtrSize got an error", name, nil, 0, file, line, err );
}
} else {
RequireNotice( "Ptr is nil", name, nil, 0, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, Jul 21, 1997 Created.
wolf Mon, Jun 12, 2000 Wrapped test for possible deferenced nil pointer
in a TARGET_API_MAC_CARBON block.
************************************************************************************/
void
_RequirePtrAlign(
const void *ptr,
const char *name,
unsigned long align,
const char *file,
long line )
{
if( ptr ) {
if( (long) ptr % align )
RequireNotice( "Ptr is misaligned", name, nil, 0, file, line, 0 );
#if !TARGET_API_MAC_CARBON
if( ptr == *(void**) 0 )
RequireNotice( "Ptr is possibly a dereferenced nil ptr", name, nil,
0, file, line, 0 );
#endif // TARGET_API_MAC_CARBON
if( (unsigned long) ptr < 256 )
RequireNotice( "Ptr is below 256 bytes", name, nil, 0, file, line, 0 );
// Force a dereference to cause a crash if the ptr is bogus
MemoryDummy( *(short*) ptr );
} else {
RequireNotice( "Ptr is nil", name, nil, 0, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, Jul 21, 1997 Created.
wolf Sat, Jan 29, 2000 Carbonized.
wolf Mon, Jun 12, 2000 Wrapped test for possible deferenced nil pointer
in a TARGET_API_MAC_CARBON block.
************************************************************************************/
void
_RequireHandle(
const void *handle, // The handle to test.
const char *name, // The name of the handle.
const char *file, // The file which contains the handle.
long line ) // The line of the file of the requirement test.
{
Ptr ptr;
OSErr err;
if( handle ) {
// Make sure the handle is a valid pointer.
if( (long) handle % 4 )
RequireNotice( "Handle is misaligned", name, nil, 0, file, line, 0 );
#if !TARGET_API_MAC_CARBON
if( handle == *(void**) 0 )
RequireNotice( "Handle is possibly a dereferenced nil ptr", name, nil,
0, file, line, 0 );
#endif // TARGET_API_MAC_CARBON
if( (long) handle < 256 )
RequireNotice( "Handle is below 256 bytes", name, nil, 0, file, line, 0 );
MemoryDummy( *(short*) handle );
// Now make sure the master pointer is valid. Note an valid empty handle will have
// a nil master pointer.
ptr = *(char**)handle;
if( (long) ptr % 4 )
RequireNotice( "Handle's master pointer is misaligned", name, nil, 0, file, line, 0 );
if( ptr != nil && (long) ptr < 256 )
RequireNotice( "Handle's master pointer is below 256 bytes", name, nil, 0, file, line, 0 );
MemoryDummy( *(short*) ptr );
// Finally, call a couple Toolbox routines to make sure the handle is Toolbox-okay.
#if TARGET_API_MAC_CARBON
err = !IsHandleValid( (Handle) handle );
if( err )
RequireNotice( "IsHandleValid returned false", name, nil, 0, file, line, 0 );
#else // TARGET_API_MAC_CARBON
(void) HandleZone( (Handle) handle );
err = MemError();
if( err )
RequireNotice( "HandleZone got an error", name, nil, 0, file, line, err );
#endif // TARGET_API_MAC_CARBON
if( !err && ptr != nil ) {
(void) GetHandleSize( (Handle) handle );
err = MemError();
if( err )
RequireNotice( "GetHandleSize got an error", name, nil, 0, file, line, err );
}
} else {
RequireNotice( "Handle is nil", name, nil, 0, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, May 17, 1999 Created.
wolf Sat, Jan 29, 2000 Carbonized.
wolf Mon, Jun 12, 2000 Wrapped test for possible deferenced nil pointer
in a TARGET_API_MAC_CARBON block.
************************************************************************************/
void
_RequireResHandle(
const void *handle, // The resource handle to test.
const char *name, // The name of the handle.
const char *file, // The file which contains the handle.
long line ) // The line of the file of the requirement test.
{
Ptr ptr;
OSErr err;
if( handle ) {
// Make sure the handle is a valid pointer.
if( (long) handle % 4 )
RequireNotice( "Resource Handle is misaligned", name, nil, 0, file, line, 0 );
#if !TARGET_API_MAC_CARBON
if( handle == *(void**) 0 )
RequireNotice( "Resource Handle is possibly a dereferenced nil ptr", name, nil,
0, file, line, 0 );
#endif // TARGET_API_MAC_CARBON
if( (long) handle < 256 )
RequireNotice( "Resource Handle is below 256 bytes", name, nil, 0, file, line, 0 );
MemoryDummy( *(short*) handle );
// Now make sure the master pointer is valid. Note an valid empty handle will have
// a nil master pointer.
ptr = *(char**)handle;
if( (long) ptr % 4 )
RequireNotice( "Resource Handle's master pointer is misaligned", name, nil, 0, file, line, 0 );
if( ptr != nil && (long) ptr < 256 )
RequireNotice( "Resource Handle's master pointer is below 256 bytes", name, nil, 0, file, line, 0 );
MemoryDummy( *(short*) ptr );
// Finally, call a couple Toolbox routines to make sure the handle is Toolbox-okay.
#if TARGET_API_MAC_CARBON
err = !IsHandleValid( (Handle) handle );
if( err )
RequireNotice( "IsHandleValid returned false", name, nil, 0, file, line, 0 );
#else // TARGET_API_MAC_CARBON
(void) HandleZone( (Handle) handle );
err = MemError();
if( err )
RequireNotice( "HandleZone got an error", name, nil, 0, file, line, err );
#endif // TARGET_API_MAC_CARBON
if( !err && ptr != nil ) {
(void) GetHandleSize( (Handle) handle );
err = MemError();
if( err )
RequireNotice( "GetHandleSize got an error", name, nil, 0, file, line, err );
GetResAttrs( (Handle) handle );
err = ResError();
if( err )
RequireNotice( "GetResAttr got an error", name, nil, 0, file, line, err );
}
} else {
RequireNotice( "Resource Handle is nil", name, nil, 0, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Aug 26, 1998 Created.
wolf Mon, Jun 12, 2000 Wrapped test for possible deferenced nil pointer
in a TARGET_API_MAC_CARBON block.
************************************************************************************/
void
_RequirePString(
const void *string,
const char *name,
long size,
long min,
long max,
const char *file,
long line )
{
long l;
if( string ) {
#if !TARGET_API_MAC_CARBON
if( string == *(void**) 0 )
RequireNotice( "String is possibly a dereferenced nil ptr", name, nil,
0, file, line, 0 );
#endif // TARGET_API_MAC_CARBON
if( (long) string < 256 )
RequireNotice( "String is below 256 bytes", name, nil, 0, file, line, 0 );
MemoryDummy( *(short*) string );
l = *(unsigned char*) string;
// Here we check if the length byte of the pascal string is greater than the
// actual allocated size of the string. Example: "unsigned char s[32]" where s[ 0 ]
// == 128. This check only works if we get the correct static type of the given
// string (Example: "unsigned char s[32]" instead of "void *s").
if( size != sizeof(void*) && l > size - 1 )
RequireNotice( "Pascal string length is greater than allocated size", name, nil, size, file, line, 0 );
if( min && l < min )
RequireNotice( "String length is less than required", name, nil, min, file, line, 0 );
if( max && l > max )
RequireNotice( "String length is greater than required", name, nil, max, file, line, 0 );
} else {
RequireNotice( "String is nil", name, nil, 0, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Feb 25, 2000 Created.
wolf Mon, Jun 12, 2000 Wrapped test for possible deferenced nil pointer
in a TARGET_API_MAC_CARBON block.
************************************************************************************/
void
_RequireCString(
const void *string,
const char *name,
long min,
long max,
const char *file,
long line )
{
long l;
if( string ) {
#if !TARGET_API_MAC_CARBON
if( string == *(void**) 0 )
RequireNotice( "String is possibly a dereferenced nil ptr", name, nil,
0, file, line, 0 );
#endif // TARGET_API_MAC_CARBON
if( (long) string < 256 )
RequireNotice( "String is below 256 bytes", name, nil, 0, file, line, 0 );
MemoryDummy( *(short*) string );
l = (long) RGetCStringLength( (char*) string );
if( min && l < min )
RequireNotice( "String length is less than required", name, nil, min, file, line, 0 );
if( max && l > max )
RequireNotice( "String length is greater than required", name, nil, max, file, line, 0 );
} else {
RequireNotice( "String is nil", name, nil, 0, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Sep 9, 1998 Created.
wolf Sat, Jul 1, 2000 Added explicit cast from AEDesc's OSType to long.
************************************************************************************/
void
_RequireAEDesc(
const AEDesc desc,
const char *name,
Boolean canBeNull,
const char *file,
long line )
{
if( !canBeNull )
_RequireHandle( desc.dataHandle, name, file, line );
switch( desc.descriptorType ) {
case 'addr':
case 'aevt':
case 'alis':
case 'appa':
case 'bool':
case 'comp':
case 'decm':
case 'doub':
case 'dspt':
case 'enum':
case 'esrc':
case 'evcl':
case 'evid':
case 'evrc':
case 'fals':
case 'fixd':
case 'from':
case 'fss ':
case 'inte':
case 'keyw':
case 'kpid':
case 'ldbl':
case 'list':
case 'long':
case 'magn':
case 'miss':
case 'optk':
case 'prop':
case 'psn ':
case 'qdrt':
case 'reco':
case 'rtid':
case 'sect':
case 'shor':
case 'sign':
case 'sing':
case 'ssid':
case 'targ':
case 'TEXT':
case 'timo':
case 'tran':
case 'true':
case 'type':
case 'Pntr':
break;
case 'null':
if( !canBeNull )
RequireNotice( "AEDesc descriptorType is null", name, nil, 0, file, line, 0 );
break;
default:
RequireNotice( "Unknown AEDesc descriptorType", name, nil, (long) desc.descriptorType, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Apr 16, 1999 Created.
************************************************************************************/
void
_RequireSwitch(
long value,
const char *name,
const char *file,
long line )
{
RequireNotice( "Unknown Switch Selector", name, nil, value, file, line, 0 );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Feb 18, 2000 Created.
wolf Tue, Oct 29, 2002 Added shouldBeEqual support.
************************************************************************************/
void
_RequireEqual(
Boolean shouldBeEqual,
long actualValue,
const char *actualName,
long expectedValue,
const char *expectedName,
const char *file,
long line )
{
if( (shouldBeEqual && (actualValue != expectedValue))
|| (!shouldBeEqual && (actualValue == expectedValue)) )
{
Str255 msg = "\pUnexpected value (looking for ";
RAppendCStringToPString( expectedName, msg, sizeof( Str255 ) - 1 );
RAppendCStringToPString( ")", msg, sizeof( Str255 ) - 1 );
RequireNotice( RPToCString( msg ), actualName, nil, actualValue, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sat, Dec 2, 2000 Created.
************************************************************************************/
void
_RequireFSSpec(
const void *specPtr,
const char *name,
const char *file,
long line )
{
const FSSpec *spec = (const FSSpec*) specPtr;
FInfo info;
OSErr err;
if( spec ) {
#if !TARGET_API_MAC_CARBON
if( spec == *(void**) 0 )
RequireNotice( "FSSpec is possibly a dereferenced nil ptr", name, nil, 0,
file, line, 0 );
#endif // TARGET_API_MAC_CARBON
if( (long) spec < 256 )
RequireNotice( "FSSpec is below 256 bytes", name, nil, 0, file, line, 0 );
MemoryDummy( *(short*) spec );
if( spec->name[ 0 ] > 64 )
RequireNotice( "FSSpec's name length is greater than the maximum possible size", name, nil, spec->name[ 0 ], file, line, 0 );
if( spec->vRefNum >= 0 )
RequireNotice( "FSSpec vRefNum is invalid", name, nil, spec->vRefNum, file, line, 0 );
err = FSpGetFInfo( spec, &info );
if( err )
RequireNotice( "FSpGetFInfo got an error", name, nil, 0, file, line, err );
} else {
RequireNotice( "FSSpec is nil", name, nil, 0, file, line, 0 );
}
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sun, Sep 7, 1997 Created.
Exists so the compiler doesn't optimize it away.
************************************************************************************/
void
MemoryDummy( short value )
{
value++;
}
/****************************************************************************************
*
* Standard Strings
*
* Same code as in StandardStrings.c, prefixed with a "R". This is so require.c can
* compile stand-alone.
*
****************************************************************************************/
#pragma mark -
#pragma mark (Standard Strings)
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Nov 11, 1997 Created.
wolf Thu, Mar 4, 1999 Added const safety.
Changed longs to UInt32s.
Added Requirement.
wolf Sat, Jul 1, 2000 Added overflow requirement and explicit cast.
************************************************************************************/
UInt32 // <- target string's new size
RAppendStringToString(
const void *source,
UInt32 sourceSize,
void *target,
UInt32 targetSize,
UInt32 maxSize ) // -> the limit of target's growth, 0 means no limit.
{
UInt32 spaceLeft = maxSize ? maxSize - targetSize : 0xFFFFFFFF;
UInt32 transferSize = sourceSize < spaceLeft ? sourceSize : spaceLeft;
RequireNote( maxSize > sourceSize, "sourceSize can't be greater than maxSize" );
RequireSInt32( transferSize );
BlockMoveData( source, ((char*)target) + targetSize, (long) transferSize );
return( targetSize + transferSize );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Nov 11, 1997 Created.
wolf Thu, Mar 4, 1999 Added const safety.
Changed longs to UInt32s.
Added Requirements.
************************************************************************************/
void
RAppendStringToPString(
const void *source,
UInt32 sourceSize,
StringPtr target,
UInt32 maxSize )
{
UInt32 newSize = RAppendStringToString( source, sourceSize, target + 1, target[ 0 ],
maxSize );
RequireUInt8( maxSize );
RequireUInt8( newSize );
target[ 0 ] = (UInt8) (newSize & 0x000000FF);
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Nov 11, 1997 Created.
wolf Thu, Mar 4, 1999 Added const safety.
Changed longs to UInt32s.
************************************************************************************/
void
RAppendPStringToPString(
const StringPtr source,
StringPtr target,
UInt32 maxSize )
{
RAppendStringToPString( source + 1, source[ 0 ], target, maxSize );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Nov 11, 1997 Created.
wolf Thu, Mar 4, 1999 Added const safety.
Changed longs to UInt32s.
************************************************************************************/
void
RAppendCStringToPString(
const char *source,
StringPtr target,
UInt32 maxSize )
{
RAppendStringToPString( source, RGetCStringLength( source ), target, maxSize );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sun, Nov 2, 1997 Created.
wolf Thu, Mar 4, 1999 Changed longs to UInt32s.
************************************************************************************/
void
RAppendLongToPString(
long number,
StringPtr to,
UInt32 maxSize )
{
Str63 str;
str[ 0 ] = RLongToString( number, str + 1, sizeof( Str63 ) );
RAppendPStringToPString( str, to, maxSize );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Sep 12, 1997 Created.
wolf Thu, Mar 4, 1999 Changed longs to UInt32s.
wolf Sat, Jul 1, 2000 Added overflow requirements, now returns an UInt8
instead of a UInt32.
************************************************************************************/
UInt8
RLongToString(
long number,
void *string,
UInt32 maxSize )
{
char *s = (char*) string;
long decimal = 1, numberSize = 0, digit;
// Write a minus sign if the number is negative and make it positive
if( number < 0 ) {
*s++ = '-';
numberSize++;
number += (-number) + (-number);
}
// Figure the number of decimal places in the given number
if( number >= 10 ) {
for( digit = number; digit /= 10; decimal *= 10 ) {}
}
// Write out the number
while( maxSize-- && decimal ) {
digit = (number / decimal); // grab one digit
number -= digit * decimal; // remove the digit from the number
decimal = decimal == 1 ? 0 : decimal / 10; // decrement our decimal place
digit += ( '0' - 0 ); // convert into ASCII
RequireSInt8( digit ); // make sure we don't overflow
*s++ = (char) digit; // place ASCII digit into string
++numberSize;
}
RequireUInt8( numberSize );
return( (UInt8) numberSize );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Sep 12, 1997 Created.
wolf Thu, Mar 4, 1999 Added const safety.
Changed longs to UInt32s.
wolf Sat, Jul 1, 2000 Added explicit cast for return value.
************************************************************************************/
UInt32
RGetCStringLength(
const char *string )
{
const char *string2 = string;
for( ; *string2; string2++ ) {}
return( (UInt32) (string2 - string) );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Feb 18, 2000 Created.
************************************************************************************/
char*
RPToCString(
StringPtr string )
{
string[ string[ 0 ] + 1 ] = 0;
return( (char*) string + 1 );
}
See more files for this project here