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