1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 * Copyright (C) 1997-2013, International Business Machines
7 * Corporation and others. All Rights Reserved.
8 *
9 *******************************************************************************
10 * file name: locavailable.cpp
11 * encoding: UTF-8
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
22 #include "unicode/utypes.h"
23 #include "unicode/locid.h"
24 #include "unicode/uloc.h"
25 #include "unicode/ures.h"
26 #include "cmemory.h"
27 #include "ucln_cmn.h"
28 #include "uassert.h"
29 #include "umutex.h"
30 #include "uresimp.h"
31
32 // C++ API ----------------------------------------------------------------- ***
33
34 U_NAMESPACE_BEGIN
35
36 static icu::Locale* availableLocaleList = NULL;
37 static int32_t availableLocaleListCount;
38 static icu::UInitOnce gInitOnceLocale = U_INITONCE_INITIALIZER;
39
40 U_NAMESPACE_END
41
42 U_CDECL_BEGIN
43
locale_available_cleanup(void)44 static UBool U_CALLCONV locale_available_cleanup(void)
45 {
46 U_NAMESPACE_USE
47
48 if (availableLocaleList) {
49 delete []availableLocaleList;
50 availableLocaleList = NULL;
51 }
52 availableLocaleListCount = 0;
53 gInitOnceLocale.reset();
54
55 return TRUE;
56 }
57
58 U_CDECL_END
59
60 U_NAMESPACE_BEGIN
61
locale_available_init()62 void U_CALLCONV locale_available_init() {
63 // This function is a friend of class Locale.
64 // This function is only invoked via umtx_initOnce().
65
66 // for now, there is a hardcoded list, so just walk through that list and set it up.
67 // Note: this function is a friend of class Locale.
68 availableLocaleListCount = uloc_countAvailable();
69 if(availableLocaleListCount) {
70 availableLocaleList = new Locale[availableLocaleListCount];
71 }
72 if (availableLocaleList == NULL) {
73 availableLocaleListCount= 0;
74 }
75 for (int32_t locCount=availableLocaleListCount-1; locCount>=0; --locCount) {
76 availableLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
77 }
78 ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup);
79 }
80
81 const Locale* U_EXPORT2
getAvailableLocales(int32_t & count)82 Locale::getAvailableLocales(int32_t& count)
83 {
84 umtx_initOnce(gInitOnceLocale, &locale_available_init);
85 count = availableLocaleListCount;
86 return availableLocaleList;
87 }
88
89
90 U_NAMESPACE_END
91
92 // C API ------------------------------------------------------------------- ***
93
94 U_NAMESPACE_USE
95
96 /* ### Constants **************************************************/
97
98 /* These strings describe the resources we attempt to load from
99 the locale ResourceBundle data file.*/
100 static const char _kIndexLocaleName[] = "res_index";
101 static const char _kIndexTag[] = "InstalledLocales";
102
103 static char** _installedLocales = NULL;
104 static int32_t _installedLocalesCount = 0;
105 static icu::UInitOnce _installedLocalesInitOnce;
106
107 /* ### Get available **************************************************/
108
uloc_cleanup(void)109 static UBool U_CALLCONV uloc_cleanup(void) {
110 char ** temp;
111
112 if (_installedLocales) {
113 temp = _installedLocales;
114 _installedLocales = NULL;
115
116 _installedLocalesCount = 0;
117 _installedLocalesInitOnce.reset();
118
119 uprv_free(temp);
120 }
121 return TRUE;
122 }
123
124 // Load Installed Locales. This function will be called exactly once
125 // via the initOnce mechanism.
126
loadInstalledLocales()127 static void U_CALLCONV loadInstalledLocales() {
128 UResourceBundle *indexLocale = NULL;
129 UResourceBundle installed;
130 UErrorCode status = U_ZERO_ERROR;
131 int32_t i = 0;
132 int32_t localeCount;
133
134 U_ASSERT(_installedLocales == NULL);
135 U_ASSERT(_installedLocalesCount == 0);
136
137 _installedLocalesCount = 0;
138 ures_initStackObject(&installed);
139 indexLocale = ures_openDirect(NULL, _kIndexLocaleName, &status);
140 ures_getByKey(indexLocale, _kIndexTag, &installed, &status);
141
142 if(U_SUCCESS(status)) {
143 localeCount = ures_getSize(&installed);
144 _installedLocales = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
145 if (_installedLocales != NULL) {
146 ures_resetIterator(&installed);
147 while(ures_hasNext(&installed)) {
148 ures_getNextString(&installed, NULL, (const char **)&_installedLocales[i++], &status);
149 }
150 _installedLocales[i] = NULL;
151 _installedLocalesCount = localeCount;
152 ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
153 }
154 }
155 ures_close(&installed);
156 ures_close(indexLocale);
157 }
158
_load_installedLocales()159 static void _load_installedLocales()
160 {
161 umtx_initOnce(_installedLocalesInitOnce, &loadInstalledLocales);
162 }
163
164 U_CAPI const char* U_EXPORT2
uloc_getAvailable(int32_t offset)165 uloc_getAvailable(int32_t offset)
166 {
167
168 _load_installedLocales();
169
170 if (offset > _installedLocalesCount)
171 return NULL;
172 return _installedLocales[offset];
173 }
174
175 U_CAPI int32_t U_EXPORT2
uloc_countAvailable()176 uloc_countAvailable()
177 {
178 _load_installedLocales();
179 return _installedLocalesCount;
180 }
181
182