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