LCOV - code coverage report
Current view: top level - intl/icu/source/common - putil.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 50 418 12.0 %
Date: 2017-07-14 16:53:18 Functions: 6 51 11.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : ******************************************************************************
       5             : *
       6             : *   Copyright (C) 1997-2016, International Business Machines
       7             : *   Corporation and others.  All Rights Reserved.
       8             : *
       9             : ******************************************************************************
      10             : *
      11             : *  FILE NAME : putil.c (previously putil.cpp and ptypes.cpp)
      12             : *
      13             : *   Date        Name        Description
      14             : *   04/14/97    aliu        Creation.
      15             : *   04/24/97    aliu        Added getDefaultDataDirectory() and
      16             : *                            getDefaultLocaleID().
      17             : *   04/28/97    aliu        Rewritten to assume Unix and apply general methods
      18             : *                            for assumed case.  Non-UNIX platforms must be
      19             : *                            special-cased.  Rewrote numeric methods dealing
      20             : *                            with NaN and Infinity to be platform independent
      21             : *                             over all IEEE 754 platforms.
      22             : *   05/13/97    aliu        Restored sign of timezone
      23             : *                            (semantics are hours West of GMT)
      24             : *   06/16/98    erm         Added IEEE_754 stuff, cleaned up isInfinite, isNan,
      25             : *                             nextDouble..
      26             : *   07/22/98    stephen     Added remainder, max, min, trunc
      27             : *   08/13/98    stephen     Added isNegativeInfinity, isPositiveInfinity
      28             : *   08/24/98    stephen     Added longBitsFromDouble
      29             : *   09/08/98    stephen     Minor changes for Mac Port
      30             : *   03/02/99    stephen     Removed openFile().  Added AS400 support.
      31             : *                            Fixed EBCDIC tables
      32             : *   04/15/99    stephen     Converted to C.
      33             : *   06/28/99    stephen     Removed mutex locking in u_isBigEndian().
      34             : *   08/04/99    jeffrey R.  Added OS/2 changes
      35             : *   11/15/99    helena      Integrated S/390 IEEE support.
      36             : *   04/26/01    Barry N.    OS/400 support for uprv_getDefaultLocaleID
      37             : *   08/15/01    Steven H.   OS/400 support for uprv_getDefaultCodepage
      38             : *   01/03/08    Steven L.   Fake Time Support
      39             : ******************************************************************************
      40             : */
      41             : 
      42             : // Defines _XOPEN_SOURCE for access to POSIX functions.
      43             : // Must be before any other #includes.
      44             : #include "uposixdefs.h"
      45             : 
      46             : // First, the platform type. Need this for U_PLATFORM.
      47             : #include "unicode/platform.h"
      48             : 
      49             : #if U_PLATFORM == U_PF_MINGW && defined __STRICT_ANSI__
      50             : /* tzset isn't defined in strict ANSI on MinGW. */
      51             : #undef __STRICT_ANSI__
      52             : #endif
      53             : 
      54             : /*
      55             :  * Cygwin with GCC requires inclusion of time.h after the above disabling strict asci mode statement.
      56             :  */
      57             : #include <time.h>
      58             : 
      59             : #if !U_PLATFORM_USES_ONLY_WIN32_API
      60             : #include <sys/time.h>
      61             : #endif
      62             : 
      63             : /* include the rest of the ICU headers */
      64             : #include "unicode/putil.h"
      65             : #include "unicode/ustring.h"
      66             : #include "putilimp.h"
      67             : #include "uassert.h"
      68             : #include "umutex.h"
      69             : #include "cmemory.h"
      70             : #include "cstring.h"
      71             : #include "locmap.h"
      72             : #include "ucln_cmn.h"
      73             : #include "charstr.h"
      74             : 
      75             : /* Include standard headers. */
      76             : #include <stdio.h>
      77             : #include <stdlib.h>
      78             : #include <string.h>
      79             : #include <math.h>
      80             : #include <locale.h>
      81             : #include <float.h>
      82             : 
      83             : #ifndef U_COMMON_IMPLEMENTATION
      84             : #error U_COMMON_IMPLEMENTATION not set - must be set for all ICU source files in common/ - see http://userguide.icu-project.org/howtouseicu
      85             : #endif
      86             : 
      87             : 
      88             : /* include system headers */
      89             : #if U_PLATFORM_USES_ONLY_WIN32_API
      90             :     /*
      91             :      * TODO: U_PLATFORM_USES_ONLY_WIN32_API includes MinGW.
      92             :      * Should Cygwin be included as well (U_PLATFORM_HAS_WIN32_API)
      93             :      * to use native APIs as much as possible?
      94             :      */
      95             : #ifndef WIN32_LEAN_AND_MEAN
      96             : #   define WIN32_LEAN_AND_MEAN
      97             : #endif
      98             : #   define VC_EXTRALEAN
      99             : #   define NOUSER
     100             : #   define NOSERVICE
     101             : #   define NOIME
     102             : #   define NOMCX
     103             : #   include <windows.h>
     104             : #   include "unicode/uloc.h"
     105             : #if U_PLATFORM_HAS_WINUWP_API == 0
     106             : #   include "wintz.h"
     107             : #else // U_PLATFORM_HAS_WINUWP_API
     108             : typedef PVOID LPMSG; // TODO: figure out how to get rid of this typedef
     109             : #include <Windows.Globalization.h>
     110             : #include <windows.system.userprofile.h>
     111             : #include <wrl/wrappers/corewrappers.h>
     112             : #include <wrl/client.h>
     113             : 
     114             : using namespace ABI::Windows::Foundation;
     115             : using namespace Microsoft::WRL;
     116             : using namespace Microsoft::WRL::Wrappers;
     117             : #endif
     118             : #elif U_PLATFORM == U_PF_OS400
     119             : #   include <float.h>
     120             : #   include <qusec.h>       /* error code structure */
     121             : #   include <qusrjobi.h>
     122             : #   include <qliept.h>      /* EPT_CALL macro  - this include must be after all other "QSYSINCs" */
     123             : #   include <mih/testptr.h> /* For uprv_maximumPtr */
     124             : #elif U_PLATFORM == U_PF_OS390
     125             : #   include "unicode/ucnv.h"   /* Needed for UCNV_SWAP_LFNL_OPTION_STRING */
     126             : #elif U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS
     127             : #   include <limits.h>
     128             : #   include <unistd.h>
     129             : #   if U_PLATFORM == U_PF_SOLARIS
     130             : #       ifndef _XPG4_2
     131             : #           define _XPG4_2
     132             : #       endif
     133             : #   endif
     134             : #elif U_PLATFORM == U_PF_QNX
     135             : #   include <sys/neutrino.h>
     136             : #endif
     137             : 
     138             : /*
     139             :  * Only include langinfo.h if we have a way to get the codeset. If we later
     140             :  * depend on more feature, we can test on U_HAVE_NL_LANGINFO.
     141             :  *
     142             :  */
     143             : 
     144             : #if U_HAVE_NL_LANGINFO_CODESET
     145             : #include <langinfo.h>
     146             : #endif
     147             : 
     148             : /**
     149             :  * Simple things (presence of functions, etc) should just go in configure.in and be added to
     150             :  * icucfg.h via autoheader.
     151             :  */
     152             : #if U_PLATFORM_IMPLEMENTS_POSIX
     153             : #   if U_PLATFORM == U_PF_OS400
     154             : #    define HAVE_DLFCN_H 0
     155             : #    define HAVE_DLOPEN 0
     156             : #   else
     157             : #   ifndef HAVE_DLFCN_H
     158             : #    define HAVE_DLFCN_H 1
     159             : #   endif
     160             : #   ifndef HAVE_DLOPEN
     161             : #    define HAVE_DLOPEN 1
     162             : #   endif
     163             : #   endif
     164             : #   ifndef HAVE_GETTIMEOFDAY
     165             : #    define HAVE_GETTIMEOFDAY 1
     166             : #   endif
     167             : #else
     168             : #   define HAVE_DLFCN_H 0
     169             : #   define HAVE_DLOPEN 0
     170             : #   define HAVE_GETTIMEOFDAY 0
     171             : #endif
     172             : 
     173             : U_NAMESPACE_USE
     174             : 
     175             : /* Define the extension for data files, again... */
     176             : #define DATA_TYPE "dat"
     177             : 
     178             : /* Leave this copyright notice here! */
     179             : static const char copyright[] = U_COPYRIGHT_STRING;
     180             : 
     181             : /* floating point implementations ------------------------------------------- */
     182             : 
     183             : /* We return QNAN rather than SNAN*/
     184             : #define SIGN 0x80000000U
     185             : 
     186             : /* Make it easy to define certain types of constants */
     187             : typedef union {
     188             :     int64_t i64; /* This must be defined first in order to allow the initialization to work. This is a C89 feature. */
     189             :     double d64;
     190             : } BitPatternConversion;
     191             : static const BitPatternConversion gNan = { (int64_t) INT64_C(0x7FF8000000000000) };
     192             : static const BitPatternConversion gInf = { (int64_t) INT64_C(0x7FF0000000000000) };
     193             : 
     194             : /*---------------------------------------------------------------------------
     195             :   Platform utilities
     196             :   Our general strategy is to assume we're on a POSIX platform.  Platforms which
     197             :   are non-POSIX must declare themselves so.  The default POSIX implementation
     198             :   will sometimes work for non-POSIX platforms as well (e.g., the NaN-related
     199             :   functions).
     200             :   ---------------------------------------------------------------------------*/
     201             : 
     202             : #if U_PLATFORM_USES_ONLY_WIN32_API || U_PLATFORM == U_PF_OS400
     203             : #   undef U_POSIX_LOCALE
     204             : #else
     205             : #   define U_POSIX_LOCALE    1
     206             : #endif
     207             : 
     208             : /*
     209             :     WARNING! u_topNBytesOfDouble and u_bottomNBytesOfDouble
     210             :     can't be properly optimized by the gcc compiler sometimes (i.e. gcc 3.2).
     211             : */
     212             : #if !IEEE_754
     213             : static char*
     214             : u_topNBytesOfDouble(double* d, int n)
     215             : {
     216             : #if U_IS_BIG_ENDIAN
     217             :     return (char*)d;
     218             : #else
     219             :     return (char*)(d + 1) - n;
     220             : #endif
     221             : }
     222             : 
     223             : static char*
     224             : u_bottomNBytesOfDouble(double* d, int n)
     225             : {
     226             : #if U_IS_BIG_ENDIAN
     227             :     return (char*)(d + 1) - n;
     228             : #else
     229             :     return (char*)d;
     230             : #endif
     231             : }
     232             : #endif   /* !IEEE_754 */
     233             : 
     234             : #if IEEE_754
     235             : static UBool
     236           0 : u_signBit(double d) {
     237             :     uint8_t hiByte;
     238             : #if U_IS_BIG_ENDIAN
     239             :     hiByte = *(uint8_t *)&d;
     240             : #else
     241           0 :     hiByte = *(((uint8_t *)&d) + sizeof(double) - 1);
     242             : #endif
     243           0 :     return (hiByte & 0x80) != 0;
     244             : }
     245             : #endif
     246             : 
     247             : 
     248             : 
     249             : #if defined (U_DEBUG_FAKETIME)
     250             : /* Override the clock to test things without having to move the system clock.
     251             :  * Assumes POSIX gettimeofday() will function
     252             :  */
     253             : UDate fakeClock_t0 = 0; /** Time to start the clock from **/
     254             : UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/
     255             : UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/
     256             : static UMutex fakeClockMutex = U_MUTEX_INTIALIZER;
     257             : 
     258             : static UDate getUTCtime_real() {
     259             :     struct timeval posixTime;
     260             :     gettimeofday(&posixTime, NULL);
     261             :     return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
     262             : }
     263             : 
     264             : static UDate getUTCtime_fake() {
     265             :     umtx_lock(&fakeClockMutex);
     266             :     if(!fakeClock_set) {
     267             :         UDate real = getUTCtime_real();
     268             :         const char *fake_start = getenv("U_FAKETIME_START");
     269             :         if((fake_start!=NULL) && (fake_start[0]!=0)) {
     270             :             sscanf(fake_start,"%lf",&fakeClock_t0);
     271             :             fakeClock_dt = fakeClock_t0 - real;
     272             :             fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, so the ICU clock will start at a preset value\n"
     273             :                     "env variable U_FAKETIME_START=%.0f (%s) for an offset of %.0f ms from the current time %.0f\n",
     274             :                     fakeClock_t0, fake_start, fakeClock_dt, real);
     275             :         } else {
     276             :           fakeClock_dt = 0;
     277             :             fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, but U_FAKETIME_START was not set.\n"
     278             :                     "Set U_FAKETIME_START to the number of milliseconds since 1/1/1970 to set the ICU clock.\n");
     279             :         }
     280             :         fakeClock_set = TRUE;
     281             :     }
     282             :     umtx_unlock(&fakeClockMutex);
     283             : 
     284             :     return getUTCtime_real() + fakeClock_dt;
     285             : }
     286             : #endif
     287             : 
     288             : #if U_PLATFORM_USES_ONLY_WIN32_API
     289             : typedef union {
     290             :     int64_t int64;
     291             :     FILETIME fileTime;
     292             : } FileTimeConversion;   /* This is like a ULARGE_INTEGER */
     293             : 
     294             : /* Number of 100 nanoseconds from 1/1/1601 to 1/1/1970 */
     295             : #define EPOCH_BIAS  INT64_C(116444736000000000)
     296             : #define HECTONANOSECOND_PER_MILLISECOND   10000
     297             : 
     298             : #endif
     299             : 
     300             : /*---------------------------------------------------------------------------
     301             :   Universal Implementations
     302             :   These are designed to work on all platforms.  Try these, and if they
     303             :   don't work on your platform, then special case your platform with new
     304             :   implementations.
     305             : ---------------------------------------------------------------------------*/
     306             : 
     307             : U_CAPI UDate U_EXPORT2
     308           0 : uprv_getUTCtime()
     309             : {
     310             : #if defined(U_DEBUG_FAKETIME)
     311             :     return getUTCtime_fake(); /* Hook for overriding the clock */
     312             : #else
     313           0 :     return uprv_getRawUTCtime();
     314             : #endif
     315             : }
     316             : 
     317             : /* Return UTC (GMT) time measured in milliseconds since 0:00 on 1/1/70.*/
     318             : U_CAPI UDate U_EXPORT2
     319           0 : uprv_getRawUTCtime()
     320             : {
     321             : #if U_PLATFORM_USES_ONLY_WIN32_API
     322             : 
     323             :     FileTimeConversion winTime;
     324             :     GetSystemTimeAsFileTime(&winTime.fileTime);
     325             :     return (UDate)((winTime.int64 - EPOCH_BIAS) / HECTONANOSECOND_PER_MILLISECOND);
     326             : #else
     327             : 
     328             : #if HAVE_GETTIMEOFDAY
     329             :     struct timeval posixTime;
     330           0 :     gettimeofday(&posixTime, NULL);
     331           0 :     return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
     332             : #else
     333             :     time_t epochtime;
     334             :     time(&epochtime);
     335             :     return (UDate)epochtime * U_MILLIS_PER_SECOND;
     336             : #endif
     337             : 
     338             : #endif
     339             : }
     340             : 
     341             : /*-----------------------------------------------------------------------------
     342             :   IEEE 754
     343             :   These methods detect and return NaN and infinity values for doubles
     344             :   conforming to IEEE 754.  Platforms which support this standard include X86,
     345             :   Mac 680x0, Mac PowerPC, AIX RS/6000, and most others.
     346             :   If this doesn't work on your platform, you have non-IEEE floating-point, and
     347             :   will need to code your own versions.  A naive implementation is to return 0.0
     348             :   for getNaN and getInfinity, and false for isNaN and isInfinite.
     349             :   ---------------------------------------------------------------------------*/
     350             : 
     351             : U_CAPI UBool U_EXPORT2
     352           0 : uprv_isNaN(double number)
     353             : {
     354             : #if IEEE_754
     355             :     BitPatternConversion convertedNumber;
     356           0 :     convertedNumber.d64 = number;
     357             :     /* Infinity is 0x7FF0000000000000U. Anything greater than that is a NaN */
     358           0 :     return (UBool)((convertedNumber.i64 & U_INT64_MAX) > gInf.i64);
     359             : 
     360             : #elif U_PLATFORM == U_PF_OS390
     361             :     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
     362             :                         sizeof(uint32_t));
     363             :     uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
     364             :                         sizeof(uint32_t));
     365             : 
     366             :     return ((highBits & 0x7F080000L) == 0x7F080000L) &&
     367             :       (lowBits == 0x00000000L);
     368             : 
     369             : #else
     370             :     /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
     371             :     /* you'll need to replace this default implementation with what's correct*/
     372             :     /* for your platform.*/
     373             :     return number != number;
     374             : #endif
     375             : }
     376             : 
     377             : U_CAPI UBool U_EXPORT2
     378           0 : uprv_isInfinite(double number)
     379             : {
     380             : #if IEEE_754
     381             :     BitPatternConversion convertedNumber;
     382           0 :     convertedNumber.d64 = number;
     383             :     /* Infinity is exactly 0x7FF0000000000000U. */
     384           0 :     return (UBool)((convertedNumber.i64 & U_INT64_MAX) == gInf.i64);
     385             : #elif U_PLATFORM == U_PF_OS390
     386             :     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
     387             :                         sizeof(uint32_t));
     388             :     uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
     389             :                         sizeof(uint32_t));
     390             : 
     391             :     return ((highBits  & ~SIGN) == 0x70FF0000L) && (lowBits == 0x00000000L);
     392             : 
     393             : #else
     394             :     /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
     395             :     /* value, you'll need to replace this default implementation with what's*/
     396             :     /* correct for your platform.*/
     397             :     return number == (2.0 * number);
     398             : #endif
     399             : }
     400             : 
     401             : U_CAPI UBool U_EXPORT2
     402           0 : uprv_isPositiveInfinity(double number)
     403             : {
     404             : #if IEEE_754 || U_PLATFORM == U_PF_OS390
     405           0 :     return (UBool)(number > 0 && uprv_isInfinite(number));
     406             : #else
     407             :     return uprv_isInfinite(number);
     408             : #endif
     409             : }
     410             : 
     411             : U_CAPI UBool U_EXPORT2
     412           0 : uprv_isNegativeInfinity(double number)
     413             : {
     414             : #if IEEE_754 || U_PLATFORM == U_PF_OS390
     415           0 :     return (UBool)(number < 0 && uprv_isInfinite(number));
     416             : 
     417             : #else
     418             :     uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
     419             :                         sizeof(uint32_t));
     420             :     return((highBits & SIGN) && uprv_isInfinite(number));
     421             : 
     422             : #endif
     423             : }
     424             : 
     425             : U_CAPI double U_EXPORT2
     426           0 : uprv_getNaN()
     427             : {
     428             : #if IEEE_754 || U_PLATFORM == U_PF_OS390
     429           0 :     return gNan.d64;
     430             : #else
     431             :     /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
     432             :     /* you'll need to replace this default implementation with what's correct*/
     433             :     /* for your platform.*/
     434             :     return 0.0;
     435             : #endif
     436             : }
     437             : 
     438             : U_CAPI double U_EXPORT2
     439           0 : uprv_getInfinity()
     440             : {
     441             : #if IEEE_754 || U_PLATFORM == U_PF_OS390
     442           0 :     return gInf.d64;
     443             : #else
     444             :     /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
     445             :     /* value, you'll need to replace this default implementation with what's*/
     446             :     /* correct for your platform.*/
     447             :     return 0.0;
     448             : #endif
     449             : }
     450             : 
     451             : U_CAPI double U_EXPORT2
     452           0 : uprv_floor(double x)
     453             : {
     454           0 :     return floor(x);
     455             : }
     456             : 
     457             : U_CAPI double U_EXPORT2
     458           0 : uprv_ceil(double x)
     459             : {
     460           0 :     return ceil(x);
     461             : }
     462             : 
     463             : U_CAPI double U_EXPORT2
     464           0 : uprv_round(double x)
     465             : {
     466           0 :     return uprv_floor(x + 0.5);
     467             : }
     468             : 
     469             : U_CAPI double U_EXPORT2
     470           0 : uprv_fabs(double x)
     471             : {
     472           0 :     return fabs(x);
     473             : }
     474             : 
     475             : U_CAPI double U_EXPORT2
     476           0 : uprv_modf(double x, double* y)
     477             : {
     478           0 :     return modf(x, y);
     479             : }
     480             : 
     481             : U_CAPI double U_EXPORT2
     482           0 : uprv_fmod(double x, double y)
     483             : {
     484           0 :     return fmod(x, y);
     485             : }
     486             : 
     487             : U_CAPI double U_EXPORT2
     488           0 : uprv_pow(double x, double y)
     489             : {
     490             :     /* This is declared as "double pow(double x, double y)" */
     491           0 :     return pow(x, y);
     492             : }
     493             : 
     494             : U_CAPI double U_EXPORT2
     495           0 : uprv_pow10(int32_t x)
     496             : {
     497           0 :     return pow(10.0, (double)x);
     498             : }
     499             : 
     500             : U_CAPI double U_EXPORT2
     501           0 : uprv_fmax(double x, double y)
     502             : {
     503             : #if IEEE_754
     504             :     /* first handle NaN*/
     505           0 :     if(uprv_isNaN(x) || uprv_isNaN(y))
     506           0 :         return uprv_getNaN();
     507             : 
     508             :     /* check for -0 and 0*/
     509           0 :     if(x == 0.0 && y == 0.0 && u_signBit(x))
     510           0 :         return y;
     511             : 
     512             : #endif
     513             : 
     514             :     /* this should work for all flt point w/o NaN and Inf special cases */
     515           0 :     return (x > y ? x : y);
     516             : }
     517             : 
     518             : U_CAPI double U_EXPORT2
     519           0 : uprv_fmin(double x, double y)
     520             : {
     521             : #if IEEE_754
     522             :     /* first handle NaN*/
     523           0 :     if(uprv_isNaN(x) || uprv_isNaN(y))
     524           0 :         return uprv_getNaN();
     525             : 
     526             :     /* check for -0 and 0*/
     527           0 :     if(x == 0.0 && y == 0.0 && u_signBit(y))
     528           0 :         return y;
     529             : 
     530             : #endif
     531             : 
     532             :     /* this should work for all flt point w/o NaN and Inf special cases */
     533           0 :     return (x > y ? y : x);
     534             : }
     535             : 
     536             : /**
     537             :  * Truncates the given double.
     538             :  * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
     539             :  * This is different than calling floor() or ceil():
     540             :  * floor(3.3) = 3, floor(-3.3) = -4
     541             :  * ceil(3.3) = 4, ceil(-3.3) = -3
     542             :  */
     543             : U_CAPI double U_EXPORT2
     544           0 : uprv_trunc(double d)
     545             : {
     546             : #if IEEE_754
     547             :     /* handle error cases*/
     548           0 :     if(uprv_isNaN(d))
     549           0 :         return uprv_getNaN();
     550           0 :     if(uprv_isInfinite(d))
     551           0 :         return uprv_getInfinity();
     552             : 
     553           0 :     if(u_signBit(d))    /* Signbit() picks up -0.0;  d<0 does not. */
     554           0 :         return ceil(d);
     555             :     else
     556           0 :         return floor(d);
     557             : 
     558             : #else
     559             :     return d >= 0 ? floor(d) : ceil(d);
     560             : 
     561             : #endif
     562             : }
     563             : 
     564             : /**
     565             :  * Return the largest positive number that can be represented by an integer
     566             :  * type of arbitrary bit length.
     567             :  */
     568             : U_CAPI double U_EXPORT2
     569           0 : uprv_maxMantissa(void)
     570             : {
     571           0 :     return pow(2.0, DBL_MANT_DIG + 1.0) - 1.0;
     572             : }
     573             : 
     574             : U_CAPI double U_EXPORT2
     575           0 : uprv_log(double d)
     576             : {
     577           0 :     return log(d);
     578             : }
     579             : 
     580             : U_CAPI void * U_EXPORT2
     581           0 : uprv_maximumPtr(void * base)
     582             : {
     583             : #if U_PLATFORM == U_PF_OS400
     584             :     /*
     585             :      * With the provided function we should never be out of range of a given segment
     586             :      * (a traditional/typical segment that is).  Our segments have 5 bytes for the
     587             :      * id and 3 bytes for the offset.  The key is that the casting takes care of
     588             :      * only retrieving the offset portion minus x1000.  Hence, the smallest offset
     589             :      * seen in a program is x001000 and when casted to an int would be 0.
     590             :      * That's why we can only add 0xffefff.  Otherwise, we would exceed the segment.
     591             :      *
     592             :      * Currently, 16MB is the current addressing limitation on i5/OS if the activation is
     593             :      * non-TERASPACE.  If it is TERASPACE it is 2GB - 4k(header information).
     594             :      * This function determines the activation based on the pointer that is passed in and
     595             :      * calculates the appropriate maximum available size for
     596             :      * each pointer type (TERASPACE and non-TERASPACE)
     597             :      *
     598             :      * Unlike other operating systems, the pointer model isn't determined at
     599             :      * compile time on i5/OS.
     600             :      */
     601             :     if ((base != NULL) && (_TESTPTR(base, _C_TERASPACE_CHECK))) {
     602             :         /* if it is a TERASPACE pointer the max is 2GB - 4k */
     603             :         return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0x7fffefff)));
     604             :     }
     605             :     /* otherwise 16MB since NULL ptr is not checkable or the ptr is not TERASPACE */
     606             :     return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0xffefff)));
     607             : 
     608             : #else
     609           0 :     return U_MAX_PTR(base);
     610             : #endif
     611             : }
     612             : 
     613             : /*---------------------------------------------------------------------------
     614             :   Platform-specific Implementations
     615             :   Try these, and if they don't work on your platform, then special case your
     616             :   platform with new implementations.
     617             :   ---------------------------------------------------------------------------*/
     618             : 
     619             : /* Generic time zone layer -------------------------------------------------- */
     620             : 
     621             : /* Time zone utilities */
     622             : U_CAPI void U_EXPORT2
     623           0 : uprv_tzset()
     624             : {
     625             : #if defined(U_TZSET)
     626           0 :     U_TZSET();
     627             : #else
     628             :     /* no initialization*/
     629             : #endif
     630           0 : }
     631             : 
     632             : U_CAPI int32_t U_EXPORT2
     633           0 : uprv_timezone()
     634             : {
     635             : #ifdef U_TIMEZONE
     636           0 :     return U_TIMEZONE;
     637             : #else
     638             :     time_t t, t1, t2;
     639             :     struct tm tmrec;
     640             :     int32_t tdiff = 0;
     641             : 
     642             :     time(&t);
     643             :     uprv_memcpy( &tmrec, localtime(&t), sizeof(tmrec) );
     644             : #if U_PLATFORM != U_PF_IPHONE
     645             :     UBool dst_checked = (tmrec.tm_isdst != 0); /* daylight savings time is checked*/
     646             : #endif
     647             :     t1 = mktime(&tmrec);                 /* local time in seconds*/
     648             :     uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
     649             :     t2 = mktime(&tmrec);                 /* GMT (or UTC) in seconds*/
     650             :     tdiff = t2 - t1;
     651             : 
     652             : #if U_PLATFORM != U_PF_IPHONE
     653             :     /* imitate NT behaviour, which returns same timezone offset to GMT for
     654             :        winter and summer.
     655             :        This does not work on all platforms. For instance, on glibc on Linux
     656             :        and on Mac OS 10.5, tdiff calculated above remains the same
     657             :        regardless of whether DST is in effect or not. iOS is another
     658             :        platform where this does not work. Linux + glibc and Mac OS 10.5
     659             :        have U_TIMEZONE defined so that this code is not reached.
     660             :     */
     661             :     if (dst_checked)
     662             :         tdiff += 3600;
     663             : #endif
     664             :     return tdiff;
     665             : #endif
     666             : }
     667             : 
     668             : /* Note that U_TZNAME does *not* have to be tzname, but if it is,
     669             :    some platforms need to have it declared here. */
     670             : 
     671             : #if defined(U_TZNAME) && (U_PLATFORM == U_PF_IRIX || U_PLATFORM_IS_DARWIN_BASED)
     672             : /* RS6000 and others reject char **tzname.  */
     673             : extern U_IMPORT char *U_TZNAME[];
     674             : #endif
     675             : 
     676             : #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)
     677             : /* These platforms are likely to use Olson timezone IDs. */
     678             : #define CHECK_LOCALTIME_LINK 1
     679             : #if U_PLATFORM_IS_DARWIN_BASED
     680             : #include <tzfile.h>
     681             : #define TZZONEINFO      (TZDIR "/")
     682             : #elif U_PLATFORM == U_PF_SOLARIS
     683             : #define TZDEFAULT       "/etc/localtime"
     684             : #define TZZONEINFO      "/usr/share/lib/zoneinfo/"
     685             : #define TZZONEINFO2     "../usr/share/lib/zoneinfo/"
     686             : #define TZ_ENV_CHECK    "localtime"
     687             : #else
     688             : #define TZDEFAULT       "/etc/localtime"
     689             : #define TZZONEINFO      "/usr/share/zoneinfo/"
     690             : #endif
     691             : #if U_HAVE_DIRENT_H
     692             : #define TZFILE_SKIP     "posixrules" /* tz file to skip when searching. */
     693             : /* Some Linux distributions have 'localtime' in /usr/share/zoneinfo
     694             :    symlinked to /etc/localtime, which makes searchForTZFile return
     695             :    'localtime' when it's the first match. */
     696             : #define TZFILE_SKIP2    "localtime"
     697             : #define SEARCH_TZFILE
     698             : #include <dirent.h>  /* Needed to search through system timezone files */
     699             : #endif
     700             : static char gTimeZoneBuffer[PATH_MAX];
     701             : static char *gTimeZoneBufferPtr = NULL;
     702             : #endif
     703             : 
     704             : #if !U_PLATFORM_USES_ONLY_WIN32_API
     705             : #define isNonDigit(ch) (ch < '0' || '9' < ch)
     706           0 : static UBool isValidOlsonID(const char *id) {
     707           0 :     int32_t idx = 0;
     708             : 
     709             :     /* Determine if this is something like Iceland (Olson ID)
     710             :     or AST4ADT (non-Olson ID) */
     711           0 :     while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') {
     712           0 :         idx++;
     713             :     }
     714             : 
     715             :     /* If we went through the whole string, then it might be okay.
     716             :     The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
     717             :     "GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
     718             :     The rest of the time it could be an Olson ID. George */
     719           0 :     return (UBool)(id[idx] == 0
     720           0 :         || uprv_strcmp(id, "PST8PDT") == 0
     721           0 :         || uprv_strcmp(id, "MST7MDT") == 0
     722           0 :         || uprv_strcmp(id, "CST6CDT") == 0
     723           0 :         || uprv_strcmp(id, "EST5EDT") == 0);
     724             : }
     725             : 
     726             : /* On some Unix-like OS, 'posix' subdirectory in
     727             :    /usr/share/zoneinfo replicates the top-level contents. 'right'
     728             :    subdirectory has the same set of files, but individual files
     729             :    are different from those in the top-level directory or 'posix'
     730             :    because 'right' has files for TAI (Int'l Atomic Time) while 'posix'
     731             :    has files for UTC.
     732             :    When the first match for /etc/localtime is in either of them
     733             :    (usually in posix because 'right' has different file contents),
     734             :    or TZ environment variable points to one of them, createTimeZone
     735             :    fails because, say, 'posix/America/New_York' is not an Olson
     736             :    timezone id ('America/New_York' is). So, we have to skip
     737             :    'posix/' and 'right/' at the beginning. */
     738           0 : static void skipZoneIDPrefix(const char** id) {
     739           0 :     if (uprv_strncmp(*id, "posix/", 6) == 0
     740           0 :         || uprv_strncmp(*id, "right/", 6) == 0)
     741             :     {
     742           0 :         *id += 6;
     743             :     }
     744           0 : }
     745             : #endif
     746             : 
     747             : #if defined(U_TZNAME) && !U_PLATFORM_USES_ONLY_WIN32_API
     748             : 
     749             : #define CONVERT_HOURS_TO_SECONDS(offset) (int32_t)(offset*3600)
     750             : typedef struct OffsetZoneMapping {
     751             :     int32_t offsetSeconds;
     752             :     int32_t daylightType; /* 0=U_DAYLIGHT_NONE, 1=daylight in June-U_DAYLIGHT_JUNE, 2=daylight in December=U_DAYLIGHT_DECEMBER*/
     753             :     const char *stdID;
     754             :     const char *dstID;
     755             :     const char *olsonID;
     756             : } OffsetZoneMapping;
     757             : 
     758             : enum { U_DAYLIGHT_NONE=0,U_DAYLIGHT_JUNE=1,U_DAYLIGHT_DECEMBER=2 };
     759             : 
     760             : /*
     761             : This list tries to disambiguate a set of abbreviated timezone IDs and offsets
     762             : and maps it to an Olson ID.
     763             : Before adding anything to this list, take a look at
     764             : icu/source/tools/tzcode/tz.alias
     765             : Sometimes no daylight savings (0) is important to define due to aliases.
     766             : This list can be tested with icu/source/test/compat/tzone.pl
     767             : More values could be added to daylightType to increase precision.
     768             : */
     769             : static const struct OffsetZoneMapping OFFSET_ZONE_MAPPINGS[] = {
     770             :     {-45900, 2, "CHAST", "CHADT", "Pacific/Chatham"},
     771             :     {-43200, 1, "PETT", "PETST", "Asia/Kamchatka"},
     772             :     {-43200, 2, "NZST", "NZDT", "Pacific/Auckland"},
     773             :     {-43200, 1, "ANAT", "ANAST", "Asia/Anadyr"},
     774             :     {-39600, 1, "MAGT", "MAGST", "Asia/Magadan"},
     775             :     {-37800, 2, "LHST", "LHST", "Australia/Lord_Howe"},
     776             :     {-36000, 2, "EST", "EST", "Australia/Sydney"},
     777             :     {-36000, 1, "SAKT", "SAKST", "Asia/Sakhalin"},
     778             :     {-36000, 1, "VLAT", "VLAST", "Asia/Vladivostok"},
     779             :     {-34200, 2, "CST", "CST", "Australia/South"},
     780             :     {-32400, 1, "YAKT", "YAKST", "Asia/Yakutsk"},
     781             :     {-32400, 1, "CHOT", "CHOST", "Asia/Choibalsan"},
     782             :     {-31500, 2, "CWST", "CWST", "Australia/Eucla"},
     783             :     {-28800, 1, "IRKT", "IRKST", "Asia/Irkutsk"},
     784             :     {-28800, 1, "ULAT", "ULAST", "Asia/Ulaanbaatar"},
     785             :     {-28800, 2, "WST", "WST", "Australia/West"},
     786             :     {-25200, 1, "HOVT", "HOVST", "Asia/Hovd"},
     787             :     {-25200, 1, "KRAT", "KRAST", "Asia/Krasnoyarsk"},
     788             :     {-21600, 1, "NOVT", "NOVST", "Asia/Novosibirsk"},
     789             :     {-21600, 1, "OMST", "OMSST", "Asia/Omsk"},
     790             :     {-18000, 1, "YEKT", "YEKST", "Asia/Yekaterinburg"},
     791             :     {-14400, 1, "SAMT", "SAMST", "Europe/Samara"},
     792             :     {-14400, 1, "AMT", "AMST", "Asia/Yerevan"},
     793             :     {-14400, 1, "AZT", "AZST", "Asia/Baku"},
     794             :     {-10800, 1, "AST", "ADT", "Asia/Baghdad"},
     795             :     {-10800, 1, "MSK", "MSD", "Europe/Moscow"},
     796             :     {-10800, 1, "VOLT", "VOLST", "Europe/Volgograd"},
     797             :     {-7200, 0, "EET", "CEST", "Africa/Tripoli"},
     798             :     {-7200, 1, "EET", "EEST", "Europe/Athens"}, /* Conflicts with Africa/Cairo */
     799             :     {-7200, 1, "IST", "IDT", "Asia/Jerusalem"},
     800             :     {-3600, 0, "CET", "WEST", "Africa/Algiers"},
     801             :     {-3600, 2, "WAT", "WAST", "Africa/Windhoek"},
     802             :     {0, 1, "GMT", "IST", "Europe/Dublin"},
     803             :     {0, 1, "GMT", "BST", "Europe/London"},
     804             :     {0, 0, "WET", "WEST", "Africa/Casablanca"},
     805             :     {0, 0, "WET", "WET", "Africa/El_Aaiun"},
     806             :     {3600, 1, "AZOT", "AZOST", "Atlantic/Azores"},
     807             :     {3600, 1, "EGT", "EGST", "America/Scoresbysund"},
     808             :     {10800, 1, "PMST", "PMDT", "America/Miquelon"},
     809             :     {10800, 2, "UYT", "UYST", "America/Montevideo"},
     810             :     {10800, 1, "WGT", "WGST", "America/Godthab"},
     811             :     {10800, 2, "BRT", "BRST", "Brazil/East"},
     812             :     {12600, 1, "NST", "NDT", "America/St_Johns"},
     813             :     {14400, 1, "AST", "ADT", "Canada/Atlantic"},
     814             :     {14400, 2, "AMT", "AMST", "America/Cuiaba"},
     815             :     {14400, 2, "CLT", "CLST", "Chile/Continental"},
     816             :     {14400, 2, "FKT", "FKST", "Atlantic/Stanley"},
     817             :     {14400, 2, "PYT", "PYST", "America/Asuncion"},
     818             :     {18000, 1, "CST", "CDT", "America/Havana"},
     819             :     {18000, 1, "EST", "EDT", "US/Eastern"}, /* Conflicts with America/Grand_Turk */
     820             :     {21600, 2, "EAST", "EASST", "Chile/EasterIsland"},
     821             :     {21600, 0, "CST", "MDT", "Canada/Saskatchewan"},
     822             :     {21600, 0, "CST", "CDT", "America/Guatemala"},
     823             :     {21600, 1, "CST", "CDT", "US/Central"}, /* Conflicts with Mexico/General */
     824             :     {25200, 1, "MST", "MDT", "US/Mountain"}, /* Conflicts with Mexico/BajaSur */
     825             :     {28800, 0, "PST", "PST", "Pacific/Pitcairn"},
     826             :     {28800, 1, "PST", "PDT", "US/Pacific"}, /* Conflicts with Mexico/BajaNorte */
     827             :     {32400, 1, "AKST", "AKDT", "US/Alaska"},
     828             :     {36000, 1, "HAST", "HADT", "US/Aleutian"}
     829             : };
     830             : 
     831             : /*#define DEBUG_TZNAME*/
     832             : 
     833           0 : static const char* remapShortTimeZone(const char *stdID, const char *dstID, int32_t daylightType, int32_t offset)
     834             : {
     835             :     int32_t idx;
     836             : #ifdef DEBUG_TZNAME
     837             :     fprintf(stderr, "TZ=%s std=%s dst=%s daylight=%d offset=%d\n", getenv("TZ"), stdID, dstID, daylightType, offset);
     838             : #endif
     839           0 :     for (idx = 0; idx < UPRV_LENGTHOF(OFFSET_ZONE_MAPPINGS); idx++)
     840             :     {
     841           0 :         if (offset == OFFSET_ZONE_MAPPINGS[idx].offsetSeconds
     842           0 :             && daylightType == OFFSET_ZONE_MAPPINGS[idx].daylightType
     843           0 :             && strcmp(OFFSET_ZONE_MAPPINGS[idx].stdID, stdID) == 0
     844           0 :             && strcmp(OFFSET_ZONE_MAPPINGS[idx].dstID, dstID) == 0)
     845             :         {
     846           0 :             return OFFSET_ZONE_MAPPINGS[idx].olsonID;
     847             :         }
     848             :     }
     849           0 :     return NULL;
     850             : }
     851             : #endif
     852             : 
     853             : #ifdef SEARCH_TZFILE
     854             : #define MAX_READ_SIZE 512
     855             : 
     856             : typedef struct DefaultTZInfo {
     857             :     char* defaultTZBuffer;
     858             :     int64_t defaultTZFileSize;
     859             :     FILE* defaultTZFilePtr;
     860             :     UBool defaultTZstatus;
     861             :     int32_t defaultTZPosition;
     862             : } DefaultTZInfo;
     863             : 
     864             : /*
     865             :  * This method compares the two files given to see if they are a match.
     866             :  * It is currently use to compare two TZ files.
     867             :  */
     868           0 : static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFileName, DefaultTZInfo* tzInfo) {
     869             :     FILE* file; 
     870             :     int64_t sizeFile;
     871             :     int64_t sizeFileLeft;
     872             :     int32_t sizeFileRead;
     873             :     int32_t sizeFileToRead;
     874             :     char bufferFile[MAX_READ_SIZE];
     875           0 :     UBool result = TRUE;
     876             : 
     877           0 :     if (tzInfo->defaultTZFilePtr == NULL) {
     878           0 :         tzInfo->defaultTZFilePtr = fopen(defaultTZFileName, "r");
     879             :     }
     880           0 :     file = fopen(TZFileName, "r");
     881             : 
     882           0 :     tzInfo->defaultTZPosition = 0; /* reset position to begin search */
     883             : 
     884           0 :     if (file != NULL && tzInfo->defaultTZFilePtr != NULL) {
     885             :         /* First check that the file size are equal. */
     886           0 :         if (tzInfo->defaultTZFileSize == 0) {
     887           0 :             fseek(tzInfo->defaultTZFilePtr, 0, SEEK_END);
     888           0 :             tzInfo->defaultTZFileSize = ftell(tzInfo->defaultTZFilePtr);
     889             :         }
     890           0 :         fseek(file, 0, SEEK_END);
     891           0 :         sizeFile = ftell(file);
     892           0 :         sizeFileLeft = sizeFile;
     893             : 
     894           0 :         if (sizeFile != tzInfo->defaultTZFileSize) {
     895           0 :             result = FALSE;
     896             :         } else {
     897             :             /* Store the data from the files in seperate buffers and
     898             :              * compare each byte to determine equality.
     899             :              */
     900           0 :             if (tzInfo->defaultTZBuffer == NULL) {
     901           0 :                 rewind(tzInfo->defaultTZFilePtr);
     902           0 :                 tzInfo->defaultTZBuffer = (char*)uprv_malloc(sizeof(char) * tzInfo->defaultTZFileSize);
     903           0 :                 sizeFileRead = fread(tzInfo->defaultTZBuffer, 1, tzInfo->defaultTZFileSize, tzInfo->defaultTZFilePtr);
     904             :             }
     905           0 :             rewind(file);
     906           0 :             while(sizeFileLeft > 0) {
     907           0 :                 uprv_memset(bufferFile, 0, MAX_READ_SIZE);
     908           0 :                 sizeFileToRead = sizeFileLeft < MAX_READ_SIZE ? sizeFileLeft : MAX_READ_SIZE;
     909             : 
     910           0 :                 sizeFileRead = fread(bufferFile, 1, sizeFileToRead, file);
     911           0 :                 if (memcmp(tzInfo->defaultTZBuffer + tzInfo->defaultTZPosition, bufferFile, sizeFileRead) != 0) {
     912           0 :                     result = FALSE;
     913           0 :                     break;
     914             :                 }
     915           0 :                 sizeFileLeft -= sizeFileRead;
     916           0 :                 tzInfo->defaultTZPosition += sizeFileRead;
     917             :             }
     918             :         }
     919             :     } else {
     920           0 :         result = FALSE;
     921             :     }
     922             : 
     923           0 :     if (file != NULL) {
     924           0 :         fclose(file);
     925             :     }
     926             : 
     927           0 :     return result;
     928             : }
     929             : 
     930             : 
     931             : /* dirent also lists two entries: "." and ".." that we can safely ignore. */
     932             : #define SKIP1 "."
     933             : #define SKIP2 ".."
     934             : static UBool U_CALLCONV putil_cleanup(void);
     935             : static CharString *gSearchTZFileResult = NULL;
     936             : 
     937             : /*
     938             :  * This method recursively traverses the directory given for a matching TZ file and returns the first match.
     939             :  * This function is not thread safe - it uses a global, gSearchTZFileResult, to hold its results.
     940             :  */
     941           0 : static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
     942           0 :     DIR* dirp = opendir(path);
     943           0 :     DIR* subDirp = NULL;
     944           0 :     struct dirent* dirEntry = NULL;
     945             : 
     946           0 :     char* result = NULL;
     947           0 :     if (dirp == NULL) {
     948           0 :         return result;
     949             :     }
     950             : 
     951           0 :     if (gSearchTZFileResult == NULL) {
     952           0 :         gSearchTZFileResult = new CharString;
     953           0 :         if (gSearchTZFileResult == NULL) {
     954           0 :             return NULL;
     955             :         }
     956           0 :         ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
     957             :     }
     958             : 
     959             :     /* Save the current path */
     960           0 :     UErrorCode status = U_ZERO_ERROR;
     961           0 :     CharString curpath(path, -1, status);
     962           0 :     if (U_FAILURE(status)) {
     963           0 :         return NULL;
     964             :     }
     965             : 
     966             :     /* Check each entry in the directory. */
     967           0 :     while((dirEntry = readdir(dirp)) != NULL) {
     968           0 :         const char* dirName = dirEntry->d_name;
     969           0 :         if (uprv_strcmp(dirName, SKIP1) != 0 && uprv_strcmp(dirName, SKIP2) != 0) {
     970             :             /* Create a newpath with the new entry to test each entry in the directory. */
     971           0 :             CharString newpath(curpath, status);
     972           0 :             newpath.append(dirName, -1, status);
     973           0 :             if (U_FAILURE(status)) {
     974           0 :                 return NULL;
     975             :             }
     976             : 
     977           0 :             if ((subDirp = opendir(newpath.data())) != NULL) {
     978             :                 /* If this new path is a directory, make a recursive call with the newpath. */
     979           0 :                 closedir(subDirp);
     980           0 :                 newpath.append('/', status);
     981           0 :                 if (U_FAILURE(status)) {
     982           0 :                     return NULL;
     983             :                 }
     984           0 :                 result = searchForTZFile(newpath.data(), tzInfo);
     985             :                 /*
     986             :                  Have to get out here. Otherwise, we'd keep looking
     987             :                  and return the first match in the top-level directory
     988             :                  if there's a match in the top-level. If not, this function
     989             :                  would return NULL and set gTimeZoneBufferPtr to NULL in initDefault().
     990             :                  It worked without this in most cases because we have a fallback of calling
     991             :                  localtime_r to figure out the default timezone.
     992             :                 */
     993           0 :                 if (result != NULL)
     994           0 :                     break;
     995           0 :             } else if (uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) {
     996           0 :                 if(compareBinaryFiles(TZDEFAULT, newpath.data(), tzInfo)) {
     997           0 :                     int32_t amountToSkip = sizeof(TZZONEINFO) - 1;
     998           0 :                     if (amountToSkip > newpath.length()) {
     999           0 :                         amountToSkip = newpath.length();
    1000             :                     }
    1001           0 :                     const char* zoneid = newpath.data() + amountToSkip;
    1002           0 :                     skipZoneIDPrefix(&zoneid);
    1003           0 :                     gSearchTZFileResult->clear();
    1004           0 :                     gSearchTZFileResult->append(zoneid, -1, status);
    1005           0 :                     if (U_FAILURE(status)) {
    1006           0 :                         return NULL;
    1007             :                     }
    1008           0 :                     result = gSearchTZFileResult->data();
    1009             :                     /* Get out after the first one found. */
    1010           0 :                     break;
    1011             :                 }
    1012             :             }
    1013             :         }
    1014             :     }
    1015           0 :     closedir(dirp);
    1016           0 :     return result;
    1017             : }
    1018             : #endif
    1019             : 
    1020             : U_CAPI void U_EXPORT2
    1021           0 : uprv_tzname_clear_cache()
    1022             : {
    1023             : #if defined(CHECK_LOCALTIME_LINK) && !defined(DEBUG_SKIP_LOCALTIME_LINK)
    1024           0 :     gTimeZoneBufferPtr = NULL;
    1025             : #endif
    1026           0 : }
    1027             : 
    1028             : // With the Universal Windows Platform we can just ask Windows for the name
    1029             : #if U_PLATFORM_HAS_WINUWP_API
    1030             : U_CAPI const char* U_EXPORT2
    1031             : uprv_getWindowsTimeZone()
    1032             : {
    1033             :     // Get default Windows timezone.   
    1034             :     ComPtr<IInspectable> calendar;
    1035             :     HRESULT hr = RoActivateInstance(
    1036             :         HStringReference(RuntimeClass_Windows_Globalization_Calendar).Get(),
    1037             :         &calendar);
    1038             :     if (SUCCEEDED(hr))
    1039             :     {
    1040             :         ComPtr<ABI::Windows::Globalization::ITimeZoneOnCalendar> timezone;
    1041             :         hr = calendar.As(&timezone);
    1042             :         if (SUCCEEDED(hr))
    1043             :         {
    1044             :             HString timezoneString;
    1045             :             hr = timezone->GetTimeZone(timezoneString.GetAddressOf());
    1046             :             if (SUCCEEDED(hr))
    1047             :             {
    1048             :                 int32_t length = wcslen(timezoneString.GetRawBuffer(NULL));
    1049             :                 char* asciiId = (char*)uprv_calloc(length + 1, sizeof(char));
    1050             :                 if (asciiId != nullptr)
    1051             :                 {
    1052             :                     u_UCharsToChars((UChar*)timezoneString.GetRawBuffer(NULL), asciiId, length);
    1053             :                     return asciiId;
    1054             :                 }
    1055             :             }
    1056             :         }
    1057             :     }
    1058             : 
    1059             :     // Failed
    1060             :     return nullptr;
    1061             : }
    1062             : #endif
    1063             : 
    1064             : U_CAPI const char* U_EXPORT2
    1065           0 : uprv_tzname(int n)
    1066             : {
    1067           0 :     const char *tzid = NULL;
    1068             : #if U_PLATFORM_USES_ONLY_WIN32_API
    1069             : #if U_PLATFORM_HAS_WINUWP_API > 0
    1070             :     tzid = uprv_getWindowsTimeZone();
    1071             : #else
    1072             :     tzid = uprv_detectWindowsTimeZone();
    1073             : #endif
    1074             : 
    1075             :     if (tzid != NULL) {
    1076             :         return tzid;
    1077             :     }
    1078             : 
    1079             : #ifndef U_TZNAME
    1080             :     // The return value is free'd in timezone.cpp on Windows because
    1081             :     // the other code path returns a pointer to a heap location.
    1082             :     // If we don't have a name already, then tzname wouldn't be any
    1083             :     // better, so just fall back.
    1084             :     return uprv_strdup("Etc/UTC");
    1085             : #endif // !U_TZNAME
    1086             : 
    1087             : #else
    1088             : 
    1089             : /*#if U_PLATFORM_IS_DARWIN_BASED
    1090             :     int ret;
    1091             : 
    1092             :     tzid = getenv("TZFILE");
    1093             :     if (tzid != NULL) {
    1094             :         return tzid;
    1095             :     }
    1096             : #endif*/
    1097             : 
    1098             : /* This code can be temporarily disabled to test tzname resolution later on. */
    1099             : #ifndef DEBUG_TZNAME
    1100           0 :     tzid = getenv("TZ");
    1101           0 :     if (tzid != NULL && isValidOlsonID(tzid)
    1102             : #if U_PLATFORM == U_PF_SOLARIS
    1103             :     /* When TZ equals localtime on Solaris, check the /etc/localtime file. */
    1104             :         && uprv_strcmp(tzid, TZ_ENV_CHECK) != 0
    1105             : #endif
    1106             :     ) {
    1107             :         /* The colon forces tzset() to treat the remainder as zoneinfo path */ 
    1108           0 :         if (tzid[0] == ':') { 
    1109           0 :             tzid++; 
    1110             :         } 
    1111             :         /* This might be a good Olson ID. */
    1112           0 :         skipZoneIDPrefix(&tzid);
    1113           0 :         return tzid;
    1114             :     }
    1115             :     /* else U_TZNAME will give a better result. */
    1116             : #endif
    1117             : 
    1118             : #if defined(CHECK_LOCALTIME_LINK) && !defined(DEBUG_SKIP_LOCALTIME_LINK)
    1119             :     /* Caller must handle threading issues */
    1120           0 :     if (gTimeZoneBufferPtr == NULL) {
    1121             :         /*
    1122             :         This is a trick to look at the name of the link to get the Olson ID
    1123             :         because the tzfile contents is underspecified.
    1124             :         This isn't guaranteed to work because it may not be a symlink.
    1125             :         */
    1126           0 :         int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer)-1);
    1127           0 :         if (0 < ret) {
    1128           0 :             int32_t tzZoneInfoLen = uprv_strlen(TZZONEINFO);
    1129           0 :             gTimeZoneBuffer[ret] = 0;
    1130           0 :             if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, tzZoneInfoLen) == 0
    1131           0 :                 && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
    1132             :             {
    1133           0 :                 return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
    1134             :             }
    1135             : #if U_PLATFORM == U_PF_SOLARIS
    1136             :             else
    1137             :             {
    1138             :                 tzZoneInfoLen = uprv_strlen(TZZONEINFO2);
    1139             :                 if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO2, tzZoneInfoLen) == 0
    1140             :                                 && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
    1141             :                 {
    1142             :                     return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
    1143             :                 }
    1144             :             }
    1145             : #endif
    1146             :         } else {
    1147             : #if defined(SEARCH_TZFILE)
    1148           0 :             DefaultTZInfo* tzInfo = (DefaultTZInfo*)uprv_malloc(sizeof(DefaultTZInfo));
    1149           0 :             if (tzInfo != NULL) {
    1150           0 :                 tzInfo->defaultTZBuffer = NULL;
    1151           0 :                 tzInfo->defaultTZFileSize = 0;
    1152           0 :                 tzInfo->defaultTZFilePtr = NULL;
    1153           0 :                 tzInfo->defaultTZstatus = FALSE;
    1154           0 :                 tzInfo->defaultTZPosition = 0;
    1155             : 
    1156           0 :                 gTimeZoneBufferPtr = searchForTZFile(TZZONEINFO, tzInfo);
    1157             : 
    1158             :                 /* Free previously allocated memory */
    1159           0 :                 if (tzInfo->defaultTZBuffer != NULL) {
    1160           0 :                     uprv_free(tzInfo->defaultTZBuffer);
    1161             :                 }
    1162           0 :                 if (tzInfo->defaultTZFilePtr != NULL) {
    1163           0 :                     fclose(tzInfo->defaultTZFilePtr);
    1164             :                 }
    1165           0 :                 uprv_free(tzInfo);
    1166             :             }
    1167             : 
    1168           0 :             if (gTimeZoneBufferPtr != NULL && isValidOlsonID(gTimeZoneBufferPtr)) {
    1169           0 :                 return gTimeZoneBufferPtr;
    1170             :             }
    1171             : #endif
    1172             :         }
    1173             :     }
    1174             :     else {
    1175           0 :         return gTimeZoneBufferPtr;
    1176             :     }
    1177             : #endif
    1178             : #endif
    1179             : 
    1180             : #ifdef U_TZNAME
    1181             : #if U_PLATFORM_USES_ONLY_WIN32_API
    1182             :     /* The return value is free'd in timezone.cpp on Windows because
    1183             :      * the other code path returns a pointer to a heap location. */
    1184             :     return uprv_strdup(U_TZNAME[n]);
    1185             : #else
    1186             :     /*
    1187             :     U_TZNAME is usually a non-unique abbreviation, which isn't normally usable.
    1188             :     So we remap the abbreviation to an olson ID.
    1189             : 
    1190             :     Since Windows exposes a little more timezone information,
    1191             :     we normally don't use this code on Windows because
    1192             :     uprv_detectWindowsTimeZone should have already given the correct answer.
    1193             :     */
    1194             :     {
    1195             :         struct tm juneSol, decemberSol;
    1196             :         int daylightType;
    1197             :         static const time_t juneSolstice=1182478260; /*2007-06-21 18:11 UT*/
    1198             :         static const time_t decemberSolstice=1198332540; /*2007-12-22 06:09 UT*/
    1199             : 
    1200             :         /* This probing will tell us when daylight savings occurs.  */
    1201           0 :         localtime_r(&juneSolstice, &juneSol);
    1202           0 :         localtime_r(&decemberSolstice, &decemberSol);
    1203           0 :         if(decemberSol.tm_isdst > 0) {
    1204           0 :           daylightType = U_DAYLIGHT_DECEMBER;
    1205           0 :         } else if(juneSol.tm_isdst > 0) {
    1206           0 :           daylightType = U_DAYLIGHT_JUNE;
    1207             :         } else {
    1208           0 :           daylightType = U_DAYLIGHT_NONE;
    1209             :         }
    1210           0 :         tzid = remapShortTimeZone(U_TZNAME[0], U_TZNAME[1], daylightType, uprv_timezone());
    1211           0 :         if (tzid != NULL) {
    1212           0 :             return tzid;
    1213             :         }
    1214             :     }
    1215           0 :     return U_TZNAME[n];
    1216             : #endif
    1217             : #else
    1218             :     return "";
    1219             : #endif
    1220             : }
    1221             : 
    1222             : /* Get and set the ICU data directory --------------------------------------- */
    1223             : 
    1224             : static icu::UInitOnce gDataDirInitOnce = U_INITONCE_INITIALIZER;
    1225             : static char *gDataDirectory = NULL;
    1226             : 
    1227             : UInitOnce gTimeZoneFilesInitOnce = U_INITONCE_INITIALIZER;
    1228             : static CharString *gTimeZoneFilesDirectory = NULL;
    1229             : 
    1230             : #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
    1231             :  static char *gCorrectedPOSIXLocale = NULL; /* Sometimes heap allocated */
    1232             :  static bool gCorrectedPOSIXLocaleHeapAllocated = false;
    1233             : #endif
    1234             : 
    1235           0 : static UBool U_CALLCONV putil_cleanup(void)
    1236             : {
    1237           0 :     if (gDataDirectory && *gDataDirectory) {
    1238           0 :         uprv_free(gDataDirectory);
    1239             :     }
    1240           0 :     gDataDirectory = NULL;
    1241           0 :     gDataDirInitOnce.reset();
    1242             : 
    1243           0 :     delete gTimeZoneFilesDirectory;
    1244           0 :     gTimeZoneFilesDirectory = NULL;
    1245           0 :     gTimeZoneFilesInitOnce.reset();
    1246             : 
    1247             : #ifdef SEARCH_TZFILE
    1248           0 :     delete gSearchTZFileResult;
    1249           0 :     gSearchTZFileResult = NULL;
    1250             : #endif
    1251             : 
    1252             : #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
    1253           0 :     if (gCorrectedPOSIXLocale && gCorrectedPOSIXLocaleHeapAllocated) {
    1254           0 :         uprv_free(gCorrectedPOSIXLocale);
    1255           0 :         gCorrectedPOSIXLocale = NULL;
    1256           0 :         gCorrectedPOSIXLocaleHeapAllocated = false;
    1257             :     }
    1258             : #endif
    1259           0 :     return TRUE;
    1260             : }
    1261             : 
    1262             : /*
    1263             :  * Set the data directory.
    1264             :  *    Make a copy of the passed string, and set the global data dir to point to it.
    1265             :  */
    1266             : U_CAPI void U_EXPORT2
    1267           3 : u_setDataDirectory(const char *directory) {
    1268             :     char *newDataDir;
    1269             :     int32_t length;
    1270             : 
    1271           3 :     if(directory==NULL || *directory==0) {
    1272             :         /* A small optimization to prevent the malloc and copy when the
    1273             :         shared library is used, and this is a way to make sure that NULL
    1274             :         is never returned.
    1275             :         */
    1276           0 :         newDataDir = (char *)"";
    1277             :     }
    1278             :     else {
    1279           3 :         length=(int32_t)uprv_strlen(directory);
    1280           3 :         newDataDir = (char *)uprv_malloc(length + 2);
    1281             :         /* Exit out if newDataDir could not be created. */
    1282           3 :         if (newDataDir == NULL) {
    1283           0 :             return;
    1284             :         }
    1285           3 :         uprv_strcpy(newDataDir, directory);
    1286             : 
    1287             : #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
    1288             :         {
    1289             :             char *p;
    1290             :             while(p = uprv_strchr(newDataDir, U_FILE_ALT_SEP_CHAR)) {
    1291             :                 *p = U_FILE_SEP_CHAR;
    1292             :             }
    1293             :         }
    1294             : #endif
    1295             :     }
    1296             : 
    1297           3 :     if (gDataDirectory && *gDataDirectory) {
    1298           0 :         uprv_free(gDataDirectory);
    1299             :     }
    1300           3 :     gDataDirectory = newDataDir;
    1301           3 :     ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
    1302             : }
    1303             : 
    1304             : U_CAPI UBool U_EXPORT2
    1305           0 : uprv_pathIsAbsolute(const char *path)
    1306             : {
    1307           0 :   if(!path || !*path) {
    1308           0 :     return FALSE;
    1309             :   }
    1310             : 
    1311           0 :   if(*path == U_FILE_SEP_CHAR) {
    1312           0 :     return TRUE;
    1313             :   }
    1314             : 
    1315             : #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
    1316             :   if(*path == U_FILE_ALT_SEP_CHAR) {
    1317             :     return TRUE;
    1318             :   }
    1319             : #endif
    1320             : 
    1321             : #if U_PLATFORM_USES_ONLY_WIN32_API
    1322             :   if( (((path[0] >= 'A') && (path[0] <= 'Z')) ||
    1323             :        ((path[0] >= 'a') && (path[0] <= 'z'))) &&
    1324             :       path[1] == ':' ) {
    1325             :     return TRUE;
    1326             :   }
    1327             : #endif
    1328             : 
    1329           0 :   return FALSE;
    1330             : }
    1331             : 
    1332             : /* Temporary backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
    1333             :    until some client wrapper makefiles are updated */
    1334             : #if U_PLATFORM_IS_DARWIN_BASED && TARGET_IPHONE_SIMULATOR
    1335             : # if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
    1336             : #  define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
    1337             : # endif
    1338             : #endif
    1339             : 
    1340           3 : static void U_CALLCONV dataDirectoryInitFn() {
    1341             :     /* If we already have the directory, then return immediately. Will happen if user called
    1342             :      * u_setDataDirectory().
    1343             :      */
    1344           3 :     if (gDataDirectory) {
    1345           3 :         return;
    1346             :     }
    1347             : 
    1348           0 :     const char *path = NULL;
    1349             : #if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
    1350             :     char datadir_path_buffer[PATH_MAX];
    1351             : #endif
    1352             : 
    1353             :     /*
    1354             :     When ICU_NO_USER_DATA_OVERRIDE is defined, users aren't allowed to
    1355             :     override ICU's data with the ICU_DATA environment variable. This prevents
    1356             :     problems where multiple custom copies of ICU's specific version of data
    1357             :     are installed on a system. Either the application must define the data
    1358             :     directory with u_setDataDirectory, define ICU_DATA_DIR when compiling
    1359             :     ICU, set the data with udata_setCommonData or trust that all of the
    1360             :     required data is contained in ICU's data library that contains
    1361             :     the entry point defined by U_ICUDATA_ENTRY_POINT.
    1362             : 
    1363             :     There may also be some platforms where environment variables
    1364             :     are not allowed.
    1365             :     */
    1366             : #   if !defined(ICU_NO_USER_DATA_OVERRIDE) && !UCONFIG_NO_FILE_IO
    1367             :     /* First try to get the environment variable */
    1368             : #       if U_PLATFORM_HAS_WINUWP_API == 0  // Windows UWP does not support getenv
    1369           0 :         path=getenv("ICU_DATA");
    1370             : #       endif
    1371             : #   endif
    1372             : 
    1373             :     /* ICU_DATA_DIR may be set as a compile option.
    1374             :      * U_ICU_DATA_DEFAULT_DIR is provided and is set by ICU at compile time
    1375             :      * and is used only when data is built in archive mode eliminating the need
    1376             :      * for ICU_DATA_DIR to be set. U_ICU_DATA_DEFAULT_DIR is set to the installation
    1377             :      * directory of the data dat file. Users should use ICU_DATA_DIR if they want to
    1378             :      * set their own path.
    1379             :      */
    1380             : #if defined(ICU_DATA_DIR) || defined(U_ICU_DATA_DEFAULT_DIR)
    1381             :     if(path==NULL || *path==0) {
    1382             : # if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
    1383             :         const char *prefix = getenv(ICU_DATA_DIR_PREFIX_ENV_VAR);
    1384             : # endif
    1385             : # ifdef ICU_DATA_DIR
    1386             :         path=ICU_DATA_DIR;
    1387             : # else
    1388             :         path=U_ICU_DATA_DEFAULT_DIR;
    1389             : # endif
    1390             : # if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
    1391             :         if (prefix != NULL) {
    1392             :             snprintf(datadir_path_buffer, PATH_MAX, "%s%s", prefix, path);
    1393             :             path=datadir_path_buffer;
    1394             :         }
    1395             : # endif
    1396             :     }
    1397             : #endif
    1398             : 
    1399             : #if defined(ICU_DATA_DIR_WINDOWS) && U_PLATFORM_HAS_WINUWP_API != 0
    1400             :     // Use data from the %windir%\globalization\icu directory
    1401             :     // This is only available if ICU is built as a system component
    1402             :     char datadir_path_buffer[MAX_PATH];
    1403             :     UINT length = GetWindowsDirectoryA(datadir_path_buffer, UPRV_LENGTHOF(datadir_path_buffer));
    1404             :     if (length > 0 && length < (UPRV_LENGTHOF(datadir_path_buffer) - sizeof(ICU_DATA_DIR_WINDOWS) - 1))
    1405             :     {
    1406             :         if (datadir_path_buffer[length - 1] != '\\')
    1407             :         {
    1408             :             datadir_path_buffer[length++] = '\\';
    1409             :             datadir_path_buffer[length] = '\0';
    1410             :         }
    1411             : 
    1412             :         if ((length + 1 + sizeof(ICU_DATA_DIR_WINDOWS)) < UPRV_LENGTHOF(datadir_path_buffer))
    1413             :         {
    1414             :             uprv_strcat(datadir_path_buffer, ICU_DATA_DIR_WINDOWS);
    1415             :             path = datadir_path_buffer;
    1416             :         }
    1417             :     }
    1418             : #endif
    1419             : 
    1420           0 :     if(path==NULL) {
    1421             :         /* It looks really bad, set it to something. */
    1422             : #if U_PLATFORM_HAS_WIN32_API
    1423             :         // Windows UWP will require icudtl.dat file in same directory as icuuc.dll
    1424             :         path = ".\\";
    1425             : #else
    1426           0 :         path = "";
    1427             : #endif
    1428             :     }
    1429             : 
    1430           0 :     u_setDataDirectory(path);
    1431           0 :     return;
    1432             : }
    1433             : 
    1434             : U_CAPI const char * U_EXPORT2
    1435          10 : u_getDataDirectory(void) {
    1436          10 :     umtx_initOnce(gDataDirInitOnce, &dataDirectoryInitFn);
    1437          10 :     return gDataDirectory;
    1438             : }
    1439             : 
    1440           0 : static void setTimeZoneFilesDir(const char *path, UErrorCode &status) {
    1441           0 :     if (U_FAILURE(status)) {
    1442           0 :         return;
    1443             :     }
    1444           0 :     gTimeZoneFilesDirectory->clear();
    1445           0 :     gTimeZoneFilesDirectory->append(path, status);
    1446             : #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
    1447             :     char *p = gTimeZoneFilesDirectory->data();
    1448             :     while (p = uprv_strchr(p, U_FILE_ALT_SEP_CHAR)) {
    1449             :         *p = U_FILE_SEP_CHAR;
    1450             :     }
    1451             : #endif
    1452             : }
    1453             : 
    1454             : #define TO_STRING(x) TO_STRING_2(x) 
    1455             : #define TO_STRING_2(x) #x
    1456             : 
    1457           0 : static void U_CALLCONV TimeZoneDataDirInitFn(UErrorCode &status) {
    1458           0 :     U_ASSERT(gTimeZoneFilesDirectory == NULL);
    1459           0 :     ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
    1460           0 :     gTimeZoneFilesDirectory = new CharString();
    1461           0 :     if (gTimeZoneFilesDirectory == NULL) {
    1462           0 :         status = U_MEMORY_ALLOCATION_ERROR;
    1463           0 :         return;
    1464             :     }
    1465             : #if U_PLATFORM_HAS_WINUWP_API == 0
    1466           0 :     const char *dir = getenv("ICU_TIMEZONE_FILES_DIR");
    1467             : #else
    1468             :     // TODO: UWP does not support alternate timezone data directories at this time
    1469             :     const char *dir = "";
    1470             : #endif // U_PLATFORM_HAS_WINUWP_API
    1471             : #if defined(U_TIMEZONE_FILES_DIR)
    1472             :     if (dir == NULL) {
    1473             :         dir = TO_STRING(U_TIMEZONE_FILES_DIR);
    1474             :     }
    1475             : #endif
    1476           0 :     if (dir == NULL) {
    1477           0 :         dir = "";
    1478             :     }
    1479           0 :     setTimeZoneFilesDir(dir, status);
    1480             : }
    1481             : 
    1482             : 
    1483             : U_CAPI const char * U_EXPORT2
    1484           0 : u_getTimeZoneFilesDirectory(UErrorCode *status) {
    1485           0 :     umtx_initOnce(gTimeZoneFilesInitOnce, &TimeZoneDataDirInitFn, *status);
    1486           0 :     return U_SUCCESS(*status) ? gTimeZoneFilesDirectory->data() : "";
    1487             : }
    1488             : 
    1489             : U_CAPI void U_EXPORT2
    1490           0 : u_setTimeZoneFilesDirectory(const char *path, UErrorCode *status) {
    1491           0 :     umtx_initOnce(gTimeZoneFilesInitOnce, &TimeZoneDataDirInitFn, *status);
    1492           0 :     setTimeZoneFilesDir(path, *status);
    1493             : 
    1494             :     // Note: this function does some extra churn, first setting based on the
    1495             :     //       environment, then immediately replacing with the value passed in.
    1496             :     //       The logic is simpler that way, and performance shouldn't be an issue.
    1497           0 : }
    1498             : 
    1499             : 
    1500             : #if U_POSIX_LOCALE
    1501             : /* A helper function used by uprv_getPOSIXIDForDefaultLocale and
    1502             :  * uprv_getPOSIXIDForDefaultCodepage. Returns the posix locale id for
    1503             :  * LC_CTYPE and LC_MESSAGES. It doesn't support other locale categories.
    1504             :  */
    1505           2 : static const char *uprv_getPOSIXIDForCategory(int category)
    1506             : {
    1507           2 :     const char* posixID = NULL;
    1508           2 :     if (category == LC_MESSAGES || category == LC_CTYPE) {
    1509             :         /*
    1510             :         * On Solaris two different calls to setlocale can result in
    1511             :         * different values. Only get this value once.
    1512             :         *
    1513             :         * We must check this first because an application can set this.
    1514             :         *
    1515             :         * LC_ALL can't be used because it's platform dependent. The LANG
    1516             :         * environment variable seems to affect LC_CTYPE variable by default.
    1517             :         * Here is what setlocale(LC_ALL, NULL) can return.
    1518             :         * HPUX can return 'C C C C C C C'
    1519             :         * Solaris can return /en_US/C/C/C/C/C on the second try.
    1520             :         * Linux can return LC_CTYPE=C;LC_NUMERIC=C;...
    1521             :         *
    1522             :         * The default codepage detection also needs to use LC_CTYPE.
    1523             :         *
    1524             :         * Do not call setlocale(LC_*, "")! Using an empty string instead
    1525             :         * of NULL, will modify the libc behavior.
    1526             :         */
    1527           2 :         posixID = setlocale(category, NULL);
    1528           2 :         if ((posixID == 0)
    1529           2 :             || (uprv_strcmp("C", posixID) == 0)
    1530           2 :             || (uprv_strcmp("POSIX", posixID) == 0))
    1531             :         {
    1532             :             /* Maybe we got some garbage.  Try something more reasonable */
    1533           0 :             posixID = getenv("LC_ALL");
    1534             :             /* Solaris speaks POSIX -  See IEEE Std 1003.1-2008 
    1535             :              * This is needed to properly handle empty env. variables
    1536             :              */
    1537             : #if U_PLATFORM == U_PF_SOLARIS
    1538             :             if ((posixID == 0) || (posixID[0] == '\0')) {
    1539             :                 posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
    1540             :                 if ((posixID == 0) || (posixID[0] == '\0')) {
    1541             : #else
    1542           0 :             if (posixID == 0) {
    1543           0 :                 posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
    1544           0 :                 if (posixID == 0) {
    1545             : #endif                    
    1546           0 :                     posixID = getenv("LANG");
    1547             :                 }
    1548             :             }
    1549             :         }
    1550             :     }
    1551           2 :     if ((posixID==0)
    1552           2 :         || (uprv_strcmp("C", posixID) == 0)
    1553           2 :         || (uprv_strcmp("POSIX", posixID) == 0))
    1554             :     {
    1555             :         /* Nothing worked.  Give it a nice POSIX default value. */
    1556           0 :         posixID = "en_US_POSIX";
    1557             :     }
    1558           2 :     return posixID;
    1559             : }
    1560             : 
    1561             : /* Return just the POSIX id for the default locale, whatever happens to be in
    1562             :  * it. It gets the value from LC_MESSAGES and indirectly from LC_ALL and LANG.
    1563             :  */
    1564           2 : static const char *uprv_getPOSIXIDForDefaultLocale(void)
    1565             : {
    1566             :     static const char* posixID = NULL;
    1567           2 :     if (posixID == 0) {
    1568           2 :         posixID = uprv_getPOSIXIDForCategory(LC_MESSAGES);
    1569             :     }
    1570           2 :     return posixID;
    1571             : }
    1572             : 
    1573             : #if !U_CHARSET_IS_UTF8
    1574             : /* Return just the POSIX id for the default codepage, whatever happens to be in
    1575             :  * it. It gets the value from LC_CTYPE and indirectly from LC_ALL and LANG.
    1576             :  */
    1577             : static const char *uprv_getPOSIXIDForDefaultCodepage(void)
    1578             : {
    1579             :     static const char* posixID = NULL;
    1580             :     if (posixID == 0) {
    1581             :         posixID = uprv_getPOSIXIDForCategory(LC_CTYPE);
    1582             :     }
    1583             :     return posixID;
    1584             : }
    1585             : #endif
    1586             : #endif
    1587             : 
    1588             : /* NOTE: The caller should handle thread safety */
    1589             : U_CAPI const char* U_EXPORT2
    1590           2 : uprv_getDefaultLocaleID()
    1591             : {
    1592             : #if U_POSIX_LOCALE
    1593             : /*
    1594             :   Note that:  (a '!' means the ID is improper somehow)
    1595             :      LC_ALL  ---->     default_loc          codepage
    1596             : --------------------------------------------------------
    1597             :      ab.CD             ab                   CD
    1598             :      ab@CD             ab__CD               -
    1599             :      ab@CD.EF          ab__CD               EF
    1600             : 
    1601             :      ab_CD.EF@GH       ab_CD_GH             EF
    1602             : 
    1603             : Some 'improper' ways to do the same as above:
    1604             :   !  ab_CD@GH.EF       ab_CD_GH             EF
    1605             :   !  ab_CD.EF@GH.IJ    ab_CD_GH             EF
    1606             :   !  ab_CD@ZZ.EF@GH.IJ ab_CD_GH             EF
    1607             : 
    1608             :      _CD@GH            _CD_GH               -
    1609             :      _CD.EF@GH         _CD_GH               EF
    1610             : 
    1611             : The variant cannot have dots in it.
    1612             : The 'rightmost' variant (@xxx) wins.
    1613             : The leftmost codepage (.xxx) wins.
    1614             : */
    1615           2 :     char *correctedPOSIXLocale = 0;
    1616           2 :     const char* posixID = uprv_getPOSIXIDForDefaultLocale();
    1617             :     const char *p;
    1618             :     const char *q;
    1619             :     int32_t len;
    1620             : 
    1621             :     /* Format: (no spaces)
    1622             :     ll [ _CC ] [ . MM ] [ @ VV]
    1623             : 
    1624             :       l = lang, C = ctry, M = charmap, V = variant
    1625             :     */
    1626             : 
    1627           2 :     if (gCorrectedPOSIXLocale != NULL) {
    1628           0 :         return gCorrectedPOSIXLocale;
    1629             :     }
    1630             : 
    1631           2 :     if ((p = uprv_strchr(posixID, '.')) != NULL) {
    1632             :         /* assume new locale can't be larger than old one? */
    1633           2 :         correctedPOSIXLocale = static_cast<char *>(uprv_malloc(uprv_strlen(posixID)+1));
    1634             :         /* Exit on memory allocation error. */
    1635           2 :         if (correctedPOSIXLocale == NULL) {
    1636           0 :             return NULL;
    1637             :         }
    1638           2 :         uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
    1639           2 :         correctedPOSIXLocale[p-posixID] = 0;
    1640             : 
    1641             :         /* do not copy after the @ */
    1642           2 :         if ((p = uprv_strchr(correctedPOSIXLocale, '@')) != NULL) {
    1643           0 :             correctedPOSIXLocale[p-correctedPOSIXLocale] = 0;
    1644             :         }
    1645             :     }
    1646             : 
    1647             :     /* Note that we scan the *uncorrected* ID. */
    1648           2 :     if ((p = uprv_strrchr(posixID, '@')) != NULL) {
    1649           0 :         if (correctedPOSIXLocale == NULL) {
    1650           0 :             correctedPOSIXLocale = static_cast<char *>(uprv_malloc(uprv_strlen(posixID)+1));
    1651             :             /* Exit on memory allocation error. */
    1652           0 :             if (correctedPOSIXLocale == NULL) {
    1653           0 :                 return NULL;
    1654             :             }
    1655           0 :             uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
    1656           0 :             correctedPOSIXLocale[p-posixID] = 0;
    1657             :         }
    1658           0 :         p++;
    1659             : 
    1660             :         /* Take care of any special cases here.. */
    1661           0 :         if (!uprv_strcmp(p, "nynorsk")) {
    1662           0 :             p = "NY";
    1663             :             /* Don't worry about no__NY. In practice, it won't appear. */
    1664             :         }
    1665             : 
    1666           0 :         if (uprv_strchr(correctedPOSIXLocale,'_') == NULL) {
    1667           0 :             uprv_strcat(correctedPOSIXLocale, "__"); /* aa@b -> aa__b */
    1668             :         }
    1669             :         else {
    1670           0 :             uprv_strcat(correctedPOSIXLocale, "_"); /* aa_CC@b -> aa_CC_b */
    1671             :         }
    1672             : 
    1673           0 :         if ((q = uprv_strchr(p, '.')) != NULL) {
    1674             :             /* How big will the resulting string be? */
    1675           0 :             len = (int32_t)(uprv_strlen(correctedPOSIXLocale) + (q-p));
    1676           0 :             uprv_strncat(correctedPOSIXLocale, p, q-p);
    1677           0 :             correctedPOSIXLocale[len] = 0;
    1678             :         }
    1679             :         else {
    1680             :             /* Anything following the @ sign */
    1681           0 :             uprv_strcat(correctedPOSIXLocale, p);
    1682             :         }
    1683             : 
    1684             :         /* Should there be a map from 'no@nynorsk' -> no_NO_NY here?
    1685             :          * How about 'russian' -> 'ru'?
    1686             :          * Many of the other locales using ISO codes will be handled by the
    1687             :          * canonicalization functions in uloc_getDefault.
    1688             :          */
    1689             :     }
    1690             : 
    1691             :     /* Was a correction made? */
    1692           2 :     if (correctedPOSIXLocale != NULL) {
    1693           2 :         posixID = correctedPOSIXLocale;
    1694             :     }
    1695             :     else {
    1696             :         /* copy it, just in case the original pointer goes away.  See j2395 */
    1697           0 :         correctedPOSIXLocale = (char *)uprv_malloc(uprv_strlen(posixID) + 1);
    1698             :         /* Exit on memory allocation error. */
    1699           0 :         if (correctedPOSIXLocale == NULL) {
    1700           0 :             return NULL;
    1701             :         }
    1702           0 :         posixID = uprv_strcpy(correctedPOSIXLocale, posixID);
    1703             :     }
    1704             : 
    1705           2 :     if (gCorrectedPOSIXLocale == NULL) {
    1706           2 :         gCorrectedPOSIXLocale = correctedPOSIXLocale;
    1707           2 :         gCorrectedPOSIXLocaleHeapAllocated = true;
    1708           2 :         ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
    1709           2 :         correctedPOSIXLocale = NULL;
    1710             :     }
    1711             : 
    1712           2 :     if (correctedPOSIXLocale != NULL) {  /* Was already set - clean up. */
    1713           0 :         uprv_free(correctedPOSIXLocale);
    1714             :     }
    1715             : 
    1716           2 :     return posixID;
    1717             : 
    1718             : #elif U_PLATFORM_USES_ONLY_WIN32_API
    1719             : #define POSIX_LOCALE_CAPACITY 64
    1720             :     UErrorCode status = U_ZERO_ERROR;
    1721             :     char *correctedPOSIXLocale = 0;
    1722             : 
    1723             :     // If we have already figured this out just use the cached value
    1724             :     if (gCorrectedPOSIXLocale != NULL) {
    1725             :         return gCorrectedPOSIXLocale;
    1726             :     }
    1727             : 
    1728             :     // No cached value, need to determine the current value
    1729             :     static WCHAR windowsLocale[LOCALE_NAME_MAX_LENGTH];
    1730             : #if U_PLATFORM_HAS_WINUWP_API == 0 
    1731             :     // If not a Universal Windows App, we'll need user default language.
    1732             :     // Vista and above should use Locale Names instead of LCIDs
    1733             :     int length = GetUserDefaultLocaleName(windowsLocale, UPRV_LENGTHOF(windowsLocale));
    1734             : #else
    1735             :     // In a UWP app, we want the top language that the application and user agreed upon
    1736             :     ComPtr<ABI::Windows::Foundation::Collections::IVectorView<HSTRING>> languageList;
    1737             : 
    1738             :     ComPtr<ABI::Windows::Globalization::IApplicationLanguagesStatics> applicationLanguagesStatics;
    1739             :     HRESULT hr = GetActivationFactory(
    1740             :         HStringReference(RuntimeClass_Windows_Globalization_ApplicationLanguages).Get(),
    1741             :         &applicationLanguagesStatics);
    1742             :     if (SUCCEEDED(hr))
    1743             :     {
    1744             :         hr = applicationLanguagesStatics->get_Languages(&languageList);
    1745             :     }
    1746             : 
    1747             :     if (FAILED(hr))
    1748             :     {
    1749             :         // If there is no application context, then use the top language from the user language profile
    1750             :         ComPtr<ABI::Windows::System::UserProfile::IGlobalizationPreferencesStatics> globalizationPreferencesStatics;
    1751             :         hr = GetActivationFactory(
    1752             :             HStringReference(RuntimeClass_Windows_System_UserProfile_GlobalizationPreferences).Get(),
    1753             :             &globalizationPreferencesStatics);
    1754             :         if (SUCCEEDED(hr))
    1755             :         {
    1756             :             hr = globalizationPreferencesStatics->get_Languages(&languageList);
    1757             :         }
    1758             :     }
    1759             : 
    1760             :     // We have a list of languages, ICU knows one, so use the top one for our locale
    1761             :     HString topLanguage;
    1762             :     if (SUCCEEDED(hr))
    1763             :     {
    1764             :         hr = languageList->GetAt(0, topLanguage.GetAddressOf());
    1765             :     }
    1766             : 
    1767             :     if (FAILED(hr))
    1768             :     {
    1769             :         // Unexpected, use en-US by default
    1770             :         if (gCorrectedPOSIXLocale == NULL) {
    1771             :             gCorrectedPOSIXLocale = "en_US";
    1772             :         }
    1773             : 
    1774             :         return gCorrectedPOSIXLocale;
    1775             :     }
    1776             : 
    1777             :     // ResolveLocaleName will get a likely subtags form consistent with Windows behavior.
    1778             :     int length = ResolveLocaleName(topLanguage.GetRawBuffer(NULL), windowsLocale, UPRV_LENGTHOF(windowsLocale));
    1779             : #endif
    1780             :     // Now we should have a Windows locale name that needs converted to the POSIX style,
    1781             :     if (length > 0)
    1782             :     {
    1783             :         // First we need to go from UTF-16 to char (and also convert from _ to - while we're at it.)
    1784             :         char modifiedWindowsLocale[LOCALE_NAME_MAX_LENGTH];
    1785             : 
    1786             :         int32_t i;
    1787             :         for (i = 0; i < UPRV_LENGTHOF(modifiedWindowsLocale); i++)
    1788             :         {
    1789             :             if (windowsLocale[i] == '_')
    1790             :             {
    1791             :                 modifiedWindowsLocale[i] = '-';
    1792             :             }
    1793             :             else
    1794             :             {
    1795             :                 modifiedWindowsLocale[i] = static_cast<char>(windowsLocale[i]);
    1796             :             }
    1797             : 
    1798             :             if (modifiedWindowsLocale[i] == '\0')
    1799             :             {
    1800             :                 break;
    1801             :             }
    1802             :         }
    1803             : 
    1804             :         if (i >= UPRV_LENGTHOF(modifiedWindowsLocale))
    1805             :         {
    1806             :             // Ran out of room, can't really happen, maybe we'll be lucky about a matching
    1807             :             // locale when tags are dropped
    1808             :             modifiedWindowsLocale[UPRV_LENGTHOF(modifiedWindowsLocale) - 1] = '\0';
    1809             :         }
    1810             : 
    1811             :         // Now normalize the resulting name
    1812             :         if (correctedPOSIXLocale)
    1813             :         {
    1814             :             int32_t posixLen = uloc_canonicalize(modifiedWindowsLocale, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status);
    1815             :             if (U_SUCCESS(status))
    1816             :             {
    1817             :                 *(correctedPOSIXLocale + posixLen) = 0;
    1818             :                 gCorrectedPOSIXLocale = correctedPOSIXLocale;
    1819             :                 gCorrectedPOSIXLocaleHeapAllocated = true;
    1820             :                 ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
    1821             :             }
    1822             :             else
    1823             :             {
    1824             :                 uprv_free(correctedPOSIXLocale);
    1825             :             }
    1826             :         }
    1827             :     }
    1828             : 
    1829             :     // If unable to find a locale we can agree upon, use en-US by default
    1830             :     if (gCorrectedPOSIXLocale == NULL) {
    1831             :         gCorrectedPOSIXLocale = "en_US";
    1832             :     }
    1833             :     return gCorrectedPOSIXLocale;
    1834             : 
    1835             : #elif U_PLATFORM == U_PF_OS400
    1836             :     /* locales are process scoped and are by definition thread safe */
    1837             :     static char correctedLocale[64];
    1838             :     const  char *localeID = getenv("LC_ALL");
    1839             :            char *p;
    1840             : 
    1841             :     if (localeID == NULL)
    1842             :         localeID = getenv("LANG");
    1843             :     if (localeID == NULL)
    1844             :         localeID = setlocale(LC_ALL, NULL);
    1845             :     /* Make sure we have something... */
    1846             :     if (localeID == NULL)
    1847             :         return "en_US_POSIX";
    1848             : 
    1849             :     /* Extract the locale name from the path. */
    1850             :     if((p = uprv_strrchr(localeID, '/')) != NULL)
    1851             :     {
    1852             :         /* Increment p to start of locale name. */
    1853             :         p++;
    1854             :         localeID = p;
    1855             :     }
    1856             : 
    1857             :     /* Copy to work location. */
    1858             :     uprv_strcpy(correctedLocale, localeID);
    1859             : 
    1860             :     /* Strip off the '.locale' extension. */
    1861             :     if((p = uprv_strchr(correctedLocale, '.')) != NULL) {
    1862             :         *p = 0;
    1863             :     }
    1864             : 
    1865             :     /* Upper case the locale name. */
    1866             :     T_CString_toUpperCase(correctedLocale);
    1867             : 
    1868             :     /* See if we are using the POSIX locale.  Any of the
    1869             :     * following are equivalent and use the same QLGPGCMA
    1870             :     * (POSIX) locale.
    1871             :     * QLGPGCMA2 means UCS2
    1872             :     * QLGPGCMA_4 means UTF-32
    1873             :     * QLGPGCMA_8 means UTF-8
    1874             :     */
    1875             :     if ((uprv_strcmp("C", correctedLocale) == 0) ||
    1876             :         (uprv_strcmp("POSIX", correctedLocale) == 0) ||
    1877             :         (uprv_strncmp("QLGPGCMA", correctedLocale, 8) == 0))
    1878             :     {
    1879             :         uprv_strcpy(correctedLocale, "en_US_POSIX");
    1880             :     }
    1881             :     else
    1882             :     {
    1883             :         int16_t LocaleLen;
    1884             : 
    1885             :         /* Lower case the lang portion. */
    1886             :         for(p = correctedLocale; *p != 0 && *p != '_'; p++)
    1887             :         {
    1888             :             *p = uprv_tolower(*p);
    1889             :         }
    1890             : 
    1891             :         /* Adjust for Euro.  After '_E' add 'URO'. */
    1892             :         LocaleLen = uprv_strlen(correctedLocale);
    1893             :         if (correctedLocale[LocaleLen - 2] == '_' &&
    1894             :             correctedLocale[LocaleLen - 1] == 'E')
    1895             :         {
    1896             :             uprv_strcat(correctedLocale, "URO");
    1897             :         }
    1898             : 
    1899             :         /* If using Lotus-based locale then convert to
    1900             :          * equivalent non Lotus.
    1901             :          */
    1902             :         else if (correctedLocale[LocaleLen - 2] == '_' &&
    1903             :             correctedLocale[LocaleLen - 1] == 'L')
    1904             :         {
    1905             :             correctedLocale[LocaleLen - 2] = 0;
    1906             :         }
    1907             : 
    1908             :         /* There are separate simplified and traditional
    1909             :          * locales called zh_HK_S and zh_HK_T.
    1910             :          */
    1911             :         else if (uprv_strncmp(correctedLocale, "zh_HK", 5) == 0)
    1912             :         {
    1913             :             uprv_strcpy(correctedLocale, "zh_HK");
    1914             :         }
    1915             : 
    1916             :         /* A special zh_CN_GBK locale...
    1917             :         */
    1918             :         else if (uprv_strcmp(correctedLocale, "zh_CN_GBK") == 0)
    1919             :         {
    1920             :             uprv_strcpy(correctedLocale, "zh_CN");
    1921             :         }
    1922             : 
    1923             :     }
    1924             : 
    1925             :     return correctedLocale;
    1926             : #endif
    1927             : 
    1928             : }
    1929             : 
    1930             : #if !U_CHARSET_IS_UTF8
    1931             : #if U_POSIX_LOCALE
    1932             : /*
    1933             : Due to various platform differences, one platform may specify a charset,
    1934             : when they really mean a different charset. Remap the names so that they are
    1935             : compatible with ICU. Only conflicting/ambiguous aliases should be resolved
    1936             : here. Before adding anything to this function, please consider adding unique
    1937             : names to the ICU alias table in the data directory.
    1938             : */
    1939             : static const char*
    1940             : remapPlatformDependentCodepage(const char *locale, const char *name) {
    1941             :     if (locale != NULL && *locale == 0) {
    1942             :         /* Make sure that an empty locale is handled the same way. */
    1943             :         locale = NULL;
    1944             :     }
    1945             :     if (name == NULL) {
    1946             :         return NULL;
    1947             :     }
    1948             : #if U_PLATFORM == U_PF_AIX
    1949             :     if (uprv_strcmp(name, "IBM-943") == 0) {
    1950             :         /* Use the ASCII compatible ibm-943 */
    1951             :         name = "Shift-JIS";
    1952             :     }
    1953             :     else if (uprv_strcmp(name, "IBM-1252") == 0) {
    1954             :         /* Use the windows-1252 that contains the Euro */
    1955             :         name = "IBM-5348";
    1956             :     }
    1957             : #elif U_PLATFORM == U_PF_SOLARIS
    1958             :     if (locale != NULL && uprv_strcmp(name, "EUC") == 0) {
    1959             :         /* Solaris underspecifies the "EUC" name. */
    1960             :         if (uprv_strcmp(locale, "zh_CN") == 0) {
    1961             :             name = "EUC-CN";
    1962             :         }
    1963             :         else if (uprv_strcmp(locale, "zh_TW") == 0) {
    1964             :             name = "EUC-TW";
    1965             :         }
    1966             :         else if (uprv_strcmp(locale, "ko_KR") == 0) {
    1967             :             name = "EUC-KR";
    1968             :         }
    1969             :     }
    1970             :     else if (uprv_strcmp(name, "eucJP") == 0) {
    1971             :         /*
    1972             :         ibm-954 is the best match.
    1973             :         ibm-33722 is the default for eucJP (similar to Windows).
    1974             :         */
    1975             :         name = "eucjis";
    1976             :     }
    1977             :     else if (uprv_strcmp(name, "646") == 0) {
    1978             :         /*
    1979             :          * The default codepage given by Solaris is 646 but the C library routines treat it as if it was
    1980             :          * ISO-8859-1 instead of US-ASCII(646).
    1981             :          */
    1982             :         name = "ISO-8859-1";
    1983             :     }
    1984             : #elif U_PLATFORM_IS_DARWIN_BASED
    1985             :     if (locale == NULL && *name == 0) {
    1986             :         /*
    1987             :         No locale was specified, and an empty name was passed in.
    1988             :         This usually indicates that nl_langinfo didn't return valid information.
    1989             :         Mac OS X uses UTF-8 by default (especially the locale data and console).
    1990             :         */
    1991             :         name = "UTF-8";
    1992             :     }
    1993             :     else if (uprv_strcmp(name, "CP949") == 0) {
    1994             :         /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
    1995             :         name = "EUC-KR";
    1996             :     }
    1997             :     else if (locale != NULL && uprv_strcmp(locale, "en_US_POSIX") != 0 && uprv_strcmp(name, "US-ASCII") == 0) {
    1998             :         /*
    1999             :          * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
    2000             :          */
    2001             :         name = "UTF-8";
    2002             :     }
    2003             : #elif U_PLATFORM == U_PF_BSD
    2004             :     if (uprv_strcmp(name, "CP949") == 0) {
    2005             :         /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
    2006             :         name = "EUC-KR";
    2007             :     }
    2008             : #elif U_PLATFORM == U_PF_HPUX
    2009             :     if (locale != NULL && uprv_strcmp(locale, "zh_HK") == 0 && uprv_strcmp(name, "big5") == 0) {
    2010             :         /* HP decided to extend big5 as hkbig5 even though it's not compatible :-( */
    2011             :         /* zh_TW.big5 is not the same charset as zh_HK.big5! */
    2012             :         name = "hkbig5";
    2013             :     }
    2014             :     else if (uprv_strcmp(name, "eucJP") == 0) {
    2015             :         /*
    2016             :         ibm-1350 is the best match, but unavailable.
    2017             :         ibm-954 is mostly a superset of ibm-1350.
    2018             :         ibm-33722 is the default for eucJP (similar to Windows).
    2019             :         */
    2020             :         name = "eucjis";
    2021             :     }
    2022             : #elif U_PLATFORM == U_PF_LINUX
    2023             :     if (locale != NULL && uprv_strcmp(name, "euc") == 0) {
    2024             :         /* Linux underspecifies the "EUC" name. */
    2025             :         if (uprv_strcmp(locale, "korean") == 0) {
    2026             :             name = "EUC-KR";
    2027             :         }
    2028             :         else if (uprv_strcmp(locale, "japanese") == 0) {
    2029             :             /* See comment below about eucJP */
    2030             :             name = "eucjis";
    2031             :         }
    2032             :     }
    2033             :     else if (uprv_strcmp(name, "eucjp") == 0) {
    2034             :         /*
    2035             :         ibm-1350 is the best match, but unavailable.
    2036             :         ibm-954 is mostly a superset of ibm-1350.
    2037             :         ibm-33722 is the default for eucJP (similar to Windows).
    2038             :         */
    2039             :         name = "eucjis";
    2040             :     }
    2041             :     else if (locale != NULL && uprv_strcmp(locale, "en_US_POSIX") != 0 &&
    2042             :             (uprv_strcmp(name, "ANSI_X3.4-1968") == 0 || uprv_strcmp(name, "US-ASCII") == 0)) {
    2043             :         /*
    2044             :          * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
    2045             :          */
    2046             :         name = "UTF-8";
    2047             :     }
    2048             :     /*
    2049             :      * Linux returns ANSI_X3.4-1968 for C/POSIX, but the call site takes care of
    2050             :      * it by falling back to 'US-ASCII' when NULL is returned from this
    2051             :      * function. So, we don't have to worry about it here.
    2052             :      */
    2053             : #endif
    2054             :     /* return NULL when "" is passed in */
    2055             :     if (*name == 0) {
    2056             :         name = NULL;
    2057             :     }
    2058             :     return name;
    2059             : }
    2060             : 
    2061             : static const char*
    2062             : getCodepageFromPOSIXID(const char *localeName, char * buffer, int32_t buffCapacity)
    2063             : {
    2064             :     char localeBuf[100];
    2065             :     const char *name = NULL;
    2066             :     char *variant = NULL;
    2067             : 
    2068             :     if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
    2069             :         size_t localeCapacity = uprv_min(sizeof(localeBuf), (name-localeName)+1);
    2070             :         uprv_strncpy(localeBuf, localeName, localeCapacity);
    2071             :         localeBuf[localeCapacity-1] = 0; /* ensure NULL termination */
    2072             :         name = uprv_strncpy(buffer, name+1, buffCapacity);
    2073             :         buffer[buffCapacity-1] = 0; /* ensure NULL termination */
    2074             :         if ((variant = const_cast<char *>(uprv_strchr(name, '@'))) != NULL) {
    2075             :             *variant = 0;
    2076             :         }
    2077             :         name = remapPlatformDependentCodepage(localeBuf, name);
    2078             :     }
    2079             :     return name;
    2080             : }
    2081             : #endif
    2082             : 
    2083             : static const char*
    2084             : int_getDefaultCodepage()
    2085             : {
    2086             : #if U_PLATFORM == U_PF_OS400
    2087             :     uint32_t ccsid = 37; /* Default to ibm-37 */
    2088             :     static char codepage[64];
    2089             :     Qwc_JOBI0400_t jobinfo;
    2090             :     Qus_EC_t error = { sizeof(Qus_EC_t) }; /* SPI error code */
    2091             : 
    2092             :     EPT_CALL(QUSRJOBI)(&jobinfo, sizeof(jobinfo), "JOBI0400",
    2093             :         "*                         ", "                ", &error);
    2094             : 
    2095             :     if (error.Bytes_Available == 0) {
    2096             :         if (jobinfo.Coded_Char_Set_ID != 0xFFFF) {
    2097             :             ccsid = (uint32_t)jobinfo.Coded_Char_Set_ID;
    2098             :         }
    2099             :         else if (jobinfo.Default_Coded_Char_Set_Id != 0xFFFF) {
    2100             :             ccsid = (uint32_t)jobinfo.Default_Coded_Char_Set_Id;
    2101             :         }
    2102             :         /* else use the default */
    2103             :     }
    2104             :     sprintf(codepage,"ibm-%d", ccsid);
    2105             :     return codepage;
    2106             : 
    2107             : #elif U_PLATFORM == U_PF_OS390
    2108             :     static char codepage[64];
    2109             : 
    2110             :     strncpy(codepage, nl_langinfo(CODESET),63-strlen(UCNV_SWAP_LFNL_OPTION_STRING));
    2111             :     strcat(codepage,UCNV_SWAP_LFNL_OPTION_STRING);
    2112             :     codepage[63] = 0; /* NULL terminate */
    2113             : 
    2114             :     return codepage;
    2115             : 
    2116             : #elif U_PLATFORM_USES_ONLY_WIN32_API
    2117             :     static char codepage[64];
    2118             :     DWORD codepageNumber = 0;
    2119             : 
    2120             : #if U_PLATFORM_HAS_WINUWP_API > 0
    2121             :     // UWP doesn't have a direct API to get the default ACP as Microsoft would rather
    2122             :     // have folks use Unicode than a "system" code page, however this is the same
    2123             :     // codepage as the system default locale codepage.  (FWIW, the system locale is
    2124             :     // ONLY used for codepage, it should never be used for anything else)
    2125             :     GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
    2126             :         (LPWSTR)&codepageNumber, sizeof(codepageNumber) / sizeof(WCHAR));
    2127             : #else
    2128             :     // Win32 apps can call GetACP
    2129             :     codepageNumber = GetACP();
    2130             : #endif
    2131             :     // Special case for UTF-8
    2132             :     if (codepageNumber == 65001)
    2133             :     { 
    2134             :         return "UTF-8";
    2135             :     }
    2136             :     // Windows codepages can look like windows-1252, so format the found number
    2137             :     // the numbers are eclectic, however all valid system code pages, besides UTF-8
    2138             :     // are between 3 and 19999
    2139             :     if (codepageNumber > 0 && codepageNumber < 20000)
    2140             :     {
    2141             :         sprintf(codepage, "windows-%ld", codepageNumber);
    2142             :         return codepage;
    2143             :     }
    2144             :     // If the codepage number call failed then return UTF-8
    2145             :     return "UTF-8";
    2146             : 
    2147             : #elif U_POSIX_LOCALE
    2148             :     static char codesetName[100];
    2149             :     const char *localeName = NULL;
    2150             :     const char *name = NULL;
    2151             : 
    2152             :     localeName = uprv_getPOSIXIDForDefaultCodepage();
    2153             :     uprv_memset(codesetName, 0, sizeof(codesetName));
    2154             :     /* On Solaris nl_langinfo returns C locale values unless setlocale
    2155             :      * was called earlier.
    2156             :      */
    2157             : #if (U_HAVE_NL_LANGINFO_CODESET && U_PLATFORM != U_PF_SOLARIS)
    2158             :     /* When available, check nl_langinfo first because it usually gives more
    2159             :        useful names. It depends on LC_CTYPE.
    2160             :        nl_langinfo may use the same buffer as setlocale. */
    2161             :     {
    2162             :         const char *codeset = nl_langinfo(U_NL_LANGINFO_CODESET);
    2163             : #if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED
    2164             :         /*
    2165             :          * On Linux and MacOSX, ensure that default codepage for non C/POSIX locale is UTF-8
    2166             :          * instead of ASCII.
    2167             :          */
    2168             :         if (uprv_strcmp(localeName, "en_US_POSIX") != 0) {
    2169             :             codeset = remapPlatformDependentCodepage(localeName, codeset);
    2170             :         } else
    2171             : #endif
    2172             :         {
    2173             :             codeset = remapPlatformDependentCodepage(NULL, codeset);
    2174             :         }
    2175             : 
    2176             :         if (codeset != NULL) {
    2177             :             uprv_strncpy(codesetName, codeset, sizeof(codesetName));
    2178             :             codesetName[sizeof(codesetName)-1] = 0;
    2179             :             return codesetName;
    2180             :         }
    2181             :     }
    2182             : #endif
    2183             : 
    2184             :     /* Use setlocale in a nice way, and then check some environment variables.
    2185             :        Maybe the application used setlocale already.
    2186             :     */
    2187             :     uprv_memset(codesetName, 0, sizeof(codesetName));
    2188             :     name = getCodepageFromPOSIXID(localeName, codesetName, sizeof(codesetName));
    2189             :     if (name) {
    2190             :         /* if we can find the codeset name from setlocale, return that. */
    2191             :         return name;
    2192             :     }
    2193             : 
    2194             :     if (*codesetName == 0)
    2195             :     {
    2196             :         /* Everything failed. Return US ASCII (ISO 646). */
    2197             :         (void)uprv_strcpy(codesetName, "US-ASCII");
    2198             :     }
    2199             :     return codesetName;
    2200             : #else
    2201             :     return "US-ASCII";
    2202             : #endif
    2203             : }
    2204             : 
    2205             : 
    2206             : U_CAPI const char*  U_EXPORT2
    2207             : uprv_getDefaultCodepage()
    2208             : {
    2209             :     static char const  *name = NULL;
    2210             :     umtx_lock(NULL);
    2211             :     if (name == NULL) {
    2212             :         name = int_getDefaultCodepage();
    2213             :     }
    2214             :     umtx_unlock(NULL);
    2215             :     return name;
    2216             : }
    2217             : #endif  /* !U_CHARSET_IS_UTF8 */
    2218             : 
    2219             : 
    2220             : /* end of platform-specific implementation -------------- */
    2221             : 
    2222             : /* version handling --------------------------------------------------------- */
    2223             : 
    2224             : U_CAPI void U_EXPORT2
    2225           0 : u_versionFromString(UVersionInfo versionArray, const char *versionString) {
    2226             :     char *end;
    2227           0 :     uint16_t part=0;
    2228             : 
    2229           0 :     if(versionArray==NULL) {
    2230           0 :         return;
    2231             :     }
    2232             : 
    2233           0 :     if(versionString!=NULL) {
    2234             :         for(;;) {
    2235           0 :             versionArray[part]=(uint8_t)uprv_strtoul(versionString, &end, 10);
    2236           0 :             if(end==versionString || ++part==U_MAX_VERSION_LENGTH || *end!=U_VERSION_DELIMITER) {
    2237           0 :                 break;
    2238             :             }
    2239           0 :             versionString=end+1;
    2240             :         }
    2241             :     }
    2242             : 
    2243           0 :     while(part<U_MAX_VERSION_LENGTH) {
    2244           0 :         versionArray[part++]=0;
    2245             :     }
    2246             : }
    2247             : 
    2248             : U_CAPI void U_EXPORT2
    2249           0 : u_versionFromUString(UVersionInfo versionArray, const UChar *versionString) {
    2250           0 :     if(versionArray!=NULL && versionString!=NULL) {
    2251             :         char versionChars[U_MAX_VERSION_STRING_LENGTH+1];
    2252           0 :         int32_t len = u_strlen(versionString);
    2253           0 :         if(len>U_MAX_VERSION_STRING_LENGTH) {
    2254           0 :             len = U_MAX_VERSION_STRING_LENGTH;
    2255             :         }
    2256           0 :         u_UCharsToChars(versionString, versionChars, len);
    2257           0 :         versionChars[len]=0;
    2258           0 :         u_versionFromString(versionArray, versionChars);
    2259             :     }
    2260           0 : }
    2261             : 
    2262             : U_CAPI void U_EXPORT2
    2263           0 : u_versionToString(const UVersionInfo versionArray, char *versionString) {
    2264             :     uint16_t count, part;
    2265             :     uint8_t field;
    2266             : 
    2267           0 :     if(versionString==NULL) {
    2268           0 :         return;
    2269             :     }
    2270             : 
    2271           0 :     if(versionArray==NULL) {
    2272           0 :         versionString[0]=0;
    2273           0 :         return;
    2274             :     }
    2275             : 
    2276             :     /* count how many fields need to be written */
    2277           0 :     for(count=4; count>0 && versionArray[count-1]==0; --count) {
    2278             :     }
    2279             : 
    2280           0 :     if(count <= 1) {
    2281           0 :         count = 2;
    2282             :     }
    2283             : 
    2284             :     /* write the first part */
    2285             :     /* write the decimal field value */
    2286           0 :     field=versionArray[0];
    2287           0 :     if(field>=100) {
    2288           0 :         *versionString++=(char)('0'+field/100);
    2289           0 :         field%=100;
    2290             :     }
    2291           0 :     if(field>=10) {
    2292           0 :         *versionString++=(char)('0'+field/10);
    2293           0 :         field%=10;
    2294             :     }
    2295           0 :     *versionString++=(char)('0'+field);
    2296             : 
    2297             :     /* write the following parts */
    2298           0 :     for(part=1; part<count; ++part) {
    2299             :         /* write a dot first */
    2300           0 :         *versionString++=U_VERSION_DELIMITER;
    2301             : 
    2302             :         /* write the decimal field value */
    2303           0 :         field=versionArray[part];
    2304           0 :         if(field>=100) {
    2305           0 :             *versionString++=(char)('0'+field/100);
    2306           0 :             field%=100;
    2307             :         }
    2308           0 :         if(field>=10) {
    2309           0 :             *versionString++=(char)('0'+field/10);
    2310           0 :             field%=10;
    2311             :         }
    2312           0 :         *versionString++=(char)('0'+field);
    2313             :     }
    2314             : 
    2315             :     /* NUL-terminate */
    2316           0 :     *versionString=0;
    2317             : }
    2318             : 
    2319             : U_CAPI void U_EXPORT2
    2320           0 : u_getVersion(UVersionInfo versionArray) {
    2321             :     (void)copyright;   // Suppress unused variable warning from clang.
    2322           0 :     u_versionFromString(versionArray, U_ICU_VERSION);
    2323           0 : }
    2324             : 
    2325             : /**
    2326             :  * icucfg.h dependent code 
    2327             :  */
    2328             : 
    2329             : #if U_ENABLE_DYLOAD
    2330             :  
    2331             : #if HAVE_DLOPEN && !U_PLATFORM_USES_ONLY_WIN32_API
    2332             : 
    2333             : #if HAVE_DLFCN_H
    2334             : 
    2335             : #ifdef __MVS__
    2336             : #ifndef __SUSV3
    2337             : #define __SUSV3 1
    2338             : #endif
    2339             : #endif
    2340             : #include <dlfcn.h>
    2341             : #endif
    2342             : 
    2343             : U_INTERNAL void * U_EXPORT2
    2344           0 : uprv_dl_open(const char *libName, UErrorCode *status) {
    2345           0 :   void *ret = NULL;
    2346           0 :   if(U_FAILURE(*status)) return ret;
    2347           0 :   ret =  dlopen(libName, RTLD_NOW|RTLD_GLOBAL);
    2348           0 :   if(ret==NULL) {
    2349             : #ifdef U_TRACE_DYLOAD
    2350             :     printf("dlerror on dlopen(%s): %s\n", libName, dlerror());
    2351             : #endif
    2352           0 :     *status = U_MISSING_RESOURCE_ERROR;
    2353             :   }
    2354           0 :   return ret;
    2355             : }
    2356             : 
    2357             : U_INTERNAL void U_EXPORT2
    2358           0 : uprv_dl_close(void *lib, UErrorCode *status) {
    2359           0 :   if(U_FAILURE(*status)) return;
    2360           0 :   dlclose(lib);
    2361             : }
    2362             : 
    2363             : U_INTERNAL UVoidFunction* U_EXPORT2
    2364           0 : uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
    2365             :   union {
    2366             :       UVoidFunction *fp;
    2367             :       void *vp;
    2368             :   } uret;
    2369           0 :   uret.fp = NULL;
    2370           0 :   if(U_FAILURE(*status)) return uret.fp;
    2371           0 :   uret.vp = dlsym(lib, sym);
    2372           0 :   if(uret.vp == NULL) {
    2373             : #ifdef U_TRACE_DYLOAD
    2374             :     printf("dlerror on dlsym(%p,%s): %s\n", lib,sym, dlerror());
    2375             : #endif
    2376           0 :     *status = U_MISSING_RESOURCE_ERROR;
    2377             :   }
    2378           0 :   return uret.fp;
    2379             : }
    2380             : 
    2381             : #else
    2382             : 
    2383             : /* null (nonexistent) implementation. */
    2384             : 
    2385             : U_INTERNAL void * U_EXPORT2
    2386             : uprv_dl_open(const char *libName, UErrorCode *status) {
    2387             :   if(U_FAILURE(*status)) return NULL;
    2388             :   *status = U_UNSUPPORTED_ERROR;
    2389             :   return NULL;
    2390             : }
    2391             : 
    2392             : U_INTERNAL void U_EXPORT2
    2393             : uprv_dl_close(void *lib, UErrorCode *status) {
    2394             :   if(U_FAILURE(*status)) return;
    2395             :   *status = U_UNSUPPORTED_ERROR;
    2396             :   return;
    2397             : }
    2398             : 
    2399             : 
    2400             : U_INTERNAL UVoidFunction* U_EXPORT2
    2401             : uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
    2402             :   if(U_SUCCESS(*status)) {
    2403             :     *status = U_UNSUPPORTED_ERROR;
    2404             :   }
    2405             :   return (UVoidFunction*)NULL;
    2406             : }
    2407             : 
    2408             : 
    2409             : 
    2410             : #endif
    2411             : 
    2412             : #elif U_PLATFORM_USES_ONLY_WIN32_API
    2413             : 
    2414             : U_INTERNAL void * U_EXPORT2
    2415             : uprv_dl_open(const char *libName, UErrorCode *status) {
    2416             :   HMODULE lib = NULL;
    2417             :   
    2418             :   if(U_FAILURE(*status)) return NULL;
    2419             :   
    2420             :   lib = LoadLibraryA(libName);
    2421             :   
    2422             :   if(lib==NULL) {
    2423             :     *status = U_MISSING_RESOURCE_ERROR;
    2424             :   }
    2425             :   
    2426             :   return (void*)lib;
    2427             : }
    2428             : 
    2429             : U_INTERNAL void U_EXPORT2
    2430             : uprv_dl_close(void *lib, UErrorCode *status) {
    2431             :   HMODULE handle = (HMODULE)lib;
    2432             :   if(U_FAILURE(*status)) return;
    2433             :   
    2434             :   FreeLibrary(handle);
    2435             :   
    2436             :   return;
    2437             : }
    2438             : 
    2439             : 
    2440             : U_INTERNAL UVoidFunction* U_EXPORT2
    2441             : uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
    2442             :   HMODULE handle = (HMODULE)lib;
    2443             :   UVoidFunction* addr = NULL;
    2444             :   
    2445             :   if(U_FAILURE(*status) || lib==NULL) return NULL;
    2446             :   
    2447             :   addr = (UVoidFunction*)GetProcAddress(handle, sym);
    2448             :   
    2449             :   if(addr==NULL) {
    2450             :     DWORD lastError = GetLastError();
    2451             :     if(lastError == ERROR_PROC_NOT_FOUND) {
    2452             :       *status = U_MISSING_RESOURCE_ERROR;
    2453             :     } else {
    2454             :       *status = U_UNSUPPORTED_ERROR; /* other unknown error. */
    2455             :     }
    2456             :   }
    2457             :   
    2458             :   return addr;
    2459             : }
    2460             : 
    2461             : 
    2462             : #else
    2463             : 
    2464             : /* No dynamic loading set. */
    2465             : 
    2466             : U_INTERNAL void * U_EXPORT2
    2467             : uprv_dl_open(const char *libName, UErrorCode *status) {
    2468             :     (void)libName;
    2469             :     if(U_FAILURE(*status)) return NULL;
    2470             :     *status = U_UNSUPPORTED_ERROR;
    2471             :     return NULL;
    2472             : }
    2473             : 
    2474             : U_INTERNAL void U_EXPORT2
    2475             : uprv_dl_close(void *lib, UErrorCode *status) {
    2476             :     (void)lib;
    2477             :     if(U_FAILURE(*status)) return;
    2478             :     *status = U_UNSUPPORTED_ERROR;
    2479             :     return;
    2480             : }
    2481             : 
    2482             : 
    2483             : U_INTERNAL UVoidFunction* U_EXPORT2
    2484             : uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
    2485             :   (void)lib;
    2486             :   (void)sym;
    2487             :   if(U_SUCCESS(*status)) {
    2488             :     *status = U_UNSUPPORTED_ERROR;
    2489             :   }
    2490             :   return (UVoidFunction*)NULL;
    2491             : }
    2492             : 
    2493             : #endif /* U_ENABLE_DYLOAD */
    2494             : 
    2495             : /*
    2496             :  * Hey, Emacs, please set the following:
    2497             :  *
    2498             :  * Local Variables:
    2499             :  * indent-tabs-mode: nil
    2500             :  * End:
    2501             :  *
    2502             :  */

Generated by: LCOV version 1.13