2 *******************************************************************************
3 * Copyright (C) 1996-2014, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
6 * file name: ucol_res.cpp
8 * tab size: 8 (not used)
12 * This file contains dependencies that the collation run-time doesn't normally
13 * need. This mainly contains resource bundle usage and collation meta information
15 * Modification history
17 * 1996-1999 various members of ICU team maintained C API for collation framework
18 * 02/16/2001 synwee Added internal method getPrevSpecialCE
19 * 03/01/2001 synwee Added maxexpansion functionality.
20 * 03/16/2001 weiv Collation framework is rewritten in C and made UCA compliant
21 * 12/08/2004 grhoten Split part of ucol.cpp into ucol_res.cpp
22 * 2012-2014 markus Rewritten in C++ again.
25 #include "unicode/utypes.h"
27 #if !UCONFIG_NO_COLLATION
29 #include "unicode/coll.h"
30 #include "unicode/localpointer.h"
31 #include "unicode/locid.h"
32 #include "unicode/tblcoll.h"
33 #include "unicode/ucol.h"
34 #include "unicode/uloc.h"
35 #include "unicode/unistr.h"
36 #include "unicode/ures.h"
39 #include "collationdatareader.h"
40 #include "collationroot.h"
41 #include "collationtailoring.h"
49 #include "unifiedcache.h"
58 static const UChar
*rootRules
= NULL
;
59 static int32_t rootRulesLength
= 0;
60 static UResourceBundle
*rootBundle
= NULL
;
61 static UInitOnce gInitOnce
= U_INITONCE_INITIALIZER
;
67 static UBool U_CALLCONV
71 ures_close(rootBundle
);
80 CollationLoader::loadRootRules(UErrorCode
&errorCode
) {
81 if(U_FAILURE(errorCode
)) { return; }
82 rootBundle
= ures_open(U_ICUDATA_COLL
, kRootLocaleName
, &errorCode
);
83 if(U_FAILURE(errorCode
)) { return; }
84 rootRules
= ures_getStringByKey(rootBundle
, "UCARules", &rootRulesLength
, &errorCode
);
85 if(U_FAILURE(errorCode
)) {
86 ures_close(rootBundle
);
90 ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES
, ucol_res_cleanup
);
94 CollationLoader::appendRootRules(UnicodeString
&s
) {
95 UErrorCode errorCode
= U_ZERO_ERROR
;
96 umtx_initOnce(gInitOnce
, CollationLoader::loadRootRules
, errorCode
);
97 if(U_SUCCESS(errorCode
)) {
98 s
.append(rootRules
, rootRulesLength
);
103 CollationLoader::loadRules(const char *localeID
, const char *collationType
,
104 UnicodeString
&rules
, UErrorCode
&errorCode
) {
105 if(U_FAILURE(errorCode
)) { return; }
106 U_ASSERT(collationType
!= NULL
&& *collationType
!= 0);
107 // Copy the type for lowercasing.
109 int32_t typeLength
= uprv_strlen(collationType
);
110 if(typeLength
>= UPRV_LENGTHOF(type
)) {
111 errorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
114 uprv_memcpy(type
, collationType
, typeLength
+ 1);
115 T_CString_toLowerCase(type
);
117 LocalUResourceBundlePointer
bundle(ures_open(U_ICUDATA_COLL
, localeID
, &errorCode
));
118 LocalUResourceBundlePointer
collations(
119 ures_getByKey(bundle
.getAlias(), "collations", NULL
, &errorCode
));
120 LocalUResourceBundlePointer
data(
121 ures_getByKeyWithFallback(collations
.getAlias(), type
, NULL
, &errorCode
));
123 const UChar
*s
= ures_getStringByKey(data
.getAlias(), "Sequence", &length
, &errorCode
);
124 if(U_FAILURE(errorCode
)) { return; }
126 // No string pointer aliasing so that we need not hold onto the resource bundle.
127 rules
.setTo(s
, length
);
128 if(rules
.isBogus()) {
129 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
133 template<> U_I18N_API
134 const CollationCacheEntry
*
135 LocaleCacheKey
<CollationCacheEntry
>::createObject(const void *creationContext
,
136 UErrorCode
&errorCode
) const {
137 CollationLoader
*loader
=
138 reinterpret_cast<CollationLoader
*>(
139 const_cast<void *>(creationContext
));
140 return loader
->createCacheEntry(errorCode
);
143 const CollationCacheEntry
*
144 CollationLoader::loadTailoring(const Locale
&locale
, UErrorCode
&errorCode
) {
145 const CollationCacheEntry
*rootEntry
= CollationRoot::getRootCacheEntry(errorCode
);
146 if(U_FAILURE(errorCode
)) { return NULL
; }
147 const char *name
= locale
.getName();
148 if(*name
== 0 || uprv_strcmp(name
, "root") == 0) {
150 // Have to add a ref.
155 // Clear warning codes before loading where they get cached.
156 errorCode
= U_ZERO_ERROR
;
157 CollationLoader
loader(rootEntry
, locale
, errorCode
);
159 // getCacheEntry adds a ref for us.
160 return loader
.getCacheEntry(errorCode
);
163 CollationLoader::CollationLoader(const CollationCacheEntry
*re
, const Locale
&requested
,
164 UErrorCode
&errorCode
)
165 : cache(UnifiedCache::getInstance(errorCode
)), rootEntry(re
),
166 validLocale(re
->validLocale
), locale(requested
),
167 typesTried(0), typeFallback(FALSE
),
168 bundle(NULL
), collations(NULL
), data(NULL
) {
171 if(U_FAILURE(errorCode
)) { return; }
173 // Canonicalize the locale ID: Ignore all irrelevant keywords.
174 const char *baseName
= locale
.getBaseName();
175 if(uprv_strcmp(locale
.getName(), baseName
) != 0) {
176 locale
= Locale(baseName
);
178 // Fetch the collation type from the locale ID.
179 int32_t typeLength
= requested
.getKeywordValue("collation",
180 type
, UPRV_LENGTHOF(type
) - 1, errorCode
);
181 if(U_FAILURE(errorCode
)) {
182 errorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
185 type
[typeLength
] = 0; // in case of U_NOT_TERMINATED_WARNING
186 if(typeLength
== 0) {
187 // No collation type.
188 } else if(uprv_stricmp(type
, "default") == 0) {
189 // Ignore "default" (case-insensitive).
192 // Copy the collation type.
193 T_CString_toLowerCase(type
);
194 locale
.setKeywordValue("collation", type
, errorCode
);
199 CollationLoader::~CollationLoader() {
201 ures_close(collations
);
205 const CollationCacheEntry
*
206 CollationLoader::createCacheEntry(UErrorCode
&errorCode
) {
207 // This is a linear lookup and fallback flow turned into a state machine.
208 // Most local variables have been turned into instance fields.
209 // In a cache miss, cache.get() calls CacheKey::createObject(),
210 // which means that we progress via recursion.
211 // loadFromCollations() will recurse to itself as well for collation type fallback.
213 return loadFromLocale(errorCode
);
214 } else if(collations
== NULL
) {
215 return loadFromBundle(errorCode
);
216 } else if(data
== NULL
) {
217 return loadFromCollations(errorCode
);
219 return loadFromData(errorCode
);
223 const CollationCacheEntry
*
224 CollationLoader::loadFromLocale(UErrorCode
&errorCode
) {
225 if(U_FAILURE(errorCode
)) { return NULL
; }
226 U_ASSERT(bundle
== NULL
);
227 bundle
= ures_openNoDefault(U_ICUDATA_COLL
, locale
.getBaseName(), &errorCode
);
228 if(errorCode
== U_MISSING_RESOURCE_ERROR
) {
229 errorCode
= U_USING_DEFAULT_WARNING
;
231 // Have to add that ref that we promise.
235 Locale
requestedLocale(locale
);
236 const char *vLocale
= ures_getLocaleByType(bundle
, ULOC_ACTUAL_LOCALE
, &errorCode
);
237 if(U_FAILURE(errorCode
)) { return NULL
; }
238 locale
= validLocale
= Locale(vLocale
); // no type until loadFromCollations()
240 locale
.setKeywordValue("collation", type
, errorCode
);
242 if(locale
!= requestedLocale
) {
243 return getCacheEntry(errorCode
);
245 return loadFromBundle(errorCode
);
249 const CollationCacheEntry
*
250 CollationLoader::loadFromBundle(UErrorCode
&errorCode
) {
251 if(U_FAILURE(errorCode
)) { return NULL
; }
252 U_ASSERT(collations
== NULL
);
253 // There are zero or more tailorings in the collations table.
254 collations
= ures_getByKey(bundle
, "collations", NULL
, &errorCode
);
255 if(errorCode
== U_MISSING_RESOURCE_ERROR
) {
256 errorCode
= U_USING_DEFAULT_WARNING
;
257 // Return the root tailoring with the validLocale, without collation type.
258 return makeCacheEntryFromRoot(validLocale
, errorCode
);
260 if(U_FAILURE(errorCode
)) { return NULL
; }
262 // Fetch the default type from the data.
264 UErrorCode internalErrorCode
= U_ZERO_ERROR
;
265 LocalUResourceBundlePointer
def(
266 ures_getByKeyWithFallback(collations
, "default", NULL
, &internalErrorCode
));
268 const UChar
*s
= ures_getString(def
.getAlias(), &length
, &internalErrorCode
);
269 if(U_SUCCESS(internalErrorCode
) && 0 < length
&& length
< UPRV_LENGTHOF(defaultType
)) {
270 u_UCharsToChars(s
, defaultType
, length
+ 1);
272 uprv_strcpy(defaultType
, "standard");
276 // Record which collation types we have looked for already,
277 // so that we do not deadlock in the cache.
279 // If there is no explicit type, then we look in the cache
280 // for the entry with the default type.
281 // If the explicit type is the default type, then we do not look in the cache
282 // for the entry with an empty type.
283 // Otherwise, two concurrent requests with opposite fallbacks would deadlock each other.
284 // Also, it is easier to always enter the next method with a non-empty type.
286 uprv_strcpy(type
, defaultType
);
287 typesTried
|= TRIED_DEFAULT
;
288 if(uprv_strcmp(type
, "search") == 0) {
289 typesTried
|= TRIED_SEARCH
;
291 if(uprv_strcmp(type
, "standard") == 0) {
292 typesTried
|= TRIED_STANDARD
;
294 locale
.setKeywordValue("collation", type
, errorCode
);
295 return getCacheEntry(errorCode
);
297 if(uprv_strcmp(type
, defaultType
) == 0) {
298 typesTried
|= TRIED_DEFAULT
;
300 if(uprv_strcmp(type
, "search") == 0) {
301 typesTried
|= TRIED_SEARCH
;
303 if(uprv_strcmp(type
, "standard") == 0) {
304 typesTried
|= TRIED_STANDARD
;
306 return loadFromCollations(errorCode
);
310 const CollationCacheEntry
*
311 CollationLoader::loadFromCollations(UErrorCode
&errorCode
) {
312 if(U_FAILURE(errorCode
)) { return NULL
; }
313 U_ASSERT(data
== NULL
);
314 // Load the collations/type tailoring, with type fallback.
315 LocalUResourceBundlePointer
localData(
316 ures_getByKeyWithFallback(collations
, type
, NULL
, &errorCode
));
317 int32_t typeLength
= uprv_strlen(type
);
318 if(errorCode
== U_MISSING_RESOURCE_ERROR
) {
319 errorCode
= U_USING_DEFAULT_WARNING
;
321 if((typesTried
& TRIED_SEARCH
) == 0 &&
322 typeLength
> 6 && uprv_strncmp(type
, "search", 6) == 0) {
323 // fall back from something like "searchjl" to "search"
324 typesTried
|= TRIED_SEARCH
;
326 } else if((typesTried
& TRIED_DEFAULT
) == 0) {
327 // fall back to the default type
328 typesTried
|= TRIED_DEFAULT
;
329 uprv_strcpy(type
, defaultType
);
330 } else if((typesTried
& TRIED_STANDARD
) == 0) {
331 // fall back to the "standard" type
332 typesTried
|= TRIED_STANDARD
;
333 uprv_strcpy(type
, "standard");
335 // Return the root tailoring with the validLocale, without collation type.
336 return makeCacheEntryFromRoot(validLocale
, errorCode
);
338 locale
.setKeywordValue("collation", type
, errorCode
);
339 return getCacheEntry(errorCode
);
341 if(U_FAILURE(errorCode
)) { return NULL
; }
343 data
= localData
.orphan();
344 const char *actualLocale
= ures_getLocaleByType(data
, ULOC_ACTUAL_LOCALE
, &errorCode
);
345 if(U_FAILURE(errorCode
)) { return NULL
; }
346 const char *vLocale
= validLocale
.getBaseName();
347 UBool actualAndValidLocalesAreDifferent
= uprv_strcmp(actualLocale
, vLocale
) != 0;
349 // Set the collation types on the informational locales,
350 // except when they match the default types (for brevity and backwards compatibility).
351 // For the valid locale, suppress the default type.
352 if(uprv_strcmp(type
, defaultType
) != 0) {
353 validLocale
.setKeywordValue("collation", type
, errorCode
);
354 if(U_FAILURE(errorCode
)) { return NULL
; }
357 // Is this the same as the root collator? If so, then use that instead.
358 if((*actualLocale
== 0 || uprv_strcmp(actualLocale
, "root") == 0) &&
359 uprv_strcmp(type
, "standard") == 0) {
361 errorCode
= U_USING_DEFAULT_WARNING
;
363 return makeCacheEntryFromRoot(validLocale
, errorCode
);
366 locale
= Locale(actualLocale
);
367 if(actualAndValidLocalesAreDifferent
) {
368 locale
.setKeywordValue("collation", type
, errorCode
);
369 const CollationCacheEntry
*entry
= getCacheEntry(errorCode
);
370 return makeCacheEntry(validLocale
, entry
, errorCode
);
372 return loadFromData(errorCode
);
376 const CollationCacheEntry
*
377 CollationLoader::loadFromData(UErrorCode
&errorCode
) {
378 if(U_FAILURE(errorCode
)) { return NULL
; }
379 LocalPointer
<CollationTailoring
> t(new CollationTailoring(rootEntry
->tailoring
->settings
));
380 if(t
.isNull() || t
->isBogus()) {
381 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
386 LocalUResourceBundlePointer
binary(ures_getByKey(data
, "%%CollationBin", NULL
, &errorCode
));
387 // Note: U_MISSING_RESOURCE_ERROR --> The old code built from rules if available
388 // but that created undesirable dependencies.
390 const uint8_t *inBytes
= ures_getBinary(binary
.getAlias(), &length
, &errorCode
);
391 CollationDataReader::read(rootEntry
->tailoring
, inBytes
, length
, *t
, errorCode
);
392 // Note: U_COLLATOR_VERSION_MISMATCH --> The old code built from rules if available
393 // but that created undesirable dependencies.
394 if(U_FAILURE(errorCode
)) { return NULL
; }
396 // Try to fetch the optional rules string.
398 UErrorCode internalErrorCode
= U_ZERO_ERROR
;
400 const UChar
*s
= ures_getStringByKey(data
, "Sequence", &length
,
402 if(U_SUCCESS(internalErrorCode
)) {
403 t
->rules
.setTo(TRUE
, s
, length
);
407 const char *actualLocale
= locale
.getBaseName(); // without type
408 const char *vLocale
= validLocale
.getBaseName();
409 UBool actualAndValidLocalesAreDifferent
= uprv_strcmp(actualLocale
, vLocale
) != 0;
411 // For the actual locale, suppress the default type *according to the actual locale*.
412 // For example, zh has default=pinyin and contains all of the Chinese tailorings.
413 // zh_Hant has default=stroke but has no other data.
414 // For the valid locale "zh_Hant" we need to suppress stroke.
415 // For the actual locale "zh" we need to suppress pinyin instead.
416 if(actualAndValidLocalesAreDifferent
) {
417 // Opening a bundle for the actual locale should always succeed.
418 LocalUResourceBundlePointer
actualBundle(
419 ures_open(U_ICUDATA_COLL
, actualLocale
, &errorCode
));
420 if(U_FAILURE(errorCode
)) { return NULL
; }
421 UErrorCode internalErrorCode
= U_ZERO_ERROR
;
422 LocalUResourceBundlePointer
def(
423 ures_getByKeyWithFallback(actualBundle
.getAlias(), "collations/default", NULL
,
424 &internalErrorCode
));
426 const UChar
*s
= ures_getString(def
.getAlias(), &length
, &internalErrorCode
);
427 if(U_SUCCESS(internalErrorCode
) && length
< UPRV_LENGTHOF(defaultType
)) {
428 u_UCharsToChars(s
, defaultType
, length
+ 1);
430 uprv_strcpy(defaultType
, "standard");
433 t
->actualLocale
= locale
;
434 if(uprv_strcmp(type
, defaultType
) != 0) {
435 t
->actualLocale
.setKeywordValue("collation", type
, errorCode
);
436 } else if(uprv_strcmp(locale
.getName(), locale
.getBaseName()) != 0) {
437 // Remove the collation keyword if it was set.
438 t
->actualLocale
.setKeywordValue("collation", NULL
, errorCode
);
440 if(U_FAILURE(errorCode
)) { return NULL
; }
443 errorCode
= U_USING_DEFAULT_WARNING
;
447 const CollationCacheEntry
*entry
= new CollationCacheEntry(validLocale
, t
.getAlias());
449 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
453 // Have to add that reference that we promise.
458 const CollationCacheEntry
*
459 CollationLoader::getCacheEntry(UErrorCode
&errorCode
) {
460 LocaleCacheKey
<CollationCacheEntry
> key(locale
);
461 const CollationCacheEntry
*entry
= NULL
;
462 cache
->get(key
, this, entry
, errorCode
);
466 const CollationCacheEntry
*
467 CollationLoader::makeCacheEntryFromRoot(
468 const Locale
&/*loc*/,
469 UErrorCode
&errorCode
) const {
470 if (U_FAILURE(errorCode
)) {
474 return makeCacheEntry(validLocale
, rootEntry
, errorCode
);
477 const CollationCacheEntry
*
478 CollationLoader::makeCacheEntry(
480 const CollationCacheEntry
*entryFromCache
,
481 UErrorCode
&errorCode
) {
482 if(U_FAILURE(errorCode
) || loc
== entryFromCache
->validLocale
) {
483 return entryFromCache
;
485 CollationCacheEntry
*entry
= new CollationCacheEntry(loc
, entryFromCache
->tailoring
);
487 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
488 entryFromCache
->removeRef();
492 entryFromCache
->removeRef();
501 ucol_open(const char *loc
,
506 UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN
);
507 UTRACE_DATA1(UTRACE_INFO
, "locale = \"%s\"", loc
);
508 UCollator
*result
= NULL
;
510 Collator
*coll
= Collator::createInstance(loc
, *status
);
511 if(U_SUCCESS(*status
)) {
512 result
= coll
->toUCollator();
514 UTRACE_EXIT_PTR_STATUS(result
, *status
);
519 U_CAPI
int32_t U_EXPORT2
520 ucol_getDisplayName( const char *objLoc
,
523 int32_t resultLength
,
528 if(U_FAILURE(*status
)) return -1;
530 if(!(result
==NULL
&& resultLength
==0)) {
531 // NULL destination for pure preflighting: empty dummy string
532 // otherwise, alias the destination buffer
533 dst
.setTo(result
, 0, resultLength
);
535 Collator::getDisplayName(Locale(objLoc
), Locale(dispLoc
), dst
);
536 return dst
.extract(result
, resultLength
, *status
);
539 U_CAPI
const char* U_EXPORT2
540 ucol_getAvailable(int32_t index
)
543 const Locale
*loc
= Collator::getAvailableLocales(count
);
544 if (loc
!= NULL
&& index
< count
) {
545 return loc
[index
].getName();
550 U_CAPI
int32_t U_EXPORT2
551 ucol_countAvailable()
554 Collator::getAvailableLocales(count
);
558 #if !UCONFIG_NO_SERVICE
559 U_CAPI UEnumeration
* U_EXPORT2
560 ucol_openAvailableLocales(UErrorCode
*status
) {
563 // This is a wrapper over Collator::getAvailableLocales()
564 if (U_FAILURE(*status
)) {
567 StringEnumeration
*s
= icu::Collator::getAvailableLocales();
569 *status
= U_MEMORY_ALLOCATION_ERROR
;
572 return uenum_openFromStringEnumeration(s
, status
);
576 // Note: KEYWORDS[0] != RESOURCE_NAME - alan
578 static const char RESOURCE_NAME
[] = "collations";
580 static const char* const KEYWORDS
[] = { "collation" };
582 #define KEYWORD_COUNT UPRV_LENGTHOF(KEYWORDS)
584 U_CAPI UEnumeration
* U_EXPORT2
585 ucol_getKeywords(UErrorCode
*status
) {
586 UEnumeration
*result
= NULL
;
587 if (U_SUCCESS(*status
)) {
588 return uenum_openCharStringsEnumeration(KEYWORDS
, KEYWORD_COUNT
, status
);
593 U_CAPI UEnumeration
* U_EXPORT2
594 ucol_getKeywordValues(const char *keyword
, UErrorCode
*status
) {
595 if (U_FAILURE(*status
)) {
598 // hard-coded to accept exactly one collation keyword
599 // modify if additional collation keyword is added later
600 if (keyword
==NULL
|| uprv_strcmp(keyword
, KEYWORDS
[0])!=0)
602 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
605 return ures_getKeywordValues(U_ICUDATA_COLL
, RESOURCE_NAME
, status
);
608 static const UEnumeration defaultKeywordValues
= {
611 ulist_close_keyword_values_iterator
,
612 ulist_count_keyword_values
,
614 ulist_next_keyword_value
,
615 ulist_reset_keyword_values_iterator
620 U_CAPI UEnumeration
* U_EXPORT2
621 ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale
,
622 UBool
/*commonlyUsed*/, UErrorCode
* status
) {
623 /* Get the locale base name. */
624 char localeBuffer
[ULOC_FULLNAME_CAPACITY
] = "";
625 uloc_getBaseName(locale
, localeBuffer
, sizeof(localeBuffer
), status
);
627 /* Create the 2 lists
628 * -values is the temp location for the keyword values
629 * -results hold the actual list used by the UEnumeration object
631 UList
*values
= ulist_createEmptyList(status
);
632 UList
*results
= ulist_createEmptyList(status
);
633 UEnumeration
*en
= (UEnumeration
*)uprv_malloc(sizeof(UEnumeration
));
634 if (U_FAILURE(*status
) || en
== NULL
) {
636 *status
= U_MEMORY_ALLOCATION_ERROR
;
640 ulist_deleteList(values
);
641 ulist_deleteList(results
);
645 memcpy(en
, &defaultKeywordValues
, sizeof(UEnumeration
));
646 en
->context
= results
;
648 /* Open the resource bundle for collation with the given locale. */
649 UResourceBundle bundle
, collations
, collres
, defres
;
650 ures_initStackObject(&bundle
);
651 ures_initStackObject(&collations
);
652 ures_initStackObject(&collres
);
653 ures_initStackObject(&defres
);
655 ures_openFillIn(&bundle
, U_ICUDATA_COLL
, localeBuffer
, status
);
657 while (U_SUCCESS(*status
)) {
658 ures_getByKey(&bundle
, RESOURCE_NAME
, &collations
, status
);
659 ures_resetIterator(&collations
);
660 while (U_SUCCESS(*status
) && ures_hasNext(&collations
)) {
661 ures_getNextResource(&collations
, &collres
, status
);
662 const char *key
= ures_getKey(&collres
);
663 /* If the key is default, get the string and store it in results list only
664 * if results list is empty.
666 if (uprv_strcmp(key
, "default") == 0) {
667 if (ulist_getListSize(results
) == 0) {
668 char *defcoll
= (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY
);
669 int32_t defcollLength
= ULOC_KEYWORDS_CAPACITY
;
671 ures_getNextResource(&collres
, &defres
, status
);
672 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
673 /* optimize - use the utf-8 string */
674 ures_getUTF8String(&defres
, defcoll
, &defcollLength
, TRUE
, status
);
677 const UChar
* defString
= ures_getString(&defres
, &defcollLength
, status
);
678 if(U_SUCCESS(*status
)) {
679 if(defcollLength
+1 > ULOC_KEYWORDS_CAPACITY
) {
680 *status
= U_BUFFER_OVERFLOW_ERROR
;
682 u_UCharsToChars(defString
, defcoll
, defcollLength
+1);
688 ulist_addItemBeginList(results
, defcoll
, TRUE
, status
);
690 } else if (uprv_strncmp(key
, "private-", 8) != 0) {
691 ulist_addItemEndList(values
, key
, FALSE
, status
);
695 /* If the locale is "" this is root so exit. */
696 if (uprv_strlen(localeBuffer
) == 0) {
699 /* Get the parent locale and open a new resource bundle. */
700 uloc_getParent(localeBuffer
, localeBuffer
, sizeof(localeBuffer
), status
);
701 ures_openFillIn(&bundle
, U_ICUDATA_COLL
, localeBuffer
, status
);
705 ures_close(&collres
);
706 ures_close(&collations
);
709 if (U_SUCCESS(*status
)) {
711 ulist_resetList(values
);
712 while ((value
= (char *)ulist_getNext(values
)) != NULL
) {
713 if (!ulist_containsString(results
, value
, (int32_t)uprv_strlen(value
))) {
714 ulist_addItemEndList(results
, value
, FALSE
, status
);
715 if (U_FAILURE(*status
)) {
722 ulist_deleteList(values
);
724 if (U_FAILURE(*status
)){
728 ulist_resetList(results
);
734 U_CAPI
int32_t U_EXPORT2
735 ucol_getFunctionalEquivalent(char* result
, int32_t resultCapacity
,
736 const char* keyword
, const char* locale
,
737 UBool
* isAvailable
, UErrorCode
* status
)
739 // N.B.: Resource name is "collations" but keyword is "collation"
740 return ures_getFunctionalEquivalent(result
, resultCapacity
, U_ICUDATA_COLL
,
741 "collations", keyword
, locale
,
742 isAvailable
, TRUE
, status
);
745 #endif /* #if !UCONFIG_NO_COLLATION */