]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/locavailable.cpp
ICU-59173.0.1.tar.gz
[apple/icu.git] / icuSources / common / locavailable.cpp
index c8baf753d6b5ba9f5d0174e55db26a99119eada3..f054db3fa0cf9409a6e5c1faa3cdd6b8f6a00846 100644 (file)
@@ -1,12 +1,14 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
 *
-*   Copyright (C) 1997-2011, International Business Machines
+*   Copyright (C) 1997-2013, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 *******************************************************************************
 *   file name:  locavailable.cpp
-*   encoding:   US-ASCII
+*   encoding:   UTF-8
 *   tab size:   8 (not used)
 *   indentation:4
 *
 #include "unicode/ures.h"
 #include "cmemory.h"
 #include "ucln_cmn.h"
+#include "uassert.h"
 #include "umutex.h"
 #include "uresimp.h"
 
 // C++ API ----------------------------------------------------------------- ***
 
+U_NAMESPACE_BEGIN
+
 static icu::Locale*  availableLocaleList = NULL;
 static int32_t  availableLocaleListCount;
+static icu::UInitOnce gInitOnce = U_INITONCE_INITIALIZER;
+
+U_NAMESPACE_END
 
 U_CDECL_BEGIN
 
@@ -42,6 +50,7 @@ static UBool U_CALLCONV locale_available_cleanup(void)
         availableLocaleList = NULL;
     }
     availableLocaleListCount = 0;
+    gInitOnce.reset();
 
     return TRUE;
 }
@@ -50,40 +59,29 @@ U_CDECL_END
 
 U_NAMESPACE_BEGIN
 
+void U_CALLCONV locale_available_init() {
+    // This function is a friend of class Locale.
+    // This function is only invoked via umtx_initOnce().
+    
+    // for now, there is a hardcoded list, so just walk through that list and set it up.
+    //  Note: this function is a friend of class Locale.
+    availableLocaleListCount = uloc_countAvailable();
+    if(availableLocaleListCount) {
+       availableLocaleList = new Locale[availableLocaleListCount];
+    }
+    if (availableLocaleList == NULL) {
+        availableLocaleListCount= 0;
+    }
+    for (int32_t locCount=availableLocaleListCount-1; locCount>=0; --locCount) {
+        availableLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
+    }
+    ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup);
+}
+
 const Locale* U_EXPORT2
 Locale::getAvailableLocales(int32_t& count)
 {
-    // for now, there is a hardcoded list, so just walk through that list and set it up.
-    UBool needInit;
-    UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
-
-    if (needInit) {
-        int32_t locCount = uloc_countAvailable();
-        Locale *newLocaleList = 0;
-        if(locCount) {
-           newLocaleList = new Locale[locCount];
-        }
-        if (newLocaleList == NULL) {
-            count = 0;
-            return NULL;
-        }
-
-        count = locCount;
-
-        while(--locCount >= 0) {
-            newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
-        }
-
-        umtx_lock(NULL);
-        if(availableLocaleList == 0) {
-            availableLocaleListCount = count;
-            availableLocaleList = newLocaleList;
-            newLocaleList = NULL;
-            ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup);
-        }
-        umtx_unlock(NULL);
-        delete []newLocaleList;
-    }
+    umtx_initOnce(gInitOnce, &locale_available_init);
     count = availableLocaleListCount;
     return availableLocaleList;
 }
@@ -104,6 +102,7 @@ static const char _kIndexTag[]        = "InstalledLocales";
 
 static char** _installedLocales = NULL;
 static int32_t _installedLocalesCount = 0;
+static icu::UInitOnce _installedLocalesInitOnce;
 
 /* ### Get available **************************************************/
 
@@ -115,57 +114,51 @@ static UBool U_CALLCONV uloc_cleanup(void) {
         _installedLocales = NULL;
 
         _installedLocalesCount = 0;
+        _installedLocalesInitOnce.reset();
 
         uprv_free(temp);
     }
     return TRUE;
 }
 
-static void _load_installedLocales()
-{
-    UBool   localesLoaded;
+// Load Installed Locales. This function will be called exactly once
+//   via the initOnce mechanism.
 
-    UMTX_CHECK(NULL, _installedLocales != NULL, localesLoaded);
+static void U_CALLCONV loadInstalledLocales() {
+    UResourceBundle *indexLocale = NULL;
+    UResourceBundle installed;
+    UErrorCode status = U_ZERO_ERROR;
+    int32_t i = 0;
+    int32_t localeCount;
     
-    if (localesLoaded == FALSE) {
-        UResourceBundle *indexLocale = NULL;
-        UResourceBundle installed;
-        UErrorCode status = U_ZERO_ERROR;
-        char ** temp;
-        int32_t i = 0;
-        int32_t localeCount;
-        
-        ures_initStackObject(&installed);
-        indexLocale = ures_openDirect(NULL, _kIndexLocaleName, &status);
-        ures_getByKey(indexLocale, _kIndexTag, &installed, &status);
-        
-        if(U_SUCCESS(status)) {
-            localeCount = ures_getSize(&installed);
-            temp = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
-            /* Check for null pointer */
-            if (temp != NULL) {
-                ures_resetIterator(&installed);
-                while(ures_hasNext(&installed)) {
-                    ures_getNextString(&installed, NULL, (const char **)&temp[i++], &status);
-                }
-                temp[i] = NULL;
-
-                umtx_lock(NULL);
-                if (_installedLocales == NULL)
-                {
-                    _installedLocalesCount = localeCount;
-                    _installedLocales = temp;
-                    temp = NULL;
-                    ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
-                } 
-                umtx_unlock(NULL);
-
-                uprv_free(temp);
+    U_ASSERT(_installedLocales == NULL);
+    U_ASSERT(_installedLocalesCount == 0);
+
+    _installedLocalesCount = 0;
+    ures_initStackObject(&installed);
+    indexLocale = ures_openDirect(NULL, _kIndexLocaleName, &status);
+    ures_getByKey(indexLocale, _kIndexTag, &installed, &status);
+    
+    if(U_SUCCESS(status)) {
+        localeCount = ures_getSize(&installed);
+        _installedLocales = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
+        if (_installedLocales != NULL) {
+            ures_resetIterator(&installed);
+            while(ures_hasNext(&installed)) {
+                ures_getNextString(&installed, NULL, (const char **)&_installedLocales[i++], &status);
             }
+            _installedLocales[i] = NULL;
+            _installedLocalesCount = localeCount;
+            ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
         }
-        ures_close(&installed);
-        ures_close(indexLocale);
     }
+    ures_close(&installed);
+    ures_close(indexLocale);
+}
+
+static void _load_installedLocales()
+{
+    umtx_initOnce(_installedLocalesInitOnce, &loadInstalledLocales);
 }
 
 U_CAPI const char* U_EXPORT2
@@ -185,3 +178,4 @@ uloc_countAvailable()
     _load_installedLocales();
     return _installedLocalesCount;
 }
+