| 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 |