intl/icu/source/common/putil.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/common/putil.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2315 @@
     1.4 +/*
     1.5 +******************************************************************************
     1.6 +*
     1.7 +*   Copyright (C) 1997-2013, International Business Machines
     1.8 +*   Corporation and others.  All Rights Reserved.
     1.9 +*
    1.10 +******************************************************************************
    1.11 +*
    1.12 +*  FILE NAME : putil.c (previously putil.cpp and ptypes.cpp)
    1.13 +*
    1.14 +*   Date        Name        Description
    1.15 +*   04/14/97    aliu        Creation.
    1.16 +*   04/24/97    aliu        Added getDefaultDataDirectory() and
    1.17 +*                            getDefaultLocaleID().
    1.18 +*   04/28/97    aliu        Rewritten to assume Unix and apply general methods
    1.19 +*                            for assumed case.  Non-UNIX platforms must be
    1.20 +*                            special-cased.  Rewrote numeric methods dealing
    1.21 +*                            with NaN and Infinity to be platform independent
    1.22 +*                             over all IEEE 754 platforms.
    1.23 +*   05/13/97    aliu        Restored sign of timezone
    1.24 +*                            (semantics are hours West of GMT)
    1.25 +*   06/16/98    erm         Added IEEE_754 stuff, cleaned up isInfinite, isNan,
    1.26 +*                             nextDouble..
    1.27 +*   07/22/98    stephen     Added remainder, max, min, trunc
    1.28 +*   08/13/98    stephen     Added isNegativeInfinity, isPositiveInfinity
    1.29 +*   08/24/98    stephen     Added longBitsFromDouble
    1.30 +*   09/08/98    stephen     Minor changes for Mac Port
    1.31 +*   03/02/99    stephen     Removed openFile().  Added AS400 support.
    1.32 +*                            Fixed EBCDIC tables
    1.33 +*   04/15/99    stephen     Converted to C.
    1.34 +*   06/28/99    stephen     Removed mutex locking in u_isBigEndian().
    1.35 +*   08/04/99    jeffrey R.  Added OS/2 changes
    1.36 +*   11/15/99    helena      Integrated S/390 IEEE support.
    1.37 +*   04/26/01    Barry N.    OS/400 support for uprv_getDefaultLocaleID
    1.38 +*   08/15/01    Steven H.   OS/400 support for uprv_getDefaultCodepage
    1.39 +*   01/03/08    Steven L.   Fake Time Support
    1.40 +******************************************************************************
    1.41 +*/
    1.42 +
    1.43 +// Defines _XOPEN_SOURCE for access to POSIX functions.
    1.44 +// Must be before any other #includes.
    1.45 +#include "uposixdefs.h"
    1.46 +
    1.47 +/* include ICU headers */
    1.48 +#include "unicode/utypes.h"
    1.49 +#include "unicode/putil.h"
    1.50 +#include "unicode/ustring.h"
    1.51 +#include "putilimp.h"
    1.52 +#include "uassert.h"
    1.53 +#include "umutex.h"
    1.54 +#include "cmemory.h"
    1.55 +#include "cstring.h"
    1.56 +#include "locmap.h"
    1.57 +#include "ucln_cmn.h"
    1.58 +
    1.59 +/* Include standard headers. */
    1.60 +#include <stdio.h>
    1.61 +#include <stdlib.h>
    1.62 +#include <string.h>
    1.63 +#include <math.h>
    1.64 +#include <locale.h>
    1.65 +#include <float.h>
    1.66 +
    1.67 +#ifndef U_COMMON_IMPLEMENTATION
    1.68 +#error U_COMMON_IMPLEMENTATION not set - must be set for all ICU source files in common/ - see http://userguide.icu-project.org/howtouseicu
    1.69 +#endif
    1.70 +
    1.71 +
    1.72 +/* include system headers */
    1.73 +#if U_PLATFORM_USES_ONLY_WIN32_API
    1.74 +    /*
    1.75 +     * TODO: U_PLATFORM_USES_ONLY_WIN32_API includes MinGW.
    1.76 +     * Should Cygwin be included as well (U_PLATFORM_HAS_WIN32_API)
    1.77 +     * to use native APIs as much as possible?
    1.78 +     */
    1.79 +#   define WIN32_LEAN_AND_MEAN
    1.80 +#   define VC_EXTRALEAN
    1.81 +#   define NOUSER
    1.82 +#   define NOSERVICE
    1.83 +#   define NOIME
    1.84 +#   define NOMCX
    1.85 +#   include <windows.h>
    1.86 +#   include "wintz.h"
    1.87 +#elif U_PLATFORM == U_PF_OS400
    1.88 +#   include <float.h>
    1.89 +#   include <qusec.h>       /* error code structure */
    1.90 +#   include <qusrjobi.h>
    1.91 +#   include <qliept.h>      /* EPT_CALL macro  - this include must be after all other "QSYSINCs" */
    1.92 +#   include <mih/testptr.h> /* For uprv_maximumPtr */
    1.93 +#elif U_PLATFORM == U_PF_CLASSIC_MACOS
    1.94 +#   include <Files.h>
    1.95 +#   include <IntlResources.h>
    1.96 +#   include <Script.h>
    1.97 +#   include <Folders.h>
    1.98 +#   include <MacTypes.h>
    1.99 +#   include <TextUtils.h>
   1.100 +#   define ICU_NO_USER_DATA_OVERRIDE 1
   1.101 +#elif U_PLATFORM == U_PF_OS390
   1.102 +#   include "unicode/ucnv.h"   /* Needed for UCNV_SWAP_LFNL_OPTION_STRING */
   1.103 +#elif U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS
   1.104 +#   include <limits.h>
   1.105 +#   include <unistd.h>
   1.106 +#   if U_PLATFORM == U_PF_SOLARIS
   1.107 +#       ifndef _XPG4_2
   1.108 +#           define _XPG4_2
   1.109 +#       endif
   1.110 +#   endif
   1.111 +#elif U_PLATFORM == U_PF_QNX
   1.112 +#   include <sys/neutrino.h>
   1.113 +#endif
   1.114 +
   1.115 +#if (U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(__STRICT_ANSI__)
   1.116 +/* tzset isn't defined in strict ANSI on Cygwin and MinGW. */
   1.117 +#undef __STRICT_ANSI__
   1.118 +#endif
   1.119 +
   1.120 +/*
   1.121 + * Cygwin with GCC requires inclusion of time.h after the above disabling strict asci mode statement.
   1.122 + */
   1.123 +#include <time.h>
   1.124 +
   1.125 +#if !U_PLATFORM_USES_ONLY_WIN32_API
   1.126 +#include <sys/time.h>
   1.127 +#endif
   1.128 +
   1.129 +/*
   1.130 + * Only include langinfo.h if we have a way to get the codeset. If we later
   1.131 + * depend on more feature, we can test on U_HAVE_NL_LANGINFO.
   1.132 + *
   1.133 + */
   1.134 +
   1.135 +#if U_HAVE_NL_LANGINFO_CODESET
   1.136 +#include <langinfo.h>
   1.137 +#endif
   1.138 +
   1.139 +/**
   1.140 + * Simple things (presence of functions, etc) should just go in configure.in and be added to
   1.141 + * icucfg.h via autoheader.
   1.142 + */
   1.143 +#if U_PLATFORM_IMPLEMENTS_POSIX
   1.144 +#   if U_PLATFORM == U_PF_OS400
   1.145 +#    define HAVE_DLFCN_H 0
   1.146 +#    define HAVE_DLOPEN 0
   1.147 +#   else
   1.148 +#   ifndef HAVE_DLFCN_H
   1.149 +#    define HAVE_DLFCN_H 1
   1.150 +#   endif
   1.151 +#   ifndef HAVE_DLOPEN
   1.152 +#    define HAVE_DLOPEN 1
   1.153 +#   endif
   1.154 +#   endif
   1.155 +#   ifndef HAVE_GETTIMEOFDAY
   1.156 +#    define HAVE_GETTIMEOFDAY 1
   1.157 +#   endif
   1.158 +#else
   1.159 +#   define HAVE_DLFCN_H 0
   1.160 +#   define HAVE_DLOPEN 0
   1.161 +#   define HAVE_GETTIMEOFDAY 0
   1.162 +#endif
   1.163 +
   1.164 +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
   1.165 +
   1.166 +/* Define the extension for data files, again... */
   1.167 +#define DATA_TYPE "dat"
   1.168 +
   1.169 +/* Leave this copyright notice here! */
   1.170 +static const char copyright[] = U_COPYRIGHT_STRING;
   1.171 +
   1.172 +/* floating point implementations ------------------------------------------- */
   1.173 +
   1.174 +/* We return QNAN rather than SNAN*/
   1.175 +#define SIGN 0x80000000U
   1.176 +
   1.177 +/* Make it easy to define certain types of constants */
   1.178 +typedef union {
   1.179 +    int64_t i64; /* This must be defined first in order to allow the initialization to work. This is a C89 feature. */
   1.180 +    double d64;
   1.181 +} BitPatternConversion;
   1.182 +static const BitPatternConversion gNan = { (int64_t) INT64_C(0x7FF8000000000000) };
   1.183 +static const BitPatternConversion gInf = { (int64_t) INT64_C(0x7FF0000000000000) };
   1.184 +
   1.185 +/*---------------------------------------------------------------------------
   1.186 +  Platform utilities
   1.187 +  Our general strategy is to assume we're on a POSIX platform.  Platforms which
   1.188 +  are non-POSIX must declare themselves so.  The default POSIX implementation
   1.189 +  will sometimes work for non-POSIX platforms as well (e.g., the NaN-related
   1.190 +  functions).
   1.191 +  ---------------------------------------------------------------------------*/
   1.192 +
   1.193 +#if U_PLATFORM_USES_ONLY_WIN32_API || U_PLATFORM == U_PF_CLASSIC_MACOS || U_PLATFORM == U_PF_OS400
   1.194 +#   undef U_POSIX_LOCALE
   1.195 +#else
   1.196 +#   define U_POSIX_LOCALE    1
   1.197 +#endif
   1.198 +
   1.199 +/*
   1.200 +    WARNING! u_topNBytesOfDouble and u_bottomNBytesOfDouble
   1.201 +    can't be properly optimized by the gcc compiler sometimes (i.e. gcc 3.2).
   1.202 +*/
   1.203 +#if !IEEE_754
   1.204 +static char*
   1.205 +u_topNBytesOfDouble(double* d, int n)
   1.206 +{
   1.207 +#if U_IS_BIG_ENDIAN
   1.208 +    return (char*)d;
   1.209 +#else
   1.210 +    return (char*)(d + 1) - n;
   1.211 +#endif
   1.212 +}
   1.213 +
   1.214 +static char*
   1.215 +u_bottomNBytesOfDouble(double* d, int n)
   1.216 +{
   1.217 +#if U_IS_BIG_ENDIAN
   1.218 +    return (char*)(d + 1) - n;
   1.219 +#else
   1.220 +    return (char*)d;
   1.221 +#endif
   1.222 +}
   1.223 +#endif   /* !IEEE_754 */
   1.224 +
   1.225 +#if IEEE_754
   1.226 +static UBool
   1.227 +u_signBit(double d) {
   1.228 +    uint8_t hiByte;
   1.229 +#if U_IS_BIG_ENDIAN
   1.230 +    hiByte = *(uint8_t *)&d;
   1.231 +#else
   1.232 +    hiByte = *(((uint8_t *)&d) + sizeof(double) - 1);
   1.233 +#endif
   1.234 +    return (hiByte & 0x80) != 0;
   1.235 +}
   1.236 +#endif
   1.237 +
   1.238 +
   1.239 +
   1.240 +#if defined (U_DEBUG_FAKETIME)
   1.241 +/* Override the clock to test things without having to move the system clock.
   1.242 + * Assumes POSIX gettimeofday() will function
   1.243 + */
   1.244 +UDate fakeClock_t0 = 0; /** Time to start the clock from **/
   1.245 +UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/
   1.246 +UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/
   1.247 +static UMutex fakeClockMutex = U_MUTEX_INTIALIZER;
   1.248 +
   1.249 +static UDate getUTCtime_real() {
   1.250 +    struct timeval posixTime;
   1.251 +    gettimeofday(&posixTime, NULL);
   1.252 +    return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
   1.253 +}
   1.254 +
   1.255 +static UDate getUTCtime_fake() {
   1.256 +    umtx_lock(&fakeClockMutex);
   1.257 +    if(!fakeClock_set) {
   1.258 +        UDate real = getUTCtime_real();
   1.259 +        const char *fake_start = getenv("U_FAKETIME_START");
   1.260 +        if((fake_start!=NULL) && (fake_start[0]!=0)) {
   1.261 +            sscanf(fake_start,"%lf",&fakeClock_t0);
   1.262 +            fakeClock_dt = fakeClock_t0 - real;
   1.263 +            fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, so the ICU clock will start at a preset value\n"
   1.264 +                    "env variable U_FAKETIME_START=%.0f (%s) for an offset of %.0f ms from the current time %.0f\n",
   1.265 +                    fakeClock_t0, fake_start, fakeClock_dt, real);
   1.266 +        } else {
   1.267 +          fakeClock_dt = 0;
   1.268 +            fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, but U_FAKETIME_START was not set.\n"
   1.269 +                    "Set U_FAKETIME_START to the number of milliseconds since 1/1/1970 to set the ICU clock.\n");
   1.270 +        }
   1.271 +        fakeClock_set = TRUE;
   1.272 +    }
   1.273 +    umtx_unlock(&fakeClockMutex);
   1.274 +
   1.275 +    return getUTCtime_real() + fakeClock_dt;
   1.276 +}
   1.277 +#endif
   1.278 +
   1.279 +#if U_PLATFORM_USES_ONLY_WIN32_API
   1.280 +typedef union {
   1.281 +    int64_t int64;
   1.282 +    FILETIME fileTime;
   1.283 +} FileTimeConversion;   /* This is like a ULARGE_INTEGER */
   1.284 +
   1.285 +/* Number of 100 nanoseconds from 1/1/1601 to 1/1/1970 */
   1.286 +#define EPOCH_BIAS  INT64_C(116444736000000000)
   1.287 +#define HECTONANOSECOND_PER_MILLISECOND   10000
   1.288 +
   1.289 +#endif
   1.290 +
   1.291 +/*---------------------------------------------------------------------------
   1.292 +  Universal Implementations
   1.293 +  These are designed to work on all platforms.  Try these, and if they
   1.294 +  don't work on your platform, then special case your platform with new
   1.295 +  implementations.
   1.296 +---------------------------------------------------------------------------*/
   1.297 +
   1.298 +U_CAPI UDate U_EXPORT2
   1.299 +uprv_getUTCtime()
   1.300 +{
   1.301 +#if defined(U_DEBUG_FAKETIME)
   1.302 +    return getUTCtime_fake(); /* Hook for overriding the clock */
   1.303 +#else
   1.304 +    return uprv_getRawUTCtime();
   1.305 +#endif
   1.306 +}
   1.307 +
   1.308 +/* Return UTC (GMT) time measured in milliseconds since 0:00 on 1/1/70.*/
   1.309 +U_CAPI UDate U_EXPORT2
   1.310 +uprv_getRawUTCtime()
   1.311 +{
   1.312 +#if U_PLATFORM == U_PF_CLASSIC_MACOS
   1.313 +    time_t t, t1, t2;
   1.314 +    struct tm tmrec;
   1.315 +
   1.316 +    uprv_memset( &tmrec, 0, sizeof(tmrec) );
   1.317 +    tmrec.tm_year = 70;
   1.318 +    tmrec.tm_mon = 0;
   1.319 +    tmrec.tm_mday = 1;
   1.320 +    t1 = mktime(&tmrec);    /* seconds of 1/1/1970*/
   1.321 +
   1.322 +    time(&t);
   1.323 +    uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
   1.324 +    t2 = mktime(&tmrec);    /* seconds of current GMT*/
   1.325 +    return (UDate)(t2 - t1) * U_MILLIS_PER_SECOND;         /* GMT (or UTC) in seconds since 1970*/
   1.326 +#elif U_PLATFORM_USES_ONLY_WIN32_API
   1.327 +
   1.328 +    FileTimeConversion winTime;
   1.329 +    GetSystemTimeAsFileTime(&winTime.fileTime);
   1.330 +    return (UDate)((winTime.int64 - EPOCH_BIAS) / HECTONANOSECOND_PER_MILLISECOND);
   1.331 +#else
   1.332 +
   1.333 +#if HAVE_GETTIMEOFDAY
   1.334 +    struct timeval posixTime;
   1.335 +    gettimeofday(&posixTime, NULL);
   1.336 +    return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
   1.337 +#else
   1.338 +    time_t epochtime;
   1.339 +    time(&epochtime);
   1.340 +    return (UDate)epochtime * U_MILLIS_PER_SECOND;
   1.341 +#endif
   1.342 +
   1.343 +#endif
   1.344 +}
   1.345 +
   1.346 +/*-----------------------------------------------------------------------------
   1.347 +  IEEE 754
   1.348 +  These methods detect and return NaN and infinity values for doubles
   1.349 +  conforming to IEEE 754.  Platforms which support this standard include X86,
   1.350 +  Mac 680x0, Mac PowerPC, AIX RS/6000, and most others.
   1.351 +  If this doesn't work on your platform, you have non-IEEE floating-point, and
   1.352 +  will need to code your own versions.  A naive implementation is to return 0.0
   1.353 +  for getNaN and getInfinity, and false for isNaN and isInfinite.
   1.354 +  ---------------------------------------------------------------------------*/
   1.355 +
   1.356 +U_CAPI UBool U_EXPORT2
   1.357 +uprv_isNaN(double number)
   1.358 +{
   1.359 +#if IEEE_754
   1.360 +    BitPatternConversion convertedNumber;
   1.361 +    convertedNumber.d64 = number;
   1.362 +    /* Infinity is 0x7FF0000000000000U. Anything greater than that is a NaN */
   1.363 +    return (UBool)((convertedNumber.i64 & U_INT64_MAX) > gInf.i64);
   1.364 +
   1.365 +#elif U_PLATFORM == U_PF_OS390
   1.366 +    uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
   1.367 +                        sizeof(uint32_t));
   1.368 +    uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
   1.369 +                        sizeof(uint32_t));
   1.370 +
   1.371 +    return ((highBits & 0x7F080000L) == 0x7F080000L) &&
   1.372 +      (lowBits == 0x00000000L);
   1.373 +
   1.374 +#else
   1.375 +    /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
   1.376 +    /* you'll need to replace this default implementation with what's correct*/
   1.377 +    /* for your platform.*/
   1.378 +    return number != number;
   1.379 +#endif
   1.380 +}
   1.381 +
   1.382 +U_CAPI UBool U_EXPORT2
   1.383 +uprv_isInfinite(double number)
   1.384 +{
   1.385 +#if IEEE_754
   1.386 +    BitPatternConversion convertedNumber;
   1.387 +    convertedNumber.d64 = number;
   1.388 +    /* Infinity is exactly 0x7FF0000000000000U. */
   1.389 +    return (UBool)((convertedNumber.i64 & U_INT64_MAX) == gInf.i64);
   1.390 +#elif U_PLATFORM == U_PF_OS390
   1.391 +    uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
   1.392 +                        sizeof(uint32_t));
   1.393 +    uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
   1.394 +                        sizeof(uint32_t));
   1.395 +
   1.396 +    return ((highBits  & ~SIGN) == 0x70FF0000L) && (lowBits == 0x00000000L);
   1.397 +
   1.398 +#else
   1.399 +    /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
   1.400 +    /* value, you'll need to replace this default implementation with what's*/
   1.401 +    /* correct for your platform.*/
   1.402 +    return number == (2.0 * number);
   1.403 +#endif
   1.404 +}
   1.405 +
   1.406 +U_CAPI UBool U_EXPORT2
   1.407 +uprv_isPositiveInfinity(double number)
   1.408 +{
   1.409 +#if IEEE_754 || U_PLATFORM == U_PF_OS390
   1.410 +    return (UBool)(number > 0 && uprv_isInfinite(number));
   1.411 +#else
   1.412 +    return uprv_isInfinite(number);
   1.413 +#endif
   1.414 +}
   1.415 +
   1.416 +U_CAPI UBool U_EXPORT2
   1.417 +uprv_isNegativeInfinity(double number)
   1.418 +{
   1.419 +#if IEEE_754 || U_PLATFORM == U_PF_OS390
   1.420 +    return (UBool)(number < 0 && uprv_isInfinite(number));
   1.421 +
   1.422 +#else
   1.423 +    uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
   1.424 +                        sizeof(uint32_t));
   1.425 +    return((highBits & SIGN) && uprv_isInfinite(number));
   1.426 +
   1.427 +#endif
   1.428 +}
   1.429 +
   1.430 +U_CAPI double U_EXPORT2
   1.431 +uprv_getNaN()
   1.432 +{
   1.433 +#if IEEE_754 || U_PLATFORM == U_PF_OS390
   1.434 +    return gNan.d64;
   1.435 +#else
   1.436 +    /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
   1.437 +    /* you'll need to replace this default implementation with what's correct*/
   1.438 +    /* for your platform.*/
   1.439 +    return 0.0;
   1.440 +#endif
   1.441 +}
   1.442 +
   1.443 +U_CAPI double U_EXPORT2
   1.444 +uprv_getInfinity()
   1.445 +{
   1.446 +#if IEEE_754 || U_PLATFORM == U_PF_OS390
   1.447 +    return gInf.d64;
   1.448 +#else
   1.449 +    /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
   1.450 +    /* value, you'll need to replace this default implementation with what's*/
   1.451 +    /* correct for your platform.*/
   1.452 +    return 0.0;
   1.453 +#endif
   1.454 +}
   1.455 +
   1.456 +U_CAPI double U_EXPORT2
   1.457 +uprv_floor(double x)
   1.458 +{
   1.459 +    return floor(x);
   1.460 +}
   1.461 +
   1.462 +U_CAPI double U_EXPORT2
   1.463 +uprv_ceil(double x)
   1.464 +{
   1.465 +    return ceil(x);
   1.466 +}
   1.467 +
   1.468 +U_CAPI double U_EXPORT2
   1.469 +uprv_round(double x)
   1.470 +{
   1.471 +    return uprv_floor(x + 0.5);
   1.472 +}
   1.473 +
   1.474 +U_CAPI double U_EXPORT2
   1.475 +uprv_fabs(double x)
   1.476 +{
   1.477 +    return fabs(x);
   1.478 +}
   1.479 +
   1.480 +U_CAPI double U_EXPORT2
   1.481 +uprv_modf(double x, double* y)
   1.482 +{
   1.483 +    return modf(x, y);
   1.484 +}
   1.485 +
   1.486 +U_CAPI double U_EXPORT2
   1.487 +uprv_fmod(double x, double y)
   1.488 +{
   1.489 +    return fmod(x, y);
   1.490 +}
   1.491 +
   1.492 +U_CAPI double U_EXPORT2
   1.493 +uprv_pow(double x, double y)
   1.494 +{
   1.495 +    /* This is declared as "double pow(double x, double y)" */
   1.496 +    return pow(x, y);
   1.497 +}
   1.498 +
   1.499 +U_CAPI double U_EXPORT2
   1.500 +uprv_pow10(int32_t x)
   1.501 +{
   1.502 +    return pow(10.0, (double)x);
   1.503 +}
   1.504 +
   1.505 +U_CAPI double U_EXPORT2
   1.506 +uprv_fmax(double x, double y)
   1.507 +{
   1.508 +#if IEEE_754
   1.509 +    /* first handle NaN*/
   1.510 +    if(uprv_isNaN(x) || uprv_isNaN(y))
   1.511 +        return uprv_getNaN();
   1.512 +
   1.513 +    /* check for -0 and 0*/
   1.514 +    if(x == 0.0 && y == 0.0 && u_signBit(x))
   1.515 +        return y;
   1.516 +
   1.517 +#endif
   1.518 +
   1.519 +    /* this should work for all flt point w/o NaN and Inf special cases */
   1.520 +    return (x > y ? x : y);
   1.521 +}
   1.522 +
   1.523 +U_CAPI double U_EXPORT2
   1.524 +uprv_fmin(double x, double y)
   1.525 +{
   1.526 +#if IEEE_754
   1.527 +    /* first handle NaN*/
   1.528 +    if(uprv_isNaN(x) || uprv_isNaN(y))
   1.529 +        return uprv_getNaN();
   1.530 +
   1.531 +    /* check for -0 and 0*/
   1.532 +    if(x == 0.0 && y == 0.0 && u_signBit(y))
   1.533 +        return y;
   1.534 +
   1.535 +#endif
   1.536 +
   1.537 +    /* this should work for all flt point w/o NaN and Inf special cases */
   1.538 +    return (x > y ? y : x);
   1.539 +}
   1.540 +
   1.541 +/**
   1.542 + * Truncates the given double.
   1.543 + * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
   1.544 + * This is different than calling floor() or ceil():
   1.545 + * floor(3.3) = 3, floor(-3.3) = -4
   1.546 + * ceil(3.3) = 4, ceil(-3.3) = -3
   1.547 + */
   1.548 +U_CAPI double U_EXPORT2
   1.549 +uprv_trunc(double d)
   1.550 +{
   1.551 +#if IEEE_754
   1.552 +    /* handle error cases*/
   1.553 +    if(uprv_isNaN(d))
   1.554 +        return uprv_getNaN();
   1.555 +    if(uprv_isInfinite(d))
   1.556 +        return uprv_getInfinity();
   1.557 +
   1.558 +    if(u_signBit(d))    /* Signbit() picks up -0.0;  d<0 does not. */
   1.559 +        return ceil(d);
   1.560 +    else
   1.561 +        return floor(d);
   1.562 +
   1.563 +#else
   1.564 +    return d >= 0 ? floor(d) : ceil(d);
   1.565 +
   1.566 +#endif
   1.567 +}
   1.568 +
   1.569 +/**
   1.570 + * Return the largest positive number that can be represented by an integer
   1.571 + * type of arbitrary bit length.
   1.572 + */
   1.573 +U_CAPI double U_EXPORT2
   1.574 +uprv_maxMantissa(void)
   1.575 +{
   1.576 +    return pow(2.0, DBL_MANT_DIG + 1.0) - 1.0;
   1.577 +}
   1.578 +
   1.579 +U_CAPI double U_EXPORT2
   1.580 +uprv_log(double d)
   1.581 +{
   1.582 +    return log(d);
   1.583 +}
   1.584 +
   1.585 +U_CAPI void * U_EXPORT2
   1.586 +uprv_maximumPtr(void * base)
   1.587 +{
   1.588 +#if U_PLATFORM == U_PF_OS400
   1.589 +    /*
   1.590 +     * With the provided function we should never be out of range of a given segment
   1.591 +     * (a traditional/typical segment that is).  Our segments have 5 bytes for the
   1.592 +     * id and 3 bytes for the offset.  The key is that the casting takes care of
   1.593 +     * only retrieving the offset portion minus x1000.  Hence, the smallest offset
   1.594 +     * seen in a program is x001000 and when casted to an int would be 0.
   1.595 +     * That's why we can only add 0xffefff.  Otherwise, we would exceed the segment.
   1.596 +     *
   1.597 +     * Currently, 16MB is the current addressing limitation on i5/OS if the activation is
   1.598 +     * non-TERASPACE.  If it is TERASPACE it is 2GB - 4k(header information).
   1.599 +     * This function determines the activation based on the pointer that is passed in and
   1.600 +     * calculates the appropriate maximum available size for
   1.601 +     * each pointer type (TERASPACE and non-TERASPACE)
   1.602 +     *
   1.603 +     * Unlike other operating systems, the pointer model isn't determined at
   1.604 +     * compile time on i5/OS.
   1.605 +     */
   1.606 +    if ((base != NULL) && (_TESTPTR(base, _C_TERASPACE_CHECK))) {
   1.607 +        /* if it is a TERASPACE pointer the max is 2GB - 4k */
   1.608 +        return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0x7fffefff)));
   1.609 +    }
   1.610 +    /* otherwise 16MB since NULL ptr is not checkable or the ptr is not TERASPACE */
   1.611 +    return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0xffefff)));
   1.612 +
   1.613 +#else
   1.614 +    return U_MAX_PTR(base);
   1.615 +#endif
   1.616 +}
   1.617 +
   1.618 +/*---------------------------------------------------------------------------
   1.619 +  Platform-specific Implementations
   1.620 +  Try these, and if they don't work on your platform, then special case your
   1.621 +  platform with new implementations.
   1.622 +  ---------------------------------------------------------------------------*/
   1.623 +
   1.624 +/* Generic time zone layer -------------------------------------------------- */
   1.625 +
   1.626 +/* Time zone utilities */
   1.627 +U_CAPI void U_EXPORT2
   1.628 +uprv_tzset()
   1.629 +{
   1.630 +#if defined(U_TZSET)
   1.631 +    U_TZSET();
   1.632 +#else
   1.633 +    /* no initialization*/
   1.634 +#endif
   1.635 +}
   1.636 +
   1.637 +U_CAPI int32_t U_EXPORT2
   1.638 +uprv_timezone()
   1.639 +{
   1.640 +#ifdef U_TIMEZONE
   1.641 +    return U_TIMEZONE;
   1.642 +#else
   1.643 +    time_t t, t1, t2;
   1.644 +    struct tm tmrec;
   1.645 +    int32_t tdiff = 0;
   1.646 +
   1.647 +    time(&t);
   1.648 +    uprv_memcpy( &tmrec, localtime(&t), sizeof(tmrec) );
   1.649 +#if U_PLATFORM != U_PF_IPHONE
   1.650 +    UBool dst_checked = (tmrec.tm_isdst != 0); /* daylight savings time is checked*/
   1.651 +#endif
   1.652 +    t1 = mktime(&tmrec);                 /* local time in seconds*/
   1.653 +    uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
   1.654 +    t2 = mktime(&tmrec);                 /* GMT (or UTC) in seconds*/
   1.655 +    tdiff = t2 - t1;
   1.656 +
   1.657 +#if U_PLATFORM != U_PF_IPHONE
   1.658 +    /* imitate NT behaviour, which returns same timezone offset to GMT for
   1.659 +       winter and summer.
   1.660 +       This does not work on all platforms. For instance, on glibc on Linux
   1.661 +       and on Mac OS 10.5, tdiff calculated above remains the same
   1.662 +       regardless of whether DST is in effect or not. iOS is another
   1.663 +       platform where this does not work. Linux + glibc and Mac OS 10.5
   1.664 +       have U_TIMEZONE defined so that this code is not reached.
   1.665 +    */
   1.666 +    if (dst_checked)
   1.667 +        tdiff += 3600;
   1.668 +#endif
   1.669 +    return tdiff;
   1.670 +#endif
   1.671 +}
   1.672 +
   1.673 +/* Note that U_TZNAME does *not* have to be tzname, but if it is,
   1.674 +   some platforms need to have it declared here. */
   1.675 +
   1.676 +#if defined(U_TZNAME) && (U_PLATFORM == U_PF_IRIX || U_PLATFORM_IS_DARWIN_BASED || (U_PLATFORM == U_PF_CYGWIN && !U_PLATFORM_USES_ONLY_WIN32_API))
   1.677 +/* RS6000 and others reject char **tzname.  */
   1.678 +extern U_IMPORT char *U_TZNAME[];
   1.679 +#endif
   1.680 +
   1.681 +#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)
   1.682 +/* These platforms are likely to use Olson timezone IDs. */
   1.683 +#define CHECK_LOCALTIME_LINK 1
   1.684 +#if U_PLATFORM_IS_DARWIN_BASED
   1.685 +#include <tzfile.h>
   1.686 +#define TZZONEINFO      (TZDIR "/")
   1.687 +#elif U_PLATFORM == U_PF_SOLARIS
   1.688 +#define TZDEFAULT       "/etc/localtime"
   1.689 +#define TZZONEINFO      "/usr/share/lib/zoneinfo/"
   1.690 +#define TZZONEINFO2     "../usr/share/lib/zoneinfo/"
   1.691 +#define TZ_ENV_CHECK    "localtime"
   1.692 +#else
   1.693 +#define TZDEFAULT       "/etc/localtime"
   1.694 +#define TZZONEINFO      "/usr/share/zoneinfo/"
   1.695 +#endif
   1.696 +#if U_HAVE_DIRENT_H
   1.697 +#define TZFILE_SKIP     "posixrules" /* tz file to skip when searching. */
   1.698 +/* Some Linux distributions have 'localtime' in /usr/share/zoneinfo
   1.699 +   symlinked to /etc/localtime, which makes searchForTZFile return
   1.700 +   'localtime' when it's the first match. */
   1.701 +#define TZFILE_SKIP2    "localtime"
   1.702 +#define SEARCH_TZFILE
   1.703 +#include <dirent.h>  /* Needed to search through system timezone files */
   1.704 +#endif
   1.705 +static char gTimeZoneBuffer[PATH_MAX];
   1.706 +static char *gTimeZoneBufferPtr = NULL;
   1.707 +#endif
   1.708 +
   1.709 +#if !U_PLATFORM_USES_ONLY_WIN32_API
   1.710 +#define isNonDigit(ch) (ch < '0' || '9' < ch)
   1.711 +static UBool isValidOlsonID(const char *id) {
   1.712 +    int32_t idx = 0;
   1.713 +
   1.714 +    /* Determine if this is something like Iceland (Olson ID)
   1.715 +    or AST4ADT (non-Olson ID) */
   1.716 +    while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') {
   1.717 +        idx++;
   1.718 +    }
   1.719 +
   1.720 +    /* If we went through the whole string, then it might be okay.
   1.721 +    The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
   1.722 +    "GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
   1.723 +    The rest of the time it could be an Olson ID. George */
   1.724 +    return (UBool)(id[idx] == 0
   1.725 +        || uprv_strcmp(id, "PST8PDT") == 0
   1.726 +        || uprv_strcmp(id, "MST7MDT") == 0
   1.727 +        || uprv_strcmp(id, "CST6CDT") == 0
   1.728 +        || uprv_strcmp(id, "EST5EDT") == 0);
   1.729 +}
   1.730 +
   1.731 +/* On some Unix-like OS, 'posix' subdirectory in
   1.732 +   /usr/share/zoneinfo replicates the top-level contents. 'right'
   1.733 +   subdirectory has the same set of files, but individual files
   1.734 +   are different from those in the top-level directory or 'posix'
   1.735 +   because 'right' has files for TAI (Int'l Atomic Time) while 'posix'
   1.736 +   has files for UTC.
   1.737 +   When the first match for /etc/localtime is in either of them
   1.738 +   (usually in posix because 'right' has different file contents),
   1.739 +   or TZ environment variable points to one of them, createTimeZone
   1.740 +   fails because, say, 'posix/America/New_York' is not an Olson
   1.741 +   timezone id ('America/New_York' is). So, we have to skip
   1.742 +   'posix/' and 'right/' at the beginning. */
   1.743 +static void skipZoneIDPrefix(const char** id) {
   1.744 +    if (uprv_strncmp(*id, "posix/", 6) == 0
   1.745 +        || uprv_strncmp(*id, "right/", 6) == 0)
   1.746 +    {
   1.747 +        *id += 6;
   1.748 +    }
   1.749 +}
   1.750 +#endif
   1.751 +
   1.752 +#if defined(U_TZNAME) && !U_PLATFORM_USES_ONLY_WIN32_API
   1.753 +
   1.754 +#define CONVERT_HOURS_TO_SECONDS(offset) (int32_t)(offset*3600)
   1.755 +typedef struct OffsetZoneMapping {
   1.756 +    int32_t offsetSeconds;
   1.757 +    int32_t daylightType; /* 0=U_DAYLIGHT_NONE, 1=daylight in June-U_DAYLIGHT_JUNE, 2=daylight in December=U_DAYLIGHT_DECEMBER*/
   1.758 +    const char *stdID;
   1.759 +    const char *dstID;
   1.760 +    const char *olsonID;
   1.761 +} OffsetZoneMapping;
   1.762 +
   1.763 +enum { U_DAYLIGHT_NONE=0,U_DAYLIGHT_JUNE=1,U_DAYLIGHT_DECEMBER=2 };
   1.764 +
   1.765 +/*
   1.766 +This list tries to disambiguate a set of abbreviated timezone IDs and offsets
   1.767 +and maps it to an Olson ID.
   1.768 +Before adding anything to this list, take a look at
   1.769 +icu/source/tools/tzcode/tz.alias
   1.770 +Sometimes no daylight savings (0) is important to define due to aliases.
   1.771 +This list can be tested with icu/source/test/compat/tzone.pl
   1.772 +More values could be added to daylightType to increase precision.
   1.773 +*/
   1.774 +static const struct OffsetZoneMapping OFFSET_ZONE_MAPPINGS[] = {
   1.775 +    {-45900, 2, "CHAST", "CHADT", "Pacific/Chatham"},
   1.776 +    {-43200, 1, "PETT", "PETST", "Asia/Kamchatka"},
   1.777 +    {-43200, 2, "NZST", "NZDT", "Pacific/Auckland"},
   1.778 +    {-43200, 1, "ANAT", "ANAST", "Asia/Anadyr"},
   1.779 +    {-39600, 1, "MAGT", "MAGST", "Asia/Magadan"},
   1.780 +    {-37800, 2, "LHST", "LHST", "Australia/Lord_Howe"},
   1.781 +    {-36000, 2, "EST", "EST", "Australia/Sydney"},
   1.782 +    {-36000, 1, "SAKT", "SAKST", "Asia/Sakhalin"},
   1.783 +    {-36000, 1, "VLAT", "VLAST", "Asia/Vladivostok"},
   1.784 +    {-34200, 2, "CST", "CST", "Australia/South"},
   1.785 +    {-32400, 1, "YAKT", "YAKST", "Asia/Yakutsk"},
   1.786 +    {-32400, 1, "CHOT", "CHOST", "Asia/Choibalsan"},
   1.787 +    {-31500, 2, "CWST", "CWST", "Australia/Eucla"},
   1.788 +    {-28800, 1, "IRKT", "IRKST", "Asia/Irkutsk"},
   1.789 +    {-28800, 1, "ULAT", "ULAST", "Asia/Ulaanbaatar"},
   1.790 +    {-28800, 2, "WST", "WST", "Australia/West"},
   1.791 +    {-25200, 1, "HOVT", "HOVST", "Asia/Hovd"},
   1.792 +    {-25200, 1, "KRAT", "KRAST", "Asia/Krasnoyarsk"},
   1.793 +    {-21600, 1, "NOVT", "NOVST", "Asia/Novosibirsk"},
   1.794 +    {-21600, 1, "OMST", "OMSST", "Asia/Omsk"},
   1.795 +    {-18000, 1, "YEKT", "YEKST", "Asia/Yekaterinburg"},
   1.796 +    {-14400, 1, "SAMT", "SAMST", "Europe/Samara"},
   1.797 +    {-14400, 1, "AMT", "AMST", "Asia/Yerevan"},
   1.798 +    {-14400, 1, "AZT", "AZST", "Asia/Baku"},
   1.799 +    {-10800, 1, "AST", "ADT", "Asia/Baghdad"},
   1.800 +    {-10800, 1, "MSK", "MSD", "Europe/Moscow"},
   1.801 +    {-10800, 1, "VOLT", "VOLST", "Europe/Volgograd"},
   1.802 +    {-7200, 0, "EET", "CEST", "Africa/Tripoli"},
   1.803 +    {-7200, 1, "EET", "EEST", "Europe/Athens"}, /* Conflicts with Africa/Cairo */
   1.804 +    {-7200, 1, "IST", "IDT", "Asia/Jerusalem"},
   1.805 +    {-3600, 0, "CET", "WEST", "Africa/Algiers"},
   1.806 +    {-3600, 2, "WAT", "WAST", "Africa/Windhoek"},
   1.807 +    {0, 1, "GMT", "IST", "Europe/Dublin"},
   1.808 +    {0, 1, "GMT", "BST", "Europe/London"},
   1.809 +    {0, 0, "WET", "WEST", "Africa/Casablanca"},
   1.810 +    {0, 0, "WET", "WET", "Africa/El_Aaiun"},
   1.811 +    {3600, 1, "AZOT", "AZOST", "Atlantic/Azores"},
   1.812 +    {3600, 1, "EGT", "EGST", "America/Scoresbysund"},
   1.813 +    {10800, 1, "PMST", "PMDT", "America/Miquelon"},
   1.814 +    {10800, 2, "UYT", "UYST", "America/Montevideo"},
   1.815 +    {10800, 1, "WGT", "WGST", "America/Godthab"},
   1.816 +    {10800, 2, "BRT", "BRST", "Brazil/East"},
   1.817 +    {12600, 1, "NST", "NDT", "America/St_Johns"},
   1.818 +    {14400, 1, "AST", "ADT", "Canada/Atlantic"},
   1.819 +    {14400, 2, "AMT", "AMST", "America/Cuiaba"},
   1.820 +    {14400, 2, "CLT", "CLST", "Chile/Continental"},
   1.821 +    {14400, 2, "FKT", "FKST", "Atlantic/Stanley"},
   1.822 +    {14400, 2, "PYT", "PYST", "America/Asuncion"},
   1.823 +    {18000, 1, "CST", "CDT", "America/Havana"},
   1.824 +    {18000, 1, "EST", "EDT", "US/Eastern"}, /* Conflicts with America/Grand_Turk */
   1.825 +    {21600, 2, "EAST", "EASST", "Chile/EasterIsland"},
   1.826 +    {21600, 0, "CST", "MDT", "Canada/Saskatchewan"},
   1.827 +    {21600, 0, "CST", "CDT", "America/Guatemala"},
   1.828 +    {21600, 1, "CST", "CDT", "US/Central"}, /* Conflicts with Mexico/General */
   1.829 +    {25200, 1, "MST", "MDT", "US/Mountain"}, /* Conflicts with Mexico/BajaSur */
   1.830 +    {28800, 0, "PST", "PST", "Pacific/Pitcairn"},
   1.831 +    {28800, 1, "PST", "PDT", "US/Pacific"}, /* Conflicts with Mexico/BajaNorte */
   1.832 +    {32400, 1, "AKST", "AKDT", "US/Alaska"},
   1.833 +    {36000, 1, "HAST", "HADT", "US/Aleutian"}
   1.834 +};
   1.835 +
   1.836 +/*#define DEBUG_TZNAME*/
   1.837 +
   1.838 +static const char* remapShortTimeZone(const char *stdID, const char *dstID, int32_t daylightType, int32_t offset)
   1.839 +{
   1.840 +    int32_t idx;
   1.841 +#ifdef DEBUG_TZNAME
   1.842 +    fprintf(stderr, "TZ=%s std=%s dst=%s daylight=%d offset=%d\n", getenv("TZ"), stdID, dstID, daylightType, offset);
   1.843 +#endif
   1.844 +    for (idx = 0; idx < LENGTHOF(OFFSET_ZONE_MAPPINGS); idx++)
   1.845 +    {
   1.846 +        if (offset == OFFSET_ZONE_MAPPINGS[idx].offsetSeconds
   1.847 +            && daylightType == OFFSET_ZONE_MAPPINGS[idx].daylightType
   1.848 +            && strcmp(OFFSET_ZONE_MAPPINGS[idx].stdID, stdID) == 0
   1.849 +            && strcmp(OFFSET_ZONE_MAPPINGS[idx].dstID, dstID) == 0)
   1.850 +        {
   1.851 +            return OFFSET_ZONE_MAPPINGS[idx].olsonID;
   1.852 +        }
   1.853 +    }
   1.854 +    return NULL;
   1.855 +}
   1.856 +#endif
   1.857 +
   1.858 +#ifdef SEARCH_TZFILE
   1.859 +#define MAX_PATH_SIZE PATH_MAX /* Set the limit for the size of the path. */
   1.860 +#define MAX_READ_SIZE 512
   1.861 +
   1.862 +typedef struct DefaultTZInfo {
   1.863 +    char* defaultTZBuffer;
   1.864 +    int64_t defaultTZFileSize;
   1.865 +    FILE* defaultTZFilePtr;
   1.866 +    UBool defaultTZstatus;
   1.867 +    int32_t defaultTZPosition;
   1.868 +} DefaultTZInfo;
   1.869 +
   1.870 +/*
   1.871 + * This method compares the two files given to see if they are a match.
   1.872 + * It is currently use to compare two TZ files.
   1.873 + */
   1.874 +static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFileName, DefaultTZInfo* tzInfo) {
   1.875 +    FILE* file; 
   1.876 +    int64_t sizeFile;
   1.877 +    int64_t sizeFileLeft;
   1.878 +    int32_t sizeFileRead;
   1.879 +    int32_t sizeFileToRead;
   1.880 +    char bufferFile[MAX_READ_SIZE];
   1.881 +    UBool result = TRUE;
   1.882 +
   1.883 +    if (tzInfo->defaultTZFilePtr == NULL) {
   1.884 +        tzInfo->defaultTZFilePtr = fopen(defaultTZFileName, "r");
   1.885 +    }
   1.886 +    file = fopen(TZFileName, "r");
   1.887 +
   1.888 +    tzInfo->defaultTZPosition = 0; /* reset position to begin search */
   1.889 +
   1.890 +    if (file != NULL && tzInfo->defaultTZFilePtr != NULL) {
   1.891 +        /* First check that the file size are equal. */
   1.892 +        if (tzInfo->defaultTZFileSize == 0) {
   1.893 +            fseek(tzInfo->defaultTZFilePtr, 0, SEEK_END);
   1.894 +            tzInfo->defaultTZFileSize = ftell(tzInfo->defaultTZFilePtr);
   1.895 +        }
   1.896 +        fseek(file, 0, SEEK_END);
   1.897 +        sizeFile = ftell(file);
   1.898 +        sizeFileLeft = sizeFile;
   1.899 +
   1.900 +        if (sizeFile != tzInfo->defaultTZFileSize) {
   1.901 +            result = FALSE;
   1.902 +        } else {
   1.903 +            /* Store the data from the files in seperate buffers and
   1.904 +             * compare each byte to determine equality.
   1.905 +             */
   1.906 +            if (tzInfo->defaultTZBuffer == NULL) {
   1.907 +                rewind(tzInfo->defaultTZFilePtr);
   1.908 +                tzInfo->defaultTZBuffer = (char*)uprv_malloc(sizeof(char) * tzInfo->defaultTZFileSize);
   1.909 +                sizeFileRead = fread(tzInfo->defaultTZBuffer, 1, tzInfo->defaultTZFileSize, tzInfo->defaultTZFilePtr);
   1.910 +            }
   1.911 +            rewind(file);
   1.912 +            while(sizeFileLeft > 0) {
   1.913 +                uprv_memset(bufferFile, 0, MAX_READ_SIZE);
   1.914 +                sizeFileToRead = sizeFileLeft < MAX_READ_SIZE ? sizeFileLeft : MAX_READ_SIZE;
   1.915 +
   1.916 +                sizeFileRead = fread(bufferFile, 1, sizeFileToRead, file);
   1.917 +                if (memcmp(tzInfo->defaultTZBuffer + tzInfo->defaultTZPosition, bufferFile, sizeFileRead) != 0) {
   1.918 +                    result = FALSE;
   1.919 +                    break;
   1.920 +                }
   1.921 +                sizeFileLeft -= sizeFileRead;
   1.922 +                tzInfo->defaultTZPosition += sizeFileRead;
   1.923 +            }
   1.924 +        }
   1.925 +    } else {
   1.926 +        result = FALSE;
   1.927 +    }
   1.928 +
   1.929 +    if (file != NULL) {
   1.930 +        fclose(file);
   1.931 +    }
   1.932 +
   1.933 +    return result;
   1.934 +}
   1.935 +/*
   1.936 + * This method recursively traverses the directory given for a matching TZ file and returns the first match.
   1.937 + */
   1.938 +/* dirent also lists two entries: "." and ".." that we can safely ignore. */
   1.939 +#define SKIP1 "."
   1.940 +#define SKIP2 ".."
   1.941 +static char SEARCH_TZFILE_RESULT[MAX_PATH_SIZE] = "";
   1.942 +static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
   1.943 +    char curpath[MAX_PATH_SIZE];
   1.944 +    DIR* dirp = opendir(path);
   1.945 +    DIR* subDirp = NULL;
   1.946 +    struct dirent* dirEntry = NULL;
   1.947 +
   1.948 +    char* result = NULL;
   1.949 +    if (dirp == NULL) {
   1.950 +        return result;
   1.951 +    }
   1.952 +
   1.953 +    /* Save the current path */
   1.954 +    uprv_memset(curpath, 0, MAX_PATH_SIZE);
   1.955 +    uprv_strcpy(curpath, path);
   1.956 +
   1.957 +    /* Check each entry in the directory. */
   1.958 +    while((dirEntry = readdir(dirp)) != NULL) {
   1.959 +        const char* dirName = dirEntry->d_name;
   1.960 +        if (uprv_strcmp(dirName, SKIP1) != 0 && uprv_strcmp(dirName, SKIP2) != 0) {
   1.961 +            /* Create a newpath with the new entry to test each entry in the directory. */
   1.962 +            char newpath[MAX_PATH_SIZE];
   1.963 +            uprv_strcpy(newpath, curpath);
   1.964 +            uprv_strcat(newpath, dirName);
   1.965 +
   1.966 +            if ((subDirp = opendir(newpath)) != NULL) {
   1.967 +                /* If this new path is a directory, make a recursive call with the newpath. */
   1.968 +                closedir(subDirp);
   1.969 +                uprv_strcat(newpath, "/");
   1.970 +                result = searchForTZFile(newpath, tzInfo);
   1.971 +                /*
   1.972 +                 Have to get out here. Otherwise, we'd keep looking
   1.973 +                 and return the first match in the top-level directory
   1.974 +                 if there's a match in the top-level. If not, this function
   1.975 +                 would return NULL and set gTimeZoneBufferPtr to NULL in initDefault().
   1.976 +                 It worked without this in most cases because we have a fallback of calling
   1.977 +                 localtime_r to figure out the default timezone.
   1.978 +                */
   1.979 +                if (result != NULL)
   1.980 +                    break;
   1.981 +            } else if (uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) {
   1.982 +                if(compareBinaryFiles(TZDEFAULT, newpath, tzInfo)) {
   1.983 +                    const char* zoneid = newpath + (sizeof(TZZONEINFO)) - 1;
   1.984 +                    skipZoneIDPrefix(&zoneid);
   1.985 +                    uprv_strcpy(SEARCH_TZFILE_RESULT, zoneid);
   1.986 +                    result = SEARCH_TZFILE_RESULT;
   1.987 +                    /* Get out after the first one found. */
   1.988 +                    break;
   1.989 +                }
   1.990 +            }
   1.991 +        }
   1.992 +    }
   1.993 +    closedir(dirp);
   1.994 +    return result;
   1.995 +}
   1.996 +#endif
   1.997 +U_CAPI const char* U_EXPORT2
   1.998 +uprv_tzname(int n)
   1.999 +{
  1.1000 +    const char *tzid = NULL;
  1.1001 +#if U_PLATFORM_USES_ONLY_WIN32_API
  1.1002 +    tzid = uprv_detectWindowsTimeZone();
  1.1003 +
  1.1004 +    if (tzid != NULL) {
  1.1005 +        return tzid;
  1.1006 +    }
  1.1007 +#else
  1.1008 +
  1.1009 +/*#if U_PLATFORM_IS_DARWIN_BASED
  1.1010 +    int ret;
  1.1011 +
  1.1012 +    tzid = getenv("TZFILE");
  1.1013 +    if (tzid != NULL) {
  1.1014 +        return tzid;
  1.1015 +    }
  1.1016 +#endif*/
  1.1017 +
  1.1018 +/* This code can be temporarily disabled to test tzname resolution later on. */
  1.1019 +#ifndef DEBUG_TZNAME
  1.1020 +    tzid = getenv("TZ");
  1.1021 +    if (tzid != NULL && isValidOlsonID(tzid)
  1.1022 +#if U_PLATFORM == U_PF_SOLARIS
  1.1023 +    /* When TZ equals localtime on Solaris, check the /etc/localtime file. */
  1.1024 +        && uprv_strcmp(tzid, TZ_ENV_CHECK) != 0
  1.1025 +#endif
  1.1026 +    ) {
  1.1027 +        /* This might be a good Olson ID. */
  1.1028 +        skipZoneIDPrefix(&tzid);
  1.1029 +        return tzid;
  1.1030 +    }
  1.1031 +    /* else U_TZNAME will give a better result. */
  1.1032 +#endif
  1.1033 +
  1.1034 +#if defined(CHECK_LOCALTIME_LINK) && !defined(DEBUG_SKIP_LOCALTIME_LINK)
  1.1035 +    /* Caller must handle threading issues */
  1.1036 +    if (gTimeZoneBufferPtr == NULL) {
  1.1037 +        /*
  1.1038 +        This is a trick to look at the name of the link to get the Olson ID
  1.1039 +        because the tzfile contents is underspecified.
  1.1040 +        This isn't guaranteed to work because it may not be a symlink.
  1.1041 +        */
  1.1042 +        int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer));
  1.1043 +        if (0 < ret) {
  1.1044 +            int32_t tzZoneInfoLen = uprv_strlen(TZZONEINFO);
  1.1045 +            gTimeZoneBuffer[ret] = 0;
  1.1046 +            if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, tzZoneInfoLen) == 0
  1.1047 +                && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
  1.1048 +            {
  1.1049 +                return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
  1.1050 +            }
  1.1051 +#if U_PLATFORM == U_PF_SOLARIS
  1.1052 +            else
  1.1053 +            {
  1.1054 +                tzZoneInfoLen = uprv_strlen(TZZONEINFO2);
  1.1055 +                if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO2, tzZoneInfoLen) == 0
  1.1056 +                                && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
  1.1057 +                {
  1.1058 +                    return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
  1.1059 +                }
  1.1060 +            }
  1.1061 +#endif
  1.1062 +        } else {
  1.1063 +#if defined(SEARCH_TZFILE)
  1.1064 +            DefaultTZInfo* tzInfo = (DefaultTZInfo*)uprv_malloc(sizeof(DefaultTZInfo));
  1.1065 +            if (tzInfo != NULL) {
  1.1066 +                tzInfo->defaultTZBuffer = NULL;
  1.1067 +                tzInfo->defaultTZFileSize = 0;
  1.1068 +                tzInfo->defaultTZFilePtr = NULL;
  1.1069 +                tzInfo->defaultTZstatus = FALSE;
  1.1070 +                tzInfo->defaultTZPosition = 0;
  1.1071 +
  1.1072 +                gTimeZoneBufferPtr = searchForTZFile(TZZONEINFO, tzInfo);
  1.1073 +
  1.1074 +                /* Free previously allocated memory */
  1.1075 +                if (tzInfo->defaultTZBuffer != NULL) {
  1.1076 +                    uprv_free(tzInfo->defaultTZBuffer);
  1.1077 +                }
  1.1078 +                if (tzInfo->defaultTZFilePtr != NULL) {
  1.1079 +                    fclose(tzInfo->defaultTZFilePtr);
  1.1080 +                }
  1.1081 +                uprv_free(tzInfo);
  1.1082 +            }
  1.1083 +
  1.1084 +            if (gTimeZoneBufferPtr != NULL && isValidOlsonID(gTimeZoneBufferPtr)) {
  1.1085 +                return gTimeZoneBufferPtr;
  1.1086 +            }
  1.1087 +#endif
  1.1088 +        }
  1.1089 +    }
  1.1090 +    else {
  1.1091 +        return gTimeZoneBufferPtr;
  1.1092 +    }
  1.1093 +#endif
  1.1094 +#endif
  1.1095 +
  1.1096 +#ifdef U_TZNAME
  1.1097 +#if U_PLATFORM_USES_ONLY_WIN32_API
  1.1098 +    /* The return value is free'd in timezone.cpp on Windows because
  1.1099 +     * the other code path returns a pointer to a heap location. */
  1.1100 +    return uprv_strdup(U_TZNAME[n]);
  1.1101 +#else
  1.1102 +    /*
  1.1103 +    U_TZNAME is usually a non-unique abbreviation, which isn't normally usable.
  1.1104 +    So we remap the abbreviation to an olson ID.
  1.1105 +
  1.1106 +    Since Windows exposes a little more timezone information,
  1.1107 +    we normally don't use this code on Windows because
  1.1108 +    uprv_detectWindowsTimeZone should have already given the correct answer.
  1.1109 +    */
  1.1110 +    {
  1.1111 +        struct tm juneSol, decemberSol;
  1.1112 +        int daylightType;
  1.1113 +        static const time_t juneSolstice=1182478260; /*2007-06-21 18:11 UT*/
  1.1114 +        static const time_t decemberSolstice=1198332540; /*2007-12-22 06:09 UT*/
  1.1115 +
  1.1116 +        /* This probing will tell us when daylight savings occurs.  */
  1.1117 +        localtime_r(&juneSolstice, &juneSol);
  1.1118 +        localtime_r(&decemberSolstice, &decemberSol);
  1.1119 +        if(decemberSol.tm_isdst > 0) {
  1.1120 +          daylightType = U_DAYLIGHT_DECEMBER;
  1.1121 +        } else if(juneSol.tm_isdst > 0) {
  1.1122 +          daylightType = U_DAYLIGHT_JUNE;
  1.1123 +        } else {
  1.1124 +          daylightType = U_DAYLIGHT_NONE;
  1.1125 +        }
  1.1126 +        tzid = remapShortTimeZone(U_TZNAME[0], U_TZNAME[1], daylightType, uprv_timezone());
  1.1127 +        if (tzid != NULL) {
  1.1128 +            return tzid;
  1.1129 +        }
  1.1130 +    }
  1.1131 +    return U_TZNAME[n];
  1.1132 +#endif
  1.1133 +#else
  1.1134 +    return "";
  1.1135 +#endif
  1.1136 +}
  1.1137 +
  1.1138 +/* Get and set the ICU data directory --------------------------------------- */
  1.1139 +
  1.1140 +static char *gDataDirectory = NULL;
  1.1141 +#if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
  1.1142 + static char *gCorrectedPOSIXLocale = NULL; /* Heap allocated */
  1.1143 +#endif
  1.1144 +
  1.1145 +static UBool U_CALLCONV putil_cleanup(void)
  1.1146 +{
  1.1147 +    if (gDataDirectory && *gDataDirectory) {
  1.1148 +        uprv_free(gDataDirectory);
  1.1149 +    }
  1.1150 +    gDataDirectory = NULL;
  1.1151 +#if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
  1.1152 +    if (gCorrectedPOSIXLocale) {
  1.1153 +        uprv_free(gCorrectedPOSIXLocale);
  1.1154 +        gCorrectedPOSIXLocale = NULL;
  1.1155 +    }
  1.1156 +#endif
  1.1157 +    return TRUE;
  1.1158 +}
  1.1159 +
  1.1160 +/*
  1.1161 + * Set the data directory.
  1.1162 + *    Make a copy of the passed string, and set the global data dir to point to it.
  1.1163 + */
  1.1164 +U_CAPI void U_EXPORT2
  1.1165 +u_setDataDirectory(const char *directory) {
  1.1166 +    char *newDataDir;
  1.1167 +    int32_t length;
  1.1168 +
  1.1169 +    if(directory==NULL || *directory==0) {
  1.1170 +        /* A small optimization to prevent the malloc and copy when the
  1.1171 +        shared library is used, and this is a way to make sure that NULL
  1.1172 +        is never returned.
  1.1173 +        */
  1.1174 +        newDataDir = (char *)"";
  1.1175 +    }
  1.1176 +    else {
  1.1177 +        length=(int32_t)uprv_strlen(directory);
  1.1178 +        newDataDir = (char *)uprv_malloc(length + 2);
  1.1179 +        /* Exit out if newDataDir could not be created. */
  1.1180 +        if (newDataDir == NULL) {
  1.1181 +            return;
  1.1182 +        }
  1.1183 +        uprv_strcpy(newDataDir, directory);
  1.1184 +
  1.1185 +#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
  1.1186 +        {
  1.1187 +            char *p;
  1.1188 +            while(p = uprv_strchr(newDataDir, U_FILE_ALT_SEP_CHAR)) {
  1.1189 +                *p = U_FILE_SEP_CHAR;
  1.1190 +            }
  1.1191 +        }
  1.1192 +#endif
  1.1193 +    }
  1.1194 +
  1.1195 +    if (gDataDirectory && *gDataDirectory) {
  1.1196 +        uprv_free(gDataDirectory);
  1.1197 +    }
  1.1198 +    gDataDirectory = newDataDir;
  1.1199 +    ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  1.1200 +}
  1.1201 +
  1.1202 +U_CAPI UBool U_EXPORT2
  1.1203 +uprv_pathIsAbsolute(const char *path)
  1.1204 +{
  1.1205 +  if(!path || !*path) {
  1.1206 +    return FALSE;
  1.1207 +  }
  1.1208 +
  1.1209 +  if(*path == U_FILE_SEP_CHAR) {
  1.1210 +    return TRUE;
  1.1211 +  }
  1.1212 +
  1.1213 +#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
  1.1214 +  if(*path == U_FILE_ALT_SEP_CHAR) {
  1.1215 +    return TRUE;
  1.1216 +  }
  1.1217 +#endif
  1.1218 +
  1.1219 +#if U_PLATFORM_USES_ONLY_WIN32_API
  1.1220 +  if( (((path[0] >= 'A') && (path[0] <= 'Z')) ||
  1.1221 +       ((path[0] >= 'a') && (path[0] <= 'z'))) &&
  1.1222 +      path[1] == ':' ) {
  1.1223 +    return TRUE;
  1.1224 +  }
  1.1225 +#endif
  1.1226 +
  1.1227 +  return FALSE;
  1.1228 +}
  1.1229 +
  1.1230 +/* Temporary backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
  1.1231 +   until some client wrapper makefiles are updated */
  1.1232 +#if U_PLATFORM_IS_DARWIN_BASED && TARGET_IPHONE_SIMULATOR
  1.1233 +# if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1.1234 +#  define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
  1.1235 +# endif
  1.1236 +#endif
  1.1237 +
  1.1238 +U_CAPI const char * U_EXPORT2
  1.1239 +u_getDataDirectory(void) {
  1.1240 +    const char *path = NULL;
  1.1241 +#if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1.1242 +    char datadir_path_buffer[PATH_MAX];
  1.1243 +#endif
  1.1244 +
  1.1245 +    /* if we have the directory, then return it immediately */
  1.1246 +    if(gDataDirectory) {
  1.1247 +        return gDataDirectory;
  1.1248 +    }
  1.1249 +
  1.1250 +    /*
  1.1251 +    When ICU_NO_USER_DATA_OVERRIDE is defined, users aren't allowed to
  1.1252 +    override ICU's data with the ICU_DATA environment variable. This prevents
  1.1253 +    problems where multiple custom copies of ICU's specific version of data
  1.1254 +    are installed on a system. Either the application must define the data
  1.1255 +    directory with u_setDataDirectory, define ICU_DATA_DIR when compiling
  1.1256 +    ICU, set the data with udata_setCommonData or trust that all of the
  1.1257 +    required data is contained in ICU's data library that contains
  1.1258 +    the entry point defined by U_ICUDATA_ENTRY_POINT.
  1.1259 +
  1.1260 +    There may also be some platforms where environment variables
  1.1261 +    are not allowed.
  1.1262 +    */
  1.1263 +#   if !defined(ICU_NO_USER_DATA_OVERRIDE) && !UCONFIG_NO_FILE_IO
  1.1264 +    /* First try to get the environment variable */
  1.1265 +    path=getenv("ICU_DATA");
  1.1266 +#   endif
  1.1267 +
  1.1268 +    /* ICU_DATA_DIR may be set as a compile option.
  1.1269 +     * U_ICU_DATA_DEFAULT_DIR is provided and is set by ICU at compile time
  1.1270 +     * and is used only when data is built in archive mode eliminating the need
  1.1271 +     * for ICU_DATA_DIR to be set. U_ICU_DATA_DEFAULT_DIR is set to the installation
  1.1272 +     * directory of the data dat file. Users should use ICU_DATA_DIR if they want to
  1.1273 +     * set their own path.
  1.1274 +     */
  1.1275 +#if defined(ICU_DATA_DIR) || defined(U_ICU_DATA_DEFAULT_DIR)
  1.1276 +    if(path==NULL || *path==0) {
  1.1277 +# if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1.1278 +        const char *prefix = getenv(ICU_DATA_DIR_PREFIX_ENV_VAR);
  1.1279 +# endif
  1.1280 +# ifdef ICU_DATA_DIR
  1.1281 +        path=ICU_DATA_DIR;
  1.1282 +# else
  1.1283 +        path=U_ICU_DATA_DEFAULT_DIR;
  1.1284 +# endif
  1.1285 +# if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
  1.1286 +        if (prefix != NULL) {
  1.1287 +            snprintf(datadir_path_buffer, PATH_MAX, "%s%s", prefix, path);
  1.1288 +            path=datadir_path_buffer;
  1.1289 +        }
  1.1290 +# endif
  1.1291 +    }
  1.1292 +#endif
  1.1293 +
  1.1294 +    if(path==NULL) {
  1.1295 +        /* It looks really bad, set it to something. */
  1.1296 +        path = "";
  1.1297 +    }
  1.1298 +
  1.1299 +    u_setDataDirectory(path);
  1.1300 +    return gDataDirectory;
  1.1301 +}
  1.1302 +
  1.1303 +
  1.1304 +
  1.1305 +
  1.1306 +
  1.1307 +/* Macintosh-specific locale information ------------------------------------ */
  1.1308 +#if U_PLATFORM == U_PF_CLASSIC_MACOS
  1.1309 +
  1.1310 +typedef struct {
  1.1311 +    int32_t script;
  1.1312 +    int32_t region;
  1.1313 +    int32_t lang;
  1.1314 +    int32_t date_region;
  1.1315 +    const char* posixID;
  1.1316 +} mac_lc_rec;
  1.1317 +
  1.1318 +/* Todo: This will be updated with a newer version from www.unicode.org web
  1.1319 +   page when it's available.*/
  1.1320 +#define MAC_LC_MAGIC_NUMBER -5
  1.1321 +#define MAC_LC_INIT_NUMBER -9
  1.1322 +
  1.1323 +static const mac_lc_rec mac_lc_recs[] = {
  1.1324 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 0, "en_US",
  1.1325 +    /* United States*/
  1.1326 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 1, "fr_FR",
  1.1327 +    /* France*/
  1.1328 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 2, "en_GB",
  1.1329 +    /* Great Britain*/
  1.1330 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 3, "de_DE",
  1.1331 +    /* Germany*/
  1.1332 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 4, "it_IT",
  1.1333 +    /* Italy*/
  1.1334 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 5, "nl_NL",
  1.1335 +    /* Metherlands*/
  1.1336 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 6, "fr_BE",
  1.1337 +    /* French for Belgium or Lxembourg*/
  1.1338 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 7, "sv_SE",
  1.1339 +    /* Sweden*/
  1.1340 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 9, "da_DK",
  1.1341 +    /* Denmark*/
  1.1342 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 10, "pt_PT",
  1.1343 +    /* Portugal*/
  1.1344 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 11, "fr_CA",
  1.1345 +    /* French Canada*/
  1.1346 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 13, "is_IS",
  1.1347 +    /* Israel*/
  1.1348 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 14, "ja_JP",
  1.1349 +    /* Japan*/
  1.1350 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 15, "en_AU",
  1.1351 +    /* Australia*/
  1.1352 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 16, "ar_AE",
  1.1353 +    /* the Arabic world (?)*/
  1.1354 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 17, "fi_FI",
  1.1355 +    /* Finland*/
  1.1356 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 18, "fr_CH",
  1.1357 +    /* French for Switzerland*/
  1.1358 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 19, "de_CH",
  1.1359 +    /* German for Switzerland*/
  1.1360 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 20, "el_GR",
  1.1361 +    /* Greece*/
  1.1362 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 21, "is_IS",
  1.1363 +    /* Iceland ===*/
  1.1364 +    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 22, "",*/
  1.1365 +    /* Malta ===*/
  1.1366 +    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 23, "",*/
  1.1367 +    /* Cyprus ===*/
  1.1368 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 24, "tr_TR",
  1.1369 +    /* Turkey ===*/
  1.1370 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 25, "sh_YU",
  1.1371 +    /* Croatian system for Yugoslavia*/
  1.1372 +    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 33, "",*/
  1.1373 +    /* Hindi system for India*/
  1.1374 +    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 34, "",*/
  1.1375 +    /* Pakistan*/
  1.1376 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 41, "lt_LT",
  1.1377 +    /* Lithuania*/
  1.1378 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 42, "pl_PL",
  1.1379 +    /* Poland*/
  1.1380 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 43, "hu_HU",
  1.1381 +    /* Hungary*/
  1.1382 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 44, "et_EE",
  1.1383 +    /* Estonia*/
  1.1384 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 45, "lv_LV",
  1.1385 +    /* Latvia*/
  1.1386 +    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 46, "",*/
  1.1387 +    /* Lapland  [Ask Rich for the data. HS]*/
  1.1388 +    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 47, "",*/
  1.1389 +    /* Faeroe Islands*/
  1.1390 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 48, "fa_IR",
  1.1391 +    /* Iran*/
  1.1392 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 49, "ru_RU",
  1.1393 +    /* Russia*/
  1.1394 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 50, "en_IE",
  1.1395 +    /* Ireland*/
  1.1396 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 51, "ko_KR",
  1.1397 +    /* Korea*/
  1.1398 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 52, "zh_CN",
  1.1399 +    /* People's Republic of China*/
  1.1400 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 53, "zh_TW",
  1.1401 +    /* Taiwan*/
  1.1402 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 54, "th_TH",
  1.1403 +    /* Thailand*/
  1.1404 +
  1.1405 +    /* fallback is en_US*/
  1.1406 +    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER,
  1.1407 +    MAC_LC_MAGIC_NUMBER, "en_US"
  1.1408 +};
  1.1409 +
  1.1410 +#endif
  1.1411 +
  1.1412 +#if U_POSIX_LOCALE
  1.1413 +/* A helper function used by uprv_getPOSIXIDForDefaultLocale and
  1.1414 + * uprv_getPOSIXIDForDefaultCodepage. Returns the posix locale id for
  1.1415 + * LC_CTYPE and LC_MESSAGES. It doesn't support other locale categories.
  1.1416 + */
  1.1417 +static const char *uprv_getPOSIXIDForCategory(int category)
  1.1418 +{
  1.1419 +    const char* posixID = NULL;
  1.1420 +    if (category == LC_MESSAGES || category == LC_CTYPE) {
  1.1421 +        /*
  1.1422 +        * On Solaris two different calls to setlocale can result in
  1.1423 +        * different values. Only get this value once.
  1.1424 +        *
  1.1425 +        * We must check this first because an application can set this.
  1.1426 +        *
  1.1427 +        * LC_ALL can't be used because it's platform dependent. The LANG
  1.1428 +        * environment variable seems to affect LC_CTYPE variable by default.
  1.1429 +        * Here is what setlocale(LC_ALL, NULL) can return.
  1.1430 +        * HPUX can return 'C C C C C C C'
  1.1431 +        * Solaris can return /en_US/C/C/C/C/C on the second try.
  1.1432 +        * Linux can return LC_CTYPE=C;LC_NUMERIC=C;...
  1.1433 +        *
  1.1434 +        * The default codepage detection also needs to use LC_CTYPE.
  1.1435 +        *
  1.1436 +        * Do not call setlocale(LC_*, "")! Using an empty string instead
  1.1437 +        * of NULL, will modify the libc behavior.
  1.1438 +        */
  1.1439 +        posixID = setlocale(category, NULL);
  1.1440 +        if ((posixID == 0)
  1.1441 +            || (uprv_strcmp("C", posixID) == 0)
  1.1442 +            || (uprv_strcmp("POSIX", posixID) == 0))
  1.1443 +        {
  1.1444 +            /* Maybe we got some garbage.  Try something more reasonable */
  1.1445 +            posixID = getenv("LC_ALL");
  1.1446 +            if (posixID == 0) {
  1.1447 +                posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
  1.1448 +                if (posixID == 0) {
  1.1449 +                    posixID = getenv("LANG");
  1.1450 +                }
  1.1451 +            }
  1.1452 +        }
  1.1453 +    }
  1.1454 +    if ((posixID==0)
  1.1455 +        || (uprv_strcmp("C", posixID) == 0)
  1.1456 +        || (uprv_strcmp("POSIX", posixID) == 0))
  1.1457 +    {
  1.1458 +        /* Nothing worked.  Give it a nice POSIX default value. */
  1.1459 +        posixID = "en_US_POSIX";
  1.1460 +    }
  1.1461 +    return posixID;
  1.1462 +}
  1.1463 +
  1.1464 +/* Return just the POSIX id for the default locale, whatever happens to be in
  1.1465 + * it. It gets the value from LC_MESSAGES and indirectly from LC_ALL and LANG.
  1.1466 + */
  1.1467 +static const char *uprv_getPOSIXIDForDefaultLocale(void)
  1.1468 +{
  1.1469 +    static const char* posixID = NULL;
  1.1470 +    if (posixID == 0) {
  1.1471 +        posixID = uprv_getPOSIXIDForCategory(LC_MESSAGES);
  1.1472 +    }
  1.1473 +    return posixID;
  1.1474 +}
  1.1475 +
  1.1476 +#if !U_CHARSET_IS_UTF8
  1.1477 +/* Return just the POSIX id for the default codepage, whatever happens to be in
  1.1478 + * it. It gets the value from LC_CTYPE and indirectly from LC_ALL and LANG.
  1.1479 + */
  1.1480 +static const char *uprv_getPOSIXIDForDefaultCodepage(void)
  1.1481 +{
  1.1482 +    static const char* posixID = NULL;
  1.1483 +    if (posixID == 0) {
  1.1484 +        posixID = uprv_getPOSIXIDForCategory(LC_CTYPE);
  1.1485 +    }
  1.1486 +    return posixID;
  1.1487 +}
  1.1488 +#endif
  1.1489 +#endif
  1.1490 +
  1.1491 +/* NOTE: The caller should handle thread safety */
  1.1492 +U_CAPI const char* U_EXPORT2
  1.1493 +uprv_getDefaultLocaleID()
  1.1494 +{
  1.1495 +#if U_POSIX_LOCALE
  1.1496 +/*
  1.1497 +  Note that:  (a '!' means the ID is improper somehow)
  1.1498 +     LC_ALL  ---->     default_loc          codepage
  1.1499 +--------------------------------------------------------
  1.1500 +     ab.CD             ab                   CD
  1.1501 +     ab@CD             ab__CD               -
  1.1502 +     ab@CD.EF          ab__CD               EF
  1.1503 +
  1.1504 +     ab_CD.EF@GH       ab_CD_GH             EF
  1.1505 +
  1.1506 +Some 'improper' ways to do the same as above:
  1.1507 +  !  ab_CD@GH.EF       ab_CD_GH             EF
  1.1508 +  !  ab_CD.EF@GH.IJ    ab_CD_GH             EF
  1.1509 +  !  ab_CD@ZZ.EF@GH.IJ ab_CD_GH             EF
  1.1510 +
  1.1511 +     _CD@GH            _CD_GH               -
  1.1512 +     _CD.EF@GH         _CD_GH               EF
  1.1513 +
  1.1514 +The variant cannot have dots in it.
  1.1515 +The 'rightmost' variant (@xxx) wins.
  1.1516 +The leftmost codepage (.xxx) wins.
  1.1517 +*/
  1.1518 +    char *correctedPOSIXLocale = 0;
  1.1519 +    const char* posixID = uprv_getPOSIXIDForDefaultLocale();
  1.1520 +    const char *p;
  1.1521 +    const char *q;
  1.1522 +    int32_t len;
  1.1523 +
  1.1524 +    /* Format: (no spaces)
  1.1525 +    ll [ _CC ] [ . MM ] [ @ VV]
  1.1526 +
  1.1527 +      l = lang, C = ctry, M = charmap, V = variant
  1.1528 +    */
  1.1529 +
  1.1530 +    if (gCorrectedPOSIXLocale != NULL) {
  1.1531 +        return gCorrectedPOSIXLocale;
  1.1532 +    }
  1.1533 +
  1.1534 +    if ((p = uprv_strchr(posixID, '.')) != NULL) {
  1.1535 +        /* assume new locale can't be larger than old one? */
  1.1536 +        correctedPOSIXLocale = static_cast<char *>(uprv_malloc(uprv_strlen(posixID)+1));
  1.1537 +        /* Exit on memory allocation error. */
  1.1538 +        if (correctedPOSIXLocale == NULL) {
  1.1539 +            return NULL;
  1.1540 +        }
  1.1541 +        uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
  1.1542 +        correctedPOSIXLocale[p-posixID] = 0;
  1.1543 +
  1.1544 +        /* do not copy after the @ */
  1.1545 +        if ((p = uprv_strchr(correctedPOSIXLocale, '@')) != NULL) {
  1.1546 +            correctedPOSIXLocale[p-correctedPOSIXLocale] = 0;
  1.1547 +        }
  1.1548 +    }
  1.1549 +
  1.1550 +    /* Note that we scan the *uncorrected* ID. */
  1.1551 +    if ((p = uprv_strrchr(posixID, '@')) != NULL) {
  1.1552 +        if (correctedPOSIXLocale == NULL) {
  1.1553 +            correctedPOSIXLocale = static_cast<char *>(uprv_malloc(uprv_strlen(posixID)+1));
  1.1554 +            /* Exit on memory allocation error. */
  1.1555 +            if (correctedPOSIXLocale == NULL) {
  1.1556 +                return NULL;
  1.1557 +            }
  1.1558 +            uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
  1.1559 +            correctedPOSIXLocale[p-posixID] = 0;
  1.1560 +        }
  1.1561 +        p++;
  1.1562 +
  1.1563 +        /* Take care of any special cases here.. */
  1.1564 +        if (!uprv_strcmp(p, "nynorsk")) {
  1.1565 +            p = "NY";
  1.1566 +            /* Don't worry about no__NY. In practice, it won't appear. */
  1.1567 +        }
  1.1568 +
  1.1569 +        if (uprv_strchr(correctedPOSIXLocale,'_') == NULL) {
  1.1570 +            uprv_strcat(correctedPOSIXLocale, "__"); /* aa@b -> aa__b */
  1.1571 +        }
  1.1572 +        else {
  1.1573 +            uprv_strcat(correctedPOSIXLocale, "_"); /* aa_CC@b -> aa_CC_b */
  1.1574 +        }
  1.1575 +
  1.1576 +        if ((q = uprv_strchr(p, '.')) != NULL) {
  1.1577 +            /* How big will the resulting string be? */
  1.1578 +            len = (int32_t)(uprv_strlen(correctedPOSIXLocale) + (q-p));
  1.1579 +            uprv_strncat(correctedPOSIXLocale, p, q-p);
  1.1580 +            correctedPOSIXLocale[len] = 0;
  1.1581 +        }
  1.1582 +        else {
  1.1583 +            /* Anything following the @ sign */
  1.1584 +            uprv_strcat(correctedPOSIXLocale, p);
  1.1585 +        }
  1.1586 +
  1.1587 +        /* Should there be a map from 'no@nynorsk' -> no_NO_NY here?
  1.1588 +         * How about 'russian' -> 'ru'?
  1.1589 +         * Many of the other locales using ISO codes will be handled by the
  1.1590 +         * canonicalization functions in uloc_getDefault.
  1.1591 +         */
  1.1592 +    }
  1.1593 +
  1.1594 +    /* Was a correction made? */
  1.1595 +    if (correctedPOSIXLocale != NULL) {
  1.1596 +        posixID = correctedPOSIXLocale;
  1.1597 +    }
  1.1598 +    else {
  1.1599 +        /* copy it, just in case the original pointer goes away.  See j2395 */
  1.1600 +        correctedPOSIXLocale = (char *)uprv_malloc(uprv_strlen(posixID) + 1);
  1.1601 +        /* Exit on memory allocation error. */
  1.1602 +        if (correctedPOSIXLocale == NULL) {
  1.1603 +            return NULL;
  1.1604 +        }
  1.1605 +        posixID = uprv_strcpy(correctedPOSIXLocale, posixID);
  1.1606 +    }
  1.1607 +
  1.1608 +    if (gCorrectedPOSIXLocale == NULL) {
  1.1609 +        gCorrectedPOSIXLocale = correctedPOSIXLocale;
  1.1610 +        ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  1.1611 +        correctedPOSIXLocale = NULL;
  1.1612 +    }
  1.1613 +
  1.1614 +    if (correctedPOSIXLocale != NULL) {  /* Was already set - clean up. */
  1.1615 +        uprv_free(correctedPOSIXLocale);
  1.1616 +    }
  1.1617 +
  1.1618 +    return posixID;
  1.1619 +
  1.1620 +#elif U_PLATFORM_USES_ONLY_WIN32_API
  1.1621 +#define POSIX_LOCALE_CAPACITY 64
  1.1622 +    UErrorCode status = U_ZERO_ERROR;
  1.1623 +    char *correctedPOSIXLocale = 0;
  1.1624 +
  1.1625 +    if (gCorrectedPOSIXLocale != NULL) {
  1.1626 +        return gCorrectedPOSIXLocale;
  1.1627 +    }
  1.1628 +
  1.1629 +    LCID id = GetThreadLocale();
  1.1630 +    correctedPOSIXLocale = static_cast<char *>(uprv_malloc(POSIX_LOCALE_CAPACITY + 1));
  1.1631 +    if (correctedPOSIXLocale) {
  1.1632 +        int32_t posixLen = uprv_convertToPosix(id, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status);
  1.1633 +        if (U_SUCCESS(status)) {
  1.1634 +            *(correctedPOSIXLocale + posixLen) = 0;
  1.1635 +            gCorrectedPOSIXLocale = correctedPOSIXLocale;
  1.1636 +            ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
  1.1637 +        } else {
  1.1638 +            uprv_free(correctedPOSIXLocale);
  1.1639 +        }
  1.1640 +    }
  1.1641 +
  1.1642 +    if (gCorrectedPOSIXLocale == NULL) {
  1.1643 +        return "en_US";
  1.1644 +    }
  1.1645 +    return gCorrectedPOSIXLocale;
  1.1646 +
  1.1647 +#elif U_PLATFORM == U_PF_CLASSIC_MACOS
  1.1648 +    int32_t script = MAC_LC_INIT_NUMBER;
  1.1649 +    /* = IntlScript(); or GetScriptManagerVariable(smSysScript);*/
  1.1650 +    int32_t region = MAC_LC_INIT_NUMBER;
  1.1651 +    /* = GetScriptManagerVariable(smRegionCode);*/
  1.1652 +    int32_t lang = MAC_LC_INIT_NUMBER;
  1.1653 +    /* = GetScriptManagerVariable(smScriptLang);*/
  1.1654 +    int32_t date_region = MAC_LC_INIT_NUMBER;
  1.1655 +    const char* posixID = 0;
  1.1656 +    int32_t count = sizeof(mac_lc_recs) / sizeof(mac_lc_rec);
  1.1657 +    int32_t i;
  1.1658 +    Intl1Hndl ih;
  1.1659 +
  1.1660 +    ih = (Intl1Hndl) GetIntlResource(1);
  1.1661 +    if (ih)
  1.1662 +        date_region = ((uint16_t)(*ih)->intl1Vers) >> 8;
  1.1663 +
  1.1664 +    for (i = 0; i < count; i++) {
  1.1665 +        if (   ((mac_lc_recs[i].script == MAC_LC_MAGIC_NUMBER)
  1.1666 +             || (mac_lc_recs[i].script == script))
  1.1667 +            && ((mac_lc_recs[i].region == MAC_LC_MAGIC_NUMBER)
  1.1668 +             || (mac_lc_recs[i].region == region))
  1.1669 +            && ((mac_lc_recs[i].lang == MAC_LC_MAGIC_NUMBER)
  1.1670 +             || (mac_lc_recs[i].lang == lang))
  1.1671 +            && ((mac_lc_recs[i].date_region == MAC_LC_MAGIC_NUMBER)
  1.1672 +             || (mac_lc_recs[i].date_region == date_region))
  1.1673 +            )
  1.1674 +        {
  1.1675 +            posixID = mac_lc_recs[i].posixID;
  1.1676 +            break;
  1.1677 +        }
  1.1678 +    }
  1.1679 +
  1.1680 +    return posixID;
  1.1681 +
  1.1682 +#elif U_PLATFORM == U_PF_OS400
  1.1683 +    /* locales are process scoped and are by definition thread safe */
  1.1684 +    static char correctedLocale[64];
  1.1685 +    const  char *localeID = getenv("LC_ALL");
  1.1686 +           char *p;
  1.1687 +
  1.1688 +    if (localeID == NULL)
  1.1689 +        localeID = getenv("LANG");
  1.1690 +    if (localeID == NULL)
  1.1691 +        localeID = setlocale(LC_ALL, NULL);
  1.1692 +    /* Make sure we have something... */
  1.1693 +    if (localeID == NULL)
  1.1694 +        return "en_US_POSIX";
  1.1695 +
  1.1696 +    /* Extract the locale name from the path. */
  1.1697 +    if((p = uprv_strrchr(localeID, '/')) != NULL)
  1.1698 +    {
  1.1699 +        /* Increment p to start of locale name. */
  1.1700 +        p++;
  1.1701 +        localeID = p;
  1.1702 +    }
  1.1703 +
  1.1704 +    /* Copy to work location. */
  1.1705 +    uprv_strcpy(correctedLocale, localeID);
  1.1706 +
  1.1707 +    /* Strip off the '.locale' extension. */
  1.1708 +    if((p = uprv_strchr(correctedLocale, '.')) != NULL) {
  1.1709 +        *p = 0;
  1.1710 +    }
  1.1711 +
  1.1712 +    /* Upper case the locale name. */
  1.1713 +    T_CString_toUpperCase(correctedLocale);
  1.1714 +
  1.1715 +    /* See if we are using the POSIX locale.  Any of the
  1.1716 +    * following are equivalent and use the same QLGPGCMA
  1.1717 +    * (POSIX) locale.
  1.1718 +    * QLGPGCMA2 means UCS2
  1.1719 +    * QLGPGCMA_4 means UTF-32
  1.1720 +    * QLGPGCMA_8 means UTF-8
  1.1721 +    */
  1.1722 +    if ((uprv_strcmp("C", correctedLocale) == 0) ||
  1.1723 +        (uprv_strcmp("POSIX", correctedLocale) == 0) ||
  1.1724 +        (uprv_strncmp("QLGPGCMA", correctedLocale, 8) == 0))
  1.1725 +    {
  1.1726 +        uprv_strcpy(correctedLocale, "en_US_POSIX");
  1.1727 +    }
  1.1728 +    else
  1.1729 +    {
  1.1730 +        int16_t LocaleLen;
  1.1731 +
  1.1732 +        /* Lower case the lang portion. */
  1.1733 +        for(p = correctedLocale; *p != 0 && *p != '_'; p++)
  1.1734 +        {
  1.1735 +            *p = uprv_tolower(*p);
  1.1736 +        }
  1.1737 +
  1.1738 +        /* Adjust for Euro.  After '_E' add 'URO'. */
  1.1739 +        LocaleLen = uprv_strlen(correctedLocale);
  1.1740 +        if (correctedLocale[LocaleLen - 2] == '_' &&
  1.1741 +            correctedLocale[LocaleLen - 1] == 'E')
  1.1742 +        {
  1.1743 +            uprv_strcat(correctedLocale, "URO");
  1.1744 +        }
  1.1745 +
  1.1746 +        /* If using Lotus-based locale then convert to
  1.1747 +         * equivalent non Lotus.
  1.1748 +         */
  1.1749 +        else if (correctedLocale[LocaleLen - 2] == '_' &&
  1.1750 +            correctedLocale[LocaleLen - 1] == 'L')
  1.1751 +        {
  1.1752 +            correctedLocale[LocaleLen - 2] = 0;
  1.1753 +        }
  1.1754 +
  1.1755 +        /* There are separate simplified and traditional
  1.1756 +         * locales called zh_HK_S and zh_HK_T.
  1.1757 +         */
  1.1758 +        else if (uprv_strncmp(correctedLocale, "zh_HK", 5) == 0)
  1.1759 +        {
  1.1760 +            uprv_strcpy(correctedLocale, "zh_HK");
  1.1761 +        }
  1.1762 +
  1.1763 +        /* A special zh_CN_GBK locale...
  1.1764 +        */
  1.1765 +        else if (uprv_strcmp(correctedLocale, "zh_CN_GBK") == 0)
  1.1766 +        {
  1.1767 +            uprv_strcpy(correctedLocale, "zh_CN");
  1.1768 +        }
  1.1769 +
  1.1770 +    }
  1.1771 +
  1.1772 +    return correctedLocale;
  1.1773 +#endif
  1.1774 +
  1.1775 +}
  1.1776 +
  1.1777 +#if !U_CHARSET_IS_UTF8
  1.1778 +#if U_POSIX_LOCALE
  1.1779 +/*
  1.1780 +Due to various platform differences, one platform may specify a charset,
  1.1781 +when they really mean a different charset. Remap the names so that they are
  1.1782 +compatible with ICU. Only conflicting/ambiguous aliases should be resolved
  1.1783 +here. Before adding anything to this function, please consider adding unique
  1.1784 +names to the ICU alias table in the data directory.
  1.1785 +*/
  1.1786 +static const char*
  1.1787 +remapPlatformDependentCodepage(const char *locale, const char *name) {
  1.1788 +    if (locale != NULL && *locale == 0) {
  1.1789 +        /* Make sure that an empty locale is handled the same way. */
  1.1790 +        locale = NULL;
  1.1791 +    }
  1.1792 +    if (name == NULL) {
  1.1793 +        return NULL;
  1.1794 +    }
  1.1795 +#if U_PLATFORM == U_PF_AIX
  1.1796 +    if (uprv_strcmp(name, "IBM-943") == 0) {
  1.1797 +        /* Use the ASCII compatible ibm-943 */
  1.1798 +        name = "Shift-JIS";
  1.1799 +    }
  1.1800 +    else if (uprv_strcmp(name, "IBM-1252") == 0) {
  1.1801 +        /* Use the windows-1252 that contains the Euro */
  1.1802 +        name = "IBM-5348";
  1.1803 +    }
  1.1804 +#elif U_PLATFORM == U_PF_SOLARIS
  1.1805 +    if (locale != NULL && uprv_strcmp(name, "EUC") == 0) {
  1.1806 +        /* Solaris underspecifies the "EUC" name. */
  1.1807 +        if (uprv_strcmp(locale, "zh_CN") == 0) {
  1.1808 +            name = "EUC-CN";
  1.1809 +        }
  1.1810 +        else if (uprv_strcmp(locale, "zh_TW") == 0) {
  1.1811 +            name = "EUC-TW";
  1.1812 +        }
  1.1813 +        else if (uprv_strcmp(locale, "ko_KR") == 0) {
  1.1814 +            name = "EUC-KR";
  1.1815 +        }
  1.1816 +    }
  1.1817 +    else if (uprv_strcmp(name, "eucJP") == 0) {
  1.1818 +        /*
  1.1819 +        ibm-954 is the best match.
  1.1820 +        ibm-33722 is the default for eucJP (similar to Windows).
  1.1821 +        */
  1.1822 +        name = "eucjis";
  1.1823 +    }
  1.1824 +    else if (uprv_strcmp(name, "646") == 0) {
  1.1825 +        /*
  1.1826 +         * The default codepage given by Solaris is 646 but the C library routines treat it as if it was
  1.1827 +         * ISO-8859-1 instead of US-ASCII(646).
  1.1828 +         */
  1.1829 +        name = "ISO-8859-1";
  1.1830 +    }
  1.1831 +#elif U_PLATFORM_IS_DARWIN_BASED
  1.1832 +    if (locale == NULL && *name == 0) {
  1.1833 +        /*
  1.1834 +        No locale was specified, and an empty name was passed in.
  1.1835 +        This usually indicates that nl_langinfo didn't return valid information.
  1.1836 +        Mac OS X uses UTF-8 by default (especially the locale data and console).
  1.1837 +        */
  1.1838 +        name = "UTF-8";
  1.1839 +    }
  1.1840 +    else if (uprv_strcmp(name, "CP949") == 0) {
  1.1841 +        /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
  1.1842 +        name = "EUC-KR";
  1.1843 +    }
  1.1844 +    else if (locale != NULL && uprv_strcmp(locale, "en_US_POSIX") != 0 && uprv_strcmp(name, "US-ASCII") == 0) {
  1.1845 +        /*
  1.1846 +         * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
  1.1847 +         */
  1.1848 +        name = "UTF-8";
  1.1849 +    }
  1.1850 +#elif U_PLATFORM == U_PF_BSD
  1.1851 +    if (uprv_strcmp(name, "CP949") == 0) {
  1.1852 +        /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
  1.1853 +        name = "EUC-KR";
  1.1854 +    }
  1.1855 +#elif U_PLATFORM == U_PF_HPUX
  1.1856 +    if (locale != NULL && uprv_strcmp(locale, "zh_HK") == 0 && uprv_strcmp(name, "big5") == 0) {
  1.1857 +        /* HP decided to extend big5 as hkbig5 even though it's not compatible :-( */
  1.1858 +        /* zh_TW.big5 is not the same charset as zh_HK.big5! */
  1.1859 +        name = "hkbig5";
  1.1860 +    }
  1.1861 +    else if (uprv_strcmp(name, "eucJP") == 0) {
  1.1862 +        /*
  1.1863 +        ibm-1350 is the best match, but unavailable.
  1.1864 +        ibm-954 is mostly a superset of ibm-1350.
  1.1865 +        ibm-33722 is the default for eucJP (similar to Windows).
  1.1866 +        */
  1.1867 +        name = "eucjis";
  1.1868 +    }
  1.1869 +#elif U_PLATFORM == U_PF_LINUX
  1.1870 +    if (locale != NULL && uprv_strcmp(name, "euc") == 0) {
  1.1871 +        /* Linux underspecifies the "EUC" name. */
  1.1872 +        if (uprv_strcmp(locale, "korean") == 0) {
  1.1873 +            name = "EUC-KR";
  1.1874 +        }
  1.1875 +        else if (uprv_strcmp(locale, "japanese") == 0) {
  1.1876 +            /* See comment below about eucJP */
  1.1877 +            name = "eucjis";
  1.1878 +        }
  1.1879 +    }
  1.1880 +    else if (uprv_strcmp(name, "eucjp") == 0) {
  1.1881 +        /*
  1.1882 +        ibm-1350 is the best match, but unavailable.
  1.1883 +        ibm-954 is mostly a superset of ibm-1350.
  1.1884 +        ibm-33722 is the default for eucJP (similar to Windows).
  1.1885 +        */
  1.1886 +        name = "eucjis";
  1.1887 +    }
  1.1888 +    else if (locale != NULL && uprv_strcmp(locale, "en_US_POSIX") != 0 &&
  1.1889 +            (uprv_strcmp(name, "ANSI_X3.4-1968") == 0 || uprv_strcmp(name, "US-ASCII") == 0)) {
  1.1890 +        /*
  1.1891 +         * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
  1.1892 +         */
  1.1893 +        name = "UTF-8";
  1.1894 +    }
  1.1895 +    /*
  1.1896 +     * Linux returns ANSI_X3.4-1968 for C/POSIX, but the call site takes care of
  1.1897 +     * it by falling back to 'US-ASCII' when NULL is returned from this
  1.1898 +     * function. So, we don't have to worry about it here.
  1.1899 +     */
  1.1900 +#endif
  1.1901 +    /* return NULL when "" is passed in */
  1.1902 +    if (*name == 0) {
  1.1903 +        name = NULL;
  1.1904 +    }
  1.1905 +    return name;
  1.1906 +}
  1.1907 +
  1.1908 +static const char*
  1.1909 +getCodepageFromPOSIXID(const char *localeName, char * buffer, int32_t buffCapacity)
  1.1910 +{
  1.1911 +    char localeBuf[100];
  1.1912 +    const char *name = NULL;
  1.1913 +    char *variant = NULL;
  1.1914 +
  1.1915 +    if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
  1.1916 +        size_t localeCapacity = uprv_min(sizeof(localeBuf), (name-localeName)+1);
  1.1917 +        uprv_strncpy(localeBuf, localeName, localeCapacity);
  1.1918 +        localeBuf[localeCapacity-1] = 0; /* ensure NULL termination */
  1.1919 +        name = uprv_strncpy(buffer, name+1, buffCapacity);
  1.1920 +        buffer[buffCapacity-1] = 0; /* ensure NULL termination */
  1.1921 +        if ((variant = const_cast<char *>(uprv_strchr(name, '@'))) != NULL) {
  1.1922 +            *variant = 0;
  1.1923 +        }
  1.1924 +        name = remapPlatformDependentCodepage(localeBuf, name);
  1.1925 +    }
  1.1926 +    return name;
  1.1927 +}
  1.1928 +#endif
  1.1929 +
  1.1930 +static const char*
  1.1931 +int_getDefaultCodepage()
  1.1932 +{
  1.1933 +#if U_PLATFORM == U_PF_OS400
  1.1934 +    uint32_t ccsid = 37; /* Default to ibm-37 */
  1.1935 +    static char codepage[64];
  1.1936 +    Qwc_JOBI0400_t jobinfo;
  1.1937 +    Qus_EC_t error = { sizeof(Qus_EC_t) }; /* SPI error code */
  1.1938 +
  1.1939 +    EPT_CALL(QUSRJOBI)(&jobinfo, sizeof(jobinfo), "JOBI0400",
  1.1940 +        "*                         ", "                ", &error);
  1.1941 +
  1.1942 +    if (error.Bytes_Available == 0) {
  1.1943 +        if (jobinfo.Coded_Char_Set_ID != 0xFFFF) {
  1.1944 +            ccsid = (uint32_t)jobinfo.Coded_Char_Set_ID;
  1.1945 +        }
  1.1946 +        else if (jobinfo.Default_Coded_Char_Set_Id != 0xFFFF) {
  1.1947 +            ccsid = (uint32_t)jobinfo.Default_Coded_Char_Set_Id;
  1.1948 +        }
  1.1949 +        /* else use the default */
  1.1950 +    }
  1.1951 +    sprintf(codepage,"ibm-%d", ccsid);
  1.1952 +    return codepage;
  1.1953 +
  1.1954 +#elif U_PLATFORM == U_PF_OS390
  1.1955 +    static char codepage[64];
  1.1956 +
  1.1957 +    strncpy(codepage, nl_langinfo(CODESET),63-strlen(UCNV_SWAP_LFNL_OPTION_STRING));
  1.1958 +    strcat(codepage,UCNV_SWAP_LFNL_OPTION_STRING);
  1.1959 +    codepage[63] = 0; /* NULL terminate */
  1.1960 +
  1.1961 +    return codepage;
  1.1962 +
  1.1963 +#elif U_PLATFORM == U_PF_CLASSIC_MACOS
  1.1964 +    return "macintosh"; /* TODO: Macintosh Roman. There must be a better way. fixme! */
  1.1965 +
  1.1966 +#elif U_PLATFORM_USES_ONLY_WIN32_API
  1.1967 +    static char codepage[64];
  1.1968 +    sprintf(codepage, "windows-%d", GetACP());
  1.1969 +    return codepage;
  1.1970 +
  1.1971 +#elif U_POSIX_LOCALE
  1.1972 +    static char codesetName[100];
  1.1973 +    const char *localeName = NULL;
  1.1974 +    const char *name = NULL;
  1.1975 +
  1.1976 +    localeName = uprv_getPOSIXIDForDefaultCodepage();
  1.1977 +    uprv_memset(codesetName, 0, sizeof(codesetName));
  1.1978 +#if U_HAVE_NL_LANGINFO_CODESET
  1.1979 +    /* When available, check nl_langinfo first because it usually gives more
  1.1980 +       useful names. It depends on LC_CTYPE.
  1.1981 +       nl_langinfo may use the same buffer as setlocale. */
  1.1982 +    {
  1.1983 +        const char *codeset = nl_langinfo(U_NL_LANGINFO_CODESET);
  1.1984 +#if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED
  1.1985 +        /*
  1.1986 +         * On Linux and MacOSX, ensure that default codepage for non C/POSIX locale is UTF-8
  1.1987 +         * instead of ASCII.
  1.1988 +         */
  1.1989 +        if (uprv_strcmp(localeName, "en_US_POSIX") != 0) {
  1.1990 +            codeset = remapPlatformDependentCodepage(localeName, codeset);
  1.1991 +        } else
  1.1992 +#endif
  1.1993 +        {
  1.1994 +            codeset = remapPlatformDependentCodepage(NULL, codeset);
  1.1995 +        }
  1.1996 +
  1.1997 +        if (codeset != NULL) {
  1.1998 +            uprv_strncpy(codesetName, codeset, sizeof(codesetName));
  1.1999 +            codesetName[sizeof(codesetName)-1] = 0;
  1.2000 +            return codesetName;
  1.2001 +        }
  1.2002 +    }
  1.2003 +#endif
  1.2004 +
  1.2005 +    /* Use setlocale in a nice way, and then check some environment variables.
  1.2006 +       Maybe the application used setlocale already.
  1.2007 +    */
  1.2008 +    uprv_memset(codesetName, 0, sizeof(codesetName));
  1.2009 +    name = getCodepageFromPOSIXID(localeName, codesetName, sizeof(codesetName));
  1.2010 +    if (name) {
  1.2011 +        /* if we can find the codeset name from setlocale, return that. */
  1.2012 +        return name;
  1.2013 +    }
  1.2014 +
  1.2015 +    if (*codesetName == 0)
  1.2016 +    {
  1.2017 +        /* Everything failed. Return US ASCII (ISO 646). */
  1.2018 +        (void)uprv_strcpy(codesetName, "US-ASCII");
  1.2019 +    }
  1.2020 +    return codesetName;
  1.2021 +#else
  1.2022 +    return "US-ASCII";
  1.2023 +#endif
  1.2024 +}
  1.2025 +
  1.2026 +
  1.2027 +U_CAPI const char*  U_EXPORT2
  1.2028 +uprv_getDefaultCodepage()
  1.2029 +{
  1.2030 +    static char const  *name = NULL;
  1.2031 +    umtx_lock(NULL);
  1.2032 +    if (name == NULL) {
  1.2033 +        name = int_getDefaultCodepage();
  1.2034 +    }
  1.2035 +    umtx_unlock(NULL);
  1.2036 +    return name;
  1.2037 +}
  1.2038 +#endif  /* !U_CHARSET_IS_UTF8 */
  1.2039 +
  1.2040 +
  1.2041 +/* end of platform-specific implementation -------------- */
  1.2042 +
  1.2043 +/* version handling --------------------------------------------------------- */
  1.2044 +
  1.2045 +U_CAPI void U_EXPORT2
  1.2046 +u_versionFromString(UVersionInfo versionArray, const char *versionString) {
  1.2047 +    char *end;
  1.2048 +    uint16_t part=0;
  1.2049 +
  1.2050 +    if(versionArray==NULL) {
  1.2051 +        return;
  1.2052 +    }
  1.2053 +
  1.2054 +    if(versionString!=NULL) {
  1.2055 +        for(;;) {
  1.2056 +            versionArray[part]=(uint8_t)uprv_strtoul(versionString, &end, 10);
  1.2057 +            if(end==versionString || ++part==U_MAX_VERSION_LENGTH || *end!=U_VERSION_DELIMITER) {
  1.2058 +                break;
  1.2059 +            }
  1.2060 +            versionString=end+1;
  1.2061 +        }
  1.2062 +    }
  1.2063 +
  1.2064 +    while(part<U_MAX_VERSION_LENGTH) {
  1.2065 +        versionArray[part++]=0;
  1.2066 +    }
  1.2067 +}
  1.2068 +
  1.2069 +U_CAPI void U_EXPORT2
  1.2070 +u_versionFromUString(UVersionInfo versionArray, const UChar *versionString) {
  1.2071 +    if(versionArray!=NULL && versionString!=NULL) {
  1.2072 +        char versionChars[U_MAX_VERSION_STRING_LENGTH+1];
  1.2073 +        int32_t len = u_strlen(versionString);
  1.2074 +        if(len>U_MAX_VERSION_STRING_LENGTH) {
  1.2075 +            len = U_MAX_VERSION_STRING_LENGTH;
  1.2076 +        }
  1.2077 +        u_UCharsToChars(versionString, versionChars, len);
  1.2078 +        versionChars[len]=0;
  1.2079 +        u_versionFromString(versionArray, versionChars);
  1.2080 +    }
  1.2081 +}
  1.2082 +
  1.2083 +U_CAPI void U_EXPORT2
  1.2084 +u_versionToString(const UVersionInfo versionArray, char *versionString) {
  1.2085 +    uint16_t count, part;
  1.2086 +    uint8_t field;
  1.2087 +
  1.2088 +    if(versionString==NULL) {
  1.2089 +        return;
  1.2090 +    }
  1.2091 +
  1.2092 +    if(versionArray==NULL) {
  1.2093 +        versionString[0]=0;
  1.2094 +        return;
  1.2095 +    }
  1.2096 +
  1.2097 +    /* count how many fields need to be written */
  1.2098 +    for(count=4; count>0 && versionArray[count-1]==0; --count) {
  1.2099 +    }
  1.2100 +
  1.2101 +    if(count <= 1) {
  1.2102 +        count = 2;
  1.2103 +    }
  1.2104 +
  1.2105 +    /* write the first part */
  1.2106 +    /* write the decimal field value */
  1.2107 +    field=versionArray[0];
  1.2108 +    if(field>=100) {
  1.2109 +        *versionString++=(char)('0'+field/100);
  1.2110 +        field%=100;
  1.2111 +    }
  1.2112 +    if(field>=10) {
  1.2113 +        *versionString++=(char)('0'+field/10);
  1.2114 +        field%=10;
  1.2115 +    }
  1.2116 +    *versionString++=(char)('0'+field);
  1.2117 +
  1.2118 +    /* write the following parts */
  1.2119 +    for(part=1; part<count; ++part) {
  1.2120 +        /* write a dot first */
  1.2121 +        *versionString++=U_VERSION_DELIMITER;
  1.2122 +
  1.2123 +        /* write the decimal field value */
  1.2124 +        field=versionArray[part];
  1.2125 +        if(field>=100) {
  1.2126 +            *versionString++=(char)('0'+field/100);
  1.2127 +            field%=100;
  1.2128 +        }
  1.2129 +        if(field>=10) {
  1.2130 +            *versionString++=(char)('0'+field/10);
  1.2131 +            field%=10;
  1.2132 +        }
  1.2133 +        *versionString++=(char)('0'+field);
  1.2134 +    }
  1.2135 +
  1.2136 +    /* NUL-terminate */
  1.2137 +    *versionString=0;
  1.2138 +}
  1.2139 +
  1.2140 +U_CAPI void U_EXPORT2
  1.2141 +u_getVersion(UVersionInfo versionArray) {
  1.2142 +    u_versionFromString(versionArray, U_ICU_VERSION);
  1.2143 +}
  1.2144 +
  1.2145 +/**
  1.2146 + * icucfg.h dependent code 
  1.2147 + */
  1.2148 +
  1.2149 +#if U_ENABLE_DYLOAD
  1.2150 + 
  1.2151 +#if HAVE_DLOPEN && !U_PLATFORM_USES_ONLY_WIN32_API
  1.2152 +
  1.2153 +#if HAVE_DLFCN_H
  1.2154 +
  1.2155 +#ifdef __MVS__
  1.2156 +#ifndef __SUSV3
  1.2157 +#define __SUSV3 1
  1.2158 +#endif
  1.2159 +#endif
  1.2160 +#include <dlfcn.h>
  1.2161 +#endif
  1.2162 +
  1.2163 +U_INTERNAL void * U_EXPORT2
  1.2164 +uprv_dl_open(const char *libName, UErrorCode *status) {
  1.2165 +  void *ret = NULL;
  1.2166 +  if(U_FAILURE(*status)) return ret;
  1.2167 +  ret =  dlopen(libName, RTLD_NOW|RTLD_GLOBAL);
  1.2168 +  if(ret==NULL) {
  1.2169 +#ifdef U_TRACE_DYLOAD
  1.2170 +    printf("dlerror on dlopen(%s): %s\n", libName, dlerror());
  1.2171 +#endif
  1.2172 +    *status = U_MISSING_RESOURCE_ERROR;
  1.2173 +  }
  1.2174 +  return ret;
  1.2175 +}
  1.2176 +
  1.2177 +U_INTERNAL void U_EXPORT2
  1.2178 +uprv_dl_close(void *lib, UErrorCode *status) {
  1.2179 +  if(U_FAILURE(*status)) return;
  1.2180 +  dlclose(lib);
  1.2181 +}
  1.2182 +
  1.2183 +U_INTERNAL UVoidFunction* U_EXPORT2
  1.2184 +uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
  1.2185 +  union {
  1.2186 +      UVoidFunction *fp;
  1.2187 +      void *vp;
  1.2188 +  } uret;
  1.2189 +  uret.fp = NULL;
  1.2190 +  if(U_FAILURE(*status)) return uret.fp;
  1.2191 +  uret.vp = dlsym(lib, sym);
  1.2192 +  if(uret.vp == NULL) {
  1.2193 +#ifdef U_TRACE_DYLOAD
  1.2194 +    printf("dlerror on dlsym(%p,%s): %s\n", lib,sym, dlerror());
  1.2195 +#endif
  1.2196 +    *status = U_MISSING_RESOURCE_ERROR;
  1.2197 +  }
  1.2198 +  return uret.fp;
  1.2199 +}
  1.2200 +
  1.2201 +#else
  1.2202 +
  1.2203 +/* null (nonexistent) implementation. */
  1.2204 +
  1.2205 +U_INTERNAL void * U_EXPORT2
  1.2206 +uprv_dl_open(const char *libName, UErrorCode *status) {
  1.2207 +  if(U_FAILURE(*status)) return NULL;
  1.2208 +  *status = U_UNSUPPORTED_ERROR;
  1.2209 +  return NULL;
  1.2210 +}
  1.2211 +
  1.2212 +U_INTERNAL void U_EXPORT2
  1.2213 +uprv_dl_close(void *lib, UErrorCode *status) {
  1.2214 +  if(U_FAILURE(*status)) return;
  1.2215 +  *status = U_UNSUPPORTED_ERROR;
  1.2216 +  return;
  1.2217 +}
  1.2218 +
  1.2219 +
  1.2220 +U_INTERNAL UVoidFunction* U_EXPORT2
  1.2221 +uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
  1.2222 +  if(U_SUCCESS(*status)) {
  1.2223 +    *status = U_UNSUPPORTED_ERROR;
  1.2224 +  }
  1.2225 +  return (UVoidFunction*)NULL;
  1.2226 +}
  1.2227 +
  1.2228 +
  1.2229 +
  1.2230 +#endif
  1.2231 +
  1.2232 +#elif U_PLATFORM_USES_ONLY_WIN32_API
  1.2233 +
  1.2234 +U_INTERNAL void * U_EXPORT2
  1.2235 +uprv_dl_open(const char *libName, UErrorCode *status) {
  1.2236 +  HMODULE lib = NULL;
  1.2237 +  
  1.2238 +  if(U_FAILURE(*status)) return NULL;
  1.2239 +  
  1.2240 +  lib = LoadLibraryA(libName);
  1.2241 +  
  1.2242 +  if(lib==NULL) {
  1.2243 +    *status = U_MISSING_RESOURCE_ERROR;
  1.2244 +  }
  1.2245 +  
  1.2246 +  return (void*)lib;
  1.2247 +}
  1.2248 +
  1.2249 +U_INTERNAL void U_EXPORT2
  1.2250 +uprv_dl_close(void *lib, UErrorCode *status) {
  1.2251 +  HMODULE handle = (HMODULE)lib;
  1.2252 +  if(U_FAILURE(*status)) return;
  1.2253 +  
  1.2254 +  FreeLibrary(handle);
  1.2255 +  
  1.2256 +  return;
  1.2257 +}
  1.2258 +
  1.2259 +
  1.2260 +U_INTERNAL UVoidFunction* U_EXPORT2
  1.2261 +uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
  1.2262 +  HMODULE handle = (HMODULE)lib;
  1.2263 +  UVoidFunction* addr = NULL;
  1.2264 +  
  1.2265 +  if(U_FAILURE(*status) || lib==NULL) return NULL;
  1.2266 +  
  1.2267 +  addr = (UVoidFunction*)GetProcAddress(handle, sym);
  1.2268 +  
  1.2269 +  if(addr==NULL) {
  1.2270 +    DWORD lastError = GetLastError();
  1.2271 +    if(lastError == ERROR_PROC_NOT_FOUND) {
  1.2272 +      *status = U_MISSING_RESOURCE_ERROR;
  1.2273 +    } else {
  1.2274 +      *status = U_UNSUPPORTED_ERROR; /* other unknown error. */
  1.2275 +    }
  1.2276 +  }
  1.2277 +  
  1.2278 +  return addr;
  1.2279 +}
  1.2280 +
  1.2281 +
  1.2282 +#else
  1.2283 +
  1.2284 +/* No dynamic loading set. */
  1.2285 +
  1.2286 +U_INTERNAL void * U_EXPORT2
  1.2287 +uprv_dl_open(const char *libName, UErrorCode *status) {
  1.2288 +    if(U_FAILURE(*status)) return NULL;
  1.2289 +    *status = U_UNSUPPORTED_ERROR;
  1.2290 +    return NULL;
  1.2291 +}
  1.2292 +
  1.2293 +U_INTERNAL void U_EXPORT2
  1.2294 +uprv_dl_close(void *lib, UErrorCode *status) {
  1.2295 +    if(U_FAILURE(*status)) return;
  1.2296 +    *status = U_UNSUPPORTED_ERROR;
  1.2297 +    return;
  1.2298 +}
  1.2299 +
  1.2300 +
  1.2301 +U_INTERNAL UVoidFunction* U_EXPORT2
  1.2302 +uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
  1.2303 +  if(U_SUCCESS(*status)) {
  1.2304 +    *status = U_UNSUPPORTED_ERROR;
  1.2305 +  }
  1.2306 +  return (UVoidFunction*)NULL;
  1.2307 +}
  1.2308 +
  1.2309 +#endif /* U_ENABLE_DYLOAD */
  1.2310 +
  1.2311 +/*
  1.2312 + * Hey, Emacs, please set the following:
  1.2313 + *
  1.2314 + * Local Variables:
  1.2315 + * indent-tabs-mode: nil
  1.2316 + * End:
  1.2317 + *
  1.2318 + */

mercurial