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