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
32U_NAMESPACE_BEGIN
33
34static icu::Locale*  availableLocaleList = NULL;
35static int32_t  availableLocaleListCount;
36static icu::UInitOnce gInitOnce = U_INITONCE_INITIALIZER;
37
38U_NAMESPACE_END
39
40U_CDECL_BEGIN
41
42static 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
56U_CDECL_END
57
58U_NAMESPACE_BEGIN
59
60void 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
79const Locale* U_EXPORT2
80Locale::getAvailableLocales(int32_t& count)
81{
82    umtx_initOnce(gInitOnce, &locale_available_init);
83    count = availableLocaleListCount;
84    return availableLocaleList;
85}
86
87
88U_NAMESPACE_END
89
90// C API ------------------------------------------------------------------- ***
91
92U_NAMESPACE_USE
93
94/* ### Constants **************************************************/
95
96/* These strings describe the resources we attempt to load from
97 the locale ResourceBundle data file.*/
98static const char _kIndexLocaleName[] = "res_index";
99static const char _kIndexTag[]        = "InstalledLocales";
100
101static char** _installedLocales = NULL;
102static int32_t _installedLocalesCount = 0;
103static icu::UInitOnce _installedLocalesInitOnce;
104
105/* ### Get available **************************************************/
106
107static 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
125static 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
157static void _load_installedLocales()
158{
159    umtx_initOnce(_installedLocalesInitOnce, &loadInstalledLocales);
160}
161
162U_CAPI const char* U_EXPORT2
163uloc_getAvailable(int32_t offset)
164{
165
166    _load_installedLocales();
167
168    if (offset > _installedLocalesCount)
169        return NULL;
170    return _installedLocales[offset];
171}
172
173U_CAPI int32_t  U_EXPORT2
174uloc_countAvailable()
175{
176    _load_installedLocales();
177    return _installedLocalesCount;
178}
179
180