2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
30 #include "CFUtilities.h"
31 #include "CFInternal.h"
32 #include <CoreFoundation/CFBundle.h>
33 #include <CoreFoundation/CFURLAccess.h>
34 #include <CoreFoundation/CFPropertyList.h>
35 #include <CoreFoundation/CFTimeZone.h>
40 #include <mach/mach.h>
42 #include <mach-o/dyld.h>
43 #include <mach-o/loader.h>
44 #include <crt_externs.h>
45 #include <Security/AuthSession.h>
47 #if defined(__WIN32__)
51 #if defined(__LINUX__) || defined(__FREEBSD__)
57 extern char **_CFGetProgname(void);
59 #define LESS16(A, W) do { if (A < ((uint64_t)1 << (W))) LESS8(A, (W) - 8); LESS8(A, (W) + 8); } while (0)
60 #define LESS8(A, W) do { if (A < ((uint64_t)1 << (W))) LESS4(A, (W) - 4); LESS4(A, (W) + 4); } while (0)
61 #define LESS4(A, W) do { if (A < ((uint64_t)1 << (W))) LESS2(A, (W) - 2); LESS2(A, (W) + 2); } while (0)
62 #define LESS2(A, W) do { if (A < ((uint64_t)1 << (W))) LESS1(A, (W) - 1); LESS1(A, (W) + 1); } while (0)
63 #define LESS1(A, W) do { if (A < ((uint64_t)1 << (W))) return (W) - 1; return (W); } while (0)
65 uint32_t CFLog2(uint64_t x
) {
66 if (x
< ((uint64_t)1 << 32))
73 // faster version for PPC
74 int Lg2d(unsigned x
) {
75 // use PPC-specific instruction to count leading zeros
78 __asm__
volatile("cntlzw %0,%1" : "=r" (ret
) : "r" (x
));
89 /* Comparator is passed the address of the values. */
90 /* Binary searches a sorted-increasing array of some type.
91 Return value is either 1) the index of the element desired,
92 if the target value exists in the list, 2) greater than or
93 equal to count, if the element is greater than all the values
94 in the list, or 3) the index of the element greater than the
97 For example, a search in the list of integers:
100 For... Will Return...
107 For instance, if you just care about found/not found:
108 index = CFBSearch(list, count, elem);
109 if (count <= index || list[index] != elem) {
115 This isn't optimal yet.
117 __private_extern__ CFIndex
CFBSearch(const void *element
, CFIndex elementSize
, const void *list
, CFIndex count
, CFComparatorFunction comparator
, void *context
) {
119 const char *ptr
= (const char *)list
;
122 case 3: if (comparator(ptr
+ elementSize
* 2, element
, context
) < 0) return 3;
123 case 2: if (comparator(ptr
+ elementSize
* 1, element
, context
) < 0) return 2;
124 case 1: if (comparator(ptr
+ elementSize
* 0, element
, context
) < 0) return 1;
128 if (comparator(ptr
+ elementSize
* (count
- 1), element
, context
) < 0) return count
;
129 if (comparator(element
, ptr
+ elementSize
* 0, context
) < 0) return 0;
130 lg
= CFLog2(count
); /* This takes about 1/3rd of the time, discounting calls to comparator */
131 idx
= (comparator(ptr
+ elementSize
* (-1 + (1 << lg
)), element
, context
) < 0) ? count
- (1 << lg
) : -1;
133 case 30: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 30)), element
, context
) < 0) idx
+= (1 << 30);
134 case 29: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 29)), element
, context
) < 0) idx
+= (1 << 29);
135 case 28: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 28)), element
, context
) < 0) idx
+= (1 << 28);
136 case 27: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 27)), element
, context
) < 0) idx
+= (1 << 27);
137 case 26: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 26)), element
, context
) < 0) idx
+= (1 << 26);
138 case 25: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 25)), element
, context
) < 0) idx
+= (1 << 25);
139 case 24: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 24)), element
, context
) < 0) idx
+= (1 << 24);
140 case 23: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 23)), element
, context
) < 0) idx
+= (1 << 23);
141 case 22: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 22)), element
, context
) < 0) idx
+= (1 << 22);
142 case 21: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 21)), element
, context
) < 0) idx
+= (1 << 21);
143 case 20: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 20)), element
, context
) < 0) idx
+= (1 << 20);
144 case 19: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 19)), element
, context
) < 0) idx
+= (1 << 19);
145 case 18: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 18)), element
, context
) < 0) idx
+= (1 << 18);
146 case 17: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 17)), element
, context
) < 0) idx
+= (1 << 17);
147 case 16: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 16)), element
, context
) < 0) idx
+= (1 << 16);
148 case 15: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 15)), element
, context
) < 0) idx
+= (1 << 15);
149 case 14: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 14)), element
, context
) < 0) idx
+= (1 << 14);
150 case 13: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 13)), element
, context
) < 0) idx
+= (1 << 13);
151 case 12: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 12)), element
, context
) < 0) idx
+= (1 << 12);
152 case 11: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 11)), element
, context
) < 0) idx
+= (1 << 11);
153 case 10: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 10)), element
, context
) < 0) idx
+= (1 << 10);
154 case 9: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 9)), element
, context
) < 0) idx
+= (1 << 9);
155 case 8: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 8)), element
, context
) < 0) idx
+= (1 << 8);
156 case 7: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 7)), element
, context
) < 0) idx
+= (1 << 7);
157 case 6: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 6)), element
, context
) < 0) idx
+= (1 << 6);
158 case 5: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 5)), element
, context
) < 0) idx
+= (1 << 5);
159 case 4: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 4)), element
, context
) < 0) idx
+= (1 << 4);
160 case 3: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 3)), element
, context
) < 0) idx
+= (1 << 3);
161 case 2: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 2)), element
, context
) < 0) idx
+= (1 << 2);
162 case 1: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 1)), element
, context
) < 0) idx
+= (1 << 1);
163 case 0: if (comparator(ptr
+ elementSize
* (idx
+ (1 << 0)), element
, context
) < 0) idx
+= (1 << 0);
169 #define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
171 CFHashCode
CFHashBytes(uint8_t *bytes
, CFIndex length
) {
172 /* The ELF hash algorithm, used in the ELF object file format */
173 UInt32 H
= 0, T1
, T2
;
176 ELF_STEP(bytes
[length
- rem
]);
177 ELF_STEP(bytes
[length
- rem
+ 1]);
178 ELF_STEP(bytes
[length
- rem
+ 2]);
179 ELF_STEP(bytes
[length
- rem
+ 3]);
183 case 3: ELF_STEP(bytes
[length
- 3]);
184 case 2: ELF_STEP(bytes
[length
- 2]);
185 case 1: ELF_STEP(bytes
[length
- 1]);
193 #if defined(__WIN32__)
199 static __stdcall
unsigned __CFWinThreadFunc(void *arg
) {
200 struct _args
*args
= arg
;
201 ((void (*)(void *))args
->func
)(args
->arg
);
202 CloseHandle(args
->handle
);
203 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, arg
);
209 __private_extern__
void *__CFStartSimpleThread(void *func
, void *arg
) {
210 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
213 pthread_attr_init(&attr
);
214 pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
215 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
216 pthread_attr_setstacksize(&attr
, 60 * 1024); // 60K stack for our internal threads is sufficient
217 pthread_create(&tid
, &attr
, func
, arg
);
218 pthread_attr_destroy(&attr
);
219 //warning CF: we dont actually know that a pthread_t is the same size as void *
223 struct _args
*args
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct _args
), 0);
224 if (__CFOASafe
) __CFSetLastAllocationEventName(args
, "CFUtilities (thread-args)");
228 /* 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. */
229 args
->handle
= (HANDLE
)_beginthreadex(NULL
, 0, (void *)__CFWinThreadFunc
, args
, CREATE_SUSPENDED
, &tid
);
230 handle
= args
->handle
;
231 ResumeThread(handle
);
236 __private_extern__ CFStringRef
_CFCreateLimitedUniqueString() {
237 /* this unique string is only unique to the current host during the current boot */
238 uint64_t tsr
= __CFReadTSR();
239 UInt32 tsrh
= (tsr
>> 32), tsrl
= (tsr
& (int64_t)0xFFFFFFFF);
240 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFUniqueString-%lu%lu$"), tsrh
, tsrl
);
244 // Looks for localized version of "nonLocalized" in the SystemVersion bundle
245 // If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL
246 // If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released
248 static CFStringRef
_CFCopyLocalizedVersionKey(CFBundleRef
*bundlePtr
, CFStringRef nonLocalized
) {
249 CFStringRef localized
= NULL
;
250 CFBundleRef locBundle
= bundlePtr
? *bundlePtr
: NULL
;
252 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle
, false);
254 locBundle
= CFBundleCreate(kCFAllocatorDefault
, url
);
259 localized
= CFBundleCopyLocalizedString(locBundle
, nonLocalized
, nonLocalized
, CFSTR("SystemVersion"));
260 if (bundlePtr
) *bundlePtr
= locBundle
; else CFRelease(locBundle
);
262 return localized
? localized
: CFRetain(nonLocalized
);
265 // Note, if this function is changed to cache the computed data using frozen named data support, it should really be called once per path (that is why the results are cached below in the functions calling this).
267 static CFDictionaryRef
_CFCopyVersionDictionary(CFStringRef path
) {
268 CFPropertyListRef plist
= NULL
;
272 url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path
, kCFURLPOSIXPathStyle
, false);
273 if (url
&& CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, url
, &data
, NULL
, NULL
, NULL
)) {
274 plist
= CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListMutableContainers
, NULL
);
277 if (url
) CFRelease(url
);
280 CFBundleRef locBundle
= NULL
;
281 CFStringRef fullVersion
, vers
, versExtra
, build
;
282 CFStringRef versionString
= _CFCopyLocalizedVersionKey(&locBundle
, _kCFSystemVersionProductVersionStringKey
);
283 CFStringRef buildString
= _CFCopyLocalizedVersionKey(&locBundle
, _kCFSystemVersionBuildStringKey
);
284 CFStringRef fullVersionString
= _CFCopyLocalizedVersionKey(&locBundle
, CFSTR("FullVersionString"));
285 if (locBundle
) CFRelease(locBundle
);
287 // Now build the full version string
288 if (CFEqual(fullVersionString
, CFSTR("FullVersionString"))) {
289 CFRelease(fullVersionString
);
290 fullVersionString
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@ %%@ (%@ %%@)"), versionString
, buildString
);
292 vers
= CFDictionaryGetValue(plist
, _kCFSystemVersionProductVersionKey
);
293 versExtra
= CFDictionaryGetValue(plist
, _kCFSystemVersionProductVersionExtraKey
);
294 if (vers
&& versExtra
) vers
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@ %@"), vers
, versExtra
);
295 build
= CFDictionaryGetValue(plist
, _kCFSystemVersionBuildVersionKey
);
296 fullVersion
= CFStringCreateWithFormat(NULL
, NULL
, fullVersionString
, (vers
? vers
: CFSTR("?")), build
? build
: CFSTR("?"));
297 if (vers
&& versExtra
) CFRelease(vers
);
299 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, _kCFSystemVersionProductVersionStringKey
, versionString
);
300 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, _kCFSystemVersionBuildStringKey
, buildString
);
301 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR("FullVersionString"), fullVersion
);
302 CFRelease(versionString
);
303 CFRelease(buildString
);
304 CFRelease(fullVersionString
);
305 CFRelease(fullVersion
);
310 CFStringRef
CFCopySystemVersionString(void) {
311 CFStringRef versionString
;
312 CFDictionaryRef dict
= _CFCopyServerVersionDictionary();
313 if (!dict
) dict
= _CFCopySystemVersionDictionary();
314 versionString
= CFDictionaryGetValue(dict
, CFSTR("FullVersionString"));
315 if (versionString
) CFRetain(versionString
);
317 return versionString
;
320 // These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired
322 CFDictionaryRef
_CFCopySystemVersionDictionary(void) {
323 static CFPropertyListRef plist
= NULL
; // Set to -1 for failed lookup
325 plist
= _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
326 if (!plist
) plist
= (CFPropertyListRef
)(-1);
328 return (plist
== (CFPropertyListRef
)(-1)) ? NULL
: CFRetain(plist
);
331 CFDictionaryRef
_CFCopyServerVersionDictionary(void) {
332 static CFPropertyListRef plist
= NULL
; // Set to -1 for failed lookup
334 plist
= _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
335 if (!plist
) plist
= (CFPropertyListRef
)(-1);
337 return (plist
== (CFPropertyListRef
)(-1)) ? NULL
: CFRetain(plist
);
340 CONST_STRING_DECL(_kCFSystemVersionProductNameKey
, "ProductName")
341 CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey
, "ProductCopyright")
342 CONST_STRING_DECL(_kCFSystemVersionProductVersionKey
, "ProductVersion")
343 CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey
, "ProductVersionExtra")
344 CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey
, "ProductUserVisibleVersion")
345 CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey
, "ProductBuildVersion")
346 CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey
, "Version")
347 CONST_STRING_DECL(_kCFSystemVersionBuildStringKey
, "Build")
349 #if defined(__MACH__)
350 CFLibraryVersion
CFGetExecutableLinkedLibraryVersion(CFStringRef libraryName
) {
351 CFLibraryVersion ret
= {0xFFFF, 0xFF, 0xFF};
352 struct mach_header
*mh
;
353 struct load_command
*lc
;
355 char library
[CFMaxPathSize
]; // search specs larger than this are pointless
357 if (!CFStringGetCString(libraryName
, library
, sizeof(library
), kCFStringEncodingUTF8
)) return ret
;
358 mh
= _dyld_get_image_header(0); // image header #0 is the executable
359 if (NULL
== mh
) return ret
;
360 lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
361 for (idx
= 0; idx
< mh
->ncmds
; idx
++) {
362 if (lc
->cmd
== LC_LOAD_DYLIB
) {
363 struct dylib_command
*dl
= (struct dylib_command
*)lc
;
364 char *path
= (char *)lc
+ dl
->dylib
.name
.offset
;
365 if (NULL
!= strstr(path
, library
)) {
366 ret
.primaryVersion
= dl
->dylib
.current_version
>> 16;
367 ret
.secondaryVersion
= (dl
->dylib
.current_version
>> 8) & 0xff;
368 ret
.tertiaryVersion
= dl
->dylib
.current_version
& 0xff;
372 lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
);
377 CFLibraryVersion
CFGetExecutingLibraryVersion(CFStringRef libraryName
) {
378 CFLibraryVersion ret
= {0xFFFF, 0xFF, 0xFF};
379 struct mach_header
*mh
;
380 struct load_command
*lc
;
381 unsigned int idx1
, idx2
, cnt
;
382 char library
[CFMaxPathSize
]; // search specs larger than this are pointless
384 if (!CFStringGetCString(libraryName
, library
, sizeof(library
), kCFStringEncodingUTF8
)) return ret
;
385 cnt
= _dyld_image_count();
386 for (idx1
= 1; idx1
< cnt
; idx1
++) {
387 char *image_name
= _dyld_get_image_name(idx1
);
388 if (NULL
== image_name
|| NULL
== strstr(image_name
, library
)) continue;
389 mh
= _dyld_get_image_header(idx1
);
390 if (NULL
== mh
) return ret
;
391 lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
392 for (idx2
= 0; idx2
< mh
->ncmds
; idx2
++) {
393 if (lc
->cmd
== LC_ID_DYLIB
) {
394 struct dylib_command
*dl
= (struct dylib_command
*)lc
;
395 ret
.primaryVersion
= dl
->dylib
.current_version
>> 16;
396 ret
.secondaryVersion
= (dl
->dylib
.current_version
>> 8) & 0xff;
397 ret
.tertiaryVersion
= dl
->dylib
.current_version
& 0xff;
408 (vers != 0xFFFF): We know the version number of the library this app was linked against
409 and (versionInfo[version].VERSIONFIELD != 0xFFFF): And we know what version number started the specified release
410 and ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD)): And it's distinct from the prev release
412 If the version the app is linked against is less than the version recorded for the specified release
413 Then stop checking and return false
414 Else stop checking and return YES
416 Continue checking (the next library)
418 #define checkLibrary(LIBNAME, VERSIONFIELD) \
419 {int vers = CFGetExecutableLinkedLibraryVersion(LIBNAME).primaryVersion; \
420 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)); }
422 CF_EXPORT Boolean
_CFExecutableLinkedOnOrAfter(CFSystemVersion version
) {
423 // The numbers in the below table should be the numbers for any version of the framework in the release.
424 // When adding new entries to this table for a new build train, it's simplest to use the versions of the
425 // first new versions of projects submitted to the new train. These can later be updated. One thing to watch for is that software updates
426 // for the previous release do not increase numbers beyond the number used for the next release!
427 // For a given train, don't ever use the last versions submitted to the previous train! (This to assure room for software updates.)
428 // If versions are the same as previous release, use 0xFFFF; this will assure the answer is a conservative NO.
429 // NOTE: Also update the CFM check below, perhaps to the previous release... (???)
430 static const struct {
431 uint16_t libSystemVersion
;
432 uint16_t cocoaVersion
;
433 uint16_t appkitVersion
;
436 uint16_t carbonVersion
;
437 uint16_t applicationServicesVersion
;
438 uint16_t coreServicesVersion
;
439 uint16_t iokitVersion
;
441 {50, 5, 577, 397, 196, 113, 16, 9, 52}, /* CFSystemVersionCheetah (used the last versions) */
442 {55, 7, 620, 425, 226, 122, 16, 10, 67}, /* CFSystemVersionPuma (used the last versions) */
443 {56, 8, 631, 431, 232, 122, 17, 11, 73}, /* CFSystemVersionJaguar */
444 {67, 9, 704, 481, 281, 126, 19, 16, 159}, /* CFSystemVersionPanther */
445 {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF} /* CFSystemVersionMerlot */
447 static char results
[CFSystemVersionMax
] = {-2, -2, -2, -2, -2}; /* We cache the results per-release; there are only a few of these... */
448 if (version
>= CFSystemVersionMax
) return false; /* Actually, we don't know the answer, and something scary is going on */
449 if (results
[version
] != -2) return results
[version
];
452 results
[version
] = (version
<= CFSystemVersionJaguar
) ? true : false;
453 return results
[version
];
456 checkLibrary(CFSTR("/libSystem."), libSystemVersion
); // Pretty much everyone links with this
457 checkLibrary(CFSTR("/Cocoa."), cocoaVersion
);
458 checkLibrary(CFSTR("/AppKit."), appkitVersion
);
459 checkLibrary(CFSTR("/Foundation."), fouVersion
);
460 checkLibrary(CFSTR("/CoreFoundation."), cfVersion
);
461 checkLibrary(CFSTR("/Carbon."), carbonVersion
);
462 checkLibrary(CFSTR("/ApplicationServices."), applicationServicesVersion
);
463 checkLibrary(CFSTR("/CoreServices."), coreServicesVersion
);
464 checkLibrary(CFSTR("/IOKit."), iokitVersion
);
466 /* If not found, then simply return NO to indicate earlier --- compatibility by default, unfortunately */
474 void CFShow(const void *obj
) { // ??? supposed to use stderr for Logging ?
477 CFStringInlineBuffer buffer
;
481 if (CFGetTypeID(obj
) == CFStringGetTypeID()) {
482 // Makes Ali marginally happier
483 str
= __CFCopyFormattingDescription(obj
, NULL
);
484 if (!str
) str
= CFCopyDescription(obj
);
486 str
= CFCopyDescription(obj
);
489 str
= CFRetain(CFSTR("(null)"));
491 cnt
= CFStringGetLength(str
);
493 CFStringInitInlineBuffer(str
, &buffer
, CFRangeMake(0, cnt
));
494 for (idx
= 0; idx
< cnt
; idx
++) {
495 UniChar ch
= __CFStringGetCharacterFromInlineBufferQuick(&buffer
, idx
);
497 fprintf (stderr
, "%c", ch
);
498 lastNL
= (ch
== '\n');
500 fprintf (stderr
, "\\u%04x", ch
);
503 if (!lastNL
) fprintf(stderr
, "\n");
505 if (str
) CFRelease(str
);
508 void CFLog(int p
, CFStringRef format
, ...) {
511 static CFSpinLock_t lock
= 0;
513 va_start(argList
, format
);
514 result
= CFStringCreateWithFormatAndArguments(NULL
, NULL
, format
, argList
);
518 #if defined(__WIN32__)
519 printf("*** CFLog (%d): %s[%d] ", p
, __argv
[0], GetCurrentProcessId());
521 // Date format: YYYY '-' MM '-' DD ' ' hh ':' mm ':' ss.fff
522 CFTimeZoneRef tz
= CFTimeZoneCopySystem(); // specifically choose system time zone for logs
523 CFGregorianDate gdate
= CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz
);
525 gdate
.second
= gdate
.second
+ 0.0005;
526 fprintf(stderr
, "%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(), p
);
530 __CFSpinUnlock(&lock
);