1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 1996-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: ucol_res.cpp
10 * tab size: 8 (not used)
14 * This file contains dependencies that the collation run-time doesn't normally
15 * need. This mainly contains resource bundle usage and collation meta information
17 * Modification history
19 * 1996-1999 various members of ICU team maintained C API for collation framework
20 * 02/16/2001 synwee Added internal method getPrevSpecialCE
21 * 03/01/2001 synwee Added maxexpansion functionality.
22 * 03/16/2001 weiv Collation framework is rewritten in C and made UCA compliant
23 * 12/08/2004 grhoten Split part of ucol.cpp into ucol_res.cpp
24 * 2012-2014 markus Rewritten in C++ again.
27 #include "unicode/utypes.h"
29 #if !UCONFIG_NO_COLLATION
31 #include "unicode/coll.h"
32 #include "unicode/localpointer.h"
33 #include "unicode/locid.h"
34 #include "unicode/tblcoll.h"
35 #include "unicode/ucol.h"
36 #include "unicode/uloc.h"
37 #include "unicode/unistr.h"
38 #include "unicode/ures.h"
42 #include "collationdatareader.h"
43 #include "collationroot.h"
44 #include "collationtailoring.h"
53 #include "unifiedcache.h"
62 static const UChar
*rootRules
= NULL
;
63 static int32_t rootRulesLength
= 0;
64 static UResourceBundle
*rootBundle
= NULL
;
65 static UInitOnce gInitOnceUcolRes
= U_INITONCE_INITIALIZER
;
71 static UBool U_CALLCONV
75 ures_close(rootBundle
);
77 gInitOnceUcolRes
.reset();
82 CollationLoader::loadRootRules(UErrorCode
&errorCode
) {
83 if(U_FAILURE(errorCode
)) { return; }
84 rootBundle
= ures_open(U_ICUDATA_COLL
, kRootLocaleName
, &errorCode
);
85 if(U_FAILURE(errorCode
)) { return; }
86 rootRules
= ures_getStringByKey(rootBundle
, "UCARules", &rootRulesLength
, &errorCode
);
87 if(U_FAILURE(errorCode
)) {
88 ures_close(rootBundle
);
92 ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES
, ucol_res_cleanup
);
98 CollationLoader::appendRootRules(UnicodeString
&s
) {
99 UErrorCode errorCode
= U_ZERO_ERROR
;
100 umtx_initOnce(gInitOnceUcolRes
, CollationLoader::loadRootRules
, errorCode
);
101 if(U_SUCCESS(errorCode
)) {
102 s
.append(rootRules
, rootRulesLength
);
107 CollationLoader::loadRules(const char *localeID
, const char *collationType
,
108 UnicodeString
&rules
, UErrorCode
&errorCode
) {
109 if(U_FAILURE(errorCode
)) { return; }
110 U_ASSERT(collationType
!= NULL
&& *collationType
!= 0);
111 // Copy the type for lowercasing.
113 int32_t typeLength
= static_cast<int32_t>(uprv_strlen(collationType
));
114 if(typeLength
>= UPRV_LENGTHOF(type
)) {
115 errorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
118 uprv_memcpy(type
, collationType
, typeLength
+ 1);
119 T_CString_toLowerCase(type
);
121 LocalUResourceBundlePointer
bundle(ures_open(U_ICUDATA_COLL
, localeID
, &errorCode
));
122 LocalUResourceBundlePointer
collations(
123 ures_getByKey(bundle
.getAlias(), "collations", NULL
, &errorCode
));
124 LocalUResourceBundlePointer
data(
125 ures_getByKeyWithFallback(collations
.getAlias(), type
, NULL
, &errorCode
));
127 const UChar
*s
= ures_getStringByKey(data
.getAlias(), "Sequence", &length
, &errorCode
);
128 if(U_FAILURE(errorCode
)) { return; }
130 // No string pointer aliasing so that we need not hold onto the resource bundle.
131 rules
.setTo(s
, length
);
132 if(rules
.isBogus()) {
133 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
137 template<> U_I18N_API
138 const CollationCacheEntry
*
139 LocaleCacheKey
<CollationCacheEntry
>::createObject(const void *creationContext
,
140 UErrorCode
&errorCode
) const {
141 CollationLoader
*loader
=
142 reinterpret_cast<CollationLoader
*>(
143 const_cast<void *>(creationContext
));
144 return loader
->createCacheEntry(errorCode
);
147 const CollationCacheEntry
*
148 CollationLoader::loadTailoring(const Locale
&locale
, UErrorCode
&errorCode
) {
149 const CollationCacheEntry
*rootEntry
= CollationRoot::getRootCacheEntry(errorCode
);
150 if(U_FAILURE(errorCode
)) { return NULL
; }
151 const char *name
= locale
.getName();
152 if(*name
== 0 || uprv_strcmp(name
, "root") == 0) {
154 // Have to add a ref.
159 // Clear warning codes before loading where they get cached.
160 errorCode
= U_ZERO_ERROR
;
161 CollationLoader
loader(rootEntry
, locale
, errorCode
);
163 // getCacheEntry adds a ref for us.
164 return loader
.getCacheEntry(errorCode
);
167 CollationLoader::CollationLoader(const CollationCacheEntry
*re
, const Locale
&requested
,
168 UErrorCode
&errorCode
)
169 : cache(UnifiedCache::getInstance(errorCode
)), rootEntry(re
),
170 validLocale(re
->validLocale
), locale(requested
),
171 typesTried(0), typeFallback(FALSE
),
172 bundle(NULL
), collations(NULL
), data(NULL
) {
175 if(U_FAILURE(errorCode
)) { return; }
177 // Canonicalize the locale ID: Ignore all irrelevant keywords.
178 const char *baseName
= locale
.getBaseName();
179 if(uprv_strcmp(locale
.getName(), baseName
) != 0) {
180 locale
= Locale(baseName
);
182 // Fetch the collation type from the locale ID.
183 int32_t typeLength
= requested
.getKeywordValue("collation",
184 type
, UPRV_LENGTHOF(type
) - 1, errorCode
);
185 if(U_FAILURE(errorCode
)) {
186 errorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
189 type
[typeLength
] = 0; // in case of U_NOT_TERMINATED_WARNING
190 if(typeLength
== 0) {
191 // No collation type.
192 } else if(uprv_stricmp(type
, "default") == 0) {
193 // Ignore "default" (case-insensitive).
196 // Copy the collation type.
197 T_CString_toLowerCase(type
);
198 locale
.setKeywordValue("collation", type
, errorCode
);
203 CollationLoader::~CollationLoader() {
205 ures_close(collations
);
209 const CollationCacheEntry
*
210 CollationLoader::createCacheEntry(UErrorCode
&errorCode
) {
211 // This is a linear lookup and fallback flow turned into a state machine.
212 // Most local variables have been turned into instance fields.
213 // In a cache miss, cache.get() calls CacheKey::createObject(),
214 // which means that we progress via recursion.
215 // loadFromCollations() will recurse to itself as well for collation type fallback.
217 return loadFromLocale(errorCode
);
218 } else if(collations
== NULL
) {
219 return loadFromBundle(errorCode
);
220 } else if(data
== NULL
) {
221 return loadFromCollations(errorCode
);
223 return loadFromData(errorCode
);
227 const CollationCacheEntry
*
228 CollationLoader::loadFromLocale(UErrorCode
&errorCode
) {
229 if(U_FAILURE(errorCode
)) { return NULL
; }
230 U_ASSERT(bundle
== NULL
);
231 bundle
= ures_openNoDefault(U_ICUDATA_COLL
, locale
.getBaseName(), &errorCode
);
232 if(errorCode
== U_MISSING_RESOURCE_ERROR
) {
233 errorCode
= U_USING_DEFAULT_WARNING
;
235 // Have to add that ref that we promise.
239 Locale
requestedLocale(locale
);
240 const char *vLocale
= ures_getLocaleByType(bundle
, ULOC_ACTUAL_LOCALE
, &errorCode
);
241 if(U_FAILURE(errorCode
)) { return NULL
; }
242 locale
= validLocale
= Locale(vLocale
); // no type until loadFromCollations()
244 locale
.setKeywordValue("collation", type
, errorCode
);
246 if(locale
!= requestedLocale
) {
247 return getCacheEntry(errorCode
);
249 return loadFromBundle(errorCode
);
253 const CollationCacheEntry
*
254 CollationLoader::loadFromBundle(UErrorCode
&errorCode
) {
255 if(U_FAILURE(errorCode
)) { return NULL
; }
256 U_ASSERT(collations
== NULL
);
257 // There are zero or more tailorings in the collations table.
258 collations
= ures_getByKey(bundle
, "collations", NULL
, &errorCode
);
259 if(errorCode
== U_MISSING_RESOURCE_ERROR
) {
260 errorCode
= U_USING_DEFAULT_WARNING
;
261 // Return the root tailoring with the validLocale, without collation type.
262 return makeCacheEntryFromRoot(validLocale
, errorCode
);
264 if(U_FAILURE(errorCode
)) { return NULL
; }
266 // Fetch the default type from the data.
268 UErrorCode internalErrorCode
= U_ZERO_ERROR
;
269 LocalUResourceBundlePointer
def(
270 ures_getByKeyWithFallback(collations
, "default", NULL
, &internalErrorCode
));
272 const UChar
*s
= ures_getString(def
.getAlias(), &length
, &internalErrorCode
);
273 if(U_SUCCESS(internalErrorCode
) && 0 < length
&& length
< UPRV_LENGTHOF(defaultType
)) {
274 u_UCharsToChars(s
, defaultType
, length
+ 1);
276 uprv_strcpy(defaultType
, "standard");
280 // Record which collation types we have looked for already,
281 // so that we do not deadlock in the cache.
283 // If there is no explicit type, then we look in the cache
284 // for the entry with the default type.
285 // If the explicit type is the default type, then we do not look in the cache
286 // for the entry with an empty type.
287 // Otherwise, two concurrent requests with opposite fallbacks would deadlock each other.
288 // Also, it is easier to always enter the next method with a non-empty type.
290 uprv_strcpy(type
, defaultType
);
291 typesTried
|= TRIED_DEFAULT
;
292 if(uprv_strcmp(type
, "search") == 0) {
293 typesTried
|= TRIED_SEARCH
;
295 if(uprv_strcmp(type
, "standard") == 0) {
296 typesTried
|= TRIED_STANDARD
;
298 locale
.setKeywordValue("collation", type
, errorCode
);
299 return getCacheEntry(errorCode
);
301 if(uprv_strcmp(type
, defaultType
) == 0) {
302 typesTried
|= TRIED_DEFAULT
;
304 if(uprv_strcmp(type
, "search") == 0) {
305 typesTried
|= TRIED_SEARCH
;
307 if(uprv_strcmp(type
, "standard") == 0) {
308 typesTried
|= TRIED_STANDARD
;
310 return loadFromCollations(errorCode
);
314 const CollationCacheEntry
*
315 CollationLoader::loadFromCollations(UErrorCode
&errorCode
) {
316 if(U_FAILURE(errorCode
)) { return NULL
; }
317 U_ASSERT(data
== NULL
);
318 // Load the collations/type tailoring, with type fallback.
319 LocalUResourceBundlePointer
localData(
320 ures_getByKeyWithFallback(collations
, type
, NULL
, &errorCode
));
321 int32_t typeLength
= static_cast<int32_t>(uprv_strlen(type
));
322 if(errorCode
== U_MISSING_RESOURCE_ERROR
) {
323 errorCode
= U_USING_DEFAULT_WARNING
;
325 if((typesTried
& TRIED_SEARCH
) == 0 &&
326 typeLength
> 6 && uprv_strncmp(type
, "search", 6) == 0) {
327 // fall back from something like "searchjl" to "search"
328 typesTried
|= TRIED_SEARCH
;
330 } else if((typesTried
& TRIED_DEFAULT
) == 0) {
331 // fall back to the default type
332 typesTried
|= TRIED_DEFAULT
;
333 uprv_strcpy(type
, defaultType
);
334 } else if((typesTried
& TRIED_STANDARD
) == 0) {
335 // fall back to the "standard" type
336 typesTried
|= TRIED_STANDARD
;
337 uprv_strcpy(type
, "standard");
339 // Return the root tailoring with the validLocale, without collation type.
340 return makeCacheEntryFromRoot(validLocale
, errorCode
);
342 locale
.setKeywordValue("collation", type
, errorCode
);
343 return getCacheEntry(errorCode
);
345 if(U_FAILURE(errorCode
)) { return NULL
; }
347 data
= localData
.orphan();
348 const char *actualLocale
= ures_getLocaleByType(data
, ULOC_ACTUAL_LOCALE
, &errorCode
);
349 if(U_FAILURE(errorCode
)) { return NULL
; }
350 const char *vLocale
= validLocale
.getBaseName();
351 UBool actualAndValidLocalesAreDifferent
= Locale(actualLocale
) != Locale(vLocale
);
353 // Set the collation types on the informational locales,
354 // except when they match the default types (for brevity and backwards compatibility).
355 // For the valid locale, suppress the default type.
356 if(uprv_strcmp(type
, defaultType
) != 0) {
357 validLocale
.setKeywordValue("collation", type
, errorCode
);
358 if(U_FAILURE(errorCode
)) { return NULL
; }
361 // Is this the same as the root collator? If so, then use that instead.
362 if((*actualLocale
== 0 || uprv_strcmp(actualLocale
, "root") == 0) &&
363 uprv_strcmp(type
, "standard") == 0) {
365 errorCode
= U_USING_DEFAULT_WARNING
;
367 return makeCacheEntryFromRoot(validLocale
, errorCode
);
370 locale
= Locale(actualLocale
);
371 if(actualAndValidLocalesAreDifferent
) {
372 locale
.setKeywordValue("collation", type
, errorCode
);
373 const CollationCacheEntry
*entry
= getCacheEntry(errorCode
);
374 return makeCacheEntry(validLocale
, entry
, errorCode
);
376 return loadFromData(errorCode
);
380 const CollationCacheEntry
*
381 CollationLoader::loadFromData(UErrorCode
&errorCode
) {
382 if(U_FAILURE(errorCode
)) { return NULL
; }
383 LocalPointer
<CollationTailoring
> t(new CollationTailoring(rootEntry
->tailoring
->settings
));
384 if(t
.isNull() || t
->isBogus()) {
385 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
390 LocalUResourceBundlePointer
binary(ures_getByKey(data
, "%%CollationBin", NULL
, &errorCode
));
391 // Note: U_MISSING_RESOURCE_ERROR --> The old code built from rules if available
392 // but that created undesirable dependencies.
394 const uint8_t *inBytes
= ures_getBinary(binary
.getAlias(), &length
, &errorCode
);
395 CollationDataReader::read(rootEntry
->tailoring
, inBytes
, length
, *t
, errorCode
);
396 // Note: U_COLLATOR_VERSION_MISMATCH --> The old code built from rules if available
397 // but that created undesirable dependencies.
398 if(U_FAILURE(errorCode
)) { return NULL
; }
400 // Try to fetch the optional rules string.
402 UErrorCode internalErrorCode
= U_ZERO_ERROR
;
404 const UChar
*s
= ures_getStringByKey(data
, "Sequence", &len
,
406 if(U_SUCCESS(internalErrorCode
)) {
407 t
->rules
.setTo(TRUE
, s
, len
);
411 const char *actualLocale
= locale
.getBaseName(); // without type
412 const char *vLocale
= validLocale
.getBaseName();
413 UBool actualAndValidLocalesAreDifferent
= Locale(actualLocale
) != Locale(vLocale
);
415 // For the actual locale, suppress the default type *according to the actual locale*.
416 // For example, zh has default=pinyin and contains all of the Chinese tailorings.
417 // zh_Hant has default=stroke but has no other data.
418 // For the valid locale "zh_Hant" we need to suppress stroke.
419 // For the actual locale "zh" we need to suppress pinyin instead.
420 if(actualAndValidLocalesAreDifferent
) {
421 // Opening a bundle for the actual locale should always succeed.
422 LocalUResourceBundlePointer
actualBundle(
423 ures_open(U_ICUDATA_COLL
, actualLocale
, &errorCode
));
424 if(U_FAILURE(errorCode
)) { return NULL
; }
425 UErrorCode internalErrorCode
= U_ZERO_ERROR
;
426 LocalUResourceBundlePointer
def(
427 ures_getByKeyWithFallback(actualBundle
.getAlias(), "collations/default", NULL
,
428 &internalErrorCode
));
430 const UChar
*s
= ures_getString(def
.getAlias(), &len
, &internalErrorCode
);
431 if(U_SUCCESS(internalErrorCode
) && len
< UPRV_LENGTHOF(defaultType
)) {
432 u_UCharsToChars(s
, defaultType
, len
+ 1);
434 uprv_strcpy(defaultType
, "standard");
437 t
->actualLocale
= locale
;
438 if(uprv_strcmp(type
, defaultType
) != 0) {
439 t
->actualLocale
.setKeywordValue("collation", type
, errorCode
);
440 } else if(uprv_strcmp(locale
.getName(), locale
.getBaseName()) != 0) {
441 // Remove the collation keyword if it was set.
442 t
->actualLocale
.setKeywordValue("collation", NULL
, errorCode
);
444 if(U_FAILURE(errorCode
)) { return NULL
; }
447 errorCode
= U_USING_DEFAULT_WARNING
;
451 const CollationCacheEntry
*entry
= new CollationCacheEntry(validLocale
, t
.getAlias());
453 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
458 // Have to add that reference that we promise.
463 const CollationCacheEntry
*
464 CollationLoader::getCacheEntry(UErrorCode
&errorCode
) {
465 LocaleCacheKey
<CollationCacheEntry
> key(locale
);
466 const CollationCacheEntry
*entry
= NULL
;
467 cache
->get(key
, this, entry
, errorCode
);
471 const CollationCacheEntry
*
472 CollationLoader::makeCacheEntryFromRoot(
473 const Locale
&/*loc*/,
474 UErrorCode
&errorCode
) const {
475 if (U_FAILURE(errorCode
)) {
479 return makeCacheEntry(validLocale
, rootEntry
, errorCode
);
482 const CollationCacheEntry
*
483 CollationLoader::makeCacheEntry(
485 const CollationCacheEntry
*entryFromCache
,
486 UErrorCode
&errorCode
) {
487 if(U_FAILURE(errorCode
) || loc
== entryFromCache
->validLocale
) {
488 return entryFromCache
;
490 CollationCacheEntry
*entry
= new CollationCacheEntry(loc
, entryFromCache
->tailoring
);
492 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
493 entryFromCache
->removeRef();
497 entryFromCache
->removeRef();
506 ucol_open(const char *loc
,
509 UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN
);
510 UTRACE_DATA1(UTRACE_INFO
, "locale = \"%s\"", loc
);
511 UCollator
*result
= NULL
;
513 Collator
*coll
= Collator::createInstance(loc
, *status
);
514 if(U_SUCCESS(*status
)) {
515 result
= coll
->toUCollator();
517 UTRACE_EXIT_PTR_STATUS(result
, *status
);
522 U_CAPI
int32_t U_EXPORT2
523 ucol_getDisplayName( const char *objLoc
,
526 int32_t resultLength
,
529 if(U_FAILURE(*status
)) return -1;
531 if(!(result
==NULL
&& resultLength
==0)) {
532 // NULL destination for pure preflighting: empty dummy string
533 // otherwise, alias the destination buffer
534 dst
.setTo(result
, 0, resultLength
);
536 Collator::getDisplayName(Locale(objLoc
), Locale(dispLoc
), dst
);
537 return dst
.extract(result
, resultLength
, *status
);
540 U_CAPI
const char* U_EXPORT2
541 ucol_getAvailable(int32_t index
)
544 const Locale
*loc
= Collator::getAvailableLocales(count
);
545 if (loc
!= NULL
&& index
< count
) {
546 return loc
[index
].getName();
551 U_CAPI
int32_t U_EXPORT2
552 ucol_countAvailable()
555 Collator::getAvailableLocales(count
);
559 #if !UCONFIG_NO_SERVICE
560 U_CAPI UEnumeration
* U_EXPORT2
561 ucol_openAvailableLocales(UErrorCode
*status
) {
562 // This is a wrapper over Collator::getAvailableLocales()
563 if (U_FAILURE(*status
)) {
566 StringEnumeration
*s
= icu::Collator::getAvailableLocales();
568 *status
= U_MEMORY_ALLOCATION_ERROR
;
571 return uenum_openFromStringEnumeration(s
, status
);
575 // Note: KEYWORDS[0] != RESOURCE_NAME - alan
577 static const char RESOURCE_NAME
[] = "collations";
579 static const char* const KEYWORDS
[] = { "collation" };
581 #define KEYWORD_COUNT UPRV_LENGTHOF(KEYWORDS)
583 U_CAPI UEnumeration
* U_EXPORT2
584 ucol_getKeywords(UErrorCode
*status
) {
585 UEnumeration
*result
= NULL
;
586 if (U_SUCCESS(*status
)) {
587 return uenum_openCharStringsEnumeration(KEYWORDS
, KEYWORD_COUNT
, status
);
592 U_CAPI UEnumeration
* U_EXPORT2
593 ucol_getKeywordValues(const char *keyword
, UErrorCode
*status
) {
594 if (U_FAILURE(*status
)) {
597 // hard-coded to accept exactly one collation keyword
598 // modify if additional collation keyword is added later
599 if (keyword
==NULL
|| uprv_strcmp(keyword
, KEYWORDS
[0])!=0)
601 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
604 return ures_getKeywordValues(U_ICUDATA_COLL
, RESOURCE_NAME
, status
);
607 static const UEnumeration defaultKeywordValues
= {
610 ulist_close_keyword_values_iterator
,
611 ulist_count_keyword_values
,
613 ulist_next_keyword_value
,
614 ulist_reset_keyword_values_iterator
619 struct KeywordsSink
: public ResourceSink
{
621 KeywordsSink(UErrorCode
&errorCode
) :
622 values(ulist_createEmptyList(&errorCode
)), hasDefault(FALSE
) {}
623 virtual ~KeywordsSink();
625 virtual void put(const char *key
, ResourceValue
&value
, UBool
/*noFallback*/,
626 UErrorCode
&errorCode
) {
627 if (U_FAILURE(errorCode
)) { return; }
628 ResourceTable collations
= value
.getTable(errorCode
);
629 for (int32_t i
= 0; collations
.getKeyAndValue(i
, key
, value
); ++i
) {
630 UResType type
= value
.getType();
631 if (type
== URES_STRING
) {
632 if (!hasDefault
&& uprv_strcmp(key
, "default") == 0) {
634 defcoll
.appendInvariantChars(value
.getUnicodeString(errorCode
), errorCode
);
635 if (U_SUCCESS(errorCode
) && !defcoll
.isEmpty()) {
636 char *ownedDefault
= uprv_strdup(defcoll
.data());
637 if (ownedDefault
== NULL
) {
638 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
641 ulist_removeString(values
, defcoll
.data());
642 ulist_addItemBeginList(values
, ownedDefault
, TRUE
, &errorCode
);
646 } else if (type
== URES_TABLE
&& uprv_strncmp(key
, "private-", 8) != 0) {
647 if (!ulist_containsString(values
, key
, (int32_t)uprv_strlen(key
))) {
648 ulist_addItemEndList(values
, key
, FALSE
, &errorCode
);
651 if (U_FAILURE(errorCode
)) { return; }
659 KeywordsSink::~KeywordsSink() {
660 ulist_deleteList(values
);
665 U_CAPI UEnumeration
* U_EXPORT2
666 ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale
,
667 UBool
/*commonlyUsed*/, UErrorCode
* status
) {
668 // Note: The parameter commonlyUsed is not used.
669 // The switch is in the method signature for consistency
670 // with other locale services.
672 // Read available collation values from collation bundles.
673 LocalUResourceBundlePointer
bundle(ures_open(U_ICUDATA_COLL
, locale
, status
));
674 KeywordsSink
sink(*status
);
675 ures_getAllItemsWithFallback(bundle
.getAlias(), RESOURCE_NAME
, sink
, *status
);
676 if (U_FAILURE(*status
)) { return NULL
; }
678 UEnumeration
*en
= (UEnumeration
*)uprv_malloc(sizeof(UEnumeration
));
680 *status
= U_MEMORY_ALLOCATION_ERROR
;
683 memcpy(en
, &defaultKeywordValues
, sizeof(UEnumeration
));
684 ulist_resetList(sink
.values
); // Initialize the iterator.
685 en
->context
= sink
.values
;
686 sink
.values
= NULL
; // Avoid deletion in the sink destructor.
690 U_CAPI
int32_t U_EXPORT2
691 ucol_getFunctionalEquivalent(char* result
, int32_t resultCapacity
,
692 const char* keyword
, const char* locale
,
693 UBool
* isAvailable
, UErrorCode
* status
)
695 // N.B.: Resource name is "collations" but keyword is "collation"
696 return ures_getFunctionalEquivalent(result
, resultCapacity
, U_ICUDATA_COLL
,
697 "collations", keyword
, locale
,
698 isAvailable
, TRUE
, status
);
701 #endif /* #if !UCONFIG_NO_COLLATION */