1/*
2*******************************************************************************
3*
4*   Copyright (C) 1997-2011, 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 "umutex.h"
27#include "uresimp.h"
28
29// C++ API ----------------------------------------------------------------- ***
30
31static icu::Locale*  availableLocaleList = NULL;
32static int32_t  availableLocaleListCount;
33
34U_CDECL_BEGIN
35
36static UBool U_CALLCONV locale_available_cleanup(void)
37{
38    U_NAMESPACE_USE
39
40    if (availableLocaleList) {
41        delete []availableLocaleList;
42        availableLocaleList = NULL;
43    }
44    availableLocaleListCount = 0;
45
46    return TRUE;
47}
48
49U_CDECL_END
50
51U_NAMESPACE_BEGIN
52
53const Locale* U_EXPORT2
54Locale::getAvailableLocales(int32_t& count)
55{
56    // for now, there is a hardcoded list, so just walk through that list and set it up.
57    UBool needInit;
58    UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
59
60    if (needInit) {
61        int32_t locCount = uloc_countAvailable();
62        Locale *newLocaleList = 0;
63        if(locCount) {
64           newLocaleList = new Locale[locCount];
65        }
66        if (newLocaleList == NULL) {
67            count = 0;
68            return NULL;
69        }
70
71        count = locCount;
72
73        while(--locCount >= 0) {
74            newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
75        }
76
77        umtx_lock(NULL);
78        if(availableLocaleList == 0) {
79            availableLocaleListCount = count;
80            availableLocaleList = newLocaleList;
81            newLocaleList = NULL;
82            ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup);
83        }
84        umtx_unlock(NULL);
85        delete []newLocaleList;
86    }
87    count = availableLocaleListCount;
88    return availableLocaleList;
89}
90
91
92U_NAMESPACE_END
93
94// C API ------------------------------------------------------------------- ***
95
96U_NAMESPACE_USE
97
98/* ### Constants **************************************************/
99
100/* These strings describe the resources we attempt to load from
101 the locale ResourceBundle data file.*/
102static const char _kIndexLocaleName[] = "res_index";
103static const char _kIndexTag[]        = "InstalledLocales";
104
105static char** _installedLocales = NULL;
106static int32_t _installedLocalesCount = 0;
107
108/* ### Get available **************************************************/
109
110static UBool U_CALLCONV uloc_cleanup(void) {
111    char ** temp;
112
113    if (_installedLocales) {
114        temp = _installedLocales;
115        _installedLocales = NULL;
116
117        _installedLocalesCount = 0;
118
119        uprv_free(temp);
120    }
121    return TRUE;
122}
123
124static void _load_installedLocales()
125{
126    UBool   localesLoaded;
127
128    UMTX_CHECK(NULL, _installedLocales != NULL, localesLoaded);
129
130    if (localesLoaded == FALSE) {
131        UResourceBundle *indexLocale = NULL;
132        UResourceBundle installed;
133        UErrorCode status = U_ZERO_ERROR;
134        char ** temp;
135        int32_t i = 0;
136        int32_t localeCount;
137
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            temp = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
145            /* Check for null pointer */
146            if (temp != NULL) {
147                ures_resetIterator(&installed);
148                while(ures_hasNext(&installed)) {
149                    ures_getNextString(&installed, NULL, (const char **)&temp[i++], &status);
150                }
151                temp[i] = NULL;
152
153                umtx_lock(NULL);
154                if (_installedLocales == NULL)
155                {
156                    _installedLocalesCount = localeCount;
157                    _installedLocales = temp;
158                    temp = NULL;
159                    ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
160                }
161                umtx_unlock(NULL);
162
163                uprv_free(temp);
164            }
165        }
166        ures_close(&installed);
167        ures_close(indexLocale);
168    }
169}
170
171U_CAPI const char* U_EXPORT2
172uloc_getAvailable(int32_t offset)
173{
174
175    _load_installedLocales();
176
177    if (offset > _installedLocalesCount)
178        return NULL;
179    return _installedLocales[offset];
180}
181
182U_CAPI int32_t  U_EXPORT2
183uloc_countAvailable()
184{
185    _load_installedLocales();
186    return _installedLocalesCount;
187}
188