/* -*- Mode: C; tab-width: 4 -*- * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. To Do: - Use StackWalk on Windows to optionally print stack frames. */ #if 0 #pragma mark == Includes == #endif //=========================================================================================================================== // Includes //=========================================================================================================================== #if( !KERNEL ) #include <ctype.h> #include <stdio.h> #include <string.h> #endif #include "CommonServices.h" #include "DebugServices.h" #if( DEBUG ) #if( TARGET_OS_VXWORKS ) #include "intLib.h" #endif #if( TARGET_OS_WIN32 ) #include <time.h> #if( !TARGET_OS_WINDOWS_CE ) #include <fcntl.h> #include <io.h> #endif #endif #if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL ) #include <IOKit/IOLib.h> #endif // If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h. #if( defined( MDNS_DEBUGMSGS ) ) #include "mDNSEmbeddedAPI.h" #endif #if 0 #pragma mark == Macros == #endif //=========================================================================================================================== // Macros //=========================================================================================================================== #define DebugIsPrint( C ) ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) ) #if 0 #pragma mark == Prototypes == #endif //=========================================================================================================================== // Prototypes //=========================================================================================================================== static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize ); // fprintf #if( DEBUG_FPRINTF_ENABLED ) static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename ); static void DebugFPrintFPrint( char *inData, size_t inSize ); #endif // iDebug (Mac OS X user and kernel) #if( DEBUG_IDEBUG_ENABLED ) static OSStatus DebugiDebugInit( void ); static void DebugiDebugPrint( char *inData, size_t inSize ); #endif // kprintf (Mac OS X Kernel) #if( DEBUG_KPRINTF_ENABLED ) static void DebugKPrintFPrint( char *inData, size_t inSize ); #endif // Mac OS X IOLog (Mac OS X Kernel) #if( DEBUG_MAC_OS_X_IOLOG_ENABLED ) static void DebugMacOSXIOLogPrint( char *inData, size_t inSize ); #endif // Mac OS X Log #if( TARGET_OS_MAC ) static OSStatus DebugMacOSXLogInit( void ); static void DebugMacOSXLogPrint( char *inData, size_t inSize ); #endif // Windows Debugger #if( TARGET_OS_WIN32 ) static void DebugWindowsDebuggerPrint( char *inData, size_t inSize ); #endif // Windows Event Log #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule ); static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize ); #endif // DebugLib support #if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) static pascal void DebugAssertOutputHandler( OSType inComponentSignature, UInt32 inOptions, const char * inAssertionString, const char * inExceptionString, const char * inErrorString, const char * inFileName, long inLineNumber, void * inValue, ConstStr255Param inOutputMsg ); #endif // Utilities static char * DebugNumVersionToString( uint32_t inVersion, char *inString ); #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) static void DebugWinEnableConsole( void ); #endif #if( TARGET_OS_WIN32 ) static TCHAR * DebugWinCharToTCharString( const char * inCharString, size_t inCharCount, TCHAR * outTCharString, size_t inTCharCountMax, size_t * outTCharCount ); #endif #if 0 #pragma mark == Globals == #endif //=========================================================================================================================== // Private Globals //=========================================================================================================================== #if( TARGET_OS_VXWORKS ) // TCP States for inetstatShow. extern char ** pTcpstates; // defined in tcpLib.c const char * kDebugTCPStates[] = { "(0) TCPS_CLOSED", "(1) TCPS_LISTEN", "(2) TCPS_SYN_SENT", "(3) TCPS_SYN_RECEIVED", "(4) TCPS_ESTABLISHED", "(5) TCPS_CLOSE_WAIT", "(6) TCPS_FIN_WAIT_1", "(7) TCPS_CLOSING", "(8) TCPS_LAST_ACK", "(9) TCPS_FIN_WAIT_2", "(10) TCPS_TIME_WAIT", }; #endif // General static bool gDebugInitialized = false; static DebugOutputType gDebugOutputType = kDebugOutputTypeNone; static DebugLevel gDebugPrintLevelMin = kDebugLevelInfo; static DebugLevel gDebugPrintLevelMax = kDebugLevelMax; static DebugLevel gDebugBreakLevel = kDebugLevelAssert; #if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) static DebugAssertOutputHandlerUPP gDebugAssertOutputHandlerUPP = NULL; #endif // Custom static DebugOutputFunctionPtr gDebugCustomOutputFunction = NULL; static void * gDebugCustomOutputContext = NULL; // fprintf #if( DEBUG_FPRINTF_ENABLED ) static FILE * gDebugFPrintFFile = NULL; #endif // MacOSXLog #if( TARGET_OS_MAC ) typedef int ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... ); static DebugMacOSXLogFunctionPtr gDebugMacOSXLogFunction = NULL; #endif // WindowsEventLog #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) static HANDLE gDebugWindowsEventLogEventSource = NULL; #endif #if 0 #pragma mark - #pragma mark == General == #endif //=========================================================================================================================== // DebugInitialize //=========================================================================================================================== DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... ) { OSStatus err; DebugOutputType type; va_list args; va_start( args, inType ); #if( TARGET_OS_VXWORKS ) // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason). if( !pTcpstates ) { pTcpstates = (char **) kDebugTCPStates; } #endif // Set up DebugLib stuff (if building with Debugging.h). #if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) if( !gDebugAssertOutputHandlerUPP ) { gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler ); check( gDebugAssertOutputHandlerUPP ); if( gDebugAssertOutputHandlerUPP ) { InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP ); } } #endif // Pre-process meta-output kind to pick an appropriate output kind for the platform. type = inType; if( type == kDebugOutputTypeMetaConsole ) { #if( TARGET_OS_MAC ) type = kDebugOutputTypeMacOSXLog; #elif( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) #if( DEBUG_FPRINTF_ENABLED ) type = kDebugOutputTypeFPrintF; #else type = kDebugOutputTypeWindowsDebugger; #endif #elif( TARGET_API_MAC_OSX_KERNEL ) #if( DEBUG_MAC_OS_X_IOLOG_ENABLED ) type = kDebugOutputTypeMacOSXIOLog; #elif( DEBUG_IDEBUG_ENABLED ) type = kDebugOutputTypeiDebug; #elif( DEBUG_KPRINTF_ENABLED ) type = kDebugOutputTypeKPrintF; #endif #elif( TARGET_OS_VXWORKS ) #if( DEBUG_FPRINTF_ENABLED ) type = kDebugOutputTypeFPrintF; #else #error target is VxWorks, but fprintf output is disabled #endif #else #if( DEBUG_FPRINTF_ENABLED ) type = kDebugOutputTypeFPrintF; #endif #endif } // Process output kind. gDebugOutputType = type; switch( type ) { case kDebugOutputTypeNone: err = kNoErr; break; case kDebugOutputTypeCustom: gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr ); gDebugCustomOutputContext = va_arg( args, void * ); err = kNoErr; break; #if( DEBUG_FPRINTF_ENABLED ) case kDebugOutputTypeFPrintF: if( inType == kDebugOutputTypeMetaConsole ) { err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL ); } else { DebugOutputTypeFlags flags; const char * filename; flags = (DebugOutputTypeFlags) va_arg( args, unsigned int ); if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile ) { filename = va_arg( args, const char * ); } else { filename = NULL; } err = DebugFPrintFInit( flags, filename ); } break; #endif #if( DEBUG_IDEBUG_ENABLED ) case kDebugOutputTypeiDebug: err = DebugiDebugInit(); break; #endif #if( DEBUG_KPRINTF_ENABLED ) case kDebugOutputTypeKPrintF: err = kNoErr; break; #endif #if( DEBUG_MAC_OS_X_IOLOG_ENABLED ) case kDebugOutputTypeMacOSXIOLog: err = kNoErr; break; #endif #if( TARGET_OS_MAC ) case kDebugOutputTypeMacOSXLog: err = DebugMacOSXLogInit(); break; #endif #if( TARGET_OS_WIN32 ) case kDebugOutputTypeWindowsDebugger: err = kNoErr; break; #endif #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) case kDebugOutputTypeWindowsEventLog: { const char * name; HMODULE module; name = va_arg( args, const char * ); module = va_arg( args, HMODULE ); err = DebugWindowsEventLogInit( name, module ); } break; #endif default: err = kParamErr; goto exit; } gDebugInitialized = true; exit: va_end( args ); return( err ); } //=========================================================================================================================== // DebugFinalize //=========================================================================================================================== DEBUG_EXPORT void DebugFinalize( void ) { #if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) check( gDebugAssertOutputHandlerUPP ); if( gDebugAssertOutputHandlerUPP ) { InstallDebugAssertOutputHandler( NULL ); DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP ); gDebugAssertOutputHandlerUPP = NULL; } #endif } //=========================================================================================================================== // DebugGetProperty //=========================================================================================================================== DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... ) { OSStatus err; va_list args; DebugLevel * level; va_start( args, inTag ); switch( inTag ) { case kDebugPropertyTagPrintLevelMin: level = va_arg( args, DebugLevel * ); *level = gDebugPrintLevelMin; err = kNoErr; break; case kDebugPropertyTagPrintLevelMax: level = va_arg( args, DebugLevel * ); *level = gDebugPrintLevelMax; err = kNoErr; break; case kDebugPropertyTagBreakLevel: level = va_arg( args, DebugLevel * ); *level = gDebugBreakLevel; err = kNoErr; break; default: err = kUnsupportedErr; break; } va_end( args ); return( err ); } //=========================================================================================================================== // DebugSetProperty //=========================================================================================================================== DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... ) { OSStatus err; va_list args; DebugLevel level; va_start( args, inTag ); switch( inTag ) { case kDebugPropertyTagPrintLevelMin: level = va_arg( args, DebugLevel ); gDebugPrintLevelMin = level; err = kNoErr; break; case kDebugPropertyTagPrintLevelMax: level = va_arg( args, DebugLevel ); gDebugPrintLevelMax = level; err = kNoErr; break; case kDebugPropertyTagBreakLevel: level = va_arg( args, DebugLevel ); gDebugBreakLevel = level; err = kNoErr; break; default: err = kUnsupportedErr; break; } va_end( args ); return( err ); } #if 0 #pragma mark - #pragma mark == Output == #endif //=========================================================================================================================== // DebugPrintF //=========================================================================================================================== DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... ) { va_list args; size_t n; // Skip if the level is not in the enabled range.. if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) ) { n = 0; goto exit; } va_start( args, inFormat ); n = DebugPrintFVAList( inLevel, inFormat, args ); va_end( args ); exit: return( n ); } //=========================================================================================================================== // DebugPrintFVAList //=========================================================================================================================== DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs ) { size_t n; char buffer[ 512 ]; // Skip if the level is not in the enabled range.. if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) ) { n = 0; goto exit; } n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs ); DebugPrint( inLevel, buffer, (size_t) n ); exit: return( n ); } //=========================================================================================================================== // DebugPrint //=========================================================================================================================== static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize ) { OSStatus err; // Skip if the level is not in the enabled range.. if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) ) { err = kRangeErr; goto exit; } // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available). if( DebugTaskLevel() & kDebugInterruptLevelMask ) { #if( TARGET_OS_VXWORKS ) logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 ); #endif err = kExecutionStateErr; goto exit; } // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage). if( !gDebugInitialized ) { debug_initialize( kDebugOutputTypeMetaConsole ); } // Print based on the current output type. switch( gDebugOutputType ) { case kDebugOutputTypeNone: break; case kDebugOutputTypeCustom: if( gDebugCustomOutputFunction ) { gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext ); } break; #if( DEBUG_FPRINTF_ENABLED ) case kDebugOutputTypeFPrintF: DebugFPrintFPrint( inData, inSize ); break; #endif #if( DEBUG_IDEBUG_ENABLED ) case kDebugOutputTypeiDebug: DebugiDebugPrint( inData, inSize ); break; #endif #if( DEBUG_KPRINTF_ENABLED ) case kDebugOutputTypeKPrintF: DebugKPrintFPrint( inData, inSize ); break; #endif #if( DEBUG_MAC_OS_X_IOLOG_ENABLED ) case kDebugOutputTypeMacOSXIOLog: DebugMacOSXIOLogPrint( inData, inSize ); break; #endif #if( TARGET_OS_MAC ) case kDebugOutputTypeMacOSXLog: DebugMacOSXLogPrint( inData, inSize ); break; #endif #if( TARGET_OS_WIN32 ) case kDebugOutputTypeWindowsDebugger: DebugWindowsDebuggerPrint( inData, inSize ); break; #endif #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) case kDebugOutputTypeWindowsEventLog: DebugWindowsEventLogPrint( inLevel, inData, inSize ); break; #endif default: break; } err = kNoErr; exit: return( err ); } //=========================================================================================================================== // DebugPrintAssert // // Warning: This routine relies on several of the strings being string constants that will exist forever because the // underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based // pointer variables (e.g. local strings). The debug macros that invoke this function only use constant // constant strings, but if this function is invoked directly from other places, it must use constant strings. //=========================================================================================================================== DEBUG_EXPORT void DebugPrintAssert( int_least32_t inErrorCode, const char * inAssertString, const char * inMessage, const char * inFilename, int_least32_t inLineNumber, const char * inFunction ) { // Skip if the level is not in the enabled range.. if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) ) { return; } if( inErrorCode != 0 ) { DebugPrintF( kDebugLevelAssert, "\n" "[ASSERT] error: %ld (%m)\n" "[ASSERT] where: \"%s\", line %ld, \"%s\"\n" "\n", inErrorCode, inErrorCode, inFilename ? inFilename : "", inLineNumber, inFunction ? inFunction : "" ); } else { DebugPrintF( kDebugLevelAssert, "\n" "[ASSERT] assert: \"%s\" %s\n" "[ASSERT] where: \"%s\", line %ld, \"%s\"\n" "\n", inAssertString ? inAssertString : "", inMessage ? inMessage : "", inFilename ? inFilename : "", inLineNumber, inFunction ? inFunction : "" ); } // Break into the debugger if enabled. #if( TARGET_OS_WIN32 ) if( gDebugBreakLevel <= kDebugLevelAssert ) { if( IsDebuggerPresent() ) { DebugBreak(); } } #endif } #if 0 #pragma mark - #endif #if( DEBUG_FPRINTF_ENABLED ) //=========================================================================================================================== // DebugFPrintFInit //=========================================================================================================================== static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename ) { OSStatus err; DebugOutputTypeFlags typeFlags; typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask; if( typeFlags == kDebugOutputTypeFlagsStdOut ) { #if( TARGET_OS_WIN32 ) DebugWinEnableConsole(); #endif gDebugFPrintFFile = stdout; } else if( typeFlags == kDebugOutputTypeFlagsStdErr ) { #if( TARGET_OS_WIN32 ) DebugWinEnableConsole(); #endif gDebugFPrintFFile = stdout; } else if( typeFlags == kDebugOutputTypeFlagsFile ) { require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr ); gDebugFPrintFFile = fopen( inFilename, "a" ); require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr ); } else { err = kParamErr; goto exit; } err = kNoErr; exit: return( err ); } //=========================================================================================================================== // DebugFPrintFPrint //=========================================================================================================================== static void DebugFPrintFPrint( char *inData, size_t inSize ) { char * p; char * q; // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform. p = inData; q = p + inSize; while( p < q ) { if( *p == '\r' ) { *p = '\n'; } ++p; } // Write the data and flush. if( gDebugFPrintFFile ) { fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData ); fflush( gDebugFPrintFFile ); } } #endif // DEBUG_FPRINTF_ENABLED #if( DEBUG_IDEBUG_ENABLED ) //=========================================================================================================================== // DebugiDebugInit //=========================================================================================================================== static OSStatus DebugiDebugInit( void ) { OSStatus err; #if( TARGET_API_MAC_OSX_KERNEL ) extern uint32_t * _giDebugReserved1; // Emulate the iDebugSetOutputType macro in iDebugServices.h. // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext. if( !_giDebugReserved1 ) { _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) ); require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr ); } *_giDebugReserved1 = 0x00010000U; err = kNoErr; exit: #else __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType ); iDebugSetOutputTypeInternal( 0x00010000U ); err = kNoErr; #endif return( err ); } //=========================================================================================================================== // DebugiDebugPrint //=========================================================================================================================== static void DebugiDebugPrint( char *inData, size_t inSize ) { #if( TARGET_API_MAC_OSX_KERNEL ) // Locally declared here so we do not need to include iDebugKext.h. // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present). // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present. typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... ); extern iDebugLogFunctionPtr _giDebugLogInternal; if( _giDebugLogInternal ) { _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData ); } #else __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... ); iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData ); #endif } #endif #if( DEBUG_KPRINTF_ENABLED ) //=========================================================================================================================== // DebugKPrintFPrint //=========================================================================================================================== static void DebugKPrintFPrint( char *inData, size_t inSize ) { extern void kprintf( const char *inFormat, ... ); kprintf( "%.*s", (int) inSize, inData ); } #endif #if( DEBUG_MAC_OS_X_IOLOG_ENABLED ) //=========================================================================================================================== // DebugMacOSXIOLogPrint //=========================================================================================================================== static void DebugMacOSXIOLogPrint( char *inData, size_t inSize ) { extern void IOLog( const char *inFormat, ... ); IOLog( "%.*s", (int) inSize, inData ); } #endif #if( TARGET_OS_MAC ) //=========================================================================================================================== // DebugMacOSXLogInit //=========================================================================================================================== static OSStatus DebugMacOSXLogInit( void ) { OSStatus err; CFStringRef path; CFURLRef url; CFBundleRef bundle; CFStringRef functionName; void * functionPtr; bundle = NULL; // Create a bundle reference for System.framework. path = CFSTR( "/System/Library/Frameworks/System.framework" ); url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true ); require_action_quiet( url, exit, err = memFullErr ); bundle = CFBundleCreate( NULL, url ); CFRelease( url ); require_action_quiet( bundle, exit, err = memFullErr ); // Get a ptr to the system's "printf" function from System.framework. functionName = CFSTR( "printf" ); functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName ); require_action_quiet( functionPtr, exit, err = memFullErr ); // Success! Note: The bundle cannot be released because it would invalidate the function ptr. gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr; bundle = NULL; err = noErr; exit: if( bundle ) { CFRelease( bundle ); } return( err ); } //=========================================================================================================================== // DebugMacOSXLogPrint //=========================================================================================================================== static void DebugMacOSXLogPrint( char *inData, size_t inSize ) { if( gDebugMacOSXLogFunction ) { gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData ); } } #endif #if( TARGET_OS_WIN32 ) //=========================================================================================================================== // DebugWindowsDebuggerPrint //=========================================================================================================================== void DebugWindowsDebuggerPrint( char *inData, size_t inSize ) { TCHAR buffer[ 512 ]; const char * src; const char * end; TCHAR * dst; char c; // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process. src = inData; if( inSize >= sizeof_array( buffer ) ) { inSize = sizeof_array( buffer ) - 1; } end = src + inSize; dst = buffer; while( src < end ) { c = *src++; if( c == '\r' ) { c = '\n'; } *dst++ = (TCHAR) c; } *dst = 0; // Print out the string to the debugger. OutputDebugString( buffer ); } #endif #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) //=========================================================================================================================== // DebugWindowsEventLogInit //=========================================================================================================================== static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule ) { OSStatus err; HKEY key; TCHAR name[ 128 ]; const char * src; TCHAR path[ MAX_PATH ]; size_t size; DWORD typesSupported; DWORD n; key = NULL; // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds. if( !inName || ( *inName == '\0' ) ) { inName = "DefaultApp"; } DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL ); // Build the path string using the fixed registry path and app name. src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"; DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size ); DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL ); // Add/Open the source name as a sub-key under the Application key in the EventLog registry key. err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL ); require_noerr_quiet( err, exit ); // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator. n = GetModuleFileName( inModule, path, sizeof_array( path ) ); err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr ); require_noerr_quiet( err, exit ); n += 1; n *= sizeof( TCHAR ); err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n ); require_noerr_quiet( err, exit ); // Set the supported event types in the TypesSupported subkey. typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE | EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE; err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) ); require_noerr_quiet( err, exit ); // Set up the event source. gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name ); err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr ); require_noerr_quiet( err, exit ); exit: if( key ) { RegCloseKey( key ); } return( err ); } //=========================================================================================================================== // DebugWindowsEventLogPrint //=========================================================================================================================== static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize ) { WORD type; TCHAR buffer[ 512 ]; const char * src; const char * end; TCHAR * dst; char c; const TCHAR * array[ 1 ]; // Map the debug level to a Windows EventLog type. if( inLevel <= kDebugLevelNotice ) { type = EVENTLOG_INFORMATION_TYPE; } else if( inLevel <= kDebugLevelWarning ) { type = EVENTLOG_WARNING_TYPE; } else { type = EVENTLOG_ERROR_TYPE; } // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process. src = inData; if( inSize >= sizeof_array( buffer ) ) { inSize = sizeof_array( buffer ) - 1; } end = src + inSize; dst = buffer; while( src < end ) { c = *src++; if( c == '\r' ) { c = '\n'; } *dst++ = (TCHAR) c; } *dst = 0; // Add the the string to the event log. array[ 0 ] = buffer; if( gDebugWindowsEventLogEventSource ) { ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL ); } } #endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE #if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) //=========================================================================================================================== // DebugAssertOutputHandler //=========================================================================================================================== static pascal void DebugAssertOutputHandler( OSType inComponentSignature, UInt32 inOptions, const char * inAssertString, const char * inExceptionString, const char * inErrorString, const char * inFileName, long inLineNumber, void * inValue, ConstStr255Param inOutputMsg ) { DEBUG_UNUSED( inComponentSignature ); DEBUG_UNUSED( inOptions ); DEBUG_UNUSED( inExceptionString ); DEBUG_UNUSED( inValue ); DEBUG_UNUSED( inOutputMsg ); DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" ); } #endif #if 0 #pragma mark - #pragma mark == Utilities == #endif //=========================================================================================================================== // DebugSNPrintF // // Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes: // // Changed names to avoid name collisions with the mDNS versions. // Changed types to standard C types since mDNSEmbeddedAPI.h may not be available. // Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h. // Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb). // Added %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription. // Added %.8a - FIbre Channel address. Arg=ptr to address. // Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr. // Added %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc. // Added %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode. // Added %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size. // Added %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size. // Added %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc. // Added %S - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr. // Added %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S. // Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S. // Added %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID. //=========================================================================================================================== DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...) { size_t length; va_list ptr; va_start(ptr,fmt); length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr); va_end(ptr); return(length); } //=========================================================================================================================== // DebugSNPrintFVAList - va_list version of DebugSNPrintF. See DebugSNPrintF for more info. //=========================================================================================================================== DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg) { static const struct DebugSNPrintF_format { unsigned leftJustify : 1; unsigned forceSign : 1; unsigned zeroPad : 1; unsigned havePrecision : 1; unsigned hSize : 1; char lSize; char altForm; char sign; // +, - or space unsigned int fieldWidth; unsigned int precision; } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; size_t nwritten = 0; int c; if (buflen == 0) return(0); buflen--; // Pre-reserve one space in the buffer for the terminating nul if (buflen == 0) goto exit; for (c = *fmt; c != 0; c = *++fmt) { if (c != '%') { *sbuffer++ = (char)c; if (++nwritten >= buflen) goto exit; } else { size_t i=0, j; // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc. // The size needs to be enough for a 256-byte domain name plus some error text. #define mDNS_VACB_Size 300 char mDNS_VACB[mDNS_VACB_Size]; #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size]) #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s)) char *s = mDNS_VACB_Lim; const char *digits = "0123456789ABCDEF"; struct DebugSNPrintF_format F = DebugSNPrintF_format_default; for(;;) // decode flags { c = *++fmt; if (c == '-') F.leftJustify = 1; else if (c == '+') F.forceSign = 1; else if (c == ' ') F.sign = ' '; else if (c == '#') F.altForm++; else if (c == '0') F.zeroPad = 1; else break; } if (c == '*') // decode field width { int f = va_arg(arg, int); if (f < 0) { f = -f; F.leftJustify = 1; } F.fieldWidth = (unsigned int)f; c = *++fmt; } else { for (; c >= '0' && c <= '9'; c = *++fmt) F.fieldWidth = (10 * F.fieldWidth) + (c - '0'); } if (c == '.') // decode precision { if ((c = *++fmt) == '*') { F.precision = va_arg(arg, unsigned int); c = *++fmt; } else for (; c >= '0' && c <= '9'; c = *++fmt) F.precision = (10 * F.precision) + (c - '0'); F.havePrecision = 1; } if (F.leftJustify) F.zeroPad = 0; conv: switch (c) // perform appropriate conversion { #if TYPE_LONGLONG_NATIVE unsigned_long_long_compat n; unsigned_long_long_compat base; #else unsigned long n; unsigned long base; #endif case 'h' : F.hSize = 1; c = *++fmt; goto conv; case 'l' : // fall through case 'L' : F.lSize++; c = *++fmt; goto conv; case 'd' : case 'i' : base = 10; goto canBeSigned; case 'u' : base = 10; goto notSigned; case 'o' : base = 8; goto notSigned; case 'b' : base = 2; goto notSigned; case 'p' : n = va_arg(arg, uintptr_t); F.havePrecision = 1; F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16; F.sign = 0; base = 16; c = 'x'; goto number; case 'x' : digits = "0123456789abcdef"; case 'X' : base = 16; goto notSigned; canBeSigned: #if TYPE_LONGLONG_NATIVE if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long); else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat); else n = (unsigned_long_long_compat)va_arg(arg, int); #else if (F.lSize == 1) n = (unsigned long)va_arg(arg, long); else if (F.lSize == 2) goto exit; else n = (unsigned long)va_arg(arg, int); #endif if (F.hSize) n = (short) n; #if TYPE_LONGLONG_NATIVE if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; } #else if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; } #endif else if (F.forceSign) F.sign = '+'; goto number; notSigned: if (F.lSize == 1) n = va_arg(arg, unsigned long); else if (F.lSize == 2) { #if TYPE_LONGLONG_NATIVE n = va_arg(arg, unsigned_long_long_compat); #else goto exit; #endif } else n = va_arg(arg, unsigned int); if (F.hSize) n = (unsigned short) n; F.sign = 0; goto number; number: if (!F.havePrecision) { if (F.zeroPad) { F.precision = F.fieldWidth; if (F.altForm) F.precision -= 2; if (F.sign) --F.precision; } if (F.precision < 1) F.precision = 1; } if (F.precision > mDNS_VACB_Size - 1) F.precision = mDNS_VACB_Size - 1; for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]); for (; i < F.precision; i++) *--s = '0'; if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; } if (F.sign) { *--s = F.sign; i++; } break; case 'a' : { unsigned char *a = va_arg(arg, unsigned char *); char pre[4] = ""; char post[32] = ""; if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } else { s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end if (F.altForm == 1) { #if(defined(MDNS_DEBUGMSGS)) mDNSAddr *ip = (mDNSAddr*)a; switch (ip->type) { case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break; case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break; default: F.precision = 0; break; } #else F.precision = 0; // mDNSEmbeddedAPI.h not included so no mDNSAddr support #endif } else if (F.altForm == 2) { #ifdef AF_INET const struct sockaddr *sa; unsigned char *port; sa = (const struct sockaddr*)a; switch (sa->sa_family) { case AF_INET: F.precision = 4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr; port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port; DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break; #ifdef AF_INET6 case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr; pre[0] = '['; pre[1] = '\0'; port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port; DebugSNPrintF(post, sizeof(post), "%%%d]:%d", (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id, (port[0] << 8) | port[1]); break; #endif default: F.precision = 0; break; } #else F.precision = 0; // socket interfaces not included so no sockaddr support #endif } switch (F.precision) { case 4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s", a[0], a[1], a[2], a[3], post); break; case 6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X", a[0], a[1], a[2], a[3], a[4], a[5]); break; case 8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break; case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s", pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break; default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size " "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break; } } } break; case 'U' : { unsigned char *a = va_arg(arg, unsigned char *); if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } else { s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]), a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break; } } break; case 'c' : *--s = (char)va_arg(arg, int); i = 1; break; case 'C' : if (F.lSize) n = va_arg(arg, unsigned long); else n = va_arg(arg, unsigned int); if (F.hSize) n = (unsigned short) n; c = (int)( n & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^'); c = (int)((n >> 8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^'); c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^'); c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^'); i = 4; break; case 's' : s = va_arg(arg, char *); if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } else switch (F.altForm) { case 0: i=0; if (F.havePrecision) // C string { while((i < F.precision) && s[i]) i++; // Make sure we don't truncate in the middle of a UTF-8 character. // If the last character is part of a multi-byte UTF-8 character, back up to the start of it. j=0; while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break; } // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back. if((j > 1) && (j <= 6)) { int test = (0xFF << (8-j)) & 0xFF; int mask = test | (1 << ((8-j)-1)); if((c & mask) == test) i += j; } } else while(s[i]) i++; break; case 1: i = (unsigned char) *s++; break; // Pascal string case 2: { // DNS label-sequence name unsigned char *a = (unsigned char *)s; s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end if (*a == 0) *s++ = '.'; // Special case for root DNS name while (*a) { if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; } if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; } s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a); a += 1 + *a; } i = (size_t)(s - mDNS_VACB); s = mDNS_VACB; // Reset s back to the start of the buffer break; } } if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } break; case 'S': { // UTF-16 string unsigned char *a = va_arg(arg, unsigned char *); uint16_t *u = (uint16_t*)a; if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } if ((!F.havePrecision || F.precision)) { if ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; } // Big Endian else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; } // Little Endian } s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end switch (F.altForm) { case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Host Endian { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; } break; case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Big Endian { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; } break; case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Little Endian { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; } break; } } s = mDNS_VACB; // Reset s back to the start of the buffer break; #if TARGET_OS_MAC case '@': { // Cocoa/CoreFoundation object CFTypeRef cfObj; CFStringRef cfStr; cfObj = (CFTypeRef) va_arg(arg, void *); cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj); s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end if (cfStr) { CFRange range; CFIndex m; range = CFRangeMake(0, CFStringGetLength(cfStr)); m = 0; CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m); CFRelease(cfStr); i = (size_t) m; } else { i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" ); } } if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } break; #endif case 'm' : { // Error Message long err; if (F.lSize) err = va_arg(arg, long); else err = va_arg(arg, int); if (F.hSize) err = (short)err; DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB)); s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end for(i=0;s[i];i++) {} } break; case 'H' : { // Hex Dump void *a = va_arg(arg, void *); size_t size = (size_t)va_arg(arg, int); size_t max = (size_t)va_arg(arg, int); DebugFlags flags = kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine | kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount; if (F.altForm == 0) flags |= kDebugFlagsNoASCII; size = (max < size) ? max : size; s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB)); } break; case 'v' : { // Version uint32_t version; version = va_arg(arg, unsigned int); DebugNumVersionToString(version, mDNS_VACB); s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end for(i=0;s[i];i++) {} } break; case 'n' : s = va_arg(arg, char *); if (F.hSize) * (short *) s = (short)nwritten; else if (F.lSize) * (long *) s = (long)nwritten; else * (int *) s = (int)nwritten; continue; default: s = mDNS_VACB; i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c); case '%' : *sbuffer++ = (char)c; if (++nwritten >= buflen) goto exit; break; } if (i < F.fieldWidth && !F.leftJustify) // Pad on the left do { *sbuffer++ = ' '; if (++nwritten >= buflen) goto exit; } while (i < --F.fieldWidth); if (i > buflen - nwritten) // Make sure we don't truncate in the middle of a UTF-8 character { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result nwritten += i; if (nwritten >= buflen) goto exit; for (; i < F.fieldWidth; i++) // Pad on the right { *sbuffer++ = ' '; if (++nwritten >= buflen) goto exit; } } } exit: *sbuffer++ = 0; return(nwritten); } //=========================================================================================================================== // DebugGetErrorString //=========================================================================================================================== DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize ) { const char * s; char * dst; char * end; #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) char buffer[ 256 ]; #endif switch( inErrorCode ) { #define CaseErrorString( X, STR ) case X: s = STR; break #define CaseErrorStringify( X ) case X: s = # X; break #define CaseErrorStringifyHardCode( VALUE, X ) case VALUE: s = # X; break // General Errors CaseErrorString( 0, "no error" ); CaseErrorString( 1, "in-progress/waiting" ); CaseErrorString( -1, "catch-all unknown error" ); // ACP Errors CaseErrorStringifyHardCode( -2, kACPBadRequestErr ); CaseErrorStringifyHardCode( -3, kACPNoMemoryErr ); CaseErrorStringifyHardCode( -4, kACPBadParamErr ); CaseErrorStringifyHardCode( -5, kACPNotFoundErr ); CaseErrorStringifyHardCode( -6, kACPBadChecksumErr ); CaseErrorStringifyHardCode( -7, kACPCommandNotHandledErr ); CaseErrorStringifyHardCode( -8, kACPNetworkErr ); CaseErrorStringifyHardCode( -9, kACPDuplicateCommandHandlerErr ); CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr ); CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr ); CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr ); CaseErrorStringifyHardCode( -13, kACPNoResourcesErr ); CaseErrorStringifyHardCode( -14, kACPBadOptionErr ); CaseErrorStringifyHardCode( -15, kACPBadSizeErr ); CaseErrorStringifyHardCode( -16, kACPBadPasswordErr ); CaseErrorStringifyHardCode( -17, kACPNotInitializedErr ); CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr ); CaseErrorStringifyHardCode( -19, kACPBadVersionErr ); CaseErrorStringifyHardCode( -20, kACPBadSignatureErr ); CaseErrorStringifyHardCode( -21, kACPBadIndexErr ); CaseErrorStringifyHardCode( -22, kACPUnsupportedErr ); CaseErrorStringifyHardCode( -23, kACPInUseErr ); CaseErrorStringifyHardCode( -24, kACPParamCountErr ); CaseErrorStringifyHardCode( -25, kACPIDErr ); CaseErrorStringifyHardCode( -26, kACPFormatErr ); CaseErrorStringifyHardCode( -27, kACPUnknownUserErr ); CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr ); CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr ); // Common Services Errors CaseErrorStringify( kUnknownErr ); CaseErrorStringify( kOptionErr ); CaseErrorStringify( kSelectorErr ); CaseErrorStringify( kExecutionStateErr ); CaseErrorStringify( kPathErr ); CaseErrorStringify( kParamErr ); CaseErrorStringify( kParamCountErr ); CaseErrorStringify( kCommandErr ); CaseErrorStringify( kIDErr ); CaseErrorStringify( kStateErr ); CaseErrorStringify( kRangeErr ); CaseErrorStringify( kRequestErr ); CaseErrorStringify( kResponseErr ); CaseErrorStringify( kChecksumErr ); CaseErrorStringify( kNotHandledErr ); CaseErrorStringify( kVersionErr ); CaseErrorStringify( kSignatureErr ); CaseErrorStringify( kFormatErr ); CaseErrorStringify( kNotInitializedErr ); CaseErrorStringify( kAlreadyInitializedErr ); CaseErrorStringify( kNotInUseErr ); CaseErrorStringify( kInUseErr ); CaseErrorStringify( kTimeoutErr ); CaseErrorStringify( kCanceledErr ); CaseErrorStringify( kAlreadyCanceledErr ); CaseErrorStringify( kCannotCancelErr ); CaseErrorStringify( kDeletedErr ); CaseErrorStringify( kNotFoundErr ); CaseErrorStringify( kNoMemoryErr ); CaseErrorStringify( kNoResourcesErr ); CaseErrorStringify( kDuplicateErr ); CaseErrorStringify( kImmutableErr ); CaseErrorStringify( kUnsupportedDataErr ); CaseErrorStringify( kIntegrityErr ); CaseErrorStringify( kIncompatibleErr ); CaseErrorStringify( kUnsupportedErr ); CaseErrorStringify( kUnexpectedErr ); CaseErrorStringify( kValueErr ); CaseErrorStringify( kNotReadableErr ); CaseErrorStringify( kNotWritableErr ); CaseErrorStringify( kBadReferenceErr ); CaseErrorStringify( kFlagErr ); CaseErrorStringify( kMalformedErr ); CaseErrorStringify( kSizeErr ); CaseErrorStringify( kNameErr ); CaseErrorStringify( kNotReadyErr ); CaseErrorStringify( kReadErr ); CaseErrorStringify( kWriteErr ); CaseErrorStringify( kMismatchErr ); CaseErrorStringify( kDateErr ); CaseErrorStringify( kUnderrunErr ); CaseErrorStringify( kOverrunErr ); CaseErrorStringify( kEndingErr ); CaseErrorStringify( kConnectionErr ); CaseErrorStringify( kAuthenticationErr ); CaseErrorStringify( kOpenErr ); CaseErrorStringify( kTypeErr ); CaseErrorStringify( kSkipErr ); CaseErrorStringify( kNoAckErr ); CaseErrorStringify( kCollisionErr ); CaseErrorStringify( kBackoffErr ); CaseErrorStringify( kNoAddressAckErr ); CaseErrorStringify( kBusyErr ); CaseErrorStringify( kNoSpaceErr ); // mDNS/DNS-SD Errors CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr ); CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr ); CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr ); CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr ); CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr ); CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr ); CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr ); CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr ); CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr ); CaseErrorStringifyHardCode( -65546, mStatus_NoCache ); CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered ); CaseErrorStringifyHardCode( -65548, mStatus_NameConflict ); CaseErrorStringifyHardCode( -65549, mStatus_Invalid ); CaseErrorStringifyHardCode( -65550, mStatus_GrowCache ); CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr ); CaseErrorStringifyHardCode( -65552, mStatus_Incompatible ); CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged ); CaseErrorStringifyHardCode( -65792, mStatus_MemFree ); // RSP Errors CaseErrorStringifyHardCode( -400000, kRSPUnknownErr ); CaseErrorStringifyHardCode( -400050, kRSPParamErr ); CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr ); CaseErrorStringifyHardCode( -405246, kRSPRangeErr ); CaseErrorStringifyHardCode( -409057, kRSPSizeErr ); CaseErrorStringifyHardCode( -400200, kRSPHardwareErr ); CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr ); CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr ); CaseErrorStringifyHardCode( -402419, kRSPIDErr ); CaseErrorStringifyHardCode( -403165, kRSPFlagErr ); CaseErrorString( -200000, "kRSPControllerStatusBase - 0x50" ); CaseErrorString( -200080, "kRSPCommandSucceededErr - 0x50" ); CaseErrorString( -200001, "kRSPCommandFailedErr - 0x01" ); CaseErrorString( -200051, "kRSPChecksumErr - 0x33" ); CaseErrorString( -200132, "kRSPCommandTimeoutErr - 0x84" ); CaseErrorString( -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" ); CaseErrorString( -200128, "kRSPCanceledErr - 0x02 Async" ); // XML Errors CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr ); CaseErrorStringifyHardCode( -100050, kXMLParamErr ); CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr ); CaseErrorStringifyHardCode( -100206, kXMLFormatErr ); CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr ); CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr ); CaseErrorStringifyHardCode( -101726, kXMLKeyErr ); CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr ); CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr ); CaseErrorStringifyHardCode( -103026, kXMLParseErr ); CaseErrorStringifyHardCode( -103159, kXMLBadDataErr ); CaseErrorStringifyHardCode( -103170, kXMLBadNameErr ); CaseErrorStringifyHardCode( -105246, kXMLRangeErr ); CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr ); CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr ); CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr ); CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr ); CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr ); CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr ); CaseErrorStringifyHardCode( -102015, kXMLDateErr ); #if( __MACH__ ) // Mach Errors CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE ); CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE ); CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL ); CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL ); CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS ); CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA ); CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST ); CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT ); CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED ); CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL ); CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY ); CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT ); CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY ); CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY ); CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER ); CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE ); CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE ); CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER ); CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER ); CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE ); CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS ); CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME ); CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT ); CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE ); CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED ); CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED ); CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY ); CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA ); CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED ); CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET ); CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR ); CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR ); CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE ); CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL ); CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER ); CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED ); // Mach OSReturn Errors CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError ); CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal ); CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances ); CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit ); CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData ); CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts ); CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet ); CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet ); CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper ); CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper ); CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass ); // IOKit Errors CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError ); CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory ); CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources ); CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError ); CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice ); CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged ); CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument ); CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead ); CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite ); CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess ); CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID ); CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported ); CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError ); CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError ); CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError ); CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock ); CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen ); CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable ); CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable ); CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned ); CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia ); CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen ); CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError ); CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError ); CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy ); CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout ); CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline ); CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady ); CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached ); CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels ); CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace ); CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists ); CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire ); CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt ); CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames ); CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge ); CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted ); CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower ); CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia ); CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia ); CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode ); CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun ); CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun ); CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError ); CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion ); CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted ); CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth ); CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding ); CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld ); CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew ); CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound ); CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid ); // IOKit FireWire Errors CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase ); CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset ); CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry ); CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending ); CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken ); CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid ); CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered ); CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers ); CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive ); CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker ); CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels ); CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable ); CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus ); CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs ); CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage ); CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower ); CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels ); CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram ); CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening ); CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept ); CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose ); CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged ); CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged ); // IOKit USB Errors CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr ); CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr ); CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr ); CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr ); CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr ); CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound ); CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound ); CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout ); CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned ); CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled ); CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound ); CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated ); CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated ); CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError ); CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr ); CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err ); CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err ); CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr ); CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr ); CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err ); CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err ); CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr ); CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr ); CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr ); CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr ); CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr ); #endif // __MACH__ // Other Errors default: s = NULL; #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) if( inBuffer && ( inBufferSize > 0 ) ) { DWORD n; n = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) inErrorCode, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), buffer, sizeof( buffer ), NULL ); if( n > 0 ) { // Remove any trailing CR's or LF's since some messages have them. while( ( n > 0 ) && isspace( ( (unsigned char *) buffer )[ n - 1 ] ) ) { buffer[ --n ] = '\0'; } s = buffer; } } #endif if( !s ) { #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE ) s = strerror( inErrorCode ); #endif if( !s ) { s = "<unknown error code>"; } } break; } // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string. if( inBuffer && ( inBufferSize > 0 ) ) { dst = inBuffer; end = dst + ( inBufferSize - 1 ); while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) ) { *dst++ = *s++; } *dst = '\0'; s = inBuffer; } return( s ); } //=========================================================================================================================== // DebugHexDump //=========================================================================================================================== DEBUG_EXPORT size_t DebugHexDump( DebugLevel inLevel, int inIndent, const char * inLabel, size_t inLabelSize, int inLabelMinWidth, const char * inType, size_t inTypeSize, const void * inDataStart, const void * inData, size_t inDataSize, DebugFlags inFlags, char * outBuffer, size_t inBufferSize ) { static const char kHexChars[] = "0123456789ABCDEF"; const uint8_t * start; const uint8_t * src; char * dst; char * end; size_t n; int offset; int width; const char * newline; char separator[ 8 ]; char * s; DEBUG_UNUSED( inType ); DEBUG_UNUSED( inTypeSize ); // Set up the function-wide variables. if( inLabelSize == kSizeCString ) { inLabelSize = strlen( inLabel ); } start = (const uint8_t *) inData; src = start; dst = outBuffer; end = dst + inBufferSize; offset = (int)( (intptr_t) inData - (intptr_t) inDataStart ); width = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth; newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n"; // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines. s = separator; if( inFlags & kDebugFlagsNoNewLine ) { if( inFlags & kDebugFlags8BitSeparator ) { *s++ = ' '; } if( inFlags & kDebugFlags16BitSeparator ) { *s++ = ' '; } if( !( inFlags & kDebugFlagsNo32BitSeparator ) ) { *s++ = ' '; } check( ( (size_t)( s - separator ) ) < sizeof( separator ) ); } *s = '\0'; for( ;; ) { char prefixString[ 32 ]; char hexString[ 64 ]; char asciiString[ 32 ]; char byteCountString[ 32 ]; int c; size_t chunkSize; size_t i; // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit. if( inDataSize == 0 ) { if( inLabel && ( inLabelSize > 0 ) ) { width = 0; if( !( inFlags & kDebugFlagsNoAddress ) ) { width += 8; // "00000000" if( !( inFlags & kDebugFlagsNoOffset ) ) { width += 1; // "+" } } if( inFlags & kDebugFlags32BitOffset ) { width += 8; // "00000000" } else if( !( inFlags & kDebugFlagsNoOffset ) ) { width += 4; // "0000" } if( outBuffer ) { dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s", width, "", ( width > 0 ) ? ": " : "", width, (int) inLabelSize, inLabel, newline ); } else { dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s", width, "", ( width > 0 ) ? ": " : "", width, (int) inLabelSize, inLabel, newline ); } } break; } // Build the prefix string. It will be in one of the following formats: // // 1) "00000000+0000[0000]" (address and offset) // 2) "00000000" (address only) // 3) "0000[0000]" (offset only) // 4) "" (no address or offset) // // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate. s = prefixString; if( !( inFlags & kDebugFlagsNoAddress ) ) { *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ]; *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ]; *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ]; *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ]; *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ]; *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 8 ) & 0xF ]; *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 4 ) & 0xF ]; *s++ = kHexChars[ ( (uintptr_t) src ) & 0xF ]; if( !( inFlags & kDebugFlagsNoOffset ) ) { *s++ = '+'; } } if( !( inFlags & kDebugFlagsNoOffset ) ) { if( inFlags & kDebugFlags32BitOffset ) { *s++ = kHexChars[ ( offset >> 28 ) & 0xF ]; *s++ = kHexChars[ ( offset >> 24 ) & 0xF ]; *s++ = kHexChars[ ( offset >> 20 ) & 0xF ]; *s++ = kHexChars[ ( offset >> 16 ) & 0xF ]; } *s++ = kHexChars[ ( offset >> 12 ) & 0xF ]; *s++ = kHexChars[ ( offset >> 8 ) & 0xF ]; *s++ = kHexChars[ ( offset >> 4 ) & 0xF ]; *s++ = kHexChars[ offset & 0xF ]; } if( s != prefixString ) { *s++ = ':'; *s++ = ' '; } check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) ); *s = '\0'; // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read. // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up). s = hexString; chunkSize = ( inDataSize < 16 ) ? inDataSize : 16; n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16; for( i = 0; i < n; ++i ) { if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) ) { *s++ = ' '; } if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) ) { *s++ = ' '; } if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) ) { *s++ = ' '; } if( i < chunkSize ) { *s++ = kHexChars[ src[ i ] >> 4 ]; *s++ = kHexChars[ src[ i ] & 0xF ]; } else { *s++ = ' '; *s++ = ' '; } } check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) ); *s = '\0'; // Build a string with the ASCII version of the data (replaces non-printable characters with '^'). // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up). s = asciiString; if( !( inFlags & kDebugFlagsNoASCII ) ) { *s++ = ' '; *s++ = '|'; for( i = 0; i < n; ++i ) { if( i < chunkSize ) { c = src[ i ]; if( !DebugIsPrint( c ) ) { c = '^'; } } else { c = '`'; } *s++ = (char) c; } *s++ = '|'; check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) ); } *s = '\0'; // Build a string indicating how bytes are in the hex dump. Only printed on the first line. s = byteCountString; if( !( inFlags & kDebugFlagsNoByteCount ) ) { if( src == start ) { s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize ); } } check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) ); *s = '\0'; // Build the entire line from all the pieces we've previously built. if( outBuffer ) { if( src == start ) { dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" // Indention "%s" // Separator (only if needed) "%s" // Prefix "%-*.*s" // Label "%s" // Separator "%s" // Hex "%s" // ASCII "%s" // Byte Count "%s", // Newline inIndent, "", ( src != start ) ? separator : "", prefixString, width, (int) inLabelSize, inLabel ? inLabel : "", ( width > 0 ) ? " " : "", hexString, asciiString, byteCountString, newline ); } else { dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" // Indention "%s" // Separator (only if needed) "%s" // Prefix "%*s" // Label Spacing "%s" // Separator "%s" // Hex "%s" // ASCII "%s" // Byte Count "%s", // Newline inIndent, "", ( src != start ) ? separator : "", prefixString, width, "", ( width > 0 ) ? " " : "", hexString, asciiString, byteCountString, newline ); } } else { if( src == start ) { dst += DebugPrintF( inLevel, "%*s" // Indention "%s" // Separator (only if needed) "%s" // Prefix "%-*.*s" // Label "%s" // Separator "%s" // Hex "%s" // ASCII "%s" // Byte Count "%s", // Newline inIndent, "", ( src != start ) ? separator : "", prefixString, width, (int) inLabelSize, inLabel, ( width > 0 ) ? " " : "", hexString, asciiString, byteCountString, newline ); } else { dst += DebugPrintF( inLevel, "%*s" // Indention "%s" // Separator (only if needed) "%s" // Prefix "%*s" // Label Spacing "%s" // Separator "%s" // Hex "%s" // ASCII "%s" // Byte Count "%s", // Newline inIndent, "", ( src != start ) ? separator : "", prefixString, width, "", ( width > 0 ) ? " " : "", hexString, asciiString, byteCountString, newline ); } } // Move to the next chunk. Exit if there is no more data. offset += (int) chunkSize; src += chunkSize; inDataSize -= chunkSize; if( inDataSize == 0 ) { break; } } // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative. return( (size_t)( dst - outBuffer ) ); } //=========================================================================================================================== // DebugNumVersionToString //=========================================================================================================================== static char * DebugNumVersionToString( uint32_t inVersion, char *inString ) { char * s; uint8_t majorRev; uint8_t minor; uint8_t bugFix; uint8_t stage; uint8_t revision; check( inString ); majorRev = (uint8_t)( ( inVersion >> 24 ) & 0xFF ); minor = (uint8_t)( ( inVersion >> 20 ) & 0x0F ); bugFix = (uint8_t)( ( inVersion >> 16 ) & 0x0F ); stage = (uint8_t)( ( inVersion >> 8 ) & 0xFF ); revision = (uint8_t)( inVersion & 0xFF ); // Convert the major, minor, and bugfix numbers. s = inString; s += sprintf( s, "%u", majorRev ); s += sprintf( s, ".%u", minor ); if( bugFix != 0 ) { s += sprintf( s, ".%u", bugFix ); } // Convert the version stage and non-release revision number. switch( stage ) { case kVersionStageDevelopment: s += sprintf( s, "d%u", revision ); break; case kVersionStageAlpha: s += sprintf( s, "a%u", revision ); break; case kVersionStageBeta: s += sprintf( s, "b%u", revision ); break; case kVersionStageFinal: // A non-release revision of zero is a special case indicating the software is GM (at the golden master // stage) and therefore, the non-release revision should not be added to the string. if( revision != 0 ) { s += sprintf( s, "f%u", revision ); } break; default: dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage ); break; } return( inString ); } //=========================================================================================================================== // DebugTaskLevel //=========================================================================================================================== DEBUG_EXPORT uint32_t DebugTaskLevel( void ) { uint32_t level; level = 0; #if( TARGET_OS_VXWORKS ) if( intContext() ) { level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask ); } #endif return( level ); } #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE ) //=========================================================================================================================== // DebugWinEnableConsole //=========================================================================================================================== #pragma warning( disable:4311 ) static void DebugWinEnableConsole( void ) { static bool sConsoleEnabled = false; BOOL result; int fileHandle; FILE * file; int err; if( sConsoleEnabled ) { goto exit; } // Create console window. result = AllocConsole(); require_quiet( result, exit ); // Redirect stdin to the console stdin. fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT ); #if( defined( __MWERKS__ ) ) file = __handle_reopen( (unsigned long) fileHandle, "r", stdin ); require_quiet( file, exit ); #else file = _fdopen( fileHandle, "r" ); require_quiet( file, exit ); *stdin = *file; #endif err = setvbuf( stdin, NULL, _IONBF, 0 ); require_noerr_quiet( err, exit ); // Redirect stdout to the console stdout. fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT ); #if( defined( __MWERKS__ ) ) file = __handle_reopen( (unsigned long) fileHandle, "w", stdout ); require_quiet( file, exit ); #else file = _fdopen( fileHandle, "w" ); require_quiet( file, exit ); *stdout = *file; #endif err = setvbuf( stdout, NULL, _IONBF, 0 ); require_noerr_quiet( err, exit ); // Redirect stderr to the console stdout. fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT ); #if( defined( __MWERKS__ ) ) file = __handle_reopen( (unsigned long) fileHandle, "w", stderr ); require_quiet( file, exit ); #else file = _fdopen( fileHandle, "w" ); require_quiet( file, exit ); *stderr = *file; #endif err = setvbuf( stderr, NULL, _IONBF, 0 ); require_noerr_quiet( err, exit ); sConsoleEnabled = true; exit: return; } #pragma warning( default:4311 ) #endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE #if( TARGET_OS_WIN32 ) //=========================================================================================================================== // DebugWinCharToTCharString //=========================================================================================================================== static TCHAR * DebugWinCharToTCharString( const char * inCharString, size_t inCharCount, TCHAR * outTCharString, size_t inTCharCountMax, size_t * outTCharCount ) { const char * src; TCHAR * dst; TCHAR * end; if( inCharCount == kSizeCString ) { inCharCount = strlen( inCharString ); } src = inCharString; dst = outTCharString; if( inTCharCountMax > 0 ) { inTCharCountMax -= 1; if( inTCharCountMax > inCharCount ) { inTCharCountMax = inCharCount; } end = dst + inTCharCountMax; while( dst < end ) { *dst++ = (TCHAR) *src++; } *dst = 0; } if( outTCharCount ) { *outTCharCount = (size_t)( dst - outTCharString ); } return( outTCharString ); } #endif #if 0 #pragma mark - #pragma mark == Debugging == #endif //=========================================================================================================================== // DebugServicesTest //=========================================================================================================================== DEBUG_EXPORT OSStatus DebugServicesTest( void ) { OSStatus err; char s[ 512 ]; uint8_t * p; uint8_t data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1 }; debug_initialize( kDebugOutputTypeMetaConsole ); // check's check( 0 && "SHOULD SEE: check" ); check( 1 && "SHOULD *NOT* SEE: check (valid)" ); check_string( 0, "SHOULD SEE: check_string" ); check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" ); check_noerr( -123 ); check_noerr( 10038 ); check_noerr( 22 ); check_noerr( 0 ); check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" ); check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" ); check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 ); check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 ); check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 ); check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 ); check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 5, 10 ); check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12, 6 ); check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 6, 10, 10 ); check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 ); check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 ); check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 ); check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 ); // require's require( 0 && "SHOULD SEE", require1 ); { err = kResponseErr; goto exit; } require1: require( 1 && "SHOULD *NOT* SEE", require2 ); goto require2Good; require2: { err = kResponseErr; goto exit; } require2Good: require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" ); { err = kResponseErr; goto exit; } require3: require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" ); goto require4Good; require4: { err = kResponseErr; goto exit; } require4Good: require_quiet( 0 && "SHOULD SEE", require5 ); { err = kResponseErr; goto exit; } require5: require_quiet( 1 && "SHOULD *NOT* SEE", require6 ); goto require6Good; require6: { err = kResponseErr; goto exit; } require6Good: require_noerr( -1, require7 ); { err = kResponseErr; goto exit; } require7: require_noerr( 0, require8 ); goto require8Good; require8: { err = kResponseErr; goto exit; } require8Good: require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string"); { err = kResponseErr; goto exit; } require9: require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" ); goto require10Good; require10: { err = kResponseErr; goto exit; } require10Good: require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" ); { err = kResponseErr; goto exit; } require11: require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" ); goto require12Good; require12: { err = kResponseErr; goto exit; } require12Good: require_noerr_quiet( -4, require13 ); { err = kResponseErr; goto exit; } require13: require_noerr_quiet( 0, require14 ); goto require14Good; require14: { err = kResponseErr; goto exit; } require14Good: require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) ); { err = kResponseErr; goto exit; } require15: require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) ); goto require16Good; require16: { err = kResponseErr; goto exit; } require16Good: require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) ); { err = kResponseErr; goto exit; } require17: require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) ); goto require18Good; require18: { err = kResponseErr; goto exit; } require18Good: require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) ); { err = kResponseErr; goto exit; } require19: require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) ); goto require20Good; require20: { err = kResponseErr; goto exit; } require20Good: require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) ); { err = kResponseErr; goto exit; } require21: require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) ); goto require22Good; require22: { err = kResponseErr; goto exit; } require22Good: require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" ); { err = kResponseErr; goto exit; } require23: require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" ); goto require24Good; require24: { err = kResponseErr; goto exit; } require24Good: #if( defined( __MWERKS__ ) ) #if( defined( __cplusplus ) && __option( exceptions ) ) #define COMPILER_HAS_EXCEPTIONS 1 #else #define COMPILER_HAS_EXCEPTIONS 0 #endif #else #if( defined( __cplusplus ) ) #define COMPILER_HAS_EXCEPTIONS 1 #else #define COMPILER_HAS_EXCEPTIONS 0 #endif #endif #if( COMPILER_HAS_EXCEPTIONS ) try { require_throw( 1 && "SHOULD *NOT* SEE" ); require_throw( 0 && "SHOULD SEE" ); } catch( ... ) { goto require26Good; } { err = kResponseErr; goto exit; } require26Good: #endif // translate_errno err = translate_errno( 1 != -1, -123, -567 ); require( ( err == 0 ) && "SHOULD *NOT* SEE", exit ); err = translate_errno( -1 != -1, -123, -567 ); require( ( err == -123 ) && "SHOULD *NOT* SEE", exit ); err = translate_errno( -1 != -1, 0, -567 ); require( ( err == -567 ) && "SHOULD *NOT* SEE", exit ); // debug_string debug_string( "debug_string" ); // DebugSNPrintF DebugSNPrintF( s, sizeof( s ), "%d", 1234 ); require_action( strcmp( s, "1234" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 ); require_action( strcmp( s, "2345" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" ); require_action( strcmp( s, "test" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" ); require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) ); require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) ); require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 ); #if( TYPE_LONGLONG_NATIVE ) DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) ); require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) ); require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) ); require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 ); #endif DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) ); require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 ); // 'AbCd' require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 ); #if( defined( MDNS_DEBUGMSGS ) ) { mDNSAddr maddr; memset( &maddr, 0, sizeof( maddr ) ); maddr.type = mDNSAddrType_IPv4; maddr.ip.v4.b[ 0 ] = 127; maddr.ip.v4.b[ 1 ] = 0; maddr.ip.v4.b[ 2 ] = 0; maddr.ip.v4.b[ 3 ] = 1; DebugSNPrintF( s, sizeof( s ), "%#a", &maddr ); require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 ); memset( &maddr, 0, sizeof( maddr ) ); maddr.type = mDNSAddrType_IPv6; maddr.ip.v6.b[ 0 ] = 0xFE; maddr.ip.v6.b[ 1 ] = 0x80; maddr.ip.v6.b[ 15 ] = 0x01; DebugSNPrintF( s, sizeof( s ), "%#a", &maddr ); require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 ); } #endif #if( AF_INET ) { struct sockaddr_in sa4; memset( &sa4, 0, sizeof( sa4 ) ); sa4.sin_family = AF_INET; p = (uint8_t *) &sa4.sin_port; p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF ); p[ 1 ] = (uint8_t)( 80 & 0xFF ); p = (uint8_t *) &sa4.sin_addr.s_addr; p[ 0 ] = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF ); p[ 1 ] = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF ); p[ 2 ] = (uint8_t)( ( INADDR_LOOPBACK >> 8 ) & 0xFF ); p[ 3 ] = (uint8_t)( INADDR_LOOPBACK & 0xFF ); DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 ); require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 ); } #endif #if( AF_INET6 ) { struct sockaddr_in6 sa6; memset( &sa6, 0, sizeof( sa6 ) ); sa6.sin6_family = AF_INET6; p = (uint8_t *) &sa6.sin6_port; p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF ); p[ 1 ] = (uint8_t)( 80 & 0xFF ); sa6.sin6_addr.s6_addr[ 0 ] = 0xFE; sa6.sin6_addr.s6_addr[ 1 ] = 0x80; sa6.sin6_addr.s6_addr[ 15 ] = 0x01; sa6.sin6_scope_id = 2; DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 ); require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 ); } #endif // Unicode DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" ); require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" ); require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" ); require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" ); require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" ); require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" ); require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" ); require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" ); require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" ); require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" ); require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" ); require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" ); require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" ); require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); #if( TARGET_RT_BIG_ENDIAN ) DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); #else DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); #endif DebugSNPrintF( s, sizeof( s ), "%S", "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%S", "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%.*S", 4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian BOM require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%.*S", 4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian BOM require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); #if( TARGET_RT_BIG_ENDIAN ) DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); #else DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); #endif DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); // Misc DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" ); require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%m", 0 ); require_action( strcmp( s, "no error" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 ); require_action( strcmp( s, "no error" ) == 0, exit, err = -1 ); DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 ); DebugPrintF( kDebugLevelMax, "%s\n\n", s ); DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8" "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 32, 32 ); DebugPrintF( kDebugLevelMax, "%s\n\n", s ); DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 ); DebugPrintF( kDebugLevelMax, "%s\n\n", s ); // Hex Dumps s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoAddress, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoOffset, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoAddress, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoOffset, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoByteCount, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4, // 'AbCd' kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine | kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine | kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); s[ 0 ] = '\0'; DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) ); DebugPrintF( kDebugLevelMax, "%s\n", s ); // dlog's dlog( kDebugLevelNotice, "dlog\n" ); dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 ); dlog( kDebugLevelNotice, "dlog string: \"%s\"\n", "test string" ); dlogmem( kDebugLevelNotice, data, sizeof( data ) ); // Done DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" ); err = kNoErr; exit: if( err ) { DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" ); } return( err ); } #endif // DEBUG