blob: c1701620adfaefe68adea7448b8f32f6ca5ec6d7 [file] [log] [blame]
/*
* Copyright (c) 2008-2009 Brent Fulgham <bfulgham@gmail.org>. All rights reserved.
* Copyright (c) 2009 Grant Erickson <gerickson@nuovations.com>. All rights reserved.
*
* This source code is a modified version of the CoreFoundation sources released by Apple Inc. under
* the terms of the APSL version 2.0 (see below).
*
* For information about changes from the original Apple source release can be found by reviewing the
* source control system for the project at https://sourceforge.net/svn/?group_id=246198.
*
* The original license information is as follows:
*
* Copyright (c) 2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* CFUtilities.c
Copyright 1998-2002, Apple, Inc. All rights reserved.
Responsibility: Christopher Kane
*/
#include "CFPriv.h"
#include "CFInternal.h"
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFURLAccess.h>
#include <CoreFoundation/CFPropertyList.h>
#include <CoreFoundation/CFTimeZone.h>
#include <CoreFoundation/CFCalendar.h>
#if (DEPLOYMENT_TARGET_MACOSX)
#include <CoreFoundation/CFLogUtilities.h>
#include <asl.h>
#include <sys/uio.h>
#endif
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if DEPLOYMENT_TARGET_MACOSX
#include <mach/mach.h>
#include <pthread.h>
#include <mach-o/loader.h>
#include <mach-o/dyld.h>
#include <crt_externs.h>
#include <dlfcn.h>
#include <vproc.h>
#include <vproc_priv.h>
#include <sys/stat.h>
#include <unistd.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <stdio.h>
#endif
#if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
#include <string.h>
#include <pthread.h>
#elif DEPLOYMENT_TARGET_WINDOWS
#include <windows.h>
#include <process.h>
#define getpid _getpid
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
typedef void* (*THREAD_FUN_TYPE)(void*);
#endif
/* Comparator is passed the address of the values. */
/* Binary searches a sorted-increasing array of some type.
Return value is either 1) the index of the element desired,
if the target value exists in the list, 2) greater than or
equal to count, if the element is greater than all the values
in the list, or 3) the index of the element greater than the
target value.
For example, a search in the list of integers:
2 3 5 7 11 13 17
For... Will Return...
2 0
5 2
23 7
1 0
9 4
For instance, if you just care about found/not found:
index = CFBSearch(list, count, elem);
if (count <= index || list[index] != elem) {
* Not found *
} else {
* Found *
}
*/
__private_extern__ CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
const char *ptr = (const char *)list;
while (0 < count) {
CFIndex half = count / 2;
const char *probe = ptr + elementSize * half;
CFComparisonResult cr = comparator(element, probe, context);
if (0 == cr) return (probe - (const char *)list) / elementSize;
ptr = (cr < 0) ? ptr : probe + elementSize;
count = (cr < 0) ? half : (half + (count & 1) - 1);
}
return (ptr - (const char *)list) / elementSize;
}
#define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) {
/* The ELF hash algorithm, used in the ELF object file format */
UInt32 H = 0, T1, T2;
SInt32 rem = length;
while (3 < rem) {
ELF_STEP(bytes[length - rem]);
ELF_STEP(bytes[length - rem + 1]);
ELF_STEP(bytes[length - rem + 2]);
ELF_STEP(bytes[length - rem + 3]);
rem -= 4;
}
switch (rem) {
case 3: ELF_STEP(bytes[length - 3]);
case 2: ELF_STEP(bytes[length - 2]);
case 1: ELF_STEP(bytes[length - 1]);
case 0: ;
}
return H;
}
#undef ELF_STEP
#if DEPLOYMENT_TARGET_MACOSX
__private_extern__ uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start) {
vm_map_t task = mach_task_self();
mach_vm_address_t address = start;
for (;;) {
mach_vm_size_t size = 0;
vm_region_basic_info_data_64_t info;
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
mach_port_t object_name;
kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
if (KERN_SUCCESS != ret) break;
boolean_t scan = (info.protection & VM_PROT_WRITE) ? 1 : 0;
if (scan) {
uintptr_t *addr = (uintptr_t *)((uintptr_t)address);
uintptr_t *end = (uintptr_t *)((uintptr_t)address + (uintptr_t)size);
while (addr < end) {
if ((uintptr_t *)start <= addr && *addr == ptr) {
return (uintptr_t)addr;
}
addr++;
}
}
address += size;
}
return 0;
}
#endif
#if DEPLOYMENT_TARGET_WINDOWS
typedef struct _args {
void *func;
void *arg;
HANDLE handle;
};
static unsigned int __stdcall __CFWinThreadFunc(void *arg) {
struct _args *args = (struct _args*)arg;
((void (*)(void *))args->func)(args->arg);
CloseHandle(args->handle);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, arg);
_endthreadex(0);
return 0;
}
#endif
__private_extern__ void *__CFStartSimpleThread(void *func, void *arg) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
pthread_attr_t attr;
pthread_t tid = 0;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, 60 * 1024); // 60K stack for our internal threads is sufficient
_CFMemoryBarrier(); // ensure arg is fully initialized and set in memory
pthread_create(&tid, &attr, (THREAD_FUN_TYPE)func, arg);
pthread_attr_destroy(&attr);
//warning CF: we dont actually know that a pthread_t is the same size as void *
return (void *)tid;
#else
unsigned tid;
struct _args *args = (struct _args*)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0);
if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)");
HANDLE handle;
args->func = func;
args->arg = arg;
/* The thread is created suspended, because otherwise there would be a race between the assignment below of the handle field, and it's possible use in the thread func above. */
args->handle = (HANDLE)_beginthreadex(NULL, 0, __CFWinThreadFunc, args, CREATE_SUSPENDED, &tid);
handle = args->handle;
ResumeThread(handle);
return handle;
#endif
}
__private_extern__ CFStringRef _CFCreateLimitedUniqueString() {
/* this unique string is only unique to the current host during the current boot */
uint64_t tsr = __CFReadTSR();
UInt32 tsrh = (UInt32)(tsr >> 32), tsrl = (UInt32)(tsr & (int64_t)0xFFFFFFFF);
return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFUniqueString-%lu%lu$"), tsrh, tsrl);
}
// Looks for localized version of "nonLocalized" in the SystemVersion bundle
// If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL
// If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released
static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
CFStringRef localized = NULL;
CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
if (!locBundle) {
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false);
if (url) {
locBundle = CFBundleCreate(kCFAllocatorSystemDefault, url);
CFRelease(url);
}
}
if (locBundle) {
localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
}
return localized ? localized : (CFStringRef)CFRetain(nonLocalized);
}
static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
CFPropertyListRef plist = NULL;
CFDataRef data;
CFURLRef url;
url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false);
if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, NULL)) {
plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL);
CFRelease(data);
}
if (url) CFRelease(url);
if (plist) {
#if DEPLOYMENT_TARGET_MACOSX
CFBundleRef locBundle = NULL;
CFStringRef fullVersion, vers, versExtra, build;
CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey);
CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey);
CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString"));
if (locBundle) CFRelease(locBundle);
// Now build the full version string
if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
CFRelease(fullVersionString);
fullVersionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
}
vers = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionKey);
versExtra = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionExtraKey);
if (vers && versExtra) vers = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %@"), vers, versExtra);
build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey);
fullVersion = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?"));
if (vers && versExtra) CFRelease(vers);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion);
CFRelease(versionString);
CFRelease(buildString);
CFRelease(fullVersionString);
CFRelease(fullVersion);
#endif
}
return (CFDictionaryRef)plist;
}
#if defined (__MACH__) || 0
CFStringRef CFCopySystemVersionString(void) {
CFStringRef versionString;
CFDictionaryRef dict = _CFCopyServerVersionDictionary();
if (!dict) dict = _CFCopySystemVersionDictionary();
versionString = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("FullVersionString"));
if (versionString) CFRetain(versionString);
CFRelease(dict);
return versionString;
}
// Obsolete: These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired
// In fact, they do not cache any more, because the file can change after
// apps are running in some situations, and apps need the new info.
// Proper caching and testing to see if the file has changed, without race
// conditions, would require semi-convoluted use of fstat().
CFDictionaryRef _CFCopySystemVersionDictionary(void) {
CFPropertyListRef plist = NULL;
plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
return (CFDictionaryRef)plist;
}
CFDictionaryRef _CFCopyServerVersionDictionary(void) {
CFPropertyListRef plist = NULL;
plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
return (CFDictionaryRef)plist;
}
CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
typedef struct {
uint16_t primaryVersion;
uint8_t secondaryVersion;
uint8_t tertiaryVersion;
} CFLibraryVersion;
CFLibraryVersion CFGetExecutableLinkedLibraryVersion(CFStringRef libraryName) {
CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
char library[CFMaxPathSize]; // search specs larger than this are pointless
if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
int32_t version = NSVersionOfLinkTimeLibrary(library);
if (-1 != version) {
ret.primaryVersion = version >> 16;
ret.secondaryVersion = (version >> 8) & 0xff;
ret.tertiaryVersion = version & 0xff;
}
return ret;
}
CFLibraryVersion CFGetExecutingLibraryVersion(CFStringRef libraryName) {
CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
char library[CFMaxPathSize]; // search specs larger than this are pointless
if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
int32_t version = NSVersionOfRunTimeLibrary(library);
if (-1 != version) {
ret.primaryVersion = version >> 16;
ret.secondaryVersion = (version >> 8) & 0xff;
ret.tertiaryVersion = version & 0xff;
}
return ret;
}
/*
If
(vers != 0xFFFF): We know the version number of the library this app was linked against
and (versionInfo[version].VERSIONFIELD != 0xFFFF): And we know what version number started the specified release
and ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD)): And it's distinct from the prev release
Then
If the version the app is linked against is less than the version recorded for the specified release
Then stop checking and return false
Else stop checking and return YES
Else
Continue checking (the next library)
*/
#define checkLibrary(LIBNAME, VERSIONFIELD) \
{uint16_t vers = (NSVersionOfLinkTimeLibrary(LIBNAME) >> 16); \
if ((vers != 0xFFFF) && (versionInfo[version].VERSIONFIELD != 0xFFFF) && ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD))) return (results[version] = ((vers < versionInfo[version].VERSIONFIELD) ? false : true)); }
CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
// The numbers in the below table should be the numbers for any version of the framework in the release.
// When adding new entries to this table for a new build train, it's simplest to use the versions of the
// first new versions of projects submitted to the new train. These can later be updated. One thing to watch for is that software updates
// for the previous release do not increase numbers beyond the number used for the next release!
// For a given train, don't ever use the last versions submitted to the previous train! (This to assure room for software updates.)
// If versions are the same as previous release, use 0xFFFF; this will assure the answer is a conservative NO.
// NOTE: Also update the CFM check below, perhaps to the previous release... (???)
static const struct {
uint16_t libSystemVersion;
uint16_t cocoaVersion;
uint16_t appkitVersion;
uint16_t fouVersion;
uint16_t cfVersion;
uint16_t carbonVersion;
uint16_t applicationServicesVersion;
uint16_t coreServicesVersion;
uint16_t iokitVersion;
} versionInfo[] = {
{50, 5, 577, 397, 196, 113, 16, 9, 52}, /* CFSystemVersionCheetah (used the last versions) */
{55, 7, 620, 425, 226, 122, 16, 10, 67}, /* CFSystemVersionPuma (used the last versions) */
{56, 8, 631, 431, 232, 122, 17, 11, 73}, /* CFSystemVersionJaguar */
{67, 9, 704, 481, 281, 126, 19, 16, 159}, /* CFSystemVersionPanther */
{73, 10, 750, 505, 305, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionTiger */
{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionChablis */
};
static char results[CFSystemVersionMax] = {-2, -2, -2, -2, -2, -2}; /* We cache the results per-release; there are only a few of these... */
if (version >= CFSystemVersionMax) return false; /* Actually, we don't know the answer, and something scary is going on */
if (results[version] != -2) return results[version];
if (_CFIsCFM()) {
results[version] = (version <= CFSystemVersionJaguar) ? true : false;
return results[version];
}
checkLibrary("System", libSystemVersion); // Pretty much everyone links with this
checkLibrary("Cocoa", cocoaVersion);
checkLibrary("AppKit", appkitVersion);
checkLibrary("Foundation", fouVersion);
checkLibrary("CoreFoundation", cfVersion);
checkLibrary("Carbon", carbonVersion);
checkLibrary("ApplicationServices", applicationServicesVersion);
checkLibrary("CoreServices", coreServicesVersion);
checkLibrary("IOKit", iokitVersion);
/* If not found, then simply return NO to indicate earlier --- compatibility by default, unfortunately */
return false;
}
#else
CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
return true;
}
#endif
#if DEPLOYMENT_TARGET_MACOSX
__private_extern__ void *__CFLookupCFNetworkFunction(const char *name) {
static void *image = NULL;
if (NULL == image) {
const char *path = NULL;
if (!issetugid()) {
path = getenv("CFNETWORK_LIBRARY_PATH");
}
if (!path) {
path = "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork";
}
image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
}
void *dyfunc = NULL;
if (image) {
dyfunc = dlsym(image, name);
}
return dyfunc;
}
#endif //__MACH__
#ifndef __CFGetSessionID_defined
__private_extern__ uint32_t __CFGetSessionID(void) {
return 0;
}
#endif
const char *_CFPrintForDebugger(const void *obj) {
static char *result = NULL;
CFStringRef str;
CFIndex cnt = 0;
free(result); // Let go of result from previous call.
result = NULL;
if (obj) {
if (CFGetTypeID(obj) == CFStringGetTypeID()) {
// Makes Ali marginally happier
str = __CFCopyFormattingDescription(obj, NULL);
if (!str) str = CFCopyDescription(obj);
} else {
str = CFCopyDescription(obj);
}
} else {
str = (CFStringRef)CFRetain(CFSTR("(null)"));
}
if (str != NULL) {
CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &cnt);
}
result = (char *) malloc(cnt + 2); // 1 for '\0', 1 for an optional '\n'
if (str != NULL) {
CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, (UInt8 *) result, cnt, &cnt);
}
result[cnt] = '\0';
if (str) CFRelease(str);
return result;
}
static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
CFStringRef str;
CFIndex idx, cnt;
CFStringInlineBuffer buffer;
bool lastNL = false;
if (obj) {
if (CFGetTypeID(obj) == CFStringGetTypeID()) {
// Makes Ali marginally happier
str = __CFCopyFormattingDescription(obj, NULL);
if (!str) str = CFCopyDescription(obj);
} else {
str = CFCopyDescription(obj);
}
} else {
str = (CFStringRef)CFRetain(CFSTR("(null)"));
}
cnt = CFStringGetLength(str);
// iTunes used OutputDebugStringW(theString);
CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
#if DEPLOYMENT_TARGET_WINDOWS
TCHAR *accumulatedBuffer = (TCHAR *)malloc((cnt+1) * sizeof(TCHAR));
#endif
for (idx = 0; idx < cnt; idx++) {
UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
#if DEPLOYMENT_TARGET_MACOSX
if (ch < 128) {
fprintf_l(file, NULL, "%c", ch);
lastNL = (ch == '\n');
} else {
fprintf_l(file, NULL, "\\u%04x", ch);
}
#elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
if (ch < 128) {
fprintf(file, "%c", ch);
lastNL = (ch == '\n');
} else {
fprintf(file, "\\u%04x", ch);
}
#endif
}
if (!lastNL) {
#if DEPLOYMENT_TARGET_MACOSX
fprintf_l(file, NULL, "\n");
#else
fprintf(file, "\n");
#endif
if (flush) fflush(file);
}
if (str) CFRelease(str);
}
void CFShow(const void *obj) {
_CFShowToFile(stderr, true, obj);
}
void CFLog(int32_t lev, CFStringRef format, ...) {
CFStringRef result;
va_list argList;
static CFSpinLock_t lock = CFSpinLockInit;
va_start(argList, format);
result = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, format, argList);
va_end(argList);
__CFSpinLock(&lock);
CFTimeZoneRef tz = CFTimeZoneCopySystem(); // specifically choose system time zone for logs
CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz);
CFRelease(tz);
gdate.second = gdate.second + 0.0005;
// Date format: YYYY '-' MM '-' DD ' ' hh ':' mm ':' ss.fff
#if DEPLOYMENT_TARGET_WINDOWS
printf("%04d-%02d-%02d %02d:%02d:%06.3f %s[%d] CFLog (%d): ", (int)gdate.year, gdate.month, gdate.day, gdate.hour, gdate.minute, gdate.second, *_CFGetProgname(), getpid(), lev);
#elif DEPLOYMENT_TARGET_LINUX
fprintf(stderr, "%04d-%02d-%02d %02d:%02d:%06.3f %s[%d:%x] CFLog: ", (int)gdate.year, gdate.month, gdate.day, gdate.hour, gdate.minute, gdate.second, *_CFGetProgname(), getpid(), (uintptr_t)pthread_self());
#else
fprintf_l(stderr, NULL, "%04d-%02d-%02d %02d:%02d:%06.3f %s[%d:%x] CFLog: ", (int)gdate.year, gdate.month, gdate.day, gdate.hour, gdate.minute, gdate.second, *_CFGetProgname(), getpid(), pthread_mach_thread_np(pthread_self()));
#endif
CFShow(result);
__CFSpinUnlock(&lock);
CFRelease(result);
}