]> git.saurik.com Git - apple/cf.git/blob - CFLocale.c
CF-476.15.tar.gz
[apple/cf.git] / CFLocale.c
1 /*
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFLocale.c
24 Copyright 2002-2003, Apple Computer, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 // Note the header file is in the OpenSource set (stripped to almost nothing), but not the .c file
29
30 #include <CoreFoundation/CFLocale.h>
31 #include <CoreFoundation/CFString.h>
32 #include <CoreFoundation/CFArray.h>
33 #include <CoreFoundation/CFDictionary.h>
34 #include <CoreFoundation/CFPreferences.h>
35 #include <CoreFoundation/CFCalendar.h>
36 #include <CoreFoundation/CFNumber.h>
37 #include "CFInternal.h"
38 #include <unicode/uloc.h> // ICU locales
39 #include <unicode/ulocdata.h> // ICU locale data
40 #include <unicode/ucurr.h> // ICU currency functions
41 #include <unicode/uset.h> // ICU Unicode sets
42 #include <unicode/putil.h> // ICU low-level utilities
43 #include <unicode/umsg.h> // ICU message formatting
44 #if DEPLOYMENT_TARGET_MACOSX
45 #include <CoreFoundation/CFNumberFormatter.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <unicode/ucol.h>
49 #endif
50
51 CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification")
52
53 static const char *kCalendarKeyword = "calendar";
54 static const char *kCollationKeyword = "collation";
55 #define kMaxICUNameSize 1024
56
57 typedef struct __CFLocale *CFMutableLocaleRef;
58
59 __private_extern__ CONST_STRING_DECL(__kCFLocaleCollatorID, "locale:collator id")
60
61 enum {
62 __kCFLocaleKeyTableCount = 16
63 };
64
65 struct key_table {
66 CFStringRef key;
67 bool (*get)(CFLocaleRef, bool user, CFTypeRef *, CFStringRef context); // returns an immutable copy & reference
68 bool (*set)(CFMutableLocaleRef, CFTypeRef, CFStringRef context);
69 bool (*name)(const char *, const char *, CFStringRef *);
70 CFStringRef context;
71 };
72
73
74 // Must forward decl. these functions:
75 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
76 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context);
77 static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out);
78 static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
79 static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out);
80 static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out);
81 static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out);
82 static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out);
83 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
84 static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out);
85 static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out);
86 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
87 static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out);
88 static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out);
89 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
90 static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
91 static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
92 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
93 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
94 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
95 static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out);
96 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
97
98 // Note string members start with an extra &, and are fixed up at init time
99 static struct key_table __CFLocaleKeyTable[__kCFLocaleKeyTableCount] = {
100 {(CFStringRef)&kCFLocaleIdentifier, __CFLocaleCopyLocaleID, __CFLocaleSetNOP, __CFLocaleFullName, NULL},
101 {(CFStringRef)&kCFLocaleLanguageCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleLanguageName, (CFStringRef)&kCFLocaleLanguageCode},
102 {(CFStringRef)&kCFLocaleCountryCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleCountryName, (CFStringRef)&kCFLocaleCountryCode},
103 {(CFStringRef)&kCFLocaleScriptCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleScriptName, (CFStringRef)&kCFLocaleScriptCode},
104 {(CFStringRef)&kCFLocaleVariantCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleVariantName, (CFStringRef)&kCFLocaleVariantCode},
105 {(CFStringRef)&kCFLocaleExemplarCharacterSet, __CFLocaleCopyExemplarCharSet, __CFLocaleSetNOP, __CFLocaleNoName, NULL},
106 {(CFStringRef)&kCFLocaleCalendarIdentifier, __CFLocaleCopyCalendarID, __CFLocaleSetNOP, __CFLocaleCalendarName, NULL},
107 {(CFStringRef)&kCFLocaleCalendar, __CFLocaleCopyCalendar, __CFLocaleSetNOP, __CFLocaleNoName, NULL},
108 {(CFStringRef)&kCFLocaleCollationIdentifier, __CFLocaleCopyCollationID, __CFLocaleSetNOP, __CFLocaleCollationName, NULL},
109 {(CFStringRef)&kCFLocaleUsesMetricSystem, __CFLocaleCopyUsesMetric, __CFLocaleSetNOP, __CFLocaleNoName, NULL},
110 {(CFStringRef)&kCFLocaleMeasurementSystem, __CFLocaleCopyMeasurementSystem, __CFLocaleSetNOP, __CFLocaleNoName, NULL},
111 {(CFStringRef)&kCFLocaleDecimalSeparator, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterDecimalSeparator},
112 {(CFStringRef)&kCFLocaleGroupingSeparator, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterGroupingSeparator},
113 {(CFStringRef)&kCFLocaleCurrencySymbol, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyShortName, (CFStringRef)&kCFNumberFormatterCurrencySymbol},
114 {(CFStringRef)&kCFLocaleCurrencyCode, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyFullName, (CFStringRef)&kCFNumberFormatterCurrencyCode},
115 {(CFStringRef)&__kCFLocaleCollatorID, __CFLocaleCopyCollatorID, __CFLocaleSetNOP, __CFLocaleNoName, NULL},
116 };
117
118
119 static CFLocaleRef __CFLocaleSystem = NULL;
120 static CFMutableDictionaryRef __CFLocaleCache = NULL;
121 static CFSpinLock_t __CFLocaleGlobalLock = CFSpinLockInit;
122
123 struct __CFLocale {
124 CFRuntimeBase _base;
125 CFStringRef _identifier; // canonical identifier, never NULL
126 CFMutableDictionaryRef _cache;
127 CFMutableDictionaryRef _overrides;
128 CFDictionaryRef _prefs;
129 CFSpinLock_t _lock;
130 };
131
132 /* Flag bits */
133 enum { /* Bits 0-1 */
134 __kCFLocaleOrdinary = 0,
135 __kCFLocaleSystem = 1,
136 __kCFLocaleUser = 2,
137 __kCFLocaleCustom = 3
138 };
139
140 CF_INLINE CFIndex __CFLocaleGetType(CFLocaleRef locale) {
141 return __CFBitfieldGetValue(((const CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0);
142 }
143
144 CF_INLINE void __CFLocaleSetType(CFLocaleRef locale, CFIndex type) {
145 __CFBitfieldSetValue(((CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0, (uint8_t)type);
146 }
147
148 CF_INLINE void __CFLocaleLockGlobal(void) {
149 __CFSpinLock(&__CFLocaleGlobalLock);
150 }
151
152 CF_INLINE void __CFLocaleUnlockGlobal(void) {
153 __CFSpinUnlock(&__CFLocaleGlobalLock);
154 }
155
156 CF_INLINE void __CFLocaleLock(CFLocaleRef locale) {
157 __CFSpinLock(&locale->_lock);
158 }
159
160 CF_INLINE void __CFLocaleUnlock(CFLocaleRef locale) {
161 __CFSpinUnlock(&locale->_lock);
162 }
163
164
165 static Boolean __CFLocaleEqual(CFTypeRef cf1, CFTypeRef cf2) {
166 CFLocaleRef locale1 = (CFLocaleRef)cf1;
167 CFLocaleRef locale2 = (CFLocaleRef)cf2;
168 // a user locale and a locale created with an ident are not the same even if their contents are
169 if (__CFLocaleGetType(locale1) != __CFLocaleGetType(locale2)) return false;
170 if (!CFEqual(locale1->_identifier, locale2->_identifier)) return false;
171 if (NULL == locale1->_overrides && NULL != locale2->_overrides) return false;
172 if (NULL != locale1->_overrides && NULL == locale2->_overrides) return false;
173 if (NULL != locale1->_overrides && !CFEqual(locale1->_overrides, locale2->_overrides)) return false;
174 if (__kCFLocaleUser == __CFLocaleGetType(locale1)) {
175 return CFEqual(locale1->_prefs, locale2->_prefs);
176 }
177 return true;
178 }
179
180 static CFHashCode __CFLocaleHash(CFTypeRef cf) {
181 CFLocaleRef locale = (CFLocaleRef)cf;
182 return CFHash(locale->_identifier);
183 }
184
185 static CFStringRef __CFLocaleCopyDescription(CFTypeRef cf) {
186 CFLocaleRef locale = (CFLocaleRef)cf;
187 const char *type = NULL;
188 switch (__CFLocaleGetType(locale)) {
189 case __kCFLocaleOrdinary: type = "ordinary"; break;
190 case __kCFLocaleSystem: type = "system"; break;
191 case __kCFLocaleUser: type = "user"; break;
192 case __kCFLocaleCustom: type = "custom"; break;
193 }
194 return CFStringCreateWithFormat(CFGetAllocator(locale), NULL, CFSTR("<CFLocale %p [%p]>{type = %s, identifier = '%@'}"), cf, CFGetAllocator(locale), type, locale->_identifier);
195 }
196
197 static void __CFLocaleDeallocate(CFTypeRef cf) {
198 CFLocaleRef locale = (CFLocaleRef)cf;
199 CFRelease(locale->_identifier);
200 if (NULL != locale->_cache) CFRelease(locale->_cache);
201 if (NULL != locale->_overrides) CFRelease(locale->_overrides);
202 if (NULL != locale->_prefs) CFRelease(locale->_prefs);
203 }
204
205 static CFTypeID __kCFLocaleTypeID = _kCFRuntimeNotATypeID;
206
207 static const CFRuntimeClass __CFLocaleClass = {
208 0,
209 "CFLocale",
210 NULL, // init
211 NULL, // copy
212 __CFLocaleDeallocate,
213 __CFLocaleEqual,
214 __CFLocaleHash,
215 NULL, //
216 __CFLocaleCopyDescription
217 };
218
219 static void __CFLocaleInitialize(void) {
220 CFIndex idx;
221 __kCFLocaleTypeID = _CFRuntimeRegisterClass(&__CFLocaleClass);
222 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
223 // table fixup to workaround compiler/language limitations
224 __CFLocaleKeyTable[idx].key = *((CFStringRef *)__CFLocaleKeyTable[idx].key);
225 if (NULL != __CFLocaleKeyTable[idx].context) {
226 __CFLocaleKeyTable[idx].context = *((CFStringRef *)__CFLocaleKeyTable[idx].context);
227 }
228 }
229 }
230
231 CFTypeID CFLocaleGetTypeID(void) {
232 if (_kCFRuntimeNotATypeID == __kCFLocaleTypeID) __CFLocaleInitialize();
233 return __kCFLocaleTypeID;
234 }
235
236 CFLocaleRef CFLocaleGetSystem(void) {
237 CFLocaleRef locale;
238 __CFLocaleLockGlobal();
239 if (NULL == __CFLocaleSystem) {
240 __CFLocaleUnlockGlobal();
241 locale = CFLocaleCreate(kCFAllocatorSystemDefault, CFSTR(""));
242 if (!locale) return NULL;
243 __CFLocaleSetType(locale, __kCFLocaleSystem);
244 __CFLocaleLockGlobal();
245 if (NULL == __CFLocaleSystem) {
246 __CFLocaleSystem = locale;
247 } else {
248 if (locale) CFRelease(locale);
249 }
250 }
251 locale = __CFLocaleSystem ? (CFLocaleRef)CFRetain(__CFLocaleSystem) : NULL;
252 __CFLocaleUnlockGlobal();
253 return locale;
254 }
255
256 static CFLocaleRef __CFLocaleCurrent = NULL;
257
258 #if DEPLOYMENT_TARGET_MACOSX
259 #define FALLBACK_LOCALE_NAME CFSTR("")
260 #endif
261
262 CFLocaleRef CFLocaleCopyCurrent(void) {
263
264 __CFLocaleLockGlobal();
265 if (__CFLocaleCurrent) {
266 CFRetain(__CFLocaleCurrent);
267 __CFLocaleUnlockGlobal();
268 return __CFLocaleCurrent;
269 }
270 __CFLocaleUnlockGlobal();
271
272 CFDictionaryRef prefs = NULL;
273 CFStringRef identifier = NULL;
274
275 struct __CFLocale *locale;
276 uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase);
277 locale = (struct __CFLocale *)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFLocaleGetTypeID(), size, NULL);
278 if (NULL == locale) {
279 return NULL;
280 }
281 __CFLocaleSetType(locale, __kCFLocaleUser);
282 if (NULL == identifier) identifier = CFRetain(FALLBACK_LOCALE_NAME);
283 locale->_identifier = identifier;
284 locale->_cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
285 locale->_overrides = NULL;
286 locale->_prefs = prefs;
287 locale->_lock = CFSpinLockInit;
288
289 __CFLocaleLockGlobal();
290 if (NULL == __CFLocaleCurrent) {
291 __CFLocaleCurrent = locale;
292 } else {
293 CFRelease(locale);
294 }
295 locale = (struct __CFLocale *)CFRetain(__CFLocaleCurrent);
296 __CFLocaleUnlockGlobal();
297 return locale;
298 }
299
300 __private_extern__ CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) {
301 return locale->_prefs;
302 }
303
304 CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef identifier) {
305 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
306 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
307 __CFGenericValidateType(identifier, CFStringGetTypeID());
308 CFStringRef localeIdentifier = NULL;
309 if (identifier) {
310 localeIdentifier = CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator, identifier);
311 }
312 if (NULL == localeIdentifier) return NULL;
313 CFStringRef old = localeIdentifier;
314 localeIdentifier = (CFStringRef)CFStringCreateCopy(allocator, localeIdentifier);
315 CFRelease(old);
316 __CFLocaleLockGlobal();
317 // Look for cases where we can return a cached instance.
318 // We only use cached objects if the allocator is the system
319 // default allocator.
320 if (!allocator) allocator = __CFGetDefaultAllocator();
321 Boolean canCache = (kCFAllocatorSystemDefault == allocator);
322 if (canCache && __CFLocaleCache) {
323 CFLocaleRef locale = (CFLocaleRef)CFDictionaryGetValue(__CFLocaleCache, localeIdentifier);
324 if (locale) {
325 CFRetain(locale);
326 __CFLocaleUnlockGlobal();
327 CFRelease(localeIdentifier);
328 return locale;
329 }
330 }
331 struct __CFLocale *locale = NULL;
332 uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase);
333 locale = (struct __CFLocale *)_CFRuntimeCreateInstance(allocator, CFLocaleGetTypeID(), size, NULL);
334 if (NULL == locale) {
335 return NULL;
336 }
337 __CFLocaleSetType(locale, __kCFLocaleOrdinary);
338 locale->_identifier = localeIdentifier;
339 locale->_cache = CFDictionaryCreateMutable(allocator, 0, NULL, &kCFTypeDictionaryValueCallBacks);
340 locale->_overrides = NULL;
341 locale->_prefs = NULL;
342 locale->_lock = CFSpinLockInit;
343 if (canCache) {
344 if (NULL == __CFLocaleCache) {
345 __CFLocaleCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
346 }
347 CFDictionarySetValue(__CFLocaleCache, localeIdentifier, locale);
348 }
349 __CFLocaleUnlockGlobal();
350 return (CFLocaleRef)locale;
351 }
352
353 CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) {
354 return (CFLocaleRef)CFRetain(locale);
355 }
356
357 CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) {
358 CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFStringRef, locale, "localeIdentifier");
359 return locale->_identifier;
360 }
361
362 CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) {
363 CF_OBJC_FUNCDISPATCH1(CFLocaleGetTypeID(), CFTypeRef, locale, "objectForKey:", key);
364 CFIndex idx, slot = -1;
365 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
366 if (__CFLocaleKeyTable[idx].key == key) {
367 slot = idx;
368 break;
369 }
370 }
371 if (-1 == slot && NULL != key) {
372 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
373 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) {
374 slot = idx;
375 break;
376 }
377 }
378 }
379 if (-1 == slot) {
380 return NULL;
381 }
382 CFTypeRef value;
383 if (NULL != locale->_overrides && CFDictionaryGetValueIfPresent(locale->_overrides, __CFLocaleKeyTable[slot].key, &value)) {
384 return value;
385 }
386 __CFLocaleLock(locale);
387 if (CFDictionaryGetValueIfPresent(locale->_cache, __CFLocaleKeyTable[slot].key, &value)) {
388 __CFLocaleUnlock(locale);
389 return value;
390 }
391 if (__kCFLocaleUser == __CFLocaleGetType(locale) && __CFLocaleKeyTable[slot].get(locale, true, &value, __CFLocaleKeyTable[slot].context)) {
392 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value);
393 if (value) CFRelease(value);
394 __CFLocaleUnlock(locale);
395 return value;
396 }
397 if (__CFLocaleKeyTable[slot].get(locale, false, &value, __CFLocaleKeyTable[slot].context)) {
398 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value);
399 if (value) CFRelease(value);
400 __CFLocaleUnlock(locale);
401 return value;
402 }
403 __CFLocaleUnlock(locale);
404 return NULL;
405 }
406
407 CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) {
408 CF_OBJC_FUNCDISPATCH2(CFLocaleGetTypeID(), CFStringRef, displayLocale, "_copyDisplayNameForKey:value:", key, value);
409 CFIndex idx, slot = -1;
410 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
411 if (__CFLocaleKeyTable[idx].key == key) {
412 slot = idx;
413 break;
414 }
415 }
416 if (-1 == slot && NULL != key) {
417 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
418 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) {
419 slot = idx;
420 break;
421 }
422 }
423 }
424 if (-1 == slot || !value) {
425 return NULL;
426 }
427 // Get the locale ID as a C string
428 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
429 char cValue[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
430 if (CFStringGetCString(displayLocale->_identifier, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII) && CFStringGetCString(value, cValue, sizeof(cValue)/sizeof(char), kCFStringEncodingASCII)) {
431 CFStringRef result;
432 if ((NULL == displayLocale->_prefs) && __CFLocaleKeyTable[slot].name(localeID, cValue, &result)) {
433 return result;
434 }
435
436 // We could not find a result using the requested language. Fall back through all preferred languages.
437 CFArrayRef langPref;
438 if (displayLocale->_prefs) {
439 langPref = (CFArrayRef)CFDictionaryGetValue(displayLocale->_prefs, CFSTR("AppleLanguages"));
440 if (langPref) CFRetain(langPref);
441 } else {
442 langPref = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication);
443 }
444 if (langPref != NULL) {
445 CFIndex count = CFArrayGetCount(langPref);
446 CFIndex i;
447 bool success = false;
448 for (i = 0; i < count && !success; ++i) {
449 CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(langPref, i);
450 CFStringRef cleanLanguage = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, language);
451 if (CFStringGetCString(cleanLanguage, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII)) {
452 success = __CFLocaleKeyTable[slot].name(localeID, cValue, &result);
453 }
454 CFRelease(cleanLanguage);
455 }
456 CFRelease(langPref);
457 if (success)
458 return result;
459 }
460 }
461 return NULL;
462 }
463
464 CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) {
465 int32_t locale, localeCount = uloc_countAvailable();
466 CFMutableSetRef working = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
467 for (locale = 0; locale < localeCount; ++locale) {
468 const char *localeID = uloc_getAvailable(locale);
469 CFStringRef string1 = CFStringCreateWithCString(kCFAllocatorSystemDefault, localeID, kCFStringEncodingASCII);
470 CFStringRef string2 = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, string1);
471 CFSetAddValue(working, string1);
472 // do not include canonicalized version as IntlFormats cannot cope with that in its popup
473 CFRelease(string1);
474 CFRelease(string2);
475 }
476 CFIndex cnt = CFSetGetCount(working);
477 STACK_BUFFER_DECL(const void *, buffer, cnt);
478 CFSetGetValues(working, buffer);
479 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, buffer, cnt, &kCFTypeArrayCallBacks);
480 CFRelease(working);
481 return result;
482 }
483
484 static CFArrayRef __CFLocaleCopyCStringsAsArray(const char* const* p) {
485 CFMutableArrayRef working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
486 for (; *p; ++p) {
487 CFStringRef string = CFStringCreateWithCString(kCFAllocatorSystemDefault, *p, kCFStringEncodingASCII);
488 CFArrayAppendValue(working, string);
489 CFRelease(string);
490 }
491 CFArrayRef result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working);
492 CFRelease(working);
493 return result;
494 }
495
496 static CFArrayRef __CFLocaleCopyUEnumerationAsArray(UEnumeration *enumer, UErrorCode *icuErr) {
497 const UChar *next = NULL;
498 int32_t len = 0;
499 CFMutableArrayRef working = NULL;
500 if (U_SUCCESS(*icuErr)) {
501 working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
502 }
503 while ((next = uenum_unext(enumer, &len, icuErr)) && U_SUCCESS(*icuErr)) {
504 CFStringRef string = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)next, (CFIndex) len);
505 CFArrayAppendValue(working, string);
506 CFRelease(string);
507 }
508 if (*icuErr == U_INDEX_OUTOFBOUNDS_ERROR) {
509 *icuErr = U_ZERO_ERROR; // Temp: Work around bug (ICU 5220) in ucurr enumerator
510 }
511 CFArrayRef result = NULL;
512 if (U_SUCCESS(*icuErr)) {
513 result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working);
514 }
515 if (working != NULL) {
516 CFRelease(working);
517 }
518 return result;
519 }
520
521 CFArrayRef CFLocaleCopyISOLanguageCodes(void) {
522 const char* const* p = uloc_getISOLanguages();
523 return __CFLocaleCopyCStringsAsArray(p);
524 }
525
526 CFArrayRef CFLocaleCopyISOCountryCodes(void) {
527 const char* const* p = uloc_getISOCountries();
528 return __CFLocaleCopyCStringsAsArray(p);
529 }
530
531 CFArrayRef CFLocaleCopyISOCurrencyCodes(void) {
532 UErrorCode icuStatus = U_ZERO_ERROR;
533 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_ALL, &icuStatus);
534 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus);
535 uenum_close(enumer);
536 return result;
537 }
538
539 CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) {
540 UErrorCode icuStatus = U_ZERO_ERROR;
541 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &icuStatus);
542 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus);
543 uenum_close(enumer);
544 return result;
545 }
546
547 CFArrayRef CFLocaleCopyPreferredLanguages(void) {
548 CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
549 CFArrayRef languagesArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication);
550 if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) {
551 for (CFIndex idx = 0, cnt = CFArrayGetCount(languagesArray); idx < cnt; idx++) {
552 CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, idx);
553 if (str && (CFStringGetTypeID() == CFGetTypeID(str))) {
554 CFStringRef ident = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str);
555 CFArrayAppendValue(newArray, ident);
556 CFRelease(ident);
557 }
558 }
559 }
560 if (languagesArray) CFRelease(languagesArray);
561 return newArray;
562 }
563
564 // -------- -------- -------- -------- -------- --------
565
566 // These functions return true or false depending on the success or failure of the function.
567 // In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is
568 // returned by reference WITH a retain on it.
569 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context) {
570 return false;
571 }
572
573 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
574 *cf = CFRetain(locale->_identifier);
575 return true;
576 }
577
578
579 static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
580 CFDictionaryRef codes = NULL;
581 // this access of _cache is protected by the lock in CFLocaleGetValue()
582 if (!CFDictionaryGetValueIfPresent(locale->_cache, CFSTR("__kCFLocaleCodes"), (const void **)&codes)) {
583 codes = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, locale->_identifier);
584 if (codes) CFDictionarySetValue(locale->_cache, CFSTR("__kCFLocaleCodes"), codes);
585 if (codes) CFRelease(codes);
586 }
587 if (codes) {
588 CFStringRef value = (CFStringRef)CFDictionaryGetValue(codes, context); // context is one of kCFLocale*Code constants
589 if (value) CFRetain(value);
590 *cf = value;
591 return true;
592 }
593 return false;
594 }
595
596 CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) {
597 UErrorCode icuErr = U_ZERO_ERROR;
598 CFMutableCharacterSetRef working = CFCharacterSetCreateMutable(NULL);
599 UChar buffer[2048]; // Suitable for most small sets
600 int32_t stringLen;
601
602 if (working == NULL)
603 return NULL;
604
605 int32_t itemCount = uset_getItemCount(set);
606 int32_t i;
607 for (i = 0; i < itemCount; ++i)
608 {
609 UChar32 start, end;
610 UChar * string;
611
612 string = buffer;
613 stringLen = uset_getItem(set, i, &start, &end, buffer, sizeof(buffer)/sizeof(UChar), &icuErr);
614 if (icuErr == U_BUFFER_OVERFLOW_ERROR)
615 {
616 string = (UChar *) malloc(sizeof(UChar)*(stringLen+1));
617 if (!string)
618 {
619 CFRelease(working);
620 return NULL;
621 }
622 icuErr = U_ZERO_ERROR;
623 (void) uset_getItem(set, i, &start, &end, string, stringLen+1, &icuErr);
624 }
625 if (U_FAILURE(icuErr))
626 {
627 if (string != buffer)
628 free(string);
629 CFRelease(working);
630 return NULL;
631 }
632 if (stringLen <= 0)
633 CFCharacterSetAddCharactersInRange(working, CFRangeMake(start, end-start+1));
634 else
635 {
636 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, (UniChar *)string, stringLen, kCFAllocatorNull);
637 CFCharacterSetAddCharactersInString(working, cfString);
638 CFRelease(cfString);
639 }
640 if (string != buffer)
641 free(string);
642 }
643
644 CFCharacterSetRef result = CFCharacterSetCreateCopy(kCFAllocatorSystemDefault, working);
645 CFRelease(working);
646 return result;
647 }
648
649
650 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
651 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
652 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) {
653 UErrorCode icuStatus = U_ZERO_ERROR;
654 ULocaleData* uld = ulocdata_open(localeID, &icuStatus);
655 USet *set = ulocdata_getExemplarSet(uld, NULL, USET_ADD_CASE_MAPPINGS, ULOCDATA_ES_STANDARD, &icuStatus);
656 ulocdata_close(uld);
657 if (U_FAILURE(icuStatus))
658 return false;
659 if (icuStatus == U_USING_DEFAULT_WARNING) // If default locale used, force to empty set
660 uset_clear(set);
661 *cf = (CFTypeRef) _CFCreateCharacterSetFromUSet(set);
662 uset_close(set);
663 return (*cf != NULL);
664 }
665 return false;
666 }
667
668 static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword)
669 {
670 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
671 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII))
672 {
673 char value[ULOC_KEYWORD_AND_VALUES_CAPACITY];
674 UErrorCode icuStatus = U_ZERO_ERROR;
675 if (uloc_getKeywordValue(localeID, keyword, value, sizeof(value)/sizeof(char), &icuStatus) > 0 && U_SUCCESS(icuStatus))
676 {
677 *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII);
678 return true;
679 }
680 }
681 *cf = NULL;
682 return false;
683 }
684
685 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
686 bool succeeded = __CFLocaleCopyICUKeyword(locale, user, cf, context, kCalendarKeyword);
687 if (succeeded) {
688 if (CFEqual(*cf, kCFGregorianCalendar)) {
689 CFRelease(*cf);
690 *cf = CFRetain(kCFGregorianCalendar);
691 } else if (CFEqual(*cf, kCFBuddhistCalendar)) {
692 CFRelease(*cf);
693 *cf = CFRetain(kCFBuddhistCalendar);
694 } else if (CFEqual(*cf, kCFJapaneseCalendar)) {
695 CFRelease(*cf);
696 *cf = CFRetain(kCFJapaneseCalendar);
697 } else if (CFEqual(*cf, kCFIslamicCalendar)) {
698 CFRelease(*cf);
699 *cf = CFRetain(kCFIslamicCalendar);
700 } else if (CFEqual(*cf, kCFIslamicCivilCalendar)) {
701 CFRelease(*cf);
702 *cf = CFRetain(kCFIslamicCivilCalendar);
703 } else if (CFEqual(*cf, kCFHebrewCalendar)) {
704 CFRelease(*cf);
705 *cf = CFRetain(kCFHebrewCalendar);
706 } else if (CFEqual(*cf, kCFChineseCalendar)) {
707 CFRelease(*cf);
708 *cf = CFRetain(kCFChineseCalendar);
709 }
710 } else {
711 *cf = CFRetain(kCFGregorianCalendar);
712 }
713 return true;
714 }
715
716 static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
717 if (__CFLocaleCopyCalendarID(locale, user, cf, context)) {
718 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)*cf);
719 CFCalendarSetLocale(calendar, locale);
720 CFRelease(*cf);
721 *cf = calendar;
722 return true;
723 }
724 return false;
725 }
726
727 static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
728 return __CFLocaleCopyICUKeyword(locale, user, cf, context, kCollationKeyword);
729 }
730
731 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
732 CFStringRef canonLocaleCFStr = NULL;
733 if (!canonLocaleCFStr) {
734 canonLocaleCFStr = CFLocaleGetIdentifier(locale);
735 CFRetain(canonLocaleCFStr);
736 }
737 *cf = canonLocaleCFStr;
738 return canonLocaleCFStr ? true : false;
739 }
740
741 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
742 bool us = false; // Default is Metric
743 bool done = false;
744
745 if (!done) {
746 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
747 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) {
748 UErrorCode icuStatus = U_ZERO_ERROR;
749 UMeasurementSystem ms = UMS_SI;
750 ms = ulocdata_getMeasurementSystem(localeID, &icuStatus);
751 if (U_SUCCESS(icuStatus)) {
752 us = (ms == UMS_US);
753 done = true;
754 }
755 }
756 }
757 if (!done)
758 us = false;
759 *cf = us ? CFRetain(kCFBooleanFalse) : CFRetain(kCFBooleanTrue);
760 return true;
761 }
762
763 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
764 if (__CFLocaleCopyUsesMetric(locale, user, cf, context)) {
765 bool us = (*cf == kCFBooleanFalse);
766 CFRelease(*cf);
767 *cf = us ? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric"));
768 return true;
769 }
770 return false;
771 }
772
773 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
774 CFStringRef str = NULL;
775 #if DEPLOYMENT_TARGET_MACOSX
776 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle);
777 str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL;
778 if (nf) CFRelease(nf);
779 #endif
780 if (str) {
781 *cf = str;
782 return true;
783 }
784 return false;
785 }
786
787 // ICU does not reliably set up currency info for other than Currency-type formatters,
788 // so we have to have another routine here which creates a Currency number formatter.
789 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
790 CFStringRef str = NULL;
791 #if DEPLOYMENT_TARGET_MACOSX
792 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle);
793 str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL;
794 if (nf) CFRelease(nf);
795 #endif
796 if (str) {
797 *cf = str;
798 return true;
799 }
800 return false;
801 }
802
803 typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *);
804
805 static bool __CFLocaleICUName(const char *locale, const char *valLocale, CFStringRef *out, __CFICUFunction icu) {
806 UErrorCode icuStatus = U_ZERO_ERROR;
807 int32_t size;
808 UChar name[kMaxICUNameSize];
809
810 size = (*icu)(valLocale, locale, name, kMaxICUNameSize, &icuStatus);
811 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) {
812 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
813 return (*out != NULL);
814 }
815 return false;
816 }
817
818 static bool __CFLocaleICUKeywordValueName(const char *locale, const char *value, const char *keyword, CFStringRef *out) {
819 UErrorCode icuStatus = U_ZERO_ERROR;
820 int32_t size = 0;
821 UChar name[kMaxICUNameSize];
822 // Need to make a fake locale ID
823 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
824 if (strlen(value) < ULOC_KEYWORD_AND_VALUES_CAPACITY) {
825 snprintf(lid, sizeof(lid), "en_US@%s=%s", keyword, value);
826 size = uloc_getDisplayKeywordValue(lid, keyword, locale, name, kMaxICUNameSize, &icuStatus);
827 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) {
828 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
829 return (*out != NULL);
830 }
831 }
832 return false;
833 }
834
835 static bool __CFLocaleICUCurrencyName(const char *locale, const char *value, UCurrNameStyle style, CFStringRef *out) {
836 int valLen = strlen(value);
837 if (valLen != 3) // not a valid ISO code
838 return false;
839 UChar curr[4];
840 UBool isChoice = FALSE;
841 int32_t size = 0;
842 UErrorCode icuStatus = U_ZERO_ERROR;
843 u_charsToUChars(value, curr, valLen);
844 curr[valLen] = '\0';
845 const UChar *name;
846 name = ucurr_getName(curr, locale, style, &isChoice, &size, &icuStatus);
847 if (U_FAILURE(icuStatus) || icuStatus == U_USING_DEFAULT_WARNING)
848 return false;
849 UChar result[kMaxICUNameSize];
850 if (isChoice)
851 {
852 UChar pattern[kMaxICUNameSize];
853 CFStringRef patternRef = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{0,choice,%S}"), name);
854 CFIndex pattlen = CFStringGetLength(patternRef);
855 CFStringGetCharacters(patternRef, CFRangeMake(0, pattlen), (UniChar *)pattern);
856 CFRelease(patternRef);
857 pattern[pattlen] = '\0'; // null terminate the pattern
858 // Format the message assuming a large amount of the currency
859 size = u_formatMessage("en_US", pattern, pattlen, result, kMaxICUNameSize, &icuStatus, 10.0);
860 if (U_FAILURE(icuStatus))
861 return false;
862 name = result;
863
864 }
865 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
866 return (*out != NULL);
867 }
868
869 static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out) {
870 UErrorCode icuStatus = U_ZERO_ERROR;
871 int32_t size;
872 UChar name[kMaxICUNameSize];
873
874 // First, try to get the full locale.
875 size = uloc_getDisplayName(value, locale, name, kMaxICUNameSize, &icuStatus);
876 if (U_FAILURE(icuStatus) || size <= 0)
877 return false;
878
879 // Did we wind up using a default somewhere?
880 if (icuStatus == U_USING_DEFAULT_WARNING) {
881 // For some locale IDs, there may be no language which has a translation for every
882 // piece. Rather than return nothing, see if we can at least handle
883 // the language part of the locale.
884 UErrorCode localStatus = U_ZERO_ERROR;
885 int32_t localSize;
886 UChar localName[kMaxICUNameSize];
887 localSize = uloc_getDisplayLanguage(value, locale, localName, kMaxICUNameSize, &localStatus);
888 if (U_FAILURE(localStatus) || size <= 0 || localStatus == U_USING_DEFAULT_WARNING)
889 return false;
890 }
891
892 // This locale is OK, so use the result.
893 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
894 return (*out != NULL);
895 }
896
897 static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out) {
898 int len = strlen(value);
899 if (len >= 2 && len <= 3)
900 return __CFLocaleICUName(locale, value, out, uloc_getDisplayLanguage);
901 return false;
902 }
903
904 static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out) {
905 // Need to make a fake locale ID
906 char lid[ULOC_FULLNAME_CAPACITY];
907 if (strlen(value) == 2) {
908 snprintf(lid, sizeof(lid), "en_%s", value);
909 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayCountry);
910 }
911 return false;
912 }
913
914 static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out) {
915 // Need to make a fake locale ID
916 char lid[ULOC_FULLNAME_CAPACITY];
917 if (strlen(value) == 4) {
918 snprintf(lid, sizeof(lid), "en_%s_US", value);
919 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayScript);
920 }
921 return false;
922 }
923
924 static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out) {
925 // Need to make a fake locale ID
926 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
927 if (strlen(value) < ULOC_FULLNAME_CAPACITY) {
928 snprintf(lid, sizeof(lid), "en_US_%s", value);
929 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayVariant);
930 }
931 return false;
932 }
933
934 static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out) {
935 return __CFLocaleICUKeywordValueName(locale, value, kCalendarKeyword, out);
936 }
937
938 static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out) {
939 return __CFLocaleICUKeywordValueName(locale, value, kCollationKeyword, out);
940 }
941
942 static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out) {
943 return __CFLocaleICUCurrencyName(locale, value, UCURR_SYMBOL_NAME, out);
944 }
945
946 static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out) {
947 return __CFLocaleICUCurrencyName(locale, value, UCURR_LONG_NAME, out);
948 }
949
950 static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) {
951 return false;
952 }
953
954 // Remember to keep the names such that they would make sense for the user locale,
955 // in addition to the others; for example, it is "Currency", not "DefaultCurrency".
956 // (And besides, "Default" is almost always implied.) Words like "Default" and
957 // "Preferred" and so on should be left out of the names.
958 CONST_STRING_DECL(kCFLocaleIdentifier, "locale:id")
959 CONST_STRING_DECL(kCFLocaleLanguageCode, "locale:language code")
960 CONST_STRING_DECL(kCFLocaleCountryCode, "locale:country code")
961 CONST_STRING_DECL(kCFLocaleScriptCode, "locale:script code")
962 CONST_STRING_DECL(kCFLocaleVariantCode, "locale:variant code")
963 CONST_STRING_DECL(kCFLocaleExemplarCharacterSet, "locale:exemplar characters")
964 CONST_STRING_DECL(kCFLocaleCalendarIdentifier, "calendar")
965 CONST_STRING_DECL(kCFLocaleCalendar, "locale:calendarref")
966 CONST_STRING_DECL(kCFLocaleCollationIdentifier, "collation")
967 CONST_STRING_DECL(kCFLocaleUsesMetricSystem, "locale:uses metric")
968 CONST_STRING_DECL(kCFLocaleMeasurementSystem, "locale:measurement system")
969 CONST_STRING_DECL(kCFLocaleDecimalSeparator, "locale:decimal separator")
970 CONST_STRING_DECL(kCFLocaleGroupingSeparator, "locale:grouping separator")
971 CONST_STRING_DECL(kCFLocaleCurrencySymbol, "locale:currency symbol")
972 CONST_STRING_DECL(kCFLocaleCurrencyCode, "currency")
973
974 CONST_STRING_DECL(kCFGregorianCalendar, "gregorian")
975 CONST_STRING_DECL(kCFBuddhistCalendar, "buddhist")
976 CONST_STRING_DECL(kCFJapaneseCalendar, "japanese")
977 CONST_STRING_DECL(kCFIslamicCalendar, "islamic")
978 CONST_STRING_DECL(kCFIslamicCivilCalendar, "islamic-civil")
979 CONST_STRING_DECL(kCFHebrewCalendar, "hebrew")
980 CONST_STRING_DECL(kCFChineseCalendar, "chinese")
981
982 #undef kMaxICUNameSize
983