Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 | */ |