]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/putil.cpp
ICU-57132.0.1.tar.gz
[apple/icu.git] / icuSources / common / putil.cpp
index 01b0683c31f6139458da30eb021048934e3888b1..46978812a4e31d0641d6c54c62e34ca0fff79f4e 100644 (file)
@@ -1,7 +1,7 @@
 /*
 ******************************************************************************
 *
-*   Copyright (C) 1997-2013, International Business Machines
+*   Copyright (C) 1997-2016, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 ******************************************************************************
@@ -52,6 +52,7 @@
 #include "cstring.h"
 #include "locmap.h"
 #include "ucln_cmn.h"
+#include "charstr.h"
 
 /* Include standard headers. */
 #include <stdio.h>
 #   include <qusrjobi.h>
 #   include <qliept.h>      /* EPT_CALL macro  - this include must be after all other "QSYSINCs" */
 #   include <mih/testptr.h> /* For uprv_maximumPtr */
-#elif U_PLATFORM == U_PF_CLASSIC_MACOS
-#   include <Files.h>
-#   include <IntlResources.h>
-#   include <Script.h>
-#   include <Folders.h>
-#   include <MacTypes.h>
-#   include <TextUtils.h>
-#   define ICU_NO_USER_DATA_OVERRIDE 1
 #elif U_PLATFORM == U_PF_OS390
 #   include "unicode/ucnv.h"   /* Needed for UCNV_SWAP_LFNL_OPTION_STRING */
 #elif U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS
 #   define HAVE_GETTIMEOFDAY 0
 #endif
 
-#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+U_NAMESPACE_USE
 
 /* Define the extension for data files, again... */
 #define DATA_TYPE "dat"
@@ -187,7 +180,7 @@ static const BitPatternConversion gInf = { (int64_t) INT64_C(0x7FF0000000000000)
   functions).
   ---------------------------------------------------------------------------*/
 
-#if U_PLATFORM_USES_ONLY_WIN32_API || U_PLATFORM == U_PF_CLASSIC_MACOS || U_PLATFORM == U_PF_OS400
+#if U_PLATFORM_USES_ONLY_WIN32_API || U_PLATFORM == U_PF_OS400
 #   undef U_POSIX_LOCALE
 #else
 #   define U_POSIX_LOCALE    1
@@ -306,21 +299,7 @@ uprv_getUTCtime()
 U_CAPI UDate U_EXPORT2
 uprv_getRawUTCtime()
 {
-#if U_PLATFORM == U_PF_CLASSIC_MACOS
-    time_t t, t1, t2;
-    struct tm tmrec;
-
-    uprv_memset( &tmrec, 0, sizeof(tmrec) );
-    tmrec.tm_year = 70;
-    tmrec.tm_mon = 0;
-    tmrec.tm_mday = 1;
-    t1 = mktime(&tmrec);    /* seconds of 1/1/1970*/
-
-    time(&t);
-    uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
-    t2 = mktime(&tmrec);    /* seconds of current GMT*/
-    return (UDate)(t2 - t1) * U_MILLIS_PER_SECOND;         /* GMT (or UTC) in seconds since 1970*/
-#elif U_PLATFORM_USES_ONLY_WIN32_API
+#if U_PLATFORM_USES_ONLY_WIN32_API
 
     FileTimeConversion winTime;
     GetSystemTimeAsFileTime(&winTime.fileTime);
@@ -639,27 +618,30 @@ uprv_timezone()
 #else
     time_t t, t1, t2;
     struct tm tmrec;
-    UBool dst_checked;
     int32_t tdiff = 0;
 
     time(&t);
     uprv_memcpy( &tmrec, localtime(&t), sizeof(tmrec) );
-    dst_checked = (tmrec.tm_isdst != 0); /* daylight savings time is checked*/
+#if U_PLATFORM != U_PF_IPHONE
+    UBool dst_checked = (tmrec.tm_isdst != 0); /* daylight savings time is checked*/
+#endif
     t1 = mktime(&tmrec);                 /* local time in seconds*/
     uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
     t2 = mktime(&tmrec);                 /* GMT (or UTC) in seconds*/
     tdiff = t2 - t1;
+
+#if U_PLATFORM != U_PF_IPHONE
     /* imitate NT behaviour, which returns same timezone offset to GMT for
        winter and summer.
        This does not work on all platforms. For instance, on glibc on Linux
        and on Mac OS 10.5, tdiff calculated above remains the same
-       regardless of whether DST is in effect or not. However, U_TIMEZONE
-       is defined on those platforms and this code is not reached so that
-       we can leave this alone. If there's a platform behaving
-       like glibc that uses this code, we need to add platform-dependent
-       preprocessor here. */
+       regardless of whether DST is in effect or not. iOS is another
+       platform where this does not work. Linux + glibc and Mac OS 10.5
+       have U_TIMEZONE defined so that this code is not reached.
+    */
     if (dst_checked)
         tdiff += 3600;
+#endif
     return tdiff;
 #endif
 }
@@ -672,7 +654,7 @@ uprv_timezone()
 extern U_IMPORT char *U_TZNAME[];
 #endif
 
-#if !UCONFIG_NO_FILE_IO && (U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS)
+#if !UCONFIG_NO_FILE_IO && ((U_PLATFORM_IS_DARWIN_BASED && (U_PLATFORM != U_PF_IPHONE || defined(U_TIMEZONE))) || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS)
 /* These platforms are likely to use Olson timezone IDs. */
 #define CHECK_LOCALTIME_LINK 1
 #if U_PLATFORM_IS_DARWIN_BASED
@@ -681,6 +663,7 @@ extern U_IMPORT char *U_TZNAME[];
 #elif U_PLATFORM == U_PF_SOLARIS
 #define TZDEFAULT       "/etc/localtime"
 #define TZZONEINFO      "/usr/share/lib/zoneinfo/"
+#define TZZONEINFO2     "../usr/share/lib/zoneinfo/"
 #define TZ_ENV_CHECK    "localtime"
 #else
 #define TZDEFAULT       "/etc/localtime"
@@ -834,7 +817,7 @@ static const char* remapShortTimeZone(const char *stdID, const char *dstID, int3
 #ifdef DEBUG_TZNAME
     fprintf(stderr, "TZ=%s std=%s dst=%s daylight=%d offset=%d\n", getenv("TZ"), stdID, dstID, daylightType, offset);
 #endif
-    for (idx = 0; idx < LENGTHOF(OFFSET_ZONE_MAPPINGS); idx++)
+    for (idx = 0; idx < UPRV_LENGTHOF(OFFSET_ZONE_MAPPINGS); idx++)
     {
         if (offset == OFFSET_ZONE_MAPPINGS[idx].offsetSeconds
             && daylightType == OFFSET_ZONE_MAPPINGS[idx].daylightType
@@ -1017,6 +1000,10 @@ uprv_tzname(int n)
         && uprv_strcmp(tzid, TZ_ENV_CHECK) != 0
 #endif
     ) {
+        /* The colon forces tzset() to treat the remainder as zoneinfo path */ 
+        if (tzid[0] == ':') { 
+            tzid++; 
+        } 
         /* This might be a good Olson ID. */
         skipZoneIDPrefix(&tzid);
         return tzid;
@@ -1041,6 +1028,17 @@ uprv_tzname(int n)
             {
                 return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
             }
+#if U_PLATFORM == U_PF_SOLARIS
+            else
+            {
+                tzZoneInfoLen = uprv_strlen(TZZONEINFO2);
+                if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO2, tzZoneInfoLen) == 0
+                                && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
+                {
+                    return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
+                }
+            }
+#endif
         } else {
 #if defined(SEARCH_TZFILE)
             DefaultTZInfo* tzInfo = (DefaultTZInfo*)uprv_malloc(sizeof(DefaultTZInfo));
@@ -1119,8 +1117,13 @@ uprv_tzname(int n)
 
 /* Get and set the ICU data directory --------------------------------------- */
 
+static icu::UInitOnce gDataDirInitOnce = U_INITONCE_INITIALIZER;
 static char *gDataDirectory = NULL;
-#if U_POSIX_LOCALE
+
+UInitOnce gTimeZoneFilesInitOnce = U_INITONCE_INITIALIZER;
+static CharString *gTimeZoneFilesDirectory = NULL;
+
+#if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
  static char *gCorrectedPOSIXLocale = NULL; /* Heap allocated */
 #endif
 
@@ -1130,7 +1133,13 @@ static UBool U_CALLCONV putil_cleanup(void)
         uprv_free(gDataDirectory);
     }
     gDataDirectory = NULL;
-#if U_POSIX_LOCALE
+    gDataDirInitOnce.reset();
+
+    delete gTimeZoneFilesDirectory;
+    gTimeZoneFilesDirectory = NULL;
+    gTimeZoneFilesInitOnce.reset();
+
+#if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
     if (gCorrectedPOSIXLocale) {
         uprv_free(gCorrectedPOSIXLocale);
         gCorrectedPOSIXLocale = NULL;
@@ -1142,7 +1151,6 @@ static UBool U_CALLCONV putil_cleanup(void)
 /*
  * Set the data directory.
  *    Make a copy of the passed string, and set the global data dir to point to it.
- *    TODO:  see bug #2849, regarding thread safety.
  */
 U_CAPI void U_EXPORT2
 u_setDataDirectory(const char *directory) {
@@ -1175,13 +1183,11 @@ u_setDataDirectory(const char *directory) {
 #endif
     }
 
-    umtx_lock(NULL);
     if (gDataDirectory && *gDataDirectory) {
         uprv_free(gDataDirectory);
     }
     gDataDirectory = newDataDir;
     ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
-    umtx_unlock(NULL);
 }
 
 U_CAPI UBool U_EXPORT2
@@ -1220,20 +1226,19 @@ uprv_pathIsAbsolute(const char *path)
 # endif
 #endif
 
-U_CAPI const char * U_EXPORT2
-u_getDataDirectory(void) {
+static void U_CALLCONV dataDirectoryInitFn() {
+    /* If we already have the directory, then return immediately. Will happen if user called
+     * u_setDataDirectory().
+     */
+    if (gDataDirectory) {
+        return;
+    }
+
     const char *path = NULL;
 #if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
     char datadir_path_buffer[PATH_MAX];
 #endif
 
-    /* if we have the directory, then return it immediately */
-    UMTX_CHECK(NULL, gDataDirectory, path);
-
-    if(path) {
-        return path;
-    }
-
     /*
     When ICU_NO_USER_DATA_OVERRIDE is defined, users aren't allowed to
     override ICU's data with the ICU_DATA environment variable. This prevents
@@ -1284,117 +1289,106 @@ u_getDataDirectory(void) {
     }
 
     u_setDataDirectory(path);
+    return;
+}
+
+U_CAPI const char * U_EXPORT2
+u_getDataDirectory(void) {
+    umtx_initOnce(gDataDirInitOnce, &dataDirectoryInitFn);
     return gDataDirectory;
 }
 
+static void setTimeZoneFilesDir(const char *path, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    gTimeZoneFilesDirectory->clear();
+    gTimeZoneFilesDirectory->append(path, status);
+#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
+    char *p = gTimeZoneFilesDirectory->data();
+    while (p = uprv_strchr(p, U_FILE_ALT_SEP_CHAR)) {
+        *p = U_FILE_SEP_CHAR;
+    }
+#endif
+}
+
+#if U_PLATFORM_IMPLEMENTS_POSIX
+#include <sys/stat.h>
+#if defined(U_TIMEZONE_FILES_DIR)
+const char tzdirbuf[] = U_TIMEZONE_FILES_DIR;
+enum { kTzfilenamebufLen = UPRV_LENGTHOF(tzdirbuf) + 24 }; // extra room for "/icutz44l.dat" or "/zoneinfo64.res"
+#endif
+#endif
 
+#define TO_STRING(x) TO_STRING_2(x) 
+#define TO_STRING_2(x) #x
 
+static void U_CALLCONV TimeZoneDataDirInitFn(UErrorCode &status) {
+    U_ASSERT(gTimeZoneFilesDirectory == NULL);
+    ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
+    gTimeZoneFilesDirectory = new CharString();
+    if (gTimeZoneFilesDirectory == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    const char *dir = getenv("ICU_TIMEZONE_FILES_DIR");
+    UBool usingUTzFilesDir = FALSE;
+#if defined(U_TIMEZONE_FILES_DIR)
+    if (dir == NULL) {
+        // dir = TO_STRING(U_TIMEZONE_FILES_DIR);
+        // Not sure why the above was done for this path only;
+        // it preserves unwanted quotes.
+        dir = tzdirbuf;
+        usingUTzFilesDir = TRUE;
+    }
+#endif
+#if U_PLATFORM_IMPLEMENTS_POSIX
+    if (dir != NULL) {
+        struct stat buf;
+        if (stat(dir, &buf) != 0) {
+            dir = NULL;
+        }
+#if defined(U_TIMEZONE_FILES_DIR)
+        else if (usingUTzFilesDir) {
+            char tzfilenamebuf[kTzfilenamebufLen];
+            uprv_strcpy(tzfilenamebuf, tzdirbuf);
+            uprv_strcat(tzfilenamebuf, U_FILE_SEP_STRING);
+#if defined(U_TIMEZONE_PACKAGE)
+            uprv_strcat(tzfilenamebuf, U_TIMEZONE_PACKAGE);
+            uprv_strcat(tzfilenamebuf, ".dat");
+#else
+            uprv_strcat(tzfilenamebuf, "zoneinfo64.res");
+#endif
+            if (stat(tzfilenamebuf, &buf) != 0) {
+                dir = NULL;
+            }
+        }
+#endif /* defined(U_TIMEZONE_FILES_DIR) */
+    }
+#endif /* U_PLATFORM_IMPLEMENTS_POSIX */
+    if (dir == NULL) {
+        dir = "";
+    }
+    setTimeZoneFilesDir(dir, status);
+}
 
 
-/* Macintosh-specific locale information ------------------------------------ */
-#if U_PLATFORM == U_PF_CLASSIC_MACOS
-
-typedef struct {
-    int32_t script;
-    int32_t region;
-    int32_t lang;
-    int32_t date_region;
-    const char* posixID;
-} mac_lc_rec;
-
-/* Todo: This will be updated with a newer version from www.unicode.org web
-   page when it's available.*/
-#define MAC_LC_MAGIC_NUMBER -5
-#define MAC_LC_INIT_NUMBER -9
-
-static const mac_lc_rec mac_lc_recs[] = {
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 0, "en_US",
-    /* United States*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 1, "fr_FR",
-    /* France*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 2, "en_GB",
-    /* Great Britain*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 3, "de_DE",
-    /* Germany*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 4, "it_IT",
-    /* Italy*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 5, "nl_NL",
-    /* Metherlands*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 6, "fr_BE",
-    /* French for Belgium or Lxembourg*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 7, "sv_SE",
-    /* Sweden*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 9, "da_DK",
-    /* Denmark*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 10, "pt_PT",
-    /* Portugal*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 11, "fr_CA",
-    /* French Canada*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 13, "is_IS",
-    /* Israel*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 14, "ja_JP",
-    /* Japan*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 15, "en_AU",
-    /* Australia*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 16, "ar_AE",
-    /* the Arabic world (?)*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 17, "fi_FI",
-    /* Finland*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 18, "fr_CH",
-    /* French for Switzerland*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 19, "de_CH",
-    /* German for Switzerland*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 20, "el_GR",
-    /* Greece*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 21, "is_IS",
-    /* Iceland ===*/
-    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 22, "",*/
-    /* Malta ===*/
-    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 23, "",*/
-    /* Cyprus ===*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 24, "tr_TR",
-    /* Turkey ===*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 25, "sh_YU",
-    /* Croatian system for Yugoslavia*/
-    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 33, "",*/
-    /* Hindi system for India*/
-    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 34, "",*/
-    /* Pakistan*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 41, "lt_LT",
-    /* Lithuania*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 42, "pl_PL",
-    /* Poland*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 43, "hu_HU",
-    /* Hungary*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 44, "et_EE",
-    /* Estonia*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 45, "lv_LV",
-    /* Latvia*/
-    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 46, "",*/
-    /* Lapland  [Ask Rich for the data. HS]*/
-    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 47, "",*/
-    /* Faeroe Islands*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 48, "fa_IR",
-    /* Iran*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 49, "ru_RU",
-    /* Russia*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 50, "en_IE",
-    /* Ireland*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 51, "ko_KR",
-    /* Korea*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 52, "zh_CN",
-    /* People's Republic of China*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 53, "zh_TW",
-    /* Taiwan*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 54, "th_TH",
-    /* Thailand*/
-
-    /* fallback is en_US*/
-    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER,
-    MAC_LC_MAGIC_NUMBER, "en_US"
-};
+U_CAPI const char * U_EXPORT2
+u_getTimeZoneFilesDirectory(UErrorCode *status) {
+    umtx_initOnce(gTimeZoneFilesInitOnce, &TimeZoneDataDirInitFn, *status);
+    return U_SUCCESS(*status) ? gTimeZoneFilesDirectory->data() : "";
+}
+
+U_CAPI void U_EXPORT2
+u_setTimeZoneFilesDirectory(const char *path, UErrorCode *status) {
+    umtx_initOnce(gTimeZoneFilesInitOnce, &TimeZoneDataDirInitFn, *status);
+    setTimeZoneFilesDir(path, *status);
+
+    // Note: this function does some extra churn, first setting based on the
+    //       environment, then immediately replacing with the value passed in.
+    //       The logic is simpler that way, and performance shouldn't be an issue.
+}
 
-#endif
 
 #if U_POSIX_LOCALE
 /* A helper function used by uprv_getPOSIXIDForDefaultLocale and
@@ -1430,9 +1424,18 @@ static const char *uprv_getPOSIXIDForCategory(int category)
         {
             /* Maybe we got some garbage.  Try something more reasonable */
             posixID = getenv("LC_ALL");
+            /* Solaris speaks POSIX -  See IEEE Std 1003.1-2008 
+             * This is needed to properly handle empty env. variables
+             */
+#if U_PLATFORM == U_PF_SOLARIS
+            if ((posixID == 0) || (posixID[0] == '\0')) {
+                posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
+                if ((posixID == 0) || (posixID[0] == '\0')) {
+#else
             if (posixID == 0) {
                 posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
                 if (posixID == 0) {
+#endif                    
                     posixID = getenv("LANG");
                 }
             }
@@ -1605,49 +1608,31 @@ The leftmost codepage (.xxx) wins.
     return posixID;
 
 #elif U_PLATFORM_USES_ONLY_WIN32_API
+#define POSIX_LOCALE_CAPACITY 64
     UErrorCode status = U_ZERO_ERROR;
-    LCID id = GetThreadLocale();
-    const char* locID = uprv_convertToPosix(id, &status);
+    char *correctedPOSIXLocale = 0;
 
-    if (U_FAILURE(status)) {
-        locID = "en_US";
-    }
-    return locID;
-
-#elif U_PLATFORM == U_PF_CLASSIC_MACOS
-    int32_t script = MAC_LC_INIT_NUMBER;
-    /* = IntlScript(); or GetScriptManagerVariable(smSysScript);*/
-    int32_t region = MAC_LC_INIT_NUMBER;
-    /* = GetScriptManagerVariable(smRegionCode);*/
-    int32_t lang = MAC_LC_INIT_NUMBER;
-    /* = GetScriptManagerVariable(smScriptLang);*/
-    int32_t date_region = MAC_LC_INIT_NUMBER;
-    const char* posixID = 0;
-    int32_t count = sizeof(mac_lc_recs) / sizeof(mac_lc_rec);
-    int32_t i;
-    Intl1Hndl ih;
-
-    ih = (Intl1Hndl) GetIntlResource(1);
-    if (ih)
-        date_region = ((uint16_t)(*ih)->intl1Vers) >> 8;
-
-    for (i = 0; i < count; i++) {
-        if (   ((mac_lc_recs[i].script == MAC_LC_MAGIC_NUMBER)
-             || (mac_lc_recs[i].script == script))
-            && ((mac_lc_recs[i].region == MAC_LC_MAGIC_NUMBER)
-             || (mac_lc_recs[i].region == region))
-            && ((mac_lc_recs[i].lang == MAC_LC_MAGIC_NUMBER)
-             || (mac_lc_recs[i].lang == lang))
-            && ((mac_lc_recs[i].date_region == MAC_LC_MAGIC_NUMBER)
-             || (mac_lc_recs[i].date_region == date_region))
-            )
-        {
-            posixID = mac_lc_recs[i].posixID;
-            break;
+    if (gCorrectedPOSIXLocale != NULL) {
+        return gCorrectedPOSIXLocale;
+    }
+
+    LCID id = GetThreadLocale();
+    correctedPOSIXLocale = static_cast<char *>(uprv_malloc(POSIX_LOCALE_CAPACITY + 1));
+    if (correctedPOSIXLocale) {
+        int32_t posixLen = uprv_convertToPosix(id, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status);
+        if (U_SUCCESS(status)) {
+            *(correctedPOSIXLocale + posixLen) = 0;
+            gCorrectedPOSIXLocale = correctedPOSIXLocale;
+            ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
+        } else {
+            uprv_free(correctedPOSIXLocale);
         }
     }
 
-    return posixID;
+    if (gCorrectedPOSIXLocale == NULL) {
+        return "en_US";
+    }
+    return gCorrectedPOSIXLocale;
 
 #elif U_PLATFORM == U_PF_OS400
     /* locales are process scoped and are by definition thread safe */
@@ -1930,9 +1915,6 @@ int_getDefaultCodepage()
 
     return codepage;
 
-#elif U_PLATFORM == U_PF_CLASSIC_MACOS
-    return "macintosh"; /* TODO: Macintosh Roman. There must be a better way. fixme! */
-
 #elif U_PLATFORM_USES_ONLY_WIN32_API
     static char codepage[64];
     sprintf(codepage, "windows-%d", GetACP());
@@ -1945,7 +1927,10 @@ int_getDefaultCodepage()
 
     localeName = uprv_getPOSIXIDForDefaultCodepage();
     uprv_memset(codesetName, 0, sizeof(codesetName));
-#if U_HAVE_NL_LANGINFO_CODESET
+    /* On Solaris nl_langinfo returns C locale values unless setlocale
+     * was called earlier.
+     */
+#if (U_HAVE_NL_LANGINFO_CODESET && U_PLATFORM != U_PF_SOLARIS)
     /* When available, check nl_langinfo first because it usually gives more
        useful names. It depends on LC_CTYPE.
        nl_langinfo may use the same buffer as setlocale. */
@@ -2109,6 +2094,7 @@ u_versionToString(const UVersionInfo versionArray, char *versionString) {
 
 U_CAPI void U_EXPORT2
 u_getVersion(UVersionInfo versionArray) {
+    (void)copyright;   // Suppress unused variable warning from clang.
     u_versionFromString(versionArray, U_ICU_VERSION);
 }
 
@@ -2255,6 +2241,7 @@ uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
 
 U_INTERNAL void * U_EXPORT2
 uprv_dl_open(const char *libName, UErrorCode *status) {
+    (void)libName;
     if(U_FAILURE(*status)) return NULL;
     *status = U_UNSUPPORTED_ERROR;
     return NULL;
@@ -2262,6 +2249,7 @@ uprv_dl_open(const char *libName, UErrorCode *status) {
 
 U_INTERNAL void U_EXPORT2
 uprv_dl_close(void *lib, UErrorCode *status) {
+    (void)lib;
     if(U_FAILURE(*status)) return;
     *status = U_UNSUPPORTED_ERROR;
     return;
@@ -2270,6 +2258,8 @@ uprv_dl_close(void *lib, UErrorCode *status) {
 
 U_INTERNAL UVoidFunction* U_EXPORT2
 uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
+  (void)lib;
+  (void)sym;
   if(U_SUCCESS(*status)) {
     *status = U_UNSUPPORTED_ERROR;
   }