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 + */