Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Relevant replacement documents include:
MoreDebugging/MoreBBLog.c
/* |
File: MoreBBLog.c |
Contains: Module to log debug traces to BBEdit. |
Written by: Quinn |
Copyright: Copyright © 2000 by Apple Computer, Inc., all rights reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
<4> 27/3/00 Quinn Add some more coercions from basic types to text. Don't assert |
if we can't AESend to BBEdit because BBEdit isn't running. |
<3> 20/3/00 Quinn Added coercions from built-in types to typeText to make |
descriptor logging more useful. Changed BBLogDesc to bypass |
Str255 limit. |
<2> 3/9/00 gaw API changes for MoreAppleEvents |
<1> 6/3/00 Quinn First checked in. |
*/ |
///////////////////////////////////////////////////////////////// |
// MoreIsBetter Setup |
#include "MoreSetup.h" |
// Mac OS Interfaces |
#include <AERegistry.h> |
#include <PLStringFuncs.h> |
#include <TextUtils.h> |
#include <Aliases.h> |
// MIB Prototypes |
#include "MoreAppleEvents.h" |
#include "MoreMemory.h" |
// Our Prototypes |
#include "MoreBBLog.h" |
///////////////////////////////////////////////////////////////// |
#if MORE_DEBUG |
static AECoercePtrUPP gBasicToTextCoerceUPP; // -> BasicToTextCoerceProc |
static pascal OSErr BasicToTextCoerceProc(DescType typeCode, const void *dataPtr, Size dataSize, DescType toType, SInt32 handlerRefCon, AEDesc *result) |
// A coercion handler to convert some basic Apple event types |
// to text. I added these types on demand, as I noticed that my |
// MoreOSL test program needed them. |
{ |
#pragma unused(handlerRefCon) |
OSStatus err; |
ccntTokenRecPtr tokenData; |
AEDesc tokenAsText; |
Handle resultH; |
AliasHandle aliasH; |
Str63 tmpStr63; |
Str255 tmpStr; |
Str255 tmpStr2; |
FSSpecPtr fssP; |
MoreAssertQ(toType == typeText); |
MoreAssertQ(result != nil); |
MoreAENullDesc(result); |
switch (typeCode) { |
case typeNull: |
case typeCurrentContainer: |
case typeObjectBeingExamined: |
// YouÕd think that the following assert would be useful, but it fires all the time. |
// MoreAssertQ(dataPtr == nil); |
MoreAssertQ(dataSize == 0); |
err = AECreateDesc(typeText, &typeCode, sizeof(typeCode), result); |
break; |
case typeToken: |
MoreAssertQ(dataSize == sizeof(ccntTokenRecord)); |
MoreAssertQ(dataPtr != nil); |
// The data for a token is a ccntTokenRecord. We extract the data, |
// then coerce the embedded descriptor to text, then add a header |
// that identifies the token as a token. |
MoreAENullDesc(&tokenAsText); |
resultH = nil; |
tokenData = (ccntTokenRecPtr) dataPtr; |
err = AECoerceDesc(&tokenData->token, typeText, &tokenAsText); |
if (err == noErr) { |
err = MoreAECopyDescriptorDataToHandle(&tokenAsText, &resultH); |
} |
if (err == noErr) { |
// Add the string "'toke-'" to the front of the handle. |
(void) Munger(resultH, 0, nil, 0, "'toke'-", 7); |
err = MemError(); |
} |
if (err == noErr) { |
HLock(resultH); |
err = AECreateDesc(typeText, *resultH, GetHandleSize(resultH), result); |
} |
MoreAEDisposeDesc(&tokenAsText); |
if (resultH != nil) { |
DisposeHandle(resultH); |
MoreAssertQ(MemError() == noErr); |
} |
break; |
case typeAbsoluteOrdinal: |
MoreAssertQ(dataSize == sizeof(DescType)); |
err = AECreateDesc(typeText, dataPtr, sizeof(DescType), result); |
break; |
case typeAlias: |
aliasH = nil; |
err = PtrToHand(dataPtr, (Handle *) &aliasH, dataSize); |
if (err == noErr) { |
err = GetAliasInfo(aliasH, asiAliasName, tmpStr63); |
} |
if (err == noErr) { |
PLstrcpy(tmpStr, "\palias("); |
PLstrcat(tmpStr, tmpStr63); |
PLstrcat(tmpStr, "\p)"); |
err = AECreateDesc(typeText, &tmpStr[1], tmpStr[0], result); |
} |
if (aliasH != nil) { |
DisposeHandle( (Handle) aliasH ); |
} |
break; |
case typeFSS: |
MoreAssertQ(dataPtr != nil); |
MoreAssertQ(dataSize == sizeof(FSSpec)); |
fssP = (FSSpecPtr) dataPtr; |
PLstrcpy(tmpStr, "\pfss("); |
PLstrcat(tmpStr, fssP->name); |
PLstrcat(tmpStr, "\p)"); |
err = AECreateDesc(typeText, &tmpStr[1], tmpStr[0], result); |
break; |
case typeBoolean: |
if ( *((Boolean *) dataPtr) ) { |
err = AECreateDesc(typeText, "true", 4, result); |
} else { |
err = AECreateDesc(typeText, "false", 5, result); |
} |
break; |
case typeTrue: |
err = AECreateDesc(typeText, "typeTrue", 8, result); |
break; |
case typeFalse: |
err = AECreateDesc(typeText, "typeFalse", 9, result); |
break; |
case typeQDPoint: |
PLstrcpy(tmpStr, "\pPoint("); |
NumToString( ((PointPtr) dataPtr)->h, tmpStr2); |
PLstrcat(tmpStr, tmpStr2); |
PLstrcat(tmpStr, "\p, "); |
NumToString( ((PointPtr) dataPtr)->v, tmpStr2); |
PLstrcat(tmpStr, tmpStr2); |
PLstrcat(tmpStr, "\p)"); |
err = AECreateDesc(typeText, &tmpStr[1], tmpStr[0], result); |
break; |
case typeQDRectangle: |
PLstrcpy(tmpStr, "\pRect("); |
NumToString( ((RectPtr) dataPtr)->left, tmpStr2); |
PLstrcat(tmpStr, tmpStr2); |
PLstrcat(tmpStr, "\p, "); |
NumToString( ((RectPtr) dataPtr)->top, tmpStr2); |
PLstrcat(tmpStr, tmpStr2); |
PLstrcat(tmpStr, "\p, "); |
NumToString( ((RectPtr) dataPtr)->right, tmpStr2); |
PLstrcat(tmpStr, tmpStr2); |
PLstrcat(tmpStr, "\p, "); |
NumToString( ((RectPtr) dataPtr)->bottom, tmpStr2); |
PLstrcat(tmpStr, tmpStr2); |
PLstrcat(tmpStr, "\p)"); |
err = AECreateDesc(typeText, &tmpStr[1], tmpStr[0], result); |
break; |
default: |
MoreAssertQ(false); |
err = errAECoercionFail; |
break; |
} |
return err; |
} |
static AECoerceDescUPP gRecordToTextCoerceUPP; // -> RecordToTextCoerceProc |
static pascal OSErr RecordToTextCoerceProc(const AEDesc *fromDesc, DescType toType, long handlerRefCon, AEDesc *toDesc) |
// A coercion handler to convert lists, records, and other things |
// coercible to records, to text. |
{ |
#pragma unused(handlerRefCon) |
OSStatus err; |
Handle result; |
AEDesc fromDescAsRecord; |
SInt32 itemIndex; |
SInt32 itemCount; |
AEKeyword thisKeyword; |
AEDesc thisElement; |
AEDesc thisElementAsText; |
Size textSize; |
MoreAssertQ(fromDesc != nil); |
MoreAssertQ(toType == typeText); |
MoreAssertQ(toDesc != nil); |
MoreAENullDesc(toDesc); |
MoreAENullDesc(&fromDescAsRecord); |
// Create a handle for the resulting text. |
result = NewHandle(0); |
err = MoreMemError(result); |
// If the incoming data is a record or a list, we handle it natively |
// so just duplicate it into the fromDescAsRecord. OTOH, if the incoming |
// data is something weird (an object specifier, say), use AECoerceDesc to |
// coerce it to a record. |
if (err == noErr) { |
if (fromDesc->descriptorType == typeAERecord || fromDesc->descriptorType == typeAEList) { |
err = AEDuplicateDesc(fromDesc, &fromDescAsRecord); |
} else { |
err = AECoerceDesc(fromDesc, typeAERecord, &fromDescAsRecord); |
} |
} |
// Iterate through each element in the record/list, coercing the element |
// to text and appending its text to the handle. |
if (err == noErr) { |
err = AECountItems(&fromDescAsRecord, &itemCount); |
} |
if (err == noErr) { |
err = PtrAndHand("{", result, 1); |
for (itemIndex = 1; itemIndex <= itemCount; itemIndex++) { |
MoreAENullDesc(&thisElement); |
MoreAENullDesc(&thisElementAsText); |
err = AEGetNthDesc(&fromDescAsRecord, itemIndex, typeWildCard, &thisKeyword, &thisElement); |
if (err == noErr) { |
err = AECoerceDesc(&thisElement, typeText, &thisElementAsText); |
// While writing this code, I spent lots of time figuring out |
// exactly what type of data couldnÕt be coerced to text and then |
// filling in that particular coercion. The following assert |
// helps detect these problems quickly. |
MoreAssertQ(err != errAECoercionFail); |
} |
// If weÕre iteratintg through a record, the keyword is meaningful |
// so add it to the output handle. |
if (err == noErr && fromDescAsRecord.descriptorType == typeAERecord) { |
err = PtrAndHand("'", result, 1); |
if (err == noErr) { |
err = PtrAndHand(&thisKeyword, result, sizeof(thisKeyword)); |
} |
if (err == noErr) { |
err = PtrAndHand("':", result, 2); |
} |
} |
// Grow the handle to make room for the text for this element, |
// then copy the text to the handle. |
if (err == noErr) { |
textSize = AEGetDescDataSize(&thisElementAsText); |
SetHandleSize(result, GetHandleSize(result) + textSize); |
err = MemError(); |
} |
if (err == noErr) { |
HLock(result); |
err = AEGetDescData(&thisElementAsText, (*result) + GetHandleSize(result) - textSize, textSize); |
HUnlock(result); |
} |
// If weÕre not the last element, add a separator. |
if (err == noErr && itemIndex < itemCount) { |
err = PtrAndHand(", ", result, 2); |
} |
MoreAEDisposeDesc(&thisElement); |
MoreAEDisposeDesc(&thisElementAsText); |
if (err != noErr) { |
break; |
} |
} |
} |
if (err == noErr) { |
err = PtrAndHand("}", result, 1); |
} |
// Create a descriptor containing the data from the text handle. |
if (err == noErr) { |
HLock(result); |
err = AECreateDesc(typeText, *result, GetHandleSize(result), toDesc); |
} |
// Clean up. |
if (result != nil) { |
DisposeHandle(result); |
MoreAssertQ(MemError() == noErr); |
} |
MoreAEDisposeDesc(&fromDescAsRecord); |
return err; |
} |
static void InstallTextCoercionHandlers(void) |
// This routine installs a bunch of coercion handles for |
// coercing various common data types to text. By adding these |
// coercions, we increase the utility of the rest of MoreBBLog, |
// which relies on being able to coerce various descriptors to text. |
{ |
OSStatus junk; |
// First install all the basic coercions. |
gBasicToTextCoerceUPP = NewAECoercePtrUPP(BasicToTextCoerceProc); |
MoreAssertQ(gBasicToTextCoerceUPP != nil); |
junk = AEInstallCoercionHandler(typeNull, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeObjectBeingExamined, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeCurrentContainer, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeToken, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeAbsoluteOrdinal, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeAlias, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeFSS, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeBoolean, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeTrue, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeFalse, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeQDPoint, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeQDRectangle, typeText, (AECoercionHandlerUPP) gBasicToTextCoerceUPP, 0, false, false); |
MoreAssertQ(junk == noErr); |
// Then install the coercions for lists, records, and things coercible |
// to records. |
gRecordToTextCoerceUPP = NewAECoerceDescUPP(RecordToTextCoerceProc); |
MoreAssertQ(gRecordToTextCoerceUPP != nil); |
junk = AEInstallCoercionHandler(typeAERecord, typeText, (AECoercionHandlerUPP) gRecordToTextCoerceUPP, 0, true, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeAEList, typeText, (AECoercionHandlerUPP) gRecordToTextCoerceUPP, 0, true, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeAppleEvent, typeText, (AECoercionHandlerUPP) gRecordToTextCoerceUPP, 0, true, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeObjectSpecifier, typeText, (AECoercionHandlerUPP) gRecordToTextCoerceUPP, 0, true, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeRangeDescriptor, typeText, (AECoercionHandlerUPP) gRecordToTextCoerceUPP, 0, true, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeCompDescriptor, typeText, (AECoercionHandlerUPP) gRecordToTextCoerceUPP, 0, true, false); |
MoreAssertQ(junk == noErr); |
junk = AEInstallCoercionHandler(typeLogicalDescriptor, typeText, (AECoercionHandlerUPP) gRecordToTextCoerceUPP, 0, true, false); |
MoreAssertQ(junk == noErr); |
} |
static const OSType kBBEditCreator = 'R*ch'; |
static UInt32 gIndent; // records the number of levels of indent, as controlled by BBLogIndent etc |
static Boolean gLogging; // determines whether logging is enabled (true) or not (false) |
extern pascal void BBLogStart(Boolean logging) |
// See comment in header file. |
{ |
OSStatus err; |
AppleEvent theEvent; |
AppleEvent junkReply; |
DescType cDoc; |
// Start up by installing our coercion handles. This enables the rest |
// of the routines to provide much nicer output. |
InstallTextCoercionHandlers(); |
gIndent = 0; |
gLogging = logging; |
if (gLogging) { |
// Send BBEdit an Apple event to make a new text window. This |
// will error if BBEdit is running, but the code to launch it |
// is an unnecessary complication. If you want to see logging, |
// you have to have BBEdit running. |
MoreAENullDesc(&theEvent); |
err = MoreAECreateAppleEventCreatorTarget(kAECoreSuite, kAECreateElement, kBBEditCreator, &theEvent); |
if (err == noErr) { |
cDoc = cDocument; |
err = AEPutParamPtr(&theEvent, keyAEObjectClass, typeType, &cDoc, sizeof(cDoc)); |
} |
if (err == noErr) { |
err = AESend(&theEvent, &junkReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); |
if (err == connectionInvalid) { // BBEdit not running |
err = noErr; |
} |
} |
MoreAEDisposeDesc(&theEvent); |
MoreAssertQ(err == noErr); |
} |
} |
extern pascal void BBLogSetState(Boolean logging) |
// See comment in header file. |
{ |
gLogging = logging; |
} |
extern pascal void BBLogText(void *textPtr, Size textSize) |
// See comment in header file. |
{ |
OSStatus err; |
AppleEvent theEvent; |
AppleEvent junkReply; |
MoreAssertQ(textPtr != nil); |
if (gLogging) { |
// Send BBEdit an insert text ('Nsrt') event. The text will go |
// into the front window, which is typically the window we created |
// during BBLogStart. |
MoreAENullDesc(&theEvent); |
err = MoreAECreateAppleEventCreatorTarget(kBBEditCreator, 'Nsrt', kBBEditCreator, &theEvent); |
if (err == noErr) { |
err = AEPutParamPtr(&theEvent, keyDirectObject, typeText, textPtr, textSize); |
} |
if (err == noErr) { |
err = AESend(&theEvent, &junkReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); |
if (err == connectionInvalid) { // BBEdit not running |
err = noErr; |
} |
} |
MoreAEDisposeDesc(&theEvent); |
MoreAssertQ(err == noErr); |
} |
} |
static void BuildLineHeader(Str255 str) |
{ |
UInt32 dateTime; |
Str255 tmpStr; |
static Str255 indentStr = "\p "; |
MoreAssertQ(str != nil); |
GetDateTime(&dateTime); |
TimeString(dateTime, true, tmpStr, nil); |
(void) PLstrcpy(str, tmpStr); |
(void) PLstrcat(str, "\p "); |
DateString(dateTime, shortDate, tmpStr, nil); |
(void) PLstrcat(str, tmpStr); |
(void) PLstrcat(str, "\p - "); |
indentStr[0] = gIndent * 2; |
(void) PLstrcat(str, indentStr); |
} |
extern pascal void BBLogLine(ConstStr255Param str) |
// See comment in header file. |
{ |
Str255 tmpStr; |
MoreAssertQ(str != nil); |
if (gLogging) { |
// Add the date and time prefix, the appropriate indent, and the CR suffix. |
BuildLineHeader(tmpStr); |
(void) PLstrcat(tmpStr, str); |
(void) PLstrcat(tmpStr, "\p\r"); |
BBLogText(&tmpStr[1], tmpStr[0]); |
} |
} |
extern pascal void BBLogIndent(void) |
// See comment in header file. |
{ |
gIndent += 1; |
} |
extern pascal void BBLogOutdent(void) |
// See comment in header file. |
{ |
MoreAssertQ(gIndent > 0); |
gIndent -= 1; |
} |
extern pascal void BBLogOutdentWithErr(OSStatus errNum) |
// See comment in header file. |
{ |
Str255 tmpStr; |
Str255 tmpStr2; |
BBLogOutdent(); |
if (gLogging) { |
if (errNum == noErr) { |
(void) PLstrcpy(tmpStr, "\perr=noErr"); |
} else { |
(void) PLstrcpy(tmpStr, "\perr="); |
NumToString(errNum, tmpStr2); |
(void) PLstrcat(tmpStr, tmpStr2); |
} |
BBLogLine(tmpStr); |
} |
} |
extern pascal void BBLogAppleEvent(ConstStr255Param tag, const AppleEvent *theEvent) |
// See comment in header file. |
{ |
OSStatus junk; |
AEEventClass classID; |
AEEventID eventID; |
DescType junkType; |
Size junkSize; |
Str255 tmpStr; |
Str255 tmpStr2; |
MoreAssertQ(tag != nil); |
MoreAssertQ(theEvent != nil); |
if (gLogging) { |
// Get the Apple event class and event IDs. |
classID = '????'; |
junk = AEGetAttributePtr(theEvent, keyEventClassAttr, typeType, &junkType, &classID, sizeof(classID), &junkSize); |
MoreAssertQ(junk == noErr); |
eventID = '????'; |
junk = AEGetAttributePtr(theEvent, keyEventIDAttr, typeType, &junkType, &eventID, sizeof(eventID), &junkSize); |
MoreAssertQ(junk == noErr); |
// Create a log string out of those IDs. Currently this |
// is the only information about the event that we log; |
// we might want to extend this in the future, with possibly |
// the parameter list (or at least the direct object). |
(void) PLstrcpy(tmpStr, tag); |
(void) PLstrcat(tmpStr, "\p='"); |
tmpStr2[0] = 4; |
*((OSType *) &tmpStr2[1]) = classID; |
(void) PLstrcat(tmpStr, tmpStr2); |
(void) PLstrcat(tmpStr, "\p', '"); |
tmpStr2[0] = 4; |
*((OSType *) &tmpStr2[1]) = eventID; |
(void) PLstrcat(tmpStr, tmpStr2); |
(void) PLstrcat(tmpStr, "\p'"); |
BBLogLine(tmpStr); |
} |
} |
extern pascal void BBLogLong(ConstStr255Param tag, SInt32 l) |
// See comment in header file. |
{ |
Str255 tmpStr; |
Str255 tmpStr2; |
MoreAssertQ(tag != nil); |
if (gLogging) { |
(void) PLstrcpy(tmpStr, tag); |
(void) PLstrcat(tmpStr, "\p="); |
NumToString(l, tmpStr2); |
(void) PLstrcat(tmpStr, tmpStr2); |
BBLogLine(tmpStr); |
} |
} |
extern pascal void BBLogDesc(ConstStr255Param tag, const AEDesc *desc) |
// See comment in header file. |
{ |
OSStatus err; |
AEDesc coercedDesc; |
Str255 descStr; |
Str255 tmpStr; |
Handle descText; |
MoreAssertQ(tag != nil); |
MoreAssertQ(desc != nil); |
if (gLogging) { |
MoreAENullDesc(&coercedDesc); |
descText = nil; |
// First try coercing the descriptor to text. |
// If we succeed, then we use the resulting textual |
// description of the descriptor. If we fail, |
// we just log the descriptor type and size |
err = AECoerceDesc(desc, typeText, &coercedDesc); |
if (err == noErr) { |
err = MoreAECopyDescriptorDataToHandle(&coercedDesc, &descText); |
// If the original descriptor type was text, add |
// some Ò Ó around the text. |
if (err == noErr && desc->descriptorType == typeText) { |
(void) Munger(descText, 0, nil, 0, "Ò", 1); |
err = MemError(); |
if (err == noErr) { |
err = PtrAndHand("Ó", descText, 1); |
} |
} |
} else { |
tmpStr[0] = 4; |
*((OSType *) &tmpStr[1]) = desc->descriptorType; |
(void) PLstrcpy(descStr, "\p'"); |
(void) PLstrcat(descStr, tmpStr); |
(void) PLstrcat(descStr, "\p'"); |
if (desc->dataHandle != nil) { |
(void) PLstrcat(descStr, "\p, size="); |
NumToString(AEGetDescDataSize(desc), tmpStr); |
(void) PLstrcat(descStr, tmpStr); |
} |
err = PtrToHand(&descStr[1], &descText, descStr[0]); |
} |
// Now that descText is set up to contain the textual |
// representation of desc, we just log it. We also |
// log the original type of the descriptor (in square |
// brackets). |
// First prepend the line header and the tag. |
if (err == noErr) { |
BuildLineHeader(tmpStr); |
(void) PLstrcat(tmpStr, tag); |
(void) PLstrcat(tmpStr, "\p="); |
(void) Munger(descText, 0, nil, 0, &tmpStr[1], tmpStr[0]); |
err = MemError(); |
} |
// Then append the original descriptor type and the CR. |
if (err == noErr) { |
(void) PLstrcpy(tmpStr, "\p ["); |
descStr[0] = 4; |
*((OSType *) &descStr[1]) = desc->descriptorType; |
(void) PLstrcat(tmpStr, descStr); |
(void) PLstrcat(tmpStr, "\p]\x0d"); |
err = PtrAndHand(&tmpStr[1], descText, tmpStr[0]); |
} |
// Finally, log the text. |
if (err == noErr) { |
HLock(descText); |
BBLogText(*descText, GetHandleSize(descText)); |
} |
// Clean up. |
if (descText != nil) { |
DisposeHandle(descText); |
MoreAssertQ(MemError() == noErr); |
} |
MoreAEDisposeDesc(&coercedDesc); |
} |
} |
extern pascal void BBLogDescType(ConstStr255Param tag, DescType theType) |
// See comment in header file. |
{ |
Str255 tmpStr; |
Str255 tmpStr2; |
MoreAssertQ(tag != nil); |
if (gLogging) { |
(void) PLstrcpy(tmpStr, tag); |
(void) PLstrcat(tmpStr, "\p='"); |
tmpStr2[0] = 4; |
*((OSType *) &tmpStr2[1]) = theType; |
(void) PLstrcat(tmpStr, tmpStr2); |
(void) PLstrcat(tmpStr, "\p'"); |
BBLogLine(tmpStr); |
} |
} |
#endif // MORE_DEBUG |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14