]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/locavailable.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / common / locavailable.cpp
CommitLineData
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
36U_NAMESPACE_BEGIN
37
4388f060 38static icu::Locale* availableLocaleList = NULL;
729e4ab9 39static int32_t availableLocaleListCount;
0f5d89e8 40static icu::UInitOnce gInitOnceLocale = U_INITONCE_INITIALIZER;
57a6839d
A
41
42U_NAMESPACE_END
729e4ab9
A
43
44U_CDECL_BEGIN
45
46static 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
60U_CDECL_END
61
62U_NAMESPACE_BEGIN
63
57a6839d
A
64void 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
83const Locale* U_EXPORT2
84Locale::getAvailableLocales(int32_t& count)
85{
0f5d89e8 86 umtx_initOnce(gInitOnceLocale, &locale_available_init);
729e4ab9
A
87 count = availableLocaleListCount;
88 return availableLocaleList;
89}
90
91
92U_NAMESPACE_END
93
94// C API ------------------------------------------------------------------- ***
95
96U_NAMESPACE_USE
97
98/* ### Constants **************************************************/
99
340931cb 100namespace {
729e4ab9 101
340931cb
A
102// Enough capacity for the two lists in the res_index.res file
103const char** gAvailableLocaleNames[2] = {};
104int32_t gAvailableLocaleCounts[2] = {};
105icu::UInitOnce ginstalledLocalesInitOnce = U_INITONCE_INITIALIZER;
729e4ab9 106
340931cb
A
107class 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
142class 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
199static 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
212static 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
220void _load_installedLocales(UErrorCode& status) {
221 umtx_initOnce(ginstalledLocalesInitOnce, &loadInstalledLocales, status);
729e4ab9
A
222}
223
340931cb
A
224} // namespace
225
729e4ab9 226U_CAPI const char* U_EXPORT2
340931cb
A
227uloc_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
240U_CAPI int32_t U_EXPORT2
340931cb
A
241uloc_countAvailable() {
242 icu::ErrorCode status;
243 _load_installedLocales(status);
244 if (status.isFailure()) {
245 return 0;
246 }
247 return gAvailableLocaleCounts[0];
248}
249
250U_CAPI UEnumeration* U_EXPORT2
251uloc_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