intl/icu/source/common/putil.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial