1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1997-2013, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: locavailable.cpp
12 * tab size: 8 (not used)
15 * created on: 2010feb25
16 * created by: Markus W. Scherer
18 * Code for available locales, separated out from other .cpp files
19 * that then do not depend on resource bundle code and res_index bundles.
22 #include "unicode/errorcode.h"
23 #include "unicode/utypes.h"
24 #include "unicode/locid.h"
25 #include "unicode/uloc.h"
26 #include "unicode/ures.h"
34 // C++ API ----------------------------------------------------------------- ***
38 static icu::Locale
* availableLocaleList
= NULL
;
39 static int32_t availableLocaleListCount
;
40 static icu::UInitOnce gInitOnceLocale
= U_INITONCE_INITIALIZER
;
46 static UBool U_CALLCONV
locale_available_cleanup(void)
50 if (availableLocaleList
) {
51 delete []availableLocaleList
;
52 availableLocaleList
= NULL
;
54 availableLocaleListCount
= 0;
55 gInitOnceLocale
.reset();
64 void U_CALLCONV
locale_available_init() {
65 // This function is a friend of class Locale.
66 // This function is only invoked via umtx_initOnce().
68 // for now, there is a hardcoded list, so just walk through that list and set it up.
69 // Note: this function is a friend of class Locale.
70 availableLocaleListCount
= uloc_countAvailable();
71 if(availableLocaleListCount
) {
72 availableLocaleList
= new Locale
[availableLocaleListCount
];
74 if (availableLocaleList
== NULL
) {
75 availableLocaleListCount
= 0;
77 for (int32_t locCount
=availableLocaleListCount
-1; locCount
>=0; --locCount
) {
78 availableLocaleList
[locCount
].setFromPOSIXID(uloc_getAvailable(locCount
));
80 ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE
, locale_available_cleanup
);
83 const Locale
* U_EXPORT2
84 Locale::getAvailableLocales(int32_t& count
)
86 umtx_initOnce(gInitOnceLocale
, &locale_available_init
);
87 count
= availableLocaleListCount
;
88 return availableLocaleList
;
94 // C API ------------------------------------------------------------------- ***
98 /* ### Constants **************************************************/
102 // Enough capacity for the two lists in the res_index.res file
103 const char** gAvailableLocaleNames
[2] = {};
104 int32_t gAvailableLocaleCounts
[2] = {};
105 icu::UInitOnce ginstalledLocalesInitOnce
= U_INITONCE_INITIALIZER
;
107 class AvailableLocalesSink
: public ResourceSink
{
109 void put(const char *key
, ResourceValue
&value
, UBool
/*noFallback*/, UErrorCode
&status
) U_OVERRIDE
{
110 ResourceTable resIndexTable
= value
.getTable(status
);
111 if (U_FAILURE(status
)) {
114 for (int32_t i
= 0; resIndexTable
.getKeyAndValue(i
, key
, value
); ++i
) {
115 ULocAvailableType type
;
116 if (uprv_strcmp(key
, "InstalledLocales") == 0) {
117 type
= ULOC_AVAILABLE_DEFAULT
;
118 } else if (uprv_strcmp(key
, "AliasLocales") == 0) {
119 type
= ULOC_AVAILABLE_ONLY_LEGACY_ALIASES
;
124 ResourceTable availableLocalesTable
= value
.getTable(status
);
125 if (U_FAILURE(status
)) {
128 gAvailableLocaleCounts
[type
] = availableLocalesTable
.getSize();
129 gAvailableLocaleNames
[type
] = static_cast<const char**>(
130 uprv_malloc(gAvailableLocaleCounts
[type
] * sizeof(const char*)));
131 if (gAvailableLocaleNames
[type
] == nullptr) {
132 status
= U_MEMORY_ALLOCATION_ERROR
;
135 for (int32_t j
= 0; availableLocalesTable
.getKeyAndValue(j
, key
, value
); ++j
) {
136 gAvailableLocaleNames
[type
][j
] = key
;
142 class AvailableLocalesStringEnumeration
: public StringEnumeration
{
144 AvailableLocalesStringEnumeration(ULocAvailableType type
) : fType(type
) {
147 const char* next(int32_t *resultLength
, UErrorCode
&) override
{
148 ULocAvailableType actualType
= fType
;
149 int32_t actualIndex
= fIndex
++;
151 // If the "combined" list was requested, resolve that now
152 if (fType
== ULOC_AVAILABLE_WITH_LEGACY_ALIASES
) {
153 int32_t defaultLocalesCount
= gAvailableLocaleCounts
[ULOC_AVAILABLE_DEFAULT
];
154 if (actualIndex
< defaultLocalesCount
) {
155 actualType
= ULOC_AVAILABLE_DEFAULT
;
157 actualIndex
-= defaultLocalesCount
;
158 actualType
= ULOC_AVAILABLE_ONLY_LEGACY_ALIASES
;
162 // Return the requested string
163 int32_t count
= gAvailableLocaleCounts
[actualType
];
165 if (actualIndex
< count
) {
166 result
= gAvailableLocaleNames
[actualType
][actualIndex
];
167 if (resultLength
!= nullptr) {
168 *resultLength
= static_cast<int32_t>(uprv_strlen(result
));
172 if (resultLength
!= nullptr) {
179 void reset(UErrorCode
&) override
{
183 int32_t count(UErrorCode
&) const override
{
184 if (fType
== ULOC_AVAILABLE_WITH_LEGACY_ALIASES
) {
185 return gAvailableLocaleCounts
[ULOC_AVAILABLE_DEFAULT
]
186 + gAvailableLocaleCounts
[ULOC_AVAILABLE_ONLY_LEGACY_ALIASES
];
188 return gAvailableLocaleCounts
[fType
];
193 ULocAvailableType fType
;
197 /* ### Get available **************************************************/
199 static UBool U_CALLCONV
uloc_cleanup(void) {
200 for (int32_t i
= 0; i
< UPRV_LENGTHOF(gAvailableLocaleNames
); i
++) {
201 uprv_free(gAvailableLocaleNames
[i
]);
202 gAvailableLocaleNames
[i
] = nullptr;
203 gAvailableLocaleCounts
[i
] = 0;
205 ginstalledLocalesInitOnce
.reset();
209 // Load Installed Locales. This function will be called exactly once
210 // via the initOnce mechanism.
212 static void U_CALLCONV
loadInstalledLocales(UErrorCode
& status
) {
213 ucln_common_registerCleanup(UCLN_COMMON_ULOC
, uloc_cleanup
);
215 icu::LocalUResourceBundlePointer
rb(ures_openDirect(NULL
, "res_index", &status
));
216 AvailableLocalesSink sink
;
217 ures_getAllItemsWithFallback(rb
.getAlias(), "", sink
, status
);
220 void _load_installedLocales(UErrorCode
& status
) {
221 umtx_initOnce(ginstalledLocalesInitOnce
, &loadInstalledLocales
, status
);
226 U_CAPI
const char* U_EXPORT2
227 uloc_getAvailable(int32_t offset
) {
228 icu::ErrorCode status
;
229 _load_installedLocales(status
);
230 if (status
.isFailure()) {
233 if (offset
> gAvailableLocaleCounts
[0]) {
234 // *status = U_ILLEGAL_ARGUMENT_ERROR;
237 return gAvailableLocaleNames
[0][offset
];
240 U_CAPI
int32_t U_EXPORT2
241 uloc_countAvailable() {
242 icu::ErrorCode status
;
243 _load_installedLocales(status
);
244 if (status
.isFailure()) {
247 return gAvailableLocaleCounts
[0];
250 U_CAPI UEnumeration
* U_EXPORT2
251 uloc_openAvailableByType(ULocAvailableType type
, UErrorCode
* status
) {
252 if (U_FAILURE(*status
)) {
255 if (type
< 0 || type
>= ULOC_AVAILABLE_COUNT
) {
256 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
259 _load_installedLocales(*status
);
260 if (U_FAILURE(*status
)) {
263 LocalPointer
<AvailableLocalesStringEnumeration
> result(
264 new AvailableLocalesStringEnumeration(type
), *status
);
265 if (U_FAILURE(*status
)) {
268 return uenum_openFromStringEnumeration(result
.orphan(), status
);