OLD | NEW |
1 /* | 1 /* |
2 ******************************************************************************* | 2 ******************************************************************************* |
3 * Copyright (C) 2002-2011, International Business Machines Corporation and | 3 * Copyright (C) 2002-2014, International Business Machines Corporation and |
4 * others. All Rights Reserved. | 4 * others. All Rights Reserved. |
5 ******************************************************************************* | 5 ******************************************************************************* |
6 */ | 6 */ |
7 #include "unicode/utypes.h" | 7 #include "unicode/utypes.h" |
8 | 8 |
9 #if !UCONFIG_NO_SERVICE || !UCONFIG_NO_TRANSLITERATION | 9 #if !UCONFIG_NO_SERVICE || !UCONFIG_NO_TRANSLITERATION |
10 | 10 |
11 #include "unicode/resbund.h" | 11 #include "unicode/resbund.h" |
12 #include "cmemory.h" | 12 #include "cmemory.h" |
13 #include "ustrfmt.h" | 13 #include "ustrfmt.h" |
14 #include "locutil.h" | 14 #include "locutil.h" |
15 #include "charstr.h" | 15 #include "charstr.h" |
16 #include "ucln_cmn.h" | 16 #include "ucln_cmn.h" |
17 #include "uassert.h" | 17 #include "uassert.h" |
18 #include "umutex.h" | 18 #include "umutex.h" |
19 | 19 |
20 // see LocaleUtility::getAvailableLocaleNames | 20 // see LocaleUtility::getAvailableLocaleNames |
| 21 static icu::UInitOnce LocaleUtilityInitOnce = U_INITONCE_INITIALIZER; |
21 static icu::Hashtable * LocaleUtility_cache = NULL; | 22 static icu::Hashtable * LocaleUtility_cache = NULL; |
22 | 23 |
23 #define UNDERSCORE_CHAR ((UChar)0x005f) | 24 #define UNDERSCORE_CHAR ((UChar)0x005f) |
24 #define AT_SIGN_CHAR ((UChar)64) | 25 #define AT_SIGN_CHAR ((UChar)64) |
25 #define PERIOD_CHAR ((UChar)46) | 26 #define PERIOD_CHAR ((UChar)46) |
26 | 27 |
27 /* | 28 /* |
28 ****************************************************************** | 29 ****************************************************************** |
29 */ | 30 */ |
30 | 31 |
31 /** | 32 /** |
32 * Release all static memory held by Locale Utility. | 33 * Release all static memory held by Locale Utility. |
33 */ | 34 */ |
34 U_CDECL_BEGIN | 35 U_CDECL_BEGIN |
35 static UBool U_CALLCONV service_cleanup(void) { | 36 static UBool U_CALLCONV service_cleanup(void) { |
36 if (LocaleUtility_cache) { | 37 if (LocaleUtility_cache) { |
37 delete LocaleUtility_cache; | 38 delete LocaleUtility_cache; |
38 LocaleUtility_cache = NULL; | 39 LocaleUtility_cache = NULL; |
39 } | 40 } |
40 return TRUE; | 41 return TRUE; |
41 } | 42 } |
| 43 |
| 44 |
| 45 static void U_CALLCONV locale_utility_init(UErrorCode &status) { |
| 46 using namespace icu; |
| 47 U_ASSERT(LocaleUtility_cache == NULL); |
| 48 ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup); |
| 49 LocaleUtility_cache = new Hashtable(status); |
| 50 if (U_FAILURE(status)) { |
| 51 delete LocaleUtility_cache; |
| 52 LocaleUtility_cache = NULL; |
| 53 return; |
| 54 } |
| 55 if (LocaleUtility_cache == NULL) { |
| 56 status = U_MEMORY_ALLOCATION_ERROR; |
| 57 return; |
| 58 } |
| 59 LocaleUtility_cache->setValueDeleter(uhash_deleteHashtable); |
| 60 } |
| 61 |
42 U_CDECL_END | 62 U_CDECL_END |
43 | 63 |
44 U_NAMESPACE_BEGIN | 64 U_NAMESPACE_BEGIN |
45 | 65 |
46 UnicodeString& | 66 UnicodeString& |
47 LocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& res
ult) | 67 LocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& res
ult) |
48 { | 68 { |
49 if (id == NULL) { | 69 if (id == NULL) { |
50 result.setToBogus(); | 70 result.setToBogus(); |
51 } else { | 71 } else { |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) | 202 LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) |
183 { | 203 { |
184 // LocaleUtility_cache is a hash-of-hashes. The top-level keys | 204 // LocaleUtility_cache is a hash-of-hashes. The top-level keys |
185 // are path strings ('bundleID') passed to | 205 // are path strings ('bundleID') passed to |
186 // ures_openAvailableLocales. The top-level values are | 206 // ures_openAvailableLocales. The top-level values are |
187 // second-level hashes. The second-level keys are result strings | 207 // second-level hashes. The second-level keys are result strings |
188 // from ures_openAvailableLocales. The second-level values are | 208 // from ures_openAvailableLocales. The second-level values are |
189 // garbage ((void*)1 or other random pointer). | 209 // garbage ((void*)1 or other random pointer). |
190 | 210 |
191 UErrorCode status = U_ZERO_ERROR; | 211 UErrorCode status = U_ZERO_ERROR; |
192 Hashtable* cache; | 212 umtx_initOnce(LocaleUtilityInitOnce, locale_utility_init, status); |
193 umtx_lock(NULL); | 213 Hashtable *cache = LocaleUtility_cache; |
194 cache = LocaleUtility_cache; | |
195 umtx_unlock(NULL); | |
196 | |
197 if (cache == NULL) { | 214 if (cache == NULL) { |
198 cache = new Hashtable(status); | 215 // Catastrophic failure. |
199 if (cache == NULL || U_FAILURE(status)) { | 216 return NULL; |
200 return NULL; // catastrophic failure; e.g. out of memory | |
201 } | |
202 cache->setValueDeleter(uhash_deleteHashtable); | |
203 Hashtable* h; // set this to final LocaleUtility_cache value | |
204 umtx_lock(NULL); | |
205 h = LocaleUtility_cache; | |
206 if (h == NULL) { | |
207 LocaleUtility_cache = h = cache; | |
208 cache = NULL; | |
209 ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup); | |
210 } | |
211 umtx_unlock(NULL); | |
212 if(cache != NULL) { | |
213 delete cache; | |
214 } | |
215 cache = h; | |
216 } | 217 } |
217 | 218 |
218 U_ASSERT(cache != NULL); | |
219 | |
220 Hashtable* htp; | 219 Hashtable* htp; |
221 umtx_lock(NULL); | 220 umtx_lock(NULL); |
222 htp = (Hashtable*) cache->get(bundleID); | 221 htp = (Hashtable*) cache->get(bundleID); |
223 umtx_unlock(NULL); | 222 umtx_unlock(NULL); |
224 | 223 |
225 if (htp == NULL) { | 224 if (htp == NULL) { |
226 htp = new Hashtable(status); | 225 htp = new Hashtable(status); |
227 if (htp && U_SUCCESS(status)) { | 226 if (htp && U_SUCCESS(status)) { |
228 CharString cbundleID; | 227 CharString cbundleID; |
229 cbundleID.appendInvariantChars(bundleID, status); | 228 cbundleID.appendInvariantChars(bundleID, status); |
230 const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data(); | 229 const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data(); |
231 UEnumeration *uenum = ures_openAvailableLocales(path, &status); | 230 UEnumeration *uenum = ures_openAvailableLocales(path, &status); |
232 for (;;) { | 231 for (;;) { |
233 const UChar* id = uenum_unext(uenum, NULL, &status); | 232 const UChar* id = uenum_unext(uenum, NULL, &status); |
234 if (id == NULL) { | 233 if (id == NULL) { |
235 break; | 234 break; |
236 } | 235 } |
237 htp->put(UnicodeString(id), (void*)htp, status); | 236 htp->put(UnicodeString(id), (void*)htp, status); |
238 } | 237 } |
239 uenum_close(uenum); | 238 uenum_close(uenum); |
240 if (U_FAILURE(status)) { | 239 if (U_FAILURE(status)) { |
241 delete htp; | 240 delete htp; |
242 return NULL; | 241 return NULL; |
243 } | 242 } |
244 umtx_lock(NULL); | 243 umtx_lock(NULL); |
245 cache->put(bundleID, (void*)htp, status); | 244 Hashtable *t = static_cast<Hashtable *>(cache->get(bundleID)); |
246 umtx_unlock(NULL); | 245 if (t != NULL) { |
| 246 // Another thread raced through this code, creating the cache en
try first. |
| 247 // Discard ours and return theirs. |
| 248 umtx_unlock(NULL); |
| 249 delete htp; |
| 250 htp = t; |
| 251 } else { |
| 252 cache->put(bundleID, (void*)htp, status); |
| 253 umtx_unlock(NULL); |
| 254 } |
247 } | 255 } |
248 } | 256 } |
249 return htp; | 257 return htp; |
250 } | 258 } |
251 | 259 |
252 UBool | 260 UBool |
253 LocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& chil
d) | 261 LocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& chil
d) |
254 { | 262 { |
255 return child.indexOf(root) == 0 && | 263 return child.indexOf(root) == 0 && |
256 (child.length() == root.length() || | 264 (child.length() == root.length() || |
257 child.charAt(root.length()) == UNDERSCORE_CHAR); | 265 child.charAt(root.length()) == UNDERSCORE_CHAR); |
258 } | 266 } |
259 | 267 |
260 U_NAMESPACE_END | 268 U_NAMESPACE_END |
261 | 269 |
262 /* !UCONFIG_NO_SERVICE */ | 270 /* !UCONFIG_NO_SERVICE */ |
263 #endif | 271 #endif |
264 | 272 |
265 | 273 |
OLD | NEW |