]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
729e4ab9 A |
3 | /* |
4 | ******************************************************************************* | |
5 | * | |
57a6839d | 6 | * Copyright (C) 1997-2013, International Business Machines |
729e4ab9 A |
7 | * Corporation and others. All Rights Reserved. |
8 | * | |
9 | ******************************************************************************* | |
10 | * file name: locavailable.cpp | |
f3c0d7a5 | 11 | * encoding: UTF-8 |
729e4ab9 A |
12 | * tab size: 8 (not used) |
13 | * indentation:4 | |
14 | * | |
15 | * created on: 2010feb25 | |
16 | * created by: Markus W. Scherer | |
17 | * | |
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. | |
20 | */ | |
21 | ||
340931cb | 22 | #include "unicode/errorcode.h" |
729e4ab9 A |
23 | #include "unicode/utypes.h" |
24 | #include "unicode/locid.h" | |
25 | #include "unicode/uloc.h" | |
26 | #include "unicode/ures.h" | |
27 | #include "cmemory.h" | |
340931cb | 28 | #include "cstring.h" |
729e4ab9 | 29 | #include "ucln_cmn.h" |
57a6839d | 30 | #include "uassert.h" |
729e4ab9 A |
31 | #include "umutex.h" |
32 | #include "uresimp.h" | |
33 | ||
34 | // C++ API ----------------------------------------------------------------- *** | |
35 | ||
57a6839d A |
36 | U_NAMESPACE_BEGIN |
37 | ||
4388f060 | 38 | static icu::Locale* availableLocaleList = NULL; |
729e4ab9 | 39 | static int32_t availableLocaleListCount; |
0f5d89e8 | 40 | static icu::UInitOnce gInitOnceLocale = U_INITONCE_INITIALIZER; |
57a6839d A |
41 | |
42 | U_NAMESPACE_END | |
729e4ab9 A |
43 | |
44 | U_CDECL_BEGIN | |
45 | ||
46 | static UBool U_CALLCONV locale_available_cleanup(void) | |
47 | { | |
48 | U_NAMESPACE_USE | |
49 | ||
50 | if (availableLocaleList) { | |
51 | delete []availableLocaleList; | |
52 | availableLocaleList = NULL; | |
53 | } | |
54 | availableLocaleListCount = 0; | |
0f5d89e8 | 55 | gInitOnceLocale.reset(); |
729e4ab9 A |
56 | |
57 | return TRUE; | |
58 | } | |
59 | ||
60 | U_CDECL_END | |
61 | ||
62 | U_NAMESPACE_BEGIN | |
63 | ||
57a6839d A |
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(). | |
67 | ||
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]; | |
73 | } | |
74 | if (availableLocaleList == NULL) { | |
75 | availableLocaleListCount= 0; | |
76 | } | |
77 | for (int32_t locCount=availableLocaleListCount-1; locCount>=0; --locCount) { | |
78 | availableLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount)); | |
79 | } | |
80 | ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup); | |
81 | } | |
82 | ||
729e4ab9 A |
83 | const Locale* U_EXPORT2 |
84 | Locale::getAvailableLocales(int32_t& count) | |
85 | { | |
0f5d89e8 | 86 | umtx_initOnce(gInitOnceLocale, &locale_available_init); |
729e4ab9 A |
87 | count = availableLocaleListCount; |
88 | return availableLocaleList; | |
89 | } | |
90 | ||
91 | ||
92 | U_NAMESPACE_END | |
93 | ||
94 | // C API ------------------------------------------------------------------- *** | |
95 | ||
96 | U_NAMESPACE_USE | |
97 | ||
98 | /* ### Constants **************************************************/ | |
99 | ||
340931cb | 100 | namespace { |
729e4ab9 | 101 | |
340931cb A |
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; | |
729e4ab9 | 106 | |
340931cb A |
107 | class AvailableLocalesSink : public ResourceSink { |
108 | public: | |
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)) { | |
112 | return; | |
113 | } | |
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; | |
120 | } else { | |
121 | // CLDRVersion, etc. | |
122 | continue; | |
123 | } | |
124 | ResourceTable availableLocalesTable = value.getTable(status); | |
125 | if (U_FAILURE(status)) { | |
126 | return; | |
127 | } | |
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; | |
133 | return; | |
134 | } | |
135 | for (int32_t j = 0; availableLocalesTable.getKeyAndValue(j, key, value); ++j) { | |
136 | gAvailableLocaleNames[type][j] = key; | |
137 | } | |
138 | } | |
139 | } | |
140 | }; | |
729e4ab9 | 141 | |
340931cb A |
142 | class AvailableLocalesStringEnumeration : public StringEnumeration { |
143 | public: | |
144 | AvailableLocalesStringEnumeration(ULocAvailableType type) : fType(type) { | |
145 | } | |
146 | ||
147 | const char* next(int32_t *resultLength, UErrorCode&) override { | |
148 | ULocAvailableType actualType = fType; | |
149 | int32_t actualIndex = fIndex++; | |
150 | ||
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; | |
156 | } else { | |
157 | actualIndex -= defaultLocalesCount; | |
158 | actualType = ULOC_AVAILABLE_ONLY_LEGACY_ALIASES; | |
159 | } | |
160 | } | |
729e4ab9 | 161 | |
340931cb A |
162 | // Return the requested string |
163 | int32_t count = gAvailableLocaleCounts[actualType]; | |
164 | const char* result; | |
165 | if (actualIndex < count) { | |
166 | result = gAvailableLocaleNames[actualType][actualIndex]; | |
167 | if (resultLength != nullptr) { | |
168 | *resultLength = static_cast<int32_t>(uprv_strlen(result)); | |
169 | } | |
170 | } else { | |
171 | result = nullptr; | |
172 | if (resultLength != nullptr) { | |
173 | *resultLength = 0; | |
174 | } | |
175 | } | |
176 | return result; | |
177 | } | |
729e4ab9 | 178 | |
340931cb A |
179 | void reset(UErrorCode&) override { |
180 | fIndex = 0; | |
181 | } | |
729e4ab9 | 182 | |
340931cb A |
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]; | |
187 | } else { | |
188 | return gAvailableLocaleCounts[fType]; | |
189 | } | |
729e4ab9 | 190 | } |
340931cb A |
191 | |
192 | private: | |
193 | ULocAvailableType fType; | |
194 | int32_t fIndex = 0; | |
195 | }; | |
196 | ||
197 | /* ### Get available **************************************************/ | |
198 | ||
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; | |
204 | } | |
205 | ginstalledLocalesInitOnce.reset(); | |
729e4ab9 A |
206 | return TRUE; |
207 | } | |
208 | ||
57a6839d A |
209 | // Load Installed Locales. This function will be called exactly once |
210 | // via the initOnce mechanism. | |
729e4ab9 | 211 | |
340931cb A |
212 | static void U_CALLCONV loadInstalledLocales(UErrorCode& status) { |
213 | ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup); | |
3d1f044b | 214 | |
340931cb A |
215 | icu::LocalUResourceBundlePointer rb(ures_openDirect(NULL, "res_index", &status)); |
216 | AvailableLocalesSink sink; | |
217 | ures_getAllItemsWithFallback(rb.getAlias(), "", sink, status); | |
57a6839d A |
218 | } |
219 | ||
340931cb A |
220 | void _load_installedLocales(UErrorCode& status) { |
221 | umtx_initOnce(ginstalledLocalesInitOnce, &loadInstalledLocales, status); | |
729e4ab9 A |
222 | } |
223 | ||
340931cb A |
224 | } // namespace |
225 | ||
729e4ab9 | 226 | U_CAPI const char* U_EXPORT2 |
340931cb A |
227 | uloc_getAvailable(int32_t offset) { |
228 | icu::ErrorCode status; | |
229 | _load_installedLocales(status); | |
230 | if (status.isFailure()) { | |
231 | return nullptr; | |
232 | } | |
233 | if (offset > gAvailableLocaleCounts[0]) { | |
234 | // *status = U_ILLEGAL_ARGUMENT_ERROR; | |
235 | return nullptr; | |
236 | } | |
237 | return gAvailableLocaleNames[0][offset]; | |
729e4ab9 A |
238 | } |
239 | ||
240 | U_CAPI int32_t U_EXPORT2 | |
340931cb A |
241 | uloc_countAvailable() { |
242 | icu::ErrorCode status; | |
243 | _load_installedLocales(status); | |
244 | if (status.isFailure()) { | |
245 | return 0; | |
246 | } | |
247 | return gAvailableLocaleCounts[0]; | |
248 | } | |
249 | ||
250 | U_CAPI UEnumeration* U_EXPORT2 | |
251 | uloc_openAvailableByType(ULocAvailableType type, UErrorCode* status) { | |
252 | if (U_FAILURE(*status)) { | |
253 | return nullptr; | |
254 | } | |
255 | if (type < 0 || type >= ULOC_AVAILABLE_COUNT) { | |
256 | *status = U_ILLEGAL_ARGUMENT_ERROR; | |
257 | return nullptr; | |
258 | } | |
259 | _load_installedLocales(*status); | |
260 | if (U_FAILURE(*status)) { | |
261 | return nullptr; | |
262 | } | |
263 | LocalPointer<AvailableLocalesStringEnumeration> result( | |
264 | new AvailableLocalesStringEnumeration(type), *status); | |
265 | if (U_FAILURE(*status)) { | |
266 | return nullptr; | |
267 | } | |
268 | return uenum_openFromStringEnumeration(result.orphan(), status); | |
729e4ab9 | 269 | } |
57a6839d | 270 |