2 ******************************************************************************
4 * Copyright (C) 1997-2012, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
9 * FILE NAME : putil.c (previously putil.cpp and ptypes.cpp)
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,
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.
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 ******************************************************************************
40 // Defines _XOPEN_SOURCE for access to POSIX functions.
41 // Must be before any other #includes.
42 #include "uposixdefs.h"
44 /* include ICU headers */
45 #include "unicode/utypes.h"
46 #include "unicode/putil.h"
47 #include "unicode/ustring.h"
56 /* Include standard headers. */
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
69 /* include system headers */
70 #if U_PLATFORM_USES_ONLY_WIN32_API
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?
76 # define WIN32_LEAN_AND_MEAN
84 #elif U_PLATFORM == U_PF_OS400
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
92 # include <IntlResources.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
103 #elif U_PLATFORM == U_PF_QNX
104 # include <sys/neutrino.h>
105 #elif U_PLATFORM == U_PF_SOLARIS
111 #if (U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(__STRICT_ANSI__)
112 /* tzset isn't defined in strict ANSI on Cygwin and MinGW. */
113 #undef __STRICT_ANSI__
117 * Cygwin with GCC requires inclusion of time.h after the above disabling strict asci mode statement.
121 #if !U_PLATFORM_USES_ONLY_WIN32_API
122 #include <sys/time.h>
126 * Only include langinfo.h if we have a way to get the codeset. If we later
127 * depend on more feature, we can test on U_HAVE_NL_LANGINFO.
131 #if U_HAVE_NL_LANGINFO_CODESET
132 #include <langinfo.h>
136 * Simple things (presence of functions, etc) should just go in configure.in and be added to
137 * icucfg.h via autoheader.
139 #if U_PLATFORM_IMPLEMENTS_POSIX
140 # if U_PLATFORM == U_PF_OS400
141 # define HAVE_DLFCN_H 0
142 # define HAVE_DLOPEN 0
144 # ifndef HAVE_DLFCN_H
145 # define HAVE_DLFCN_H 1
148 # define HAVE_DLOPEN 1
151 # ifndef HAVE_GETTIMEOFDAY
152 # define HAVE_GETTIMEOFDAY 1
155 # define HAVE_DLFCN_H 0
156 # define HAVE_DLOPEN 0
157 # define HAVE_GETTIMEOFDAY 0
160 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
162 /* Define the extension for data files, again... */
163 #define DATA_TYPE "dat"
165 /* Leave this copyright notice here! */
166 static const char copyright
[] = U_COPYRIGHT_STRING
;
168 /* floating point implementations ------------------------------------------- */
170 /* We return QNAN rather than SNAN*/
171 #define SIGN 0x80000000U
173 /* Make it easy to define certain types of constants */
175 int64_t i64
; /* This must be defined first in order to allow the initialization to work. This is a C89 feature. */
177 } BitPatternConversion
;
178 static const BitPatternConversion gNan
= { (int64_t) INT64_C(0x7FF8000000000000) };
179 static const BitPatternConversion gInf
= { (int64_t) INT64_C(0x7FF0000000000000) };
181 /*---------------------------------------------------------------------------
183 Our general strategy is to assume we're on a POSIX platform. Platforms which
184 are non-POSIX must declare themselves so. The default POSIX implementation
185 will sometimes work for non-POSIX platforms as well (e.g., the NaN-related
187 ---------------------------------------------------------------------------*/
189 #if U_PLATFORM_USES_ONLY_WIN32_API || U_PLATFORM == U_PF_CLASSIC_MACOS || U_PLATFORM == U_PF_OS400
190 # undef U_POSIX_LOCALE
192 # define U_POSIX_LOCALE 1
196 WARNING! u_topNBytesOfDouble and u_bottomNBytesOfDouble
197 can't be properly optimized by the gcc compiler sometimes (i.e. gcc 3.2).
201 u_topNBytesOfDouble(double* d
, int n
)
206 return (char*)(d
+ 1) - n
;
211 u_bottomNBytesOfDouble(double* d
, int n
)
214 return (char*)(d
+ 1) - n
;
219 #endif /* !IEEE_754 */
223 u_signBit(double d
) {
226 hiByte
= *(uint8_t *)&d
;
228 hiByte
= *(((uint8_t *)&d
) + sizeof(double) - 1);
230 return (hiByte
& 0x80) != 0;
236 #if defined (U_DEBUG_FAKETIME)
237 /* Override the clock to test things without having to move the system clock.
238 * Assumes POSIX gettimeofday() will function
240 UDate fakeClock_t0
= 0; /** Time to start the clock from **/
241 UDate fakeClock_dt
= 0; /** Offset (fake time - real time) **/
242 UBool fakeClock_set
= FALSE
; /** True if fake clock has spun up **/
243 static UMTX fakeClockMutex
= NULL
;
245 static UDate
getUTCtime_real() {
246 struct timeval posixTime
;
247 gettimeofday(&posixTime
, NULL
);
248 return (UDate
)(((int64_t)posixTime
.tv_sec
* U_MILLIS_PER_SECOND
) + (posixTime
.tv_usec
/1000));
251 static UDate
getUTCtime_fake() {
252 umtx_lock(&fakeClockMutex
);
254 UDate real
= getUTCtime_real();
255 const char *fake_start
= getenv("U_FAKETIME_START");
256 if((fake_start
!=NULL
) && (fake_start
[0]!=0)) {
257 sscanf(fake_start
,"%lf",&fakeClock_t0
);
258 fakeClock_dt
= fakeClock_t0
- real
;
259 fprintf(stderr
,"U_DEBUG_FAKETIME was set at compile time, so the ICU clock will start at a preset value\n"
260 "env variable U_FAKETIME_START=%.0f (%s) for an offset of %.0f ms from the current time %.0f\n",
261 fakeClock_t0
, fake_start
, fakeClock_dt
, real
);
264 fprintf(stderr
,"U_DEBUG_FAKETIME was set at compile time, but U_FAKETIME_START was not set.\n"
265 "Set U_FAKETIME_START to the number of milliseconds since 1/1/1970 to set the ICU clock.\n");
267 fakeClock_set
= TRUE
;
269 umtx_unlock(&fakeClockMutex
);
271 return getUTCtime_real() + fakeClock_dt
;
275 #if U_PLATFORM_USES_ONLY_WIN32_API
279 } FileTimeConversion
; /* This is like a ULARGE_INTEGER */
281 /* Number of 100 nanoseconds from 1/1/1601 to 1/1/1970 */
282 #define EPOCH_BIAS INT64_C(116444736000000000)
283 #define HECTONANOSECOND_PER_MILLISECOND 10000
287 /*---------------------------------------------------------------------------
288 Universal Implementations
289 These are designed to work on all platforms. Try these, and if they
290 don't work on your platform, then special case your platform with new
292 ---------------------------------------------------------------------------*/
294 U_CAPI UDate U_EXPORT2
297 #if defined(U_DEBUG_FAKETIME)
298 return getUTCtime_fake(); /* Hook for overriding the clock */
300 return uprv_getRawUTCtime();
304 /* Return UTC (GMT) time measured in milliseconds since 0:00 on 1/1/70.*/
305 U_CAPI UDate U_EXPORT2
308 #if U_PLATFORM == U_PF_CLASSIC_MACOS
312 uprv_memset( &tmrec
, 0, sizeof(tmrec
) );
316 t1
= mktime(&tmrec
); /* seconds of 1/1/1970*/
319 uprv_memcpy( &tmrec
, gmtime(&t
), sizeof(tmrec
) );
320 t2
= mktime(&tmrec
); /* seconds of current GMT*/
321 return (UDate
)(t2
- t1
) * U_MILLIS_PER_SECOND
; /* GMT (or UTC) in seconds since 1970*/
322 #elif U_PLATFORM_USES_ONLY_WIN32_API
324 FileTimeConversion winTime
;
325 GetSystemTimeAsFileTime(&winTime
.fileTime
);
326 return (UDate
)((winTime
.int64
- EPOCH_BIAS
) / HECTONANOSECOND_PER_MILLISECOND
);
329 #if HAVE_GETTIMEOFDAY
330 struct timeval posixTime
;
331 gettimeofday(&posixTime
, NULL
);
332 return (UDate
)(((int64_t)posixTime
.tv_sec
* U_MILLIS_PER_SECOND
) + (posixTime
.tv_usec
/1000));
336 return (UDate
)epochtime
* U_MILLIS_PER_SECOND
;
342 /*-----------------------------------------------------------------------------
344 These methods detect and return NaN and infinity values for doubles
345 conforming to IEEE 754. Platforms which support this standard include X86,
346 Mac 680x0, Mac PowerPC, AIX RS/6000, and most others.
347 If this doesn't work on your platform, you have non-IEEE floating-point, and
348 will need to code your own versions. A naive implementation is to return 0.0
349 for getNaN and getInfinity, and false for isNaN and isInfinite.
350 ---------------------------------------------------------------------------*/
352 U_CAPI UBool U_EXPORT2
353 uprv_isNaN(double number
)
356 BitPatternConversion convertedNumber
;
357 convertedNumber
.d64
= number
;
358 /* Infinity is 0x7FF0000000000000U. Anything greater than that is a NaN */
359 return (UBool
)((convertedNumber
.i64
& U_INT64_MAX
) > gInf
.i64
);
361 #elif U_PLATFORM == U_PF_OS390
362 uint32_t highBits
= *(uint32_t*)u_topNBytesOfDouble(&number
,
364 uint32_t lowBits
= *(uint32_t*)u_bottomNBytesOfDouble(&number
,
367 return ((highBits
& 0x7F080000L
) == 0x7F080000L
) &&
368 (lowBits
== 0x00000000L
);
371 /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
372 /* you'll need to replace this default implementation with what's correct*/
373 /* for your platform.*/
374 return number
!= number
;
378 U_CAPI UBool U_EXPORT2
379 uprv_isInfinite(double number
)
382 BitPatternConversion convertedNumber
;
383 convertedNumber
.d64
= number
;
384 /* Infinity is exactly 0x7FF0000000000000U. */
385 return (UBool
)((convertedNumber
.i64
& U_INT64_MAX
) == gInf
.i64
);
386 #elif U_PLATFORM == U_PF_OS390
387 uint32_t highBits
= *(uint32_t*)u_topNBytesOfDouble(&number
,
389 uint32_t lowBits
= *(uint32_t*)u_bottomNBytesOfDouble(&number
,
392 return ((highBits
& ~SIGN
) == 0x70FF0000L
) && (lowBits
== 0x00000000L
);
395 /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
396 /* value, you'll need to replace this default implementation with what's*/
397 /* correct for your platform.*/
398 return number
== (2.0 * number
);
402 U_CAPI UBool U_EXPORT2
403 uprv_isPositiveInfinity(double number
)
405 #if IEEE_754 || U_PLATFORM == U_PF_OS390
406 return (UBool
)(number
> 0 && uprv_isInfinite(number
));
408 return uprv_isInfinite(number
);
412 U_CAPI UBool U_EXPORT2
413 uprv_isNegativeInfinity(double number
)
415 #if IEEE_754 || U_PLATFORM == U_PF_OS390
416 return (UBool
)(number
< 0 && uprv_isInfinite(number
));
419 uint32_t highBits
= *(uint32_t*)u_topNBytesOfDouble(&number
,
421 return((highBits
& SIGN
) && uprv_isInfinite(number
));
426 U_CAPI
double U_EXPORT2
429 #if IEEE_754 || U_PLATFORM == U_PF_OS390
432 /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
433 /* you'll need to replace this default implementation with what's correct*/
434 /* for your platform.*/
439 U_CAPI
double U_EXPORT2
442 #if IEEE_754 || U_PLATFORM == U_PF_OS390
445 /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
446 /* value, you'll need to replace this default implementation with what's*/
447 /* correct for your platform.*/
452 U_CAPI
double U_EXPORT2
458 U_CAPI
double U_EXPORT2
464 U_CAPI
double U_EXPORT2
467 return uprv_floor(x
+ 0.5);
470 U_CAPI
double U_EXPORT2
476 U_CAPI
double U_EXPORT2
477 uprv_modf(double x
, double* y
)
482 U_CAPI
double U_EXPORT2
483 uprv_fmod(double x
, double y
)
488 U_CAPI
double U_EXPORT2
489 uprv_pow(double x
, double y
)
491 /* This is declared as "double pow(double x, double y)" */
495 U_CAPI
double U_EXPORT2
496 uprv_pow10(int32_t x
)
498 return pow(10.0, (double)x
);
501 U_CAPI
double U_EXPORT2
502 uprv_fmax(double x
, double y
)
505 /* first handle NaN*/
506 if(uprv_isNaN(x
) || uprv_isNaN(y
))
507 return uprv_getNaN();
509 /* check for -0 and 0*/
510 if(x
== 0.0 && y
== 0.0 && u_signBit(x
))
515 /* this should work for all flt point w/o NaN and Inf special cases */
516 return (x
> y
? x
: y
);
519 U_CAPI
double U_EXPORT2
520 uprv_fmin(double x
, double y
)
523 /* first handle NaN*/
524 if(uprv_isNaN(x
) || uprv_isNaN(y
))
525 return uprv_getNaN();
527 /* check for -0 and 0*/
528 if(x
== 0.0 && y
== 0.0 && u_signBit(y
))
533 /* this should work for all flt point w/o NaN and Inf special cases */
534 return (x
> y
? y
: x
);
538 * Truncates the given double.
539 * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
540 * This is different than calling floor() or ceil():
541 * floor(3.3) = 3, floor(-3.3) = -4
542 * ceil(3.3) = 4, ceil(-3.3) = -3
544 U_CAPI
double U_EXPORT2
548 /* handle error cases*/
550 return uprv_getNaN();
551 if(uprv_isInfinite(d
))
552 return uprv_getInfinity();
554 if(u_signBit(d
)) /* Signbit() picks up -0.0; d<0 does not. */
560 return d
>= 0 ? floor(d
) : ceil(d
);
566 * Return the largest positive number that can be represented by an integer
567 * type of arbitrary bit length.
569 U_CAPI
double U_EXPORT2
570 uprv_maxMantissa(void)
572 return pow(2.0, DBL_MANT_DIG
+ 1.0) - 1.0;
575 U_CAPI
double U_EXPORT2
581 U_CAPI
void * U_EXPORT2
582 uprv_maximumPtr(void * base
)
584 #if U_PLATFORM == U_PF_OS400
586 * With the provided function we should never be out of range of a given segment
587 * (a traditional/typical segment that is). Our segments have 5 bytes for the
588 * id and 3 bytes for the offset. The key is that the casting takes care of
589 * only retrieving the offset portion minus x1000. Hence, the smallest offset
590 * seen in a program is x001000 and when casted to an int would be 0.
591 * That's why we can only add 0xffefff. Otherwise, we would exceed the segment.
593 * Currently, 16MB is the current addressing limitation on i5/OS if the activation is
594 * non-TERASPACE. If it is TERASPACE it is 2GB - 4k(header information).
595 * This function determines the activation based on the pointer that is passed in and
596 * calculates the appropriate maximum available size for
597 * each pointer type (TERASPACE and non-TERASPACE)
599 * Unlike other operating systems, the pointer model isn't determined at
600 * compile time on i5/OS.
602 if ((base
!= NULL
) && (_TESTPTR(base
, _C_TERASPACE_CHECK
))) {
603 /* if it is a TERASPACE pointer the max is 2GB - 4k */
604 return ((void *)(((char *)base
)-((uint32_t)(base
))+((uint32_t)0x7fffefff)));
606 /* otherwise 16MB since NULL ptr is not checkable or the ptr is not TERASPACE */
607 return ((void *)(((char *)base
)-((uint32_t)(base
))+((uint32_t)0xffefff)));
610 return U_MAX_PTR(base
);
614 /*---------------------------------------------------------------------------
615 Platform-specific Implementations
616 Try these, and if they don't work on your platform, then special case your
617 platform with new implementations.
618 ---------------------------------------------------------------------------*/
620 /* Generic time zone layer -------------------------------------------------- */
622 /* Time zone utilities */
623 U_CAPI
void U_EXPORT2
629 /* no initialization*/
633 U_CAPI
int32_t U_EXPORT2
645 uprv_memcpy( &tmrec
, localtime(&t
), sizeof(tmrec
) );
646 dst_checked
= (tmrec
.tm_isdst
!= 0); /* daylight savings time is checked*/
647 t1
= mktime(&tmrec
); /* local time in seconds*/
648 uprv_memcpy( &tmrec
, gmtime(&t
), sizeof(tmrec
) );
649 t2
= mktime(&tmrec
); /* GMT (or UTC) in seconds*/
651 /* imitate NT behaviour, which returns same timezone offset to GMT for
659 /* Note that U_TZNAME does *not* have to be tzname, but if it is,
660 some platforms need to have it declared here. */
662 #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))
663 /* RS6000 and others reject char **tzname. */
664 extern U_IMPORT
char *U_TZNAME
[];
667 #if !UCONFIG_NO_FILE_IO && (U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD)
668 /* These platforms are likely to use Olson timezone IDs. */
669 #define CHECK_LOCALTIME_LINK 1
670 #if U_PLATFORM_IS_DARWIN_BASED
672 #define TZZONEINFO (TZDIR "/")
674 #define TZDEFAULT "/etc/localtime"
675 #define TZZONEINFO "/usr/share/zoneinfo/"
678 #define TZFILE_SKIP "posixrules" /* tz file to skip when searching. */
679 /* Some Linux distributions have 'localtime' in /usr/share/zoneinfo
680 symlinked to /etc/localtime, which makes searchForTZFile return
681 'localtime' when it's the first match. */
682 #define TZFILE_SKIP2 "localtime"
683 #define SEARCH_TZFILE
684 #include <dirent.h> /* Needed to search through system timezone files */
686 static char gTimeZoneBuffer
[PATH_MAX
];
687 static char *gTimeZoneBufferPtr
= NULL
;
690 #if !U_PLATFORM_USES_ONLY_WIN32_API
691 #define isNonDigit(ch) (ch < '0' || '9' < ch)
692 static UBool
isValidOlsonID(const char *id
) {
695 /* Determine if this is something like Iceland (Olson ID)
696 or AST4ADT (non-Olson ID) */
697 while (id
[idx
] && isNonDigit(id
[idx
]) && id
[idx
] != ',') {
701 /* If we went through the whole string, then it might be okay.
702 The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
703 "GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
704 The rest of the time it could be an Olson ID. George */
705 return (UBool
)(id
[idx
] == 0
706 || uprv_strcmp(id
, "PST8PDT") == 0
707 || uprv_strcmp(id
, "MST7MDT") == 0
708 || uprv_strcmp(id
, "CST6CDT") == 0
709 || uprv_strcmp(id
, "EST5EDT") == 0);
712 /* On some Unix-like OS, 'posix' subdirectory in
713 /usr/share/zoneinfo replicates the top-level contents. 'right'
714 subdirectory has the same set of files, but individual files
715 are different from those in the top-level directory or 'posix'
716 because 'right' has files for TAI (Int'l Atomic Time) while 'posix'
718 When the first match for /etc/localtime is in either of them
719 (usually in posix because 'right' has different file contents),
720 or TZ environment variable points to one of them, createTimeZone
721 fails because, say, 'posix/America/New_York' is not an Olson
722 timezone id ('America/New_York' is). So, we have to skip
723 'posix/' and 'right/' at the beginning. */
724 static void skipZoneIDPrefix(const char** id
) {
725 if (uprv_strncmp(*id
, "posix/", 6) == 0
726 || uprv_strncmp(*id
, "right/", 6) == 0)
733 #if defined(U_TZNAME) && !U_PLATFORM_USES_ONLY_WIN32_API
735 #define CONVERT_HOURS_TO_SECONDS(offset) (int32_t)(offset*3600)
736 typedef struct OffsetZoneMapping
{
737 int32_t offsetSeconds
;
738 int32_t daylightType
; /* 0=U_DAYLIGHT_NONE, 1=daylight in June-U_DAYLIGHT_JUNE, 2=daylight in December=U_DAYLIGHT_DECEMBER*/
744 enum { U_DAYLIGHT_NONE
=0,U_DAYLIGHT_JUNE
=1,U_DAYLIGHT_DECEMBER
=2 };
747 This list tries to disambiguate a set of abbreviated timezone IDs and offsets
748 and maps it to an Olson ID.
749 Before adding anything to this list, take a look at
750 icu/source/tools/tzcode/tz.alias
751 Sometimes no daylight savings (0) is important to define due to aliases.
752 This list can be tested with icu/source/test/compat/tzone.pl
753 More values could be added to daylightType to increase precision.
755 static const struct OffsetZoneMapping OFFSET_ZONE_MAPPINGS
[] = {
756 {-45900, 2, "CHAST", "CHADT", "Pacific/Chatham"},
757 {-43200, 1, "PETT", "PETST", "Asia/Kamchatka"},
758 {-43200, 2, "NZST", "NZDT", "Pacific/Auckland"},
759 {-43200, 1, "ANAT", "ANAST", "Asia/Anadyr"},
760 {-39600, 1, "MAGT", "MAGST", "Asia/Magadan"},
761 {-37800, 2, "LHST", "LHST", "Australia/Lord_Howe"},
762 {-36000, 2, "EST", "EST", "Australia/Sydney"},
763 {-36000, 1, "SAKT", "SAKST", "Asia/Sakhalin"},
764 {-36000, 1, "VLAT", "VLAST", "Asia/Vladivostok"},
765 {-34200, 2, "CST", "CST", "Australia/South"},
766 {-32400, 1, "YAKT", "YAKST", "Asia/Yakutsk"},
767 {-32400, 1, "CHOT", "CHOST", "Asia/Choibalsan"},
768 {-31500, 2, "CWST", "CWST", "Australia/Eucla"},
769 {-28800, 1, "IRKT", "IRKST", "Asia/Irkutsk"},
770 {-28800, 1, "ULAT", "ULAST", "Asia/Ulaanbaatar"},
771 {-28800, 2, "WST", "WST", "Australia/West"},
772 {-25200, 1, "HOVT", "HOVST", "Asia/Hovd"},
773 {-25200, 1, "KRAT", "KRAST", "Asia/Krasnoyarsk"},
774 {-21600, 1, "NOVT", "NOVST", "Asia/Novosibirsk"},
775 {-21600, 1, "OMST", "OMSST", "Asia/Omsk"},
776 {-18000, 1, "YEKT", "YEKST", "Asia/Yekaterinburg"},
777 {-14400, 1, "SAMT", "SAMST", "Europe/Samara"},
778 {-14400, 1, "AMT", "AMST", "Asia/Yerevan"},
779 {-14400, 1, "AZT", "AZST", "Asia/Baku"},
780 {-10800, 1, "AST", "ADT", "Asia/Baghdad"},
781 {-10800, 1, "MSK", "MSD", "Europe/Moscow"},
782 {-10800, 1, "VOLT", "VOLST", "Europe/Volgograd"},
783 {-7200, 0, "EET", "CEST", "Africa/Tripoli"},
784 {-7200, 1, "EET", "EEST", "Europe/Athens"}, /* Conflicts with Africa/Cairo */
785 {-7200, 1, "IST", "IDT", "Asia/Jerusalem"},
786 {-3600, 0, "CET", "WEST", "Africa/Algiers"},
787 {-3600, 2, "WAT", "WAST", "Africa/Windhoek"},
788 {0, 1, "GMT", "IST", "Europe/Dublin"},
789 {0, 1, "GMT", "BST", "Europe/London"},
790 {0, 0, "WET", "WEST", "Africa/Casablanca"},
791 {0, 0, "WET", "WET", "Africa/El_Aaiun"},
792 {3600, 1, "AZOT", "AZOST", "Atlantic/Azores"},
793 {3600, 1, "EGT", "EGST", "America/Scoresbysund"},
794 {10800, 1, "PMST", "PMDT", "America/Miquelon"},
795 {10800, 2, "UYT", "UYST", "America/Montevideo"},
796 {10800, 1, "WGT", "WGST", "America/Godthab"},
797 {10800, 2, "BRT", "BRST", "Brazil/East"},
798 {12600, 1, "NST", "NDT", "America/St_Johns"},
799 {14400, 1, "AST", "ADT", "Canada/Atlantic"},
800 {14400, 2, "AMT", "AMST", "America/Cuiaba"},
801 {14400, 2, "CLT", "CLST", "Chile/Continental"},
802 {14400, 2, "FKT", "FKST", "Atlantic/Stanley"},
803 {14400, 2, "PYT", "PYST", "America/Asuncion"},
804 {18000, 1, "CST", "CDT", "America/Havana"},
805 {18000, 1, "EST", "EDT", "US/Eastern"}, /* Conflicts with America/Grand_Turk */
806 {21600, 2, "EAST", "EASST", "Chile/EasterIsland"},
807 {21600, 0, "CST", "MDT", "Canada/Saskatchewan"},
808 {21600, 0, "CST", "CDT", "America/Guatemala"},
809 {21600, 1, "CST", "CDT", "US/Central"}, /* Conflicts with Mexico/General */
810 {25200, 1, "MST", "MDT", "US/Mountain"}, /* Conflicts with Mexico/BajaSur */
811 {28800, 0, "PST", "PST", "Pacific/Pitcairn"},
812 {28800, 1, "PST", "PDT", "US/Pacific"}, /* Conflicts with Mexico/BajaNorte */
813 {32400, 1, "AKST", "AKDT", "US/Alaska"},
814 {36000, 1, "HAST", "HADT", "US/Aleutian"}
817 /*#define DEBUG_TZNAME*/
819 static const char* remapShortTimeZone(const char *stdID
, const char *dstID
, int32_t daylightType
, int32_t offset
)
823 fprintf(stderr
, "TZ=%s std=%s dst=%s daylight=%d offset=%d\n", getenv("TZ"), stdID
, dstID
, daylightType
, offset
);
825 for (idx
= 0; idx
< LENGTHOF(OFFSET_ZONE_MAPPINGS
); idx
++)
827 if (offset
== OFFSET_ZONE_MAPPINGS
[idx
].offsetSeconds
828 && daylightType
== OFFSET_ZONE_MAPPINGS
[idx
].daylightType
829 && strcmp(OFFSET_ZONE_MAPPINGS
[idx
].stdID
, stdID
) == 0
830 && strcmp(OFFSET_ZONE_MAPPINGS
[idx
].dstID
, dstID
) == 0)
832 return OFFSET_ZONE_MAPPINGS
[idx
].olsonID
;
840 #define MAX_PATH_SIZE PATH_MAX /* Set the limit for the size of the path. */
841 #define MAX_READ_SIZE 512
843 typedef struct DefaultTZInfo
{
844 char* defaultTZBuffer
;
845 int64_t defaultTZFileSize
;
846 FILE* defaultTZFilePtr
;
847 UBool defaultTZstatus
;
848 int32_t defaultTZPosition
;
852 * This method compares the two files given to see if they are a match.
853 * It is currently use to compare two TZ files.
855 static UBool
compareBinaryFiles(const char* defaultTZFileName
, const char* TZFileName
, DefaultTZInfo
* tzInfo
) {
858 int64_t sizeFileLeft
;
859 int32_t sizeFileRead
;
860 int32_t sizeFileToRead
;
861 char bufferFile
[MAX_READ_SIZE
];
864 if (tzInfo
->defaultTZFilePtr
== NULL
) {
865 tzInfo
->defaultTZFilePtr
= fopen(defaultTZFileName
, "r");
867 file
= fopen(TZFileName
, "r");
869 tzInfo
->defaultTZPosition
= 0; /* reset position to begin search */
871 if (file
!= NULL
&& tzInfo
->defaultTZFilePtr
!= NULL
) {
872 /* First check that the file size are equal. */
873 if (tzInfo
->defaultTZFileSize
== 0) {
874 fseek(tzInfo
->defaultTZFilePtr
, 0, SEEK_END
);
875 tzInfo
->defaultTZFileSize
= ftell(tzInfo
->defaultTZFilePtr
);
877 fseek(file
, 0, SEEK_END
);
878 sizeFile
= ftell(file
);
879 sizeFileLeft
= sizeFile
;
881 if (sizeFile
!= tzInfo
->defaultTZFileSize
) {
884 /* Store the data from the files in seperate buffers and
885 * compare each byte to determine equality.
887 if (tzInfo
->defaultTZBuffer
== NULL
) {
888 rewind(tzInfo
->defaultTZFilePtr
);
889 tzInfo
->defaultTZBuffer
= (char*)uprv_malloc(sizeof(char) * tzInfo
->defaultTZFileSize
);
890 sizeFileRead
= fread(tzInfo
->defaultTZBuffer
, 1, tzInfo
->defaultTZFileSize
, tzInfo
->defaultTZFilePtr
);
893 while(sizeFileLeft
> 0) {
894 uprv_memset(bufferFile
, 0, MAX_READ_SIZE
);
895 sizeFileToRead
= sizeFileLeft
< MAX_READ_SIZE
? sizeFileLeft
: MAX_READ_SIZE
;
897 sizeFileRead
= fread(bufferFile
, 1, sizeFileToRead
, file
);
898 if (memcmp(tzInfo
->defaultTZBuffer
+ tzInfo
->defaultTZPosition
, bufferFile
, sizeFileRead
) != 0) {
902 sizeFileLeft
-= sizeFileRead
;
903 tzInfo
->defaultTZPosition
+= sizeFileRead
;
917 * This method recursively traverses the directory given for a matching TZ file and returns the first match.
919 /* dirent also lists two entries: "." and ".." that we can safely ignore. */
922 static char SEARCH_TZFILE_RESULT
[MAX_PATH_SIZE
] = "";
923 static char* searchForTZFile(const char* path
, DefaultTZInfo
* tzInfo
) {
924 char curpath
[MAX_PATH_SIZE
];
925 DIR* dirp
= opendir(path
);
927 struct dirent
* dirEntry
= NULL
;
934 /* Save the current path */
935 uprv_memset(curpath
, 0, MAX_PATH_SIZE
);
936 uprv_strcpy(curpath
, path
);
938 /* Check each entry in the directory. */
939 while((dirEntry
= readdir(dirp
)) != NULL
) {
940 const char* dirName
= dirEntry
->d_name
;
941 if (uprv_strcmp(dirName
, SKIP1
) != 0 && uprv_strcmp(dirName
, SKIP2
) != 0) {
942 /* Create a newpath with the new entry to test each entry in the directory. */
943 char newpath
[MAX_PATH_SIZE
];
944 uprv_strcpy(newpath
, curpath
);
945 uprv_strcat(newpath
, dirName
);
947 if ((subDirp
= opendir(newpath
)) != NULL
) {
948 /* If this new path is a directory, make a recursive call with the newpath. */
950 uprv_strcat(newpath
, "/");
951 result
= searchForTZFile(newpath
, tzInfo
);
953 Have to get out here. Otherwise, we'd keep looking
954 and return the first match in the top-level directory
955 if there's a match in the top-level. If not, this function
956 would return NULL and set gTimeZoneBufferPtr to NULL in initDefault().
957 It worked without this in most cases because we have a fallback of calling
958 localtime_r to figure out the default timezone.
962 } else if (uprv_strcmp(TZFILE_SKIP
, dirName
) != 0 && uprv_strcmp(TZFILE_SKIP2
, dirName
) != 0) {
963 if(compareBinaryFiles(TZDEFAULT
, newpath
, tzInfo
)) {
964 const char* zoneid
= newpath
+ (sizeof(TZZONEINFO
)) - 1;
965 skipZoneIDPrefix(&zoneid
);
966 uprv_strcpy(SEARCH_TZFILE_RESULT
, zoneid
);
967 result
= SEARCH_TZFILE_RESULT
;
968 /* Get out after the first one found. */
978 U_CAPI
const char* U_EXPORT2
981 const char *tzid
= NULL
;
982 #if U_PLATFORM_USES_ONLY_WIN32_API
983 tzid
= uprv_detectWindowsTimeZone();
990 /*#if U_PLATFORM_IS_DARWIN_BASED
993 tzid = getenv("TZFILE");
999 /* This code can be temporarily disabled to test tzname resolution later on. */
1000 #ifndef DEBUG_TZNAME
1001 tzid
= getenv("TZ");
1002 if (tzid
!= NULL
&& isValidOlsonID(tzid
))
1004 /* This might be a good Olson ID. */
1005 skipZoneIDPrefix(&tzid
);
1008 /* else U_TZNAME will give a better result. */
1011 #if defined(CHECK_LOCALTIME_LINK) && !defined(DEBUG_SKIP_LOCALTIME_LINK)
1012 /* Caller must handle threading issues */
1013 if (gTimeZoneBufferPtr
== NULL
) {
1015 This is a trick to look at the name of the link to get the Olson ID
1016 because the tzfile contents is underspecified.
1017 This isn't guaranteed to work because it may not be a symlink.
1019 int32_t ret
= (int32_t)readlink(TZDEFAULT
, gTimeZoneBuffer
, sizeof(gTimeZoneBuffer
));
1021 int32_t tzZoneInfoLen
= uprv_strlen(TZZONEINFO
);
1022 gTimeZoneBuffer
[ret
] = 0;
1023 if (uprv_strncmp(gTimeZoneBuffer
, TZZONEINFO
, tzZoneInfoLen
) == 0
1024 && isValidOlsonID(gTimeZoneBuffer
+ tzZoneInfoLen
))
1026 return (gTimeZoneBufferPtr
= gTimeZoneBuffer
+ tzZoneInfoLen
);
1029 #if defined(SEARCH_TZFILE)
1030 DefaultTZInfo
* tzInfo
= (DefaultTZInfo
*)uprv_malloc(sizeof(DefaultTZInfo
));
1031 if (tzInfo
!= NULL
) {
1032 tzInfo
->defaultTZBuffer
= NULL
;
1033 tzInfo
->defaultTZFileSize
= 0;
1034 tzInfo
->defaultTZFilePtr
= NULL
;
1035 tzInfo
->defaultTZstatus
= FALSE
;
1036 tzInfo
->defaultTZPosition
= 0;
1038 gTimeZoneBufferPtr
= searchForTZFile(TZZONEINFO
, tzInfo
);
1040 /* Free previously allocated memory */
1041 if (tzInfo
->defaultTZBuffer
!= NULL
) {
1042 uprv_free(tzInfo
->defaultTZBuffer
);
1044 if (tzInfo
->defaultTZFilePtr
!= NULL
) {
1045 fclose(tzInfo
->defaultTZFilePtr
);
1050 if (gTimeZoneBufferPtr
!= NULL
&& isValidOlsonID(gTimeZoneBufferPtr
)) {
1051 return gTimeZoneBufferPtr
;
1057 return gTimeZoneBufferPtr
;
1063 #if U_PLATFORM_USES_ONLY_WIN32_API
1064 /* The return value is free'd in timezone.cpp on Windows because
1065 * the other code path returns a pointer to a heap location. */
1066 return uprv_strdup(U_TZNAME
[n
]);
1069 U_TZNAME is usually a non-unique abbreviation, which isn't normally usable.
1070 So we remap the abbreviation to an olson ID.
1072 Since Windows exposes a little more timezone information,
1073 we normally don't use this code on Windows because
1074 uprv_detectWindowsTimeZone should have already given the correct answer.
1077 struct tm juneSol
, decemberSol
;
1079 static const time_t juneSolstice
=1182478260; /*2007-06-21 18:11 UT*/
1080 static const time_t decemberSolstice
=1198332540; /*2007-12-22 06:09 UT*/
1082 /* This probing will tell us when daylight savings occurs. */
1083 localtime_r(&juneSolstice
, &juneSol
);
1084 localtime_r(&decemberSolstice
, &decemberSol
);
1085 if(decemberSol
.tm_isdst
> 0) {
1086 daylightType
= U_DAYLIGHT_DECEMBER
;
1087 } else if(juneSol
.tm_isdst
> 0) {
1088 daylightType
= U_DAYLIGHT_JUNE
;
1090 daylightType
= U_DAYLIGHT_NONE
;
1092 tzid
= remapShortTimeZone(U_TZNAME
[0], U_TZNAME
[1], daylightType
, uprv_timezone());
1104 /* Get and set the ICU data directory --------------------------------------- */
1106 static char *gDataDirectory
= NULL
;
1108 static char *gCorrectedPOSIXLocale
= NULL
; /* Heap allocated */
1111 static UBool U_CALLCONV
putil_cleanup(void)
1113 if (gDataDirectory
&& *gDataDirectory
) {
1114 uprv_free(gDataDirectory
);
1116 gDataDirectory
= NULL
;
1118 if (gCorrectedPOSIXLocale
) {
1119 uprv_free(gCorrectedPOSIXLocale
);
1120 gCorrectedPOSIXLocale
= NULL
;
1127 * Set the data directory.
1128 * Make a copy of the passed string, and set the global data dir to point to it.
1129 * TODO: see bug #2849, regarding thread safety.
1131 U_CAPI
void U_EXPORT2
1132 u_setDataDirectory(const char *directory
) {
1136 if(directory
==NULL
|| *directory
==0) {
1137 /* A small optimization to prevent the malloc and copy when the
1138 shared library is used, and this is a way to make sure that NULL
1141 newDataDir
= (char *)"";
1144 length
=(int32_t)uprv_strlen(directory
);
1145 newDataDir
= (char *)uprv_malloc(length
+ 2);
1146 /* Exit out if newDataDir could not be created. */
1147 if (newDataDir
== NULL
) {
1150 uprv_strcpy(newDataDir
, directory
);
1152 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
1155 while(p
= uprv_strchr(newDataDir
, U_FILE_ALT_SEP_CHAR
)) {
1156 *p
= U_FILE_SEP_CHAR
;
1163 if (gDataDirectory
&& *gDataDirectory
) {
1164 uprv_free(gDataDirectory
);
1166 gDataDirectory
= newDataDir
;
1167 ucln_common_registerCleanup(UCLN_COMMON_PUTIL
, putil_cleanup
);
1171 U_CAPI UBool U_EXPORT2
1172 uprv_pathIsAbsolute(const char *path
)
1174 if(!path
|| !*path
) {
1178 if(*path
== U_FILE_SEP_CHAR
) {
1182 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
1183 if(*path
== U_FILE_ALT_SEP_CHAR
) {
1188 #if U_PLATFORM_USES_ONLY_WIN32_API
1189 if( (((path
[0] >= 'A') && (path
[0] <= 'Z')) ||
1190 ((path
[0] >= 'a') && (path
[0] <= 'z'))) &&
1199 /* Temporary backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
1200 until some client wrapper makefiles are updated */
1201 #if U_PLATFORM_IS_DARWIN_BASED && TARGET_IPHONE_SIMULATOR
1202 # if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
1203 # define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
1207 U_CAPI
const char * U_EXPORT2
1208 u_getDataDirectory(void) {
1209 const char *path
= NULL
;
1210 #if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
1211 char datadir_path_buffer
[PATH_MAX
];
1214 /* if we have the directory, then return it immediately */
1215 UMTX_CHECK(NULL
, gDataDirectory
, path
);
1222 When ICU_NO_USER_DATA_OVERRIDE is defined, users aren't allowed to
1223 override ICU's data with the ICU_DATA environment variable. This prevents
1224 problems where multiple custom copies of ICU's specific version of data
1225 are installed on a system. Either the application must define the data
1226 directory with u_setDataDirectory, define ICU_DATA_DIR when compiling
1227 ICU, set the data with udata_setCommonData or trust that all of the
1228 required data is contained in ICU's data library that contains
1229 the entry point defined by U_ICUDATA_ENTRY_POINT.
1231 There may also be some platforms where environment variables
1234 # if !defined(ICU_NO_USER_DATA_OVERRIDE) && !UCONFIG_NO_FILE_IO
1235 /* First try to get the environment variable */
1236 path
=getenv("ICU_DATA");
1239 /* ICU_DATA_DIR may be set as a compile option.
1240 * U_ICU_DATA_DEFAULT_DIR is provided and is set by ICU at compile time
1241 * and is used only when data is built in archive mode eliminating the need
1242 * for ICU_DATA_DIR to be set. U_ICU_DATA_DEFAULT_DIR is set to the installation
1243 * directory of the data dat file. Users should use ICU_DATA_DIR if they want to
1244 * set their own path.
1246 #if defined(ICU_DATA_DIR) || defined(U_ICU_DATA_DEFAULT_DIR)
1247 if(path
==NULL
|| *path
==0) {
1248 # if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
1249 const char *prefix
= getenv(ICU_DATA_DIR_PREFIX_ENV_VAR
);
1251 # ifdef ICU_DATA_DIR
1254 path
=U_ICU_DATA_DEFAULT_DIR
;
1256 # if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
1257 if (prefix
!= NULL
) {
1258 snprintf(datadir_path_buffer
, PATH_MAX
, "%s%s", prefix
, path
);
1259 path
=datadir_path_buffer
;
1266 /* It looks really bad, set it to something. */
1270 u_setDataDirectory(path
);
1271 return gDataDirectory
;
1278 /* Macintosh-specific locale information ------------------------------------ */
1279 #if U_PLATFORM == U_PF_CLASSIC_MACOS
1285 int32_t date_region
;
1286 const char* posixID
;
1289 /* Todo: This will be updated with a newer version from www.unicode.org web
1290 page when it's available.*/
1291 #define MAC_LC_MAGIC_NUMBER -5
1292 #define MAC_LC_INIT_NUMBER -9
1294 static const mac_lc_rec mac_lc_recs
[] = {
1295 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 0, "en_US",
1297 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 1, "fr_FR",
1299 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 2, "en_GB",
1301 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 3, "de_DE",
1303 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 4, "it_IT",
1305 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 5, "nl_NL",
1307 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 6, "fr_BE",
1308 /* French for Belgium or Lxembourg*/
1309 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 7, "sv_SE",
1311 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 9, "da_DK",
1313 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 10, "pt_PT",
1315 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 11, "fr_CA",
1317 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 13, "is_IS",
1319 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 14, "ja_JP",
1321 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 15, "en_AU",
1323 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 16, "ar_AE",
1324 /* the Arabic world (?)*/
1325 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 17, "fi_FI",
1327 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 18, "fr_CH",
1328 /* French for Switzerland*/
1329 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 19, "de_CH",
1330 /* German for Switzerland*/
1331 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 20, "el_GR",
1333 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 21, "is_IS",
1335 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 22, "",*/
1337 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 23, "",*/
1339 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 24, "tr_TR",
1341 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 25, "sh_YU",
1342 /* Croatian system for Yugoslavia*/
1343 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 33, "",*/
1344 /* Hindi system for India*/
1345 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 34, "",*/
1347 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 41, "lt_LT",
1349 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 42, "pl_PL",
1351 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 43, "hu_HU",
1353 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 44, "et_EE",
1355 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 45, "lv_LV",
1357 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 46, "",*/
1358 /* Lapland [Ask Rich for the data. HS]*/
1359 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 47, "",*/
1361 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 48, "fa_IR",
1363 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 49, "ru_RU",
1365 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 50, "en_IE",
1367 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 51, "ko_KR",
1369 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 52, "zh_CN",
1370 /* People's Republic of China*/
1371 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 53, "zh_TW",
1373 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 54, "th_TH",
1376 /* fallback is en_US*/
1377 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
,
1378 MAC_LC_MAGIC_NUMBER
, "en_US"
1384 /* A helper function used by uprv_getPOSIXIDForDefaultLocale and
1385 * uprv_getPOSIXIDForDefaultCodepage. Returns the posix locale id for
1386 * LC_CTYPE and LC_MESSAGES. It doesn't support other locale categories.
1388 static const char *uprv_getPOSIXIDForCategory(int category
)
1390 const char* posixID
= NULL
;
1391 if (category
== LC_MESSAGES
|| category
== LC_CTYPE
) {
1393 * On Solaris two different calls to setlocale can result in
1394 * different values. Only get this value once.
1396 * We must check this first because an application can set this.
1398 * LC_ALL can't be used because it's platform dependent. The LANG
1399 * environment variable seems to affect LC_CTYPE variable by default.
1400 * Here is what setlocale(LC_ALL, NULL) can return.
1401 * HPUX can return 'C C C C C C C'
1402 * Solaris can return /en_US/C/C/C/C/C on the second try.
1403 * Linux can return LC_CTYPE=C;LC_NUMERIC=C;...
1405 * The default codepage detection also needs to use LC_CTYPE.
1407 * Do not call setlocale(LC_*, "")! Using an empty string instead
1408 * of NULL, will modify the libc behavior.
1410 posixID
= setlocale(category
, NULL
);
1412 || (uprv_strcmp("C", posixID
) == 0)
1413 || (uprv_strcmp("POSIX", posixID
) == 0))
1415 /* Maybe we got some garbage. Try something more reasonable */
1416 posixID
= getenv("LC_ALL");
1418 posixID
= getenv(category
== LC_MESSAGES
? "LC_MESSAGES" : "LC_CTYPE");
1420 posixID
= getenv("LANG");
1426 || (uprv_strcmp("C", posixID
) == 0)
1427 || (uprv_strcmp("POSIX", posixID
) == 0))
1429 /* Nothing worked. Give it a nice POSIX default value. */
1430 posixID
= "en_US_POSIX";
1435 /* Return just the POSIX id for the default locale, whatever happens to be in
1436 * it. It gets the value from LC_MESSAGES and indirectly from LC_ALL and LANG.
1438 static const char *uprv_getPOSIXIDForDefaultLocale(void)
1440 static const char* posixID
= NULL
;
1442 posixID
= uprv_getPOSIXIDForCategory(LC_MESSAGES
);
1447 /* Return just the POSIX id for the default codepage, whatever happens to be in
1448 * it. It gets the value from LC_CTYPE and indirectly from LC_ALL and LANG.
1450 static const char *uprv_getPOSIXIDForDefaultCodepage(void)
1452 static const char* posixID
= NULL
;
1454 posixID
= uprv_getPOSIXIDForCategory(LC_CTYPE
);
1460 /* NOTE: The caller should handle thread safety */
1461 U_CAPI
const char* U_EXPORT2
1462 uprv_getDefaultLocaleID()
1466 Note that: (a '!' means the ID is improper somehow)
1467 LC_ALL ----> default_loc codepage
1468 --------------------------------------------------------
1473 ab_CD.EF@GH ab_CD_GH EF
1475 Some 'improper' ways to do the same as above:
1476 ! ab_CD@GH.EF ab_CD_GH EF
1477 ! ab_CD.EF@GH.IJ ab_CD_GH EF
1478 ! ab_CD@ZZ.EF@GH.IJ ab_CD_GH EF
1483 The variant cannot have dots in it.
1484 The 'rightmost' variant (@xxx) wins.
1485 The leftmost codepage (.xxx) wins.
1487 char *correctedPOSIXLocale
= 0;
1488 const char* posixID
= uprv_getPOSIXIDForDefaultLocale();
1493 /* Format: (no spaces)
1494 ll [ _CC ] [ . MM ] [ @ VV]
1496 l = lang, C = ctry, M = charmap, V = variant
1499 if (gCorrectedPOSIXLocale
!= NULL
) {
1500 return gCorrectedPOSIXLocale
;
1503 if ((p
= uprv_strchr(posixID
, '.')) != NULL
) {
1504 /* assume new locale can't be larger than old one? */
1505 correctedPOSIXLocale
= reinterpret_cast<char *>(uprv_malloc(uprv_strlen(posixID
)+1));
1506 /* Exit on memory allocation error. */
1507 if (correctedPOSIXLocale
== NULL
) {
1510 uprv_strncpy(correctedPOSIXLocale
, posixID
, p
-posixID
);
1511 correctedPOSIXLocale
[p
-posixID
] = 0;
1513 /* do not copy after the @ */
1514 if ((p
= uprv_strchr(correctedPOSIXLocale
, '@')) != NULL
) {
1515 correctedPOSIXLocale
[p
-correctedPOSIXLocale
] = 0;
1519 /* Note that we scan the *uncorrected* ID. */
1520 if ((p
= uprv_strrchr(posixID
, '@')) != NULL
) {
1521 if (correctedPOSIXLocale
== NULL
) {
1522 correctedPOSIXLocale
= reinterpret_cast<char *>(uprv_malloc(uprv_strlen(posixID
)+1));
1523 /* Exit on memory allocation error. */
1524 if (correctedPOSIXLocale
== NULL
) {
1527 uprv_strncpy(correctedPOSIXLocale
, posixID
, p
-posixID
);
1528 correctedPOSIXLocale
[p
-posixID
] = 0;
1532 /* Take care of any special cases here.. */
1533 if (!uprv_strcmp(p
, "nynorsk")) {
1535 /* Don't worry about no__NY. In practice, it won't appear. */
1538 if (uprv_strchr(correctedPOSIXLocale
,'_') == NULL
) {
1539 uprv_strcat(correctedPOSIXLocale
, "__"); /* aa@b -> aa__b */
1542 uprv_strcat(correctedPOSIXLocale
, "_"); /* aa_CC@b -> aa_CC_b */
1545 if ((q
= uprv_strchr(p
, '.')) != NULL
) {
1546 /* How big will the resulting string be? */
1547 len
= (int32_t)(uprv_strlen(correctedPOSIXLocale
) + (q
-p
));
1548 uprv_strncat(correctedPOSIXLocale
, p
, q
-p
);
1549 correctedPOSIXLocale
[len
] = 0;
1552 /* Anything following the @ sign */
1553 uprv_strcat(correctedPOSIXLocale
, p
);
1556 /* Should there be a map from 'no@nynorsk' -> no_NO_NY here?
1557 * How about 'russian' -> 'ru'?
1558 * Many of the other locales using ISO codes will be handled by the
1559 * canonicalization functions in uloc_getDefault.
1563 /* Was a correction made? */
1564 if (correctedPOSIXLocale
!= NULL
) {
1565 posixID
= correctedPOSIXLocale
;
1568 /* copy it, just in case the original pointer goes away. See j2395 */
1569 correctedPOSIXLocale
= (char *)uprv_malloc(uprv_strlen(posixID
) + 1);
1570 /* Exit on memory allocation error. */
1571 if (correctedPOSIXLocale
== NULL
) {
1574 posixID
= uprv_strcpy(correctedPOSIXLocale
, posixID
);
1577 if (gCorrectedPOSIXLocale
== NULL
) {
1578 gCorrectedPOSIXLocale
= correctedPOSIXLocale
;
1579 ucln_common_registerCleanup(UCLN_COMMON_PUTIL
, putil_cleanup
);
1580 correctedPOSIXLocale
= NULL
;
1583 if (correctedPOSIXLocale
!= NULL
) { /* Was already set - clean up. */
1584 uprv_free(correctedPOSIXLocale
);
1589 #elif U_PLATFORM_USES_ONLY_WIN32_API
1590 UErrorCode status
= U_ZERO_ERROR
;
1591 LCID id
= GetThreadLocale();
1592 const char* locID
= uprv_convertToPosix(id
, &status
);
1594 if (U_FAILURE(status
)) {
1599 #elif U_PLATFORM == U_PF_CLASSIC_MACOS
1600 int32_t script
= MAC_LC_INIT_NUMBER
;
1601 /* = IntlScript(); or GetScriptManagerVariable(smSysScript);*/
1602 int32_t region
= MAC_LC_INIT_NUMBER
;
1603 /* = GetScriptManagerVariable(smRegionCode);*/
1604 int32_t lang
= MAC_LC_INIT_NUMBER
;
1605 /* = GetScriptManagerVariable(smScriptLang);*/
1606 int32_t date_region
= MAC_LC_INIT_NUMBER
;
1607 const char* posixID
= 0;
1608 int32_t count
= sizeof(mac_lc_recs
) / sizeof(mac_lc_rec
);
1612 ih
= (Intl1Hndl
) GetIntlResource(1);
1614 date_region
= ((uint16_t)(*ih
)->intl1Vers
) >> 8;
1616 for (i
= 0; i
< count
; i
++) {
1617 if ( ((mac_lc_recs
[i
].script
== MAC_LC_MAGIC_NUMBER
)
1618 || (mac_lc_recs
[i
].script
== script
))
1619 && ((mac_lc_recs
[i
].region
== MAC_LC_MAGIC_NUMBER
)
1620 || (mac_lc_recs
[i
].region
== region
))
1621 && ((mac_lc_recs
[i
].lang
== MAC_LC_MAGIC_NUMBER
)
1622 || (mac_lc_recs
[i
].lang
== lang
))
1623 && ((mac_lc_recs
[i
].date_region
== MAC_LC_MAGIC_NUMBER
)
1624 || (mac_lc_recs
[i
].date_region
== date_region
))
1627 posixID
= mac_lc_recs
[i
].posixID
;
1634 #elif U_PLATFORM == U_PF_OS400
1635 /* locales are process scoped and are by definition thread safe */
1636 static char correctedLocale
[64];
1637 const char *localeID
= getenv("LC_ALL");
1640 if (localeID
== NULL
)
1641 localeID
= getenv("LANG");
1642 if (localeID
== NULL
)
1643 localeID
= setlocale(LC_ALL
, NULL
);
1644 /* Make sure we have something... */
1645 if (localeID
== NULL
)
1646 return "en_US_POSIX";
1648 /* Extract the locale name from the path. */
1649 if((p
= uprv_strrchr(localeID
, '/')) != NULL
)
1651 /* Increment p to start of locale name. */
1656 /* Copy to work location. */
1657 uprv_strcpy(correctedLocale
, localeID
);
1659 /* Strip off the '.locale' extension. */
1660 if((p
= uprv_strchr(correctedLocale
, '.')) != NULL
) {
1664 /* Upper case the locale name. */
1665 T_CString_toUpperCase(correctedLocale
);
1667 /* See if we are using the POSIX locale. Any of the
1668 * following are equivalent and use the same QLGPGCMA
1670 * QLGPGCMA2 means UCS2
1671 * QLGPGCMA_4 means UTF-32
1672 * QLGPGCMA_8 means UTF-8
1674 if ((uprv_strcmp("C", correctedLocale
) == 0) ||
1675 (uprv_strcmp("POSIX", correctedLocale
) == 0) ||
1676 (uprv_strncmp("QLGPGCMA", correctedLocale
, 8) == 0))
1678 uprv_strcpy(correctedLocale
, "en_US_POSIX");
1684 /* Lower case the lang portion. */
1685 for(p
= correctedLocale
; *p
!= 0 && *p
!= '_'; p
++)
1687 *p
= uprv_tolower(*p
);
1690 /* Adjust for Euro. After '_E' add 'URO'. */
1691 LocaleLen
= uprv_strlen(correctedLocale
);
1692 if (correctedLocale
[LocaleLen
- 2] == '_' &&
1693 correctedLocale
[LocaleLen
- 1] == 'E')
1695 uprv_strcat(correctedLocale
, "URO");
1698 /* If using Lotus-based locale then convert to
1699 * equivalent non Lotus.
1701 else if (correctedLocale
[LocaleLen
- 2] == '_' &&
1702 correctedLocale
[LocaleLen
- 1] == 'L')
1704 correctedLocale
[LocaleLen
- 2] = 0;
1707 /* There are separate simplified and traditional
1708 * locales called zh_HK_S and zh_HK_T.
1710 else if (uprv_strncmp(correctedLocale
, "zh_HK", 5) == 0)
1712 uprv_strcpy(correctedLocale
, "zh_HK");
1715 /* A special zh_CN_GBK locale...
1717 else if (uprv_strcmp(correctedLocale
, "zh_CN_GBK") == 0)
1719 uprv_strcpy(correctedLocale
, "zh_CN");
1724 return correctedLocale
;
1729 #if !U_CHARSET_IS_UTF8
1732 Due to various platform differences, one platform may specify a charset,
1733 when they really mean a different charset. Remap the names so that they are
1734 compatible with ICU. Only conflicting/ambiguous aliases should be resolved
1735 here. Before adding anything to this function, please consider adding unique
1736 names to the ICU alias table in the data directory.
1739 remapPlatformDependentCodepage(const char *locale
, const char *name
) {
1740 if (locale
!= NULL
&& *locale
== 0) {
1741 /* Make sure that an empty locale is handled the same way. */
1747 #if U_PLATFORM == U_PF_AIX
1748 if (uprv_strcmp(name
, "IBM-943") == 0) {
1749 /* Use the ASCII compatible ibm-943 */
1752 else if (uprv_strcmp(name
, "IBM-1252") == 0) {
1753 /* Use the windows-1252 that contains the Euro */
1756 #elif U_PLATFORM == U_PF_SOLARIS
1757 if (locale
!= NULL
&& uprv_strcmp(name
, "EUC") == 0) {
1758 /* Solaris underspecifies the "EUC" name. */
1759 if (uprv_strcmp(locale
, "zh_CN") == 0) {
1762 else if (uprv_strcmp(locale
, "zh_TW") == 0) {
1765 else if (uprv_strcmp(locale
, "ko_KR") == 0) {
1769 else if (uprv_strcmp(name
, "eucJP") == 0) {
1771 ibm-954 is the best match.
1772 ibm-33722 is the default for eucJP (similar to Windows).
1776 else if (uprv_strcmp(name
, "646") == 0) {
1778 * The default codepage given by Solaris is 646 but the C library routines treat it as if it was
1779 * ISO-8859-1 instead of US-ASCII(646).
1781 name
= "ISO-8859-1";
1783 #elif U_PLATFORM_IS_DARWIN_BASED
1784 if (locale
== NULL
&& *name
== 0) {
1786 No locale was specified, and an empty name was passed in.
1787 This usually indicates that nl_langinfo didn't return valid information.
1788 Mac OS X uses UTF-8 by default (especially the locale data and console).
1792 else if (uprv_strcmp(name
, "CP949") == 0) {
1793 /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
1796 else if (locale
!= NULL
&& uprv_strcmp(locale
, "en_US_POSIX") != 0 && uprv_strcmp(name
, "US-ASCII") == 0) {
1798 * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
1802 #elif U_PLATFORM == U_PF_BSD
1803 if (uprv_strcmp(name
, "CP949") == 0) {
1804 /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
1807 #elif U_PLATFORM == U_PF_HPUX
1808 if (locale
!= NULL
&& uprv_strcmp(locale
, "zh_HK") == 0 && uprv_strcmp(name
, "big5") == 0) {
1809 /* HP decided to extend big5 as hkbig5 even though it's not compatible :-( */
1810 /* zh_TW.big5 is not the same charset as zh_HK.big5! */
1813 else if (uprv_strcmp(name
, "eucJP") == 0) {
1815 ibm-1350 is the best match, but unavailable.
1816 ibm-954 is mostly a superset of ibm-1350.
1817 ibm-33722 is the default for eucJP (similar to Windows).
1821 #elif U_PLATFORM == U_PF_LINUX
1822 if (locale
!= NULL
&& uprv_strcmp(name
, "euc") == 0) {
1823 /* Linux underspecifies the "EUC" name. */
1824 if (uprv_strcmp(locale
, "korean") == 0) {
1827 else if (uprv_strcmp(locale
, "japanese") == 0) {
1828 /* See comment below about eucJP */
1832 else if (uprv_strcmp(name
, "eucjp") == 0) {
1834 ibm-1350 is the best match, but unavailable.
1835 ibm-954 is mostly a superset of ibm-1350.
1836 ibm-33722 is the default for eucJP (similar to Windows).
1840 else if (locale
!= NULL
&& uprv_strcmp(locale
, "en_US_POSIX") != 0 &&
1841 (uprv_strcmp(name
, "ANSI_X3.4-1968") == 0 || uprv_strcmp(name
, "US-ASCII") == 0)) {
1843 * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
1848 * Linux returns ANSI_X3.4-1968 for C/POSIX, but the call site takes care of
1849 * it by falling back to 'US-ASCII' when NULL is returned from this
1850 * function. So, we don't have to worry about it here.
1853 /* return NULL when "" is passed in */
1861 getCodepageFromPOSIXID(const char *localeName
, char * buffer
, int32_t buffCapacity
)
1863 char localeBuf
[100];
1864 const char *name
= NULL
;
1865 char *variant
= NULL
;
1867 if (localeName
!= NULL
&& (name
= (uprv_strchr(localeName
, '.'))) != NULL
) {
1868 size_t localeCapacity
= uprv_min(sizeof(localeBuf
), (name
-localeName
)+1);
1869 uprv_strncpy(localeBuf
, localeName
, localeCapacity
);
1870 localeBuf
[localeCapacity
-1] = 0; /* ensure NULL termination */
1871 name
= uprv_strncpy(buffer
, name
+1, buffCapacity
);
1872 buffer
[buffCapacity
-1] = 0; /* ensure NULL termination */
1873 if ((variant
= const_cast<char *>(uprv_strchr(name
, '@'))) != NULL
) {
1876 name
= remapPlatformDependentCodepage(localeBuf
, name
);
1883 int_getDefaultCodepage()
1885 #if U_PLATFORM == U_PF_OS400
1886 uint32_t ccsid
= 37; /* Default to ibm-37 */
1887 static char codepage
[64];
1888 Qwc_JOBI0400_t jobinfo
;
1889 Qus_EC_t error
= { sizeof(Qus_EC_t
) }; /* SPI error code */
1891 EPT_CALL(QUSRJOBI
)(&jobinfo
, sizeof(jobinfo
), "JOBI0400",
1894 if (error
.Bytes_Available
== 0) {
1895 if (jobinfo
.Coded_Char_Set_ID
!= 0xFFFF) {
1896 ccsid
= (uint32_t)jobinfo
.Coded_Char_Set_ID
;
1898 else if (jobinfo
.Default_Coded_Char_Set_Id
!= 0xFFFF) {
1899 ccsid
= (uint32_t)jobinfo
.Default_Coded_Char_Set_Id
;
1901 /* else use the default */
1903 sprintf(codepage
,"ibm-%d", ccsid
);
1906 #elif U_PLATFORM == U_PF_OS390
1907 static char codepage
[64];
1909 strncpy(codepage
, nl_langinfo(CODESET
),63-strlen(UCNV_SWAP_LFNL_OPTION_STRING
));
1910 strcat(codepage
,UCNV_SWAP_LFNL_OPTION_STRING
);
1911 codepage
[63] = 0; /* NULL terminate */
1915 #elif U_PLATFORM == U_PF_CLASSIC_MACOS
1916 return "macintosh"; /* TODO: Macintosh Roman. There must be a better way. fixme! */
1918 #elif U_PLATFORM_USES_ONLY_WIN32_API
1919 static char codepage
[64];
1920 sprintf(codepage
, "windows-%d", GetACP());
1923 #elif U_POSIX_LOCALE
1924 static char codesetName
[100];
1925 const char *localeName
= NULL
;
1926 const char *name
= NULL
;
1928 localeName
= uprv_getPOSIXIDForDefaultCodepage();
1929 uprv_memset(codesetName
, 0, sizeof(codesetName
));
1930 #if U_HAVE_NL_LANGINFO_CODESET
1931 /* When available, check nl_langinfo first because it usually gives more
1932 useful names. It depends on LC_CTYPE.
1933 nl_langinfo may use the same buffer as setlocale. */
1935 const char *codeset
= nl_langinfo(U_NL_LANGINFO_CODESET
);
1936 #if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED
1938 * On Linux and MacOSX, ensure that default codepage for non C/POSIX locale is UTF-8
1941 if (uprv_strcmp(localeName
, "en_US_POSIX") != 0) {
1942 codeset
= remapPlatformDependentCodepage(localeName
, codeset
);
1946 codeset
= remapPlatformDependentCodepage(NULL
, codeset
);
1949 if (codeset
!= NULL
) {
1950 uprv_strncpy(codesetName
, codeset
, sizeof(codesetName
));
1951 codesetName
[sizeof(codesetName
)-1] = 0;
1957 /* Use setlocale in a nice way, and then check some environment variables.
1958 Maybe the application used setlocale already.
1960 uprv_memset(codesetName
, 0, sizeof(codesetName
));
1961 name
= getCodepageFromPOSIXID(localeName
, codesetName
, sizeof(codesetName
));
1963 /* if we can find the codeset name from setlocale, return that. */
1967 if (*codesetName
== 0)
1969 /* Everything failed. Return US ASCII (ISO 646). */
1970 (void)uprv_strcpy(codesetName
, "US-ASCII");
1979 U_CAPI
const char* U_EXPORT2
1980 uprv_getDefaultCodepage()
1982 static char const *name
= NULL
;
1985 name
= int_getDefaultCodepage();
1990 #endif /* !U_CHARSET_IS_UTF8 */
1993 /* end of platform-specific implementation -------------- */
1995 /* version handling --------------------------------------------------------- */
1997 U_CAPI
void U_EXPORT2
1998 u_versionFromString(UVersionInfo versionArray
, const char *versionString
) {
2002 if(versionArray
==NULL
) {
2006 if(versionString
!=NULL
) {
2008 versionArray
[part
]=(uint8_t)uprv_strtoul(versionString
, &end
, 10);
2009 if(end
==versionString
|| ++part
==U_MAX_VERSION_LENGTH
|| *end
!=U_VERSION_DELIMITER
) {
2012 versionString
=end
+1;
2016 while(part
<U_MAX_VERSION_LENGTH
) {
2017 versionArray
[part
++]=0;
2021 U_CAPI
void U_EXPORT2
2022 u_versionFromUString(UVersionInfo versionArray
, const UChar
*versionString
) {
2023 if(versionArray
!=NULL
&& versionString
!=NULL
) {
2024 char versionChars
[U_MAX_VERSION_STRING_LENGTH
+1];
2025 int32_t len
= u_strlen(versionString
);
2026 if(len
>U_MAX_VERSION_STRING_LENGTH
) {
2027 len
= U_MAX_VERSION_STRING_LENGTH
;
2029 u_UCharsToChars(versionString
, versionChars
, len
);
2030 versionChars
[len
]=0;
2031 u_versionFromString(versionArray
, versionChars
);
2035 U_CAPI
void U_EXPORT2
2036 u_versionToString(const UVersionInfo versionArray
, char *versionString
) {
2037 uint16_t count
, part
;
2040 if(versionString
==NULL
) {
2044 if(versionArray
==NULL
) {
2049 /* count how many fields need to be written */
2050 for(count
=4; count
>0 && versionArray
[count
-1]==0; --count
) {
2057 /* write the first part */
2058 /* write the decimal field value */
2059 field
=versionArray
[0];
2061 *versionString
++=(char)('0'+field
/100);
2065 *versionString
++=(char)('0'+field
/10);
2068 *versionString
++=(char)('0'+field
);
2070 /* write the following parts */
2071 for(part
=1; part
<count
; ++part
) {
2072 /* write a dot first */
2073 *versionString
++=U_VERSION_DELIMITER
;
2075 /* write the decimal field value */
2076 field
=versionArray
[part
];
2078 *versionString
++=(char)('0'+field
/100);
2082 *versionString
++=(char)('0'+field
/10);
2085 *versionString
++=(char)('0'+field
);
2092 U_CAPI
void U_EXPORT2
2093 u_getVersion(UVersionInfo versionArray
) {
2094 u_versionFromString(versionArray
, U_ICU_VERSION
);
2098 * icucfg.h dependent code
2103 #if HAVE_DLOPEN && !U_PLATFORM_HAS_WIN32_API
2115 U_INTERNAL
void * U_EXPORT2
2116 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2118 if(U_FAILURE(*status
)) return ret
;
2119 ret
= dlopen(libName
, RTLD_NOW
|RTLD_GLOBAL
);
2121 #ifdef U_TRACE_DYLOAD
2122 printf("dlerror on dlopen(%s): %s\n", libName
, dlerror());
2124 *status
= U_MISSING_RESOURCE_ERROR
;
2129 U_INTERNAL
void U_EXPORT2
2130 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2131 if(U_FAILURE(*status
)) return;
2135 U_INTERNAL UVoidFunction
* U_EXPORT2
2136 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2142 if(U_FAILURE(*status
)) return uret
.fp
;
2143 uret
.vp
= dlsym(lib
, sym
);
2144 if(uret
.vp
== NULL
) {
2145 #ifdef U_TRACE_DYLOAD
2146 printf("dlerror on dlsym(%p,%s): %s\n", lib
,sym
, dlerror());
2148 *status
= U_MISSING_RESOURCE_ERROR
;
2155 /* null (nonexistent) implementation. */
2157 U_INTERNAL
void * U_EXPORT2
2158 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2159 if(U_FAILURE(*status
)) return NULL
;
2160 *status
= U_UNSUPPORTED_ERROR
;
2164 U_INTERNAL
void U_EXPORT2
2165 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2166 if(U_FAILURE(*status
)) return;
2167 *status
= U_UNSUPPORTED_ERROR
;
2172 U_INTERNAL UVoidFunction
* U_EXPORT2
2173 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2174 if(U_SUCCESS(*status
)) {
2175 *status
= U_UNSUPPORTED_ERROR
;
2177 return (UVoidFunction
*)NULL
;
2184 #elif U_PLATFORM_HAS_WIN32_API
2186 U_INTERNAL
void * U_EXPORT2
2187 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2190 if(U_FAILURE(*status
)) return NULL
;
2192 lib
= LoadLibraryA(libName
);
2195 *status
= U_MISSING_RESOURCE_ERROR
;
2201 U_INTERNAL
void U_EXPORT2
2202 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2203 HMODULE handle
= (HMODULE
)lib
;
2204 if(U_FAILURE(*status
)) return;
2206 FreeLibrary(handle
);
2212 U_INTERNAL UVoidFunction
* U_EXPORT2
2213 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2214 HMODULE handle
= (HMODULE
)lib
;
2215 UVoidFunction
* addr
= NULL
;
2217 if(U_FAILURE(*status
) || lib
==NULL
) return NULL
;
2219 addr
= (UVoidFunction
*)GetProcAddress(handle
, sym
);
2222 DWORD lastError
= GetLastError();
2223 if(lastError
== ERROR_PROC_NOT_FOUND
) {
2224 *status
= U_MISSING_RESOURCE_ERROR
;
2226 *status
= U_UNSUPPORTED_ERROR
; /* other unknown error. */
2236 /* No dynamic loading set. */
2238 U_INTERNAL
void * U_EXPORT2
2239 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2240 if(U_FAILURE(*status
)) return NULL
;
2241 *status
= U_UNSUPPORTED_ERROR
;
2245 U_INTERNAL
void U_EXPORT2
2246 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2247 if(U_FAILURE(*status
)) return;
2248 *status
= U_UNSUPPORTED_ERROR
;
2253 U_INTERNAL UVoidFunction
* U_EXPORT2
2254 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2255 if(U_SUCCESS(*status
)) {
2256 *status
= U_UNSUPPORTED_ERROR
;
2258 return (UVoidFunction
*)NULL
;
2261 #endif /* U_ENABLE_DYLOAD */
2264 * Hey, Emacs, please set the following:
2267 * indent-tabs-mode: nil