2 ******************************************************************************
4 * Copyright (C) 1997-2014, 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 || U_PLATFORM == U_PF_SOLARIS
103 # if U_PLATFORM == U_PF_SOLARIS
108 #elif U_PLATFORM == U_PF_QNX
109 # include <sys/neutrino.h>
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__
118 * Cygwin with GCC requires inclusion of time.h after the above disabling strict asci mode statement.
122 #if !U_PLATFORM_USES_ONLY_WIN32_API
123 #include <sys/time.h>
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.
132 #if U_HAVE_NL_LANGINFO_CODESET
133 #include <langinfo.h>
137 * Simple things (presence of functions, etc) should just go in configure.in and be added to
138 * icucfg.h via autoheader.
140 #if U_PLATFORM_IMPLEMENTS_POSIX
141 # if U_PLATFORM == U_PF_OS400
142 # define HAVE_DLFCN_H 0
143 # define HAVE_DLOPEN 0
145 # ifndef HAVE_DLFCN_H
146 # define HAVE_DLFCN_H 1
149 # define HAVE_DLOPEN 1
152 # ifndef HAVE_GETTIMEOFDAY
153 # define HAVE_GETTIMEOFDAY 1
156 # define HAVE_DLFCN_H 0
157 # define HAVE_DLOPEN 0
158 # define HAVE_GETTIMEOFDAY 0
161 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
163 /* Define the extension for data files, again... */
164 #define DATA_TYPE "dat"
166 /* Leave this copyright notice here! */
167 static const char copyright
[] = U_COPYRIGHT_STRING
;
169 /* floating point implementations ------------------------------------------- */
171 /* We return QNAN rather than SNAN*/
172 #define SIGN 0x80000000U
174 /* Make it easy to define certain types of constants */
176 int64_t i64
; /* This must be defined first in order to allow the initialization to work. This is a C89 feature. */
178 } BitPatternConversion
;
179 static const BitPatternConversion gNan
= { (int64_t) INT64_C(0x7FF8000000000000) };
180 static const BitPatternConversion gInf
= { (int64_t) INT64_C(0x7FF0000000000000) };
182 /*---------------------------------------------------------------------------
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
188 ---------------------------------------------------------------------------*/
190 #if U_PLATFORM_USES_ONLY_WIN32_API || U_PLATFORM == U_PF_CLASSIC_MACOS || U_PLATFORM == U_PF_OS400
191 # undef U_POSIX_LOCALE
193 # define U_POSIX_LOCALE 1
197 WARNING! u_topNBytesOfDouble and u_bottomNBytesOfDouble
198 can't be properly optimized by the gcc compiler sometimes (i.e. gcc 3.2).
202 u_topNBytesOfDouble(double* d
, int n
)
207 return (char*)(d
+ 1) - n
;
212 u_bottomNBytesOfDouble(double* d
, int n
)
215 return (char*)(d
+ 1) - n
;
220 #endif /* !IEEE_754 */
224 u_signBit(double d
) {
227 hiByte
= *(uint8_t *)&d
;
229 hiByte
= *(((uint8_t *)&d
) + sizeof(double) - 1);
231 return (hiByte
& 0x80) != 0;
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
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
;
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));
252 static UDate
getUTCtime_fake() {
253 umtx_lock(&fakeClockMutex
);
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
);
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");
268 fakeClock_set
= TRUE
;
270 umtx_unlock(&fakeClockMutex
);
272 return getUTCtime_real() + fakeClock_dt
;
276 #if U_PLATFORM_USES_ONLY_WIN32_API
280 } FileTimeConversion
; /* This is like a ULARGE_INTEGER */
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
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
293 ---------------------------------------------------------------------------*/
295 U_CAPI UDate U_EXPORT2
298 #if defined(U_DEBUG_FAKETIME)
299 return getUTCtime_fake(); /* Hook for overriding the clock */
301 return uprv_getRawUTCtime();
305 /* Return UTC (GMT) time measured in milliseconds since 0:00 on 1/1/70.*/
306 U_CAPI UDate U_EXPORT2
309 #if U_PLATFORM == U_PF_CLASSIC_MACOS
313 uprv_memset( &tmrec
, 0, sizeof(tmrec
) );
317 t1
= mktime(&tmrec
); /* seconds of 1/1/1970*/
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
325 FileTimeConversion winTime
;
326 GetSystemTimeAsFileTime(&winTime
.fileTime
);
327 return (UDate
)((winTime
.int64
- EPOCH_BIAS
) / HECTONANOSECOND_PER_MILLISECOND
);
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));
337 return (UDate
)epochtime
* U_MILLIS_PER_SECOND
;
343 /*-----------------------------------------------------------------------------
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 ---------------------------------------------------------------------------*/
353 U_CAPI UBool U_EXPORT2
354 uprv_isNaN(double number
)
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
);
362 #elif U_PLATFORM == U_PF_OS390
363 uint32_t highBits
= *(uint32_t*)u_topNBytesOfDouble(&number
,
365 uint32_t lowBits
= *(uint32_t*)u_bottomNBytesOfDouble(&number
,
368 return ((highBits
& 0x7F080000L
) == 0x7F080000L
) &&
369 (lowBits
== 0x00000000L
);
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
;
379 U_CAPI UBool U_EXPORT2
380 uprv_isInfinite(double number
)
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
,
390 uint32_t lowBits
= *(uint32_t*)u_bottomNBytesOfDouble(&number
,
393 return ((highBits
& ~SIGN
) == 0x70FF0000L
) && (lowBits
== 0x00000000L
);
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
);
403 U_CAPI UBool U_EXPORT2
404 uprv_isPositiveInfinity(double number
)
406 #if IEEE_754 || U_PLATFORM == U_PF_OS390
407 return (UBool
)(number
> 0 && uprv_isInfinite(number
));
409 return uprv_isInfinite(number
);
413 U_CAPI UBool U_EXPORT2
414 uprv_isNegativeInfinity(double number
)
416 #if IEEE_754 || U_PLATFORM == U_PF_OS390
417 return (UBool
)(number
< 0 && uprv_isInfinite(number
));
420 uint32_t highBits
= *(uint32_t*)u_topNBytesOfDouble(&number
,
422 return((highBits
& SIGN
) && uprv_isInfinite(number
));
427 U_CAPI
double U_EXPORT2
430 #if IEEE_754 || U_PLATFORM == U_PF_OS390
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.*/
440 U_CAPI
double U_EXPORT2
443 #if IEEE_754 || U_PLATFORM == U_PF_OS390
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.*/
453 U_CAPI
double U_EXPORT2
459 U_CAPI
double U_EXPORT2
465 U_CAPI
double U_EXPORT2
468 return uprv_floor(x
+ 0.5);
471 U_CAPI
double U_EXPORT2
477 U_CAPI
double U_EXPORT2
478 uprv_modf(double x
, double* y
)
483 U_CAPI
double U_EXPORT2
484 uprv_fmod(double x
, double y
)
489 U_CAPI
double U_EXPORT2
490 uprv_pow(double x
, double y
)
492 /* This is declared as "double pow(double x, double y)" */
496 U_CAPI
double U_EXPORT2
497 uprv_pow10(int32_t x
)
499 return pow(10.0, (double)x
);
502 U_CAPI
double U_EXPORT2
503 uprv_fmax(double x
, double y
)
506 /* first handle NaN*/
507 if(uprv_isNaN(x
) || uprv_isNaN(y
))
508 return uprv_getNaN();
510 /* check for -0 and 0*/
511 if(x
== 0.0 && y
== 0.0 && u_signBit(x
))
516 /* this should work for all flt point w/o NaN and Inf special cases */
517 return (x
> y
? x
: y
);
520 U_CAPI
double U_EXPORT2
521 uprv_fmin(double x
, double y
)
524 /* first handle NaN*/
525 if(uprv_isNaN(x
) || uprv_isNaN(y
))
526 return uprv_getNaN();
528 /* check for -0 and 0*/
529 if(x
== 0.0 && y
== 0.0 && u_signBit(y
))
534 /* this should work for all flt point w/o NaN and Inf special cases */
535 return (x
> y
? y
: x
);
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
545 U_CAPI
double U_EXPORT2
549 /* handle error cases*/
551 return uprv_getNaN();
552 if(uprv_isInfinite(d
))
553 return uprv_getInfinity();
555 if(u_signBit(d
)) /* Signbit() picks up -0.0; d<0 does not. */
561 return d
>= 0 ? floor(d
) : ceil(d
);
567 * Return the largest positive number that can be represented by an integer
568 * type of arbitrary bit length.
570 U_CAPI
double U_EXPORT2
571 uprv_maxMantissa(void)
573 return pow(2.0, DBL_MANT_DIG
+ 1.0) - 1.0;
576 U_CAPI
double U_EXPORT2
582 U_CAPI
void * U_EXPORT2
583 uprv_maximumPtr(void * base
)
585 #if U_PLATFORM == U_PF_OS400
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.
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)
600 * Unlike other operating systems, the pointer model isn't determined at
601 * compile time on i5/OS.
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)));
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)));
611 return U_MAX_PTR(base
);
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 ---------------------------------------------------------------------------*/
621 /* Generic time zone layer -------------------------------------------------- */
623 /* Time zone utilities */
624 U_CAPI
void U_EXPORT2
630 /* no initialization*/
634 U_CAPI
int32_t U_EXPORT2
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*/
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*/
654 #if U_PLATFORM != U_PF_IPHONE
655 /* imitate NT behaviour, which returns same timezone offset to GMT for
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.
670 /* Note that U_TZNAME does *not* have to be tzname, but if it is,
671 some platforms need to have it declared here. */
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
[];
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
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"
690 #define TZDEFAULT "/etc/localtime"
691 #define TZZONEINFO "/usr/share/zoneinfo/"
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 */
702 static char gTimeZoneBuffer
[PATH_MAX
];
703 static char *gTimeZoneBufferPtr
= NULL
;
706 #if !U_PLATFORM_USES_ONLY_WIN32_API
707 #define isNonDigit(ch) (ch < '0' || '9' < ch)
708 static UBool
isValidOlsonID(const char *id
) {
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
] != ',') {
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);
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'
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)
749 #if defined(U_TZNAME) && !U_PLATFORM_USES_ONLY_WIN32_API
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*/
760 enum { U_DAYLIGHT_NONE
=0,U_DAYLIGHT_JUNE
=1,U_DAYLIGHT_DECEMBER
=2 };
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.
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"}
833 /*#define DEBUG_TZNAME*/
835 static const char* remapShortTimeZone(const char *stdID
, const char *dstID
, int32_t daylightType
, int32_t offset
)
839 fprintf(stderr
, "TZ=%s std=%s dst=%s daylight=%d offset=%d\n", getenv("TZ"), stdID
, dstID
, daylightType
, offset
);
841 for (idx
= 0; idx
< LENGTHOF(OFFSET_ZONE_MAPPINGS
); idx
++)
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)
848 return OFFSET_ZONE_MAPPINGS
[idx
].olsonID
;
856 #define MAX_PATH_SIZE PATH_MAX /* Set the limit for the size of the path. */
857 #define MAX_READ_SIZE 512
859 typedef struct DefaultTZInfo
{
860 char* defaultTZBuffer
;
861 int64_t defaultTZFileSize
;
862 FILE* defaultTZFilePtr
;
863 UBool defaultTZstatus
;
864 int32_t defaultTZPosition
;
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.
871 static UBool
compareBinaryFiles(const char* defaultTZFileName
, const char* TZFileName
, DefaultTZInfo
* tzInfo
) {
874 int64_t sizeFileLeft
;
875 int32_t sizeFileRead
;
876 int32_t sizeFileToRead
;
877 char bufferFile
[MAX_READ_SIZE
];
880 if (tzInfo
->defaultTZFilePtr
== NULL
) {
881 tzInfo
->defaultTZFilePtr
= fopen(defaultTZFileName
, "r");
883 file
= fopen(TZFileName
, "r");
885 tzInfo
->defaultTZPosition
= 0; /* reset position to begin search */
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
);
893 fseek(file
, 0, SEEK_END
);
894 sizeFile
= ftell(file
);
895 sizeFileLeft
= sizeFile
;
897 if (sizeFile
!= tzInfo
->defaultTZFileSize
) {
900 /* Store the data from the files in seperate buffers and
901 * compare each byte to determine equality.
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
);
909 while(sizeFileLeft
> 0) {
910 uprv_memset(bufferFile
, 0, MAX_READ_SIZE
);
911 sizeFileToRead
= sizeFileLeft
< MAX_READ_SIZE
? sizeFileLeft
: MAX_READ_SIZE
;
913 sizeFileRead
= fread(bufferFile
, 1, sizeFileToRead
, file
);
914 if (memcmp(tzInfo
->defaultTZBuffer
+ tzInfo
->defaultTZPosition
, bufferFile
, sizeFileRead
) != 0) {
918 sizeFileLeft
-= sizeFileRead
;
919 tzInfo
->defaultTZPosition
+= sizeFileRead
;
933 * This method recursively traverses the directory given for a matching TZ file and returns the first match.
935 /* dirent also lists two entries: "." and ".." that we can safely ignore. */
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
);
943 struct dirent
* dirEntry
= NULL
;
950 /* Save the current path */
951 uprv_memset(curpath
, 0, MAX_PATH_SIZE
);
952 uprv_strcpy(curpath
, path
);
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
);
963 if ((subDirp
= opendir(newpath
)) != NULL
) {
964 /* If this new path is a directory, make a recursive call with the newpath. */
966 uprv_strcat(newpath
, "/");
967 result
= searchForTZFile(newpath
, tzInfo
);
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.
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. */
994 U_CAPI
const char* U_EXPORT2
997 const char *tzid
= NULL
;
998 #if U_PLATFORM_USES_ONLY_WIN32_API
999 tzid
= uprv_detectWindowsTimeZone();
1006 /*#if U_PLATFORM_IS_DARWIN_BASED
1009 tzid = getenv("TZFILE");
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
1024 /* This might be a good Olson ID. */
1025 skipZoneIDPrefix(&tzid
);
1028 /* else U_TZNAME will give a better result. */
1031 #if defined(CHECK_LOCALTIME_LINK) && !defined(DEBUG_SKIP_LOCALTIME_LINK)
1032 /* Caller must handle threading issues */
1033 if (gTimeZoneBufferPtr
== NULL
) {
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.
1039 int32_t ret
= (int32_t)readlink(TZDEFAULT
, gTimeZoneBuffer
, sizeof(gTimeZoneBuffer
));
1041 int32_t tzZoneInfoLen
= uprv_strlen(TZZONEINFO
);
1042 gTimeZoneBuffer
[ret
] = 0;
1043 if (uprv_strncmp(gTimeZoneBuffer
, TZZONEINFO
, tzZoneInfoLen
) == 0
1044 && isValidOlsonID(gTimeZoneBuffer
+ tzZoneInfoLen
))
1046 return (gTimeZoneBufferPtr
= gTimeZoneBuffer
+ tzZoneInfoLen
);
1048 #if U_PLATFORM == U_PF_SOLARIS
1051 tzZoneInfoLen
= uprv_strlen(TZZONEINFO2
);
1052 if (uprv_strncmp(gTimeZoneBuffer
, TZZONEINFO2
, tzZoneInfoLen
) == 0
1053 && isValidOlsonID(gTimeZoneBuffer
+ tzZoneInfoLen
))
1055 return (gTimeZoneBufferPtr
= gTimeZoneBuffer
+ tzZoneInfoLen
);
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;
1069 gTimeZoneBufferPtr
= searchForTZFile(TZZONEINFO
, tzInfo
);
1071 /* Free previously allocated memory */
1072 if (tzInfo
->defaultTZBuffer
!= NULL
) {
1073 uprv_free(tzInfo
->defaultTZBuffer
);
1075 if (tzInfo
->defaultTZFilePtr
!= NULL
) {
1076 fclose(tzInfo
->defaultTZFilePtr
);
1081 if (gTimeZoneBufferPtr
!= NULL
&& isValidOlsonID(gTimeZoneBufferPtr
)) {
1082 return gTimeZoneBufferPtr
;
1088 return gTimeZoneBufferPtr
;
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
]);
1100 U_TZNAME is usually a non-unique abbreviation, which isn't normally usable.
1101 So we remap the abbreviation to an olson ID.
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.
1108 struct tm juneSol
, decemberSol
;
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*/
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
;
1121 daylightType
= U_DAYLIGHT_NONE
;
1123 tzid
= remapShortTimeZone(U_TZNAME
[0], U_TZNAME
[1], daylightType
, uprv_timezone());
1135 /* Get and set the ICU data directory --------------------------------------- */
1137 static char *gDataDirectory
= NULL
;
1138 #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
1139 static char *gCorrectedPOSIXLocale
= NULL
; /* Heap allocated */
1142 static UBool U_CALLCONV
putil_cleanup(void)
1144 if (gDataDirectory
&& *gDataDirectory
) {
1145 uprv_free(gDataDirectory
);
1147 gDataDirectory
= NULL
;
1148 #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
1149 if (gCorrectedPOSIXLocale
) {
1150 uprv_free(gCorrectedPOSIXLocale
);
1151 gCorrectedPOSIXLocale
= NULL
;
1158 * Set the data directory.
1159 * Make a copy of the passed string, and set the global data dir to point to it.
1161 U_CAPI
void U_EXPORT2
1162 u_setDataDirectory(const char *directory
) {
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
1171 newDataDir
= (char *)"";
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
) {
1180 uprv_strcpy(newDataDir
, directory
);
1182 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
1185 while(p
= uprv_strchr(newDataDir
, U_FILE_ALT_SEP_CHAR
)) {
1186 *p
= U_FILE_SEP_CHAR
;
1192 if (gDataDirectory
&& *gDataDirectory
) {
1193 uprv_free(gDataDirectory
);
1195 gDataDirectory
= newDataDir
;
1196 ucln_common_registerCleanup(UCLN_COMMON_PUTIL
, putil_cleanup
);
1199 U_CAPI UBool U_EXPORT2
1200 uprv_pathIsAbsolute(const char *path
)
1202 if(!path
|| !*path
) {
1206 if(*path
== U_FILE_SEP_CHAR
) {
1210 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
1211 if(*path
== U_FILE_ALT_SEP_CHAR
) {
1216 #if U_PLATFORM_USES_ONLY_WIN32_API
1217 if( (((path
[0] >= 'A') && (path
[0] <= 'Z')) ||
1218 ((path
[0] >= 'a') && (path
[0] <= 'z'))) &&
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"
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
];
1242 /* if we have the directory, then return it immediately */
1243 if(gDataDirectory
) {
1244 return gDataDirectory
;
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.
1257 There may also be some platforms where environment variables
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");
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.
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
);
1277 # ifdef ICU_DATA_DIR
1280 path
=U_ICU_DATA_DEFAULT_DIR
;
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
;
1292 /* It looks really bad, set it to something. */
1296 u_setDataDirectory(path
);
1297 return gDataDirectory
;
1304 /* Macintosh-specific locale information ------------------------------------ */
1305 #if U_PLATFORM == U_PF_CLASSIC_MACOS
1311 int32_t date_region
;
1312 const char* posixID
;
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
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",
1323 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 1, "fr_FR",
1325 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 2, "en_GB",
1327 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 3, "de_DE",
1329 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 4, "it_IT",
1331 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 5, "nl_NL",
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",
1337 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 9, "da_DK",
1339 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 10, "pt_PT",
1341 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 11, "fr_CA",
1343 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 13, "is_IS",
1345 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 14, "ja_JP",
1347 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 15, "en_AU",
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",
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",
1359 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 21, "is_IS",
1361 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 22, "",*/
1363 /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 23, "",*/
1365 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 24, "tr_TR",
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, "",*/
1373 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 41, "lt_LT",
1375 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 42, "pl_PL",
1377 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 43, "hu_HU",
1379 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 44, "et_EE",
1381 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 45, "lv_LV",
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, "",*/
1387 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 48, "fa_IR",
1389 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 49, "ru_RU",
1391 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 50, "en_IE",
1393 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 51, "ko_KR",
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",
1399 MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, MAC_LC_MAGIC_NUMBER
, 54, "th_TH",
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"
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.
1414 static const char *uprv_getPOSIXIDForCategory(int category
)
1416 const char* posixID
= NULL
;
1417 if (category
== LC_MESSAGES
|| category
== LC_CTYPE
) {
1419 * On Solaris two different calls to setlocale can result in
1420 * different values. Only get this value once.
1422 * We must check this first because an application can set this.
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;...
1431 * The default codepage detection also needs to use LC_CTYPE.
1433 * Do not call setlocale(LC_*, "")! Using an empty string instead
1434 * of NULL, will modify the libc behavior.
1436 posixID
= setlocale(category
, NULL
);
1438 || (uprv_strcmp("C", posixID
) == 0)
1439 || (uprv_strcmp("POSIX", posixID
) == 0))
1441 /* Maybe we got some garbage. Try something more reasonable */
1442 posixID
= getenv("LC_ALL");
1444 posixID
= getenv(category
== LC_MESSAGES
? "LC_MESSAGES" : "LC_CTYPE");
1446 posixID
= getenv("LANG");
1452 || (uprv_strcmp("C", posixID
) == 0)
1453 || (uprv_strcmp("POSIX", posixID
) == 0))
1455 /* Nothing worked. Give it a nice POSIX default value. */
1456 posixID
= "en_US_POSIX";
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.
1464 static const char *uprv_getPOSIXIDForDefaultLocale(void)
1466 static const char* posixID
= NULL
;
1468 posixID
= uprv_getPOSIXIDForCategory(LC_MESSAGES
);
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.
1477 static const char *uprv_getPOSIXIDForDefaultCodepage(void)
1479 static const char* posixID
= NULL
;
1481 posixID
= uprv_getPOSIXIDForCategory(LC_CTYPE
);
1488 /* NOTE: The caller should handle thread safety */
1489 U_CAPI
const char* U_EXPORT2
1490 uprv_getDefaultLocaleID()
1494 Note that: (a '!' means the ID is improper somehow)
1495 LC_ALL ----> default_loc codepage
1496 --------------------------------------------------------
1501 ab_CD.EF@GH ab_CD_GH EF
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
1511 The variant cannot have dots in it.
1512 The 'rightmost' variant (@xxx) wins.
1513 The leftmost codepage (.xxx) wins.
1515 char *correctedPOSIXLocale
= 0;
1516 const char* posixID
= uprv_getPOSIXIDForDefaultLocale();
1521 /* Format: (no spaces)
1522 ll [ _CC ] [ . MM ] [ @ VV]
1524 l = lang, C = ctry, M = charmap, V = variant
1527 if (gCorrectedPOSIXLocale
!= NULL
) {
1528 return gCorrectedPOSIXLocale
;
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
) {
1538 uprv_strncpy(correctedPOSIXLocale
, posixID
, p
-posixID
);
1539 correctedPOSIXLocale
[p
-posixID
] = 0;
1541 /* do not copy after the @ */
1542 if ((p
= uprv_strchr(correctedPOSIXLocale
, '@')) != NULL
) {
1543 correctedPOSIXLocale
[p
-correctedPOSIXLocale
] = 0;
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
) {
1555 uprv_strncpy(correctedPOSIXLocale
, posixID
, p
-posixID
);
1556 correctedPOSIXLocale
[p
-posixID
] = 0;
1560 /* Take care of any special cases here.. */
1561 if (!uprv_strcmp(p
, "nynorsk")) {
1563 /* Don't worry about no__NY. In practice, it won't appear. */
1566 if (uprv_strchr(correctedPOSIXLocale
,'_') == NULL
) {
1567 uprv_strcat(correctedPOSIXLocale
, "__"); /* aa@b -> aa__b */
1570 uprv_strcat(correctedPOSIXLocale
, "_"); /* aa_CC@b -> aa_CC_b */
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;
1580 /* Anything following the @ sign */
1581 uprv_strcat(correctedPOSIXLocale
, p
);
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.
1591 /* Was a correction made? */
1592 if (correctedPOSIXLocale
!= NULL
) {
1593 posixID
= correctedPOSIXLocale
;
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
) {
1602 posixID
= uprv_strcpy(correctedPOSIXLocale
, posixID
);
1605 if (gCorrectedPOSIXLocale
== NULL
) {
1606 gCorrectedPOSIXLocale
= correctedPOSIXLocale
;
1607 ucln_common_registerCleanup(UCLN_COMMON_PUTIL
, putil_cleanup
);
1608 correctedPOSIXLocale
= NULL
;
1611 if (correctedPOSIXLocale
!= NULL
) { /* Was already set - clean up. */
1612 uprv_free(correctedPOSIXLocale
);
1617 #elif U_PLATFORM_USES_ONLY_WIN32_API
1618 #define POSIX_LOCALE_CAPACITY 64
1619 UErrorCode status
= U_ZERO_ERROR
;
1620 char *correctedPOSIXLocale
= 0;
1622 if (gCorrectedPOSIXLocale
!= NULL
) {
1623 return gCorrectedPOSIXLocale
;
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
);
1635 uprv_free(correctedPOSIXLocale
);
1639 if (gCorrectedPOSIXLocale
== NULL
) {
1642 return gCorrectedPOSIXLocale
;
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
);
1657 ih
= (Intl1Hndl
) GetIntlResource(1);
1659 date_region
= ((uint16_t)(*ih
)->intl1Vers
) >> 8;
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
))
1672 posixID
= mac_lc_recs
[i
].posixID
;
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");
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";
1693 /* Extract the locale name from the path. */
1694 if((p
= uprv_strrchr(localeID
, '/')) != NULL
)
1696 /* Increment p to start of locale name. */
1701 /* Copy to work location. */
1702 uprv_strcpy(correctedLocale
, localeID
);
1704 /* Strip off the '.locale' extension. */
1705 if((p
= uprv_strchr(correctedLocale
, '.')) != NULL
) {
1709 /* Upper case the locale name. */
1710 T_CString_toUpperCase(correctedLocale
);
1712 /* See if we are using the POSIX locale. Any of the
1713 * following are equivalent and use the same QLGPGCMA
1715 * QLGPGCMA2 means UCS2
1716 * QLGPGCMA_4 means UTF-32
1717 * QLGPGCMA_8 means UTF-8
1719 if ((uprv_strcmp("C", correctedLocale
) == 0) ||
1720 (uprv_strcmp("POSIX", correctedLocale
) == 0) ||
1721 (uprv_strncmp("QLGPGCMA", correctedLocale
, 8) == 0))
1723 uprv_strcpy(correctedLocale
, "en_US_POSIX");
1729 /* Lower case the lang portion. */
1730 for(p
= correctedLocale
; *p
!= 0 && *p
!= '_'; p
++)
1732 *p
= uprv_tolower(*p
);
1735 /* Adjust for Euro. After '_E' add 'URO'. */
1736 LocaleLen
= uprv_strlen(correctedLocale
);
1737 if (correctedLocale
[LocaleLen
- 2] == '_' &&
1738 correctedLocale
[LocaleLen
- 1] == 'E')
1740 uprv_strcat(correctedLocale
, "URO");
1743 /* If using Lotus-based locale then convert to
1744 * equivalent non Lotus.
1746 else if (correctedLocale
[LocaleLen
- 2] == '_' &&
1747 correctedLocale
[LocaleLen
- 1] == 'L')
1749 correctedLocale
[LocaleLen
- 2] = 0;
1752 /* There are separate simplified and traditional
1753 * locales called zh_HK_S and zh_HK_T.
1755 else if (uprv_strncmp(correctedLocale
, "zh_HK", 5) == 0)
1757 uprv_strcpy(correctedLocale
, "zh_HK");
1760 /* A special zh_CN_GBK locale...
1762 else if (uprv_strcmp(correctedLocale
, "zh_CN_GBK") == 0)
1764 uprv_strcpy(correctedLocale
, "zh_CN");
1769 return correctedLocale
;
1774 #if !U_CHARSET_IS_UTF8
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.
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. */
1792 #if U_PLATFORM == U_PF_AIX
1793 if (uprv_strcmp(name
, "IBM-943") == 0) {
1794 /* Use the ASCII compatible ibm-943 */
1797 else if (uprv_strcmp(name
, "IBM-1252") == 0) {
1798 /* Use the windows-1252 that contains the Euro */
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) {
1807 else if (uprv_strcmp(locale
, "zh_TW") == 0) {
1810 else if (uprv_strcmp(locale
, "ko_KR") == 0) {
1814 else if (uprv_strcmp(name
, "eucJP") == 0) {
1816 ibm-954 is the best match.
1817 ibm-33722 is the default for eucJP (similar to Windows).
1821 else if (uprv_strcmp(name
, "646") == 0) {
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).
1826 name
= "ISO-8859-1";
1828 #elif U_PLATFORM_IS_DARWIN_BASED
1829 if (locale
== NULL
&& *name
== 0) {
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).
1837 else if (uprv_strcmp(name
, "CP949") == 0) {
1838 /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
1841 else if (locale
!= NULL
&& uprv_strcmp(locale
, "en_US_POSIX") != 0 && uprv_strcmp(name
, "US-ASCII") == 0) {
1843 * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
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. */
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! */
1858 else if (uprv_strcmp(name
, "eucJP") == 0) {
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).
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) {
1872 else if (uprv_strcmp(locale
, "japanese") == 0) {
1873 /* See comment below about eucJP */
1877 else if (uprv_strcmp(name
, "eucjp") == 0) {
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).
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)) {
1888 * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
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.
1898 /* return NULL when "" is passed in */
1906 getCodepageFromPOSIXID(const char *localeName
, char * buffer
, int32_t buffCapacity
)
1908 char localeBuf
[100];
1909 const char *name
= NULL
;
1910 char *variant
= NULL
;
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
) {
1921 name
= remapPlatformDependentCodepage(localeBuf
, name
);
1928 int_getDefaultCodepage()
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 */
1936 EPT_CALL(QUSRJOBI
)(&jobinfo
, sizeof(jobinfo
), "JOBI0400",
1939 if (error
.Bytes_Available
== 0) {
1940 if (jobinfo
.Coded_Char_Set_ID
!= 0xFFFF) {
1941 ccsid
= (uint32_t)jobinfo
.Coded_Char_Set_ID
;
1943 else if (jobinfo
.Default_Coded_Char_Set_Id
!= 0xFFFF) {
1944 ccsid
= (uint32_t)jobinfo
.Default_Coded_Char_Set_Id
;
1946 /* else use the default */
1948 sprintf(codepage
,"ibm-%d", ccsid
);
1951 #elif U_PLATFORM == U_PF_OS390
1952 static char codepage
[64];
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 */
1960 #elif U_PLATFORM == U_PF_CLASSIC_MACOS
1961 return "macintosh"; /* TODO: Macintosh Roman. There must be a better way. fixme! */
1963 #elif U_PLATFORM_USES_ONLY_WIN32_API
1964 static char codepage
[64];
1965 sprintf(codepage
, "windows-%d", GetACP());
1968 #elif U_POSIX_LOCALE
1969 static char codesetName
[100];
1970 const char *localeName
= NULL
;
1971 const char *name
= NULL
;
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. */
1980 const char *codeset
= nl_langinfo(U_NL_LANGINFO_CODESET
);
1981 #if U_PLATFORM_IS_DARWIN_BASED || U_PLATFORM_IS_LINUX_BASED
1983 * On Linux and MacOSX, ensure that default codepage for non C/POSIX locale is UTF-8
1986 if (uprv_strcmp(localeName
, "en_US_POSIX") != 0) {
1987 codeset
= remapPlatformDependentCodepage(localeName
, codeset
);
1991 codeset
= remapPlatformDependentCodepage(NULL
, codeset
);
1994 if (codeset
!= NULL
) {
1995 uprv_strncpy(codesetName
, codeset
, sizeof(codesetName
));
1996 codesetName
[sizeof(codesetName
)-1] = 0;
2002 /* Use setlocale in a nice way, and then check some environment variables.
2003 Maybe the application used setlocale already.
2005 uprv_memset(codesetName
, 0, sizeof(codesetName
));
2006 name
= getCodepageFromPOSIXID(localeName
, codesetName
, sizeof(codesetName
));
2008 /* if we can find the codeset name from setlocale, return that. */
2012 if (*codesetName
== 0)
2014 /* Everything failed. Return US ASCII (ISO 646). */
2015 (void)uprv_strcpy(codesetName
, "US-ASCII");
2024 U_CAPI
const char* U_EXPORT2
2025 uprv_getDefaultCodepage()
2027 static char const *name
= NULL
;
2030 name
= int_getDefaultCodepage();
2035 #endif /* !U_CHARSET_IS_UTF8 */
2038 /* end of platform-specific implementation -------------- */
2040 /* version handling --------------------------------------------------------- */
2042 U_CAPI
void U_EXPORT2
2043 u_versionFromString(UVersionInfo versionArray
, const char *versionString
) {
2047 if(versionArray
==NULL
) {
2051 if(versionString
!=NULL
) {
2053 versionArray
[part
]=(uint8_t)uprv_strtoul(versionString
, &end
, 10);
2054 if(end
==versionString
|| ++part
==U_MAX_VERSION_LENGTH
|| *end
!=U_VERSION_DELIMITER
) {
2057 versionString
=end
+1;
2061 while(part
<U_MAX_VERSION_LENGTH
) {
2062 versionArray
[part
++]=0;
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
;
2074 u_UCharsToChars(versionString
, versionChars
, len
);
2075 versionChars
[len
]=0;
2076 u_versionFromString(versionArray
, versionChars
);
2080 U_CAPI
void U_EXPORT2
2081 u_versionToString(const UVersionInfo versionArray
, char *versionString
) {
2082 uint16_t count
, part
;
2085 if(versionString
==NULL
) {
2089 if(versionArray
==NULL
) {
2094 /* count how many fields need to be written */
2095 for(count
=4; count
>0 && versionArray
[count
-1]==0; --count
) {
2102 /* write the first part */
2103 /* write the decimal field value */
2104 field
=versionArray
[0];
2106 *versionString
++=(char)('0'+field
/100);
2110 *versionString
++=(char)('0'+field
/10);
2113 *versionString
++=(char)('0'+field
);
2115 /* write the following parts */
2116 for(part
=1; part
<count
; ++part
) {
2117 /* write a dot first */
2118 *versionString
++=U_VERSION_DELIMITER
;
2120 /* write the decimal field value */
2121 field
=versionArray
[part
];
2123 *versionString
++=(char)('0'+field
/100);
2127 *versionString
++=(char)('0'+field
/10);
2130 *versionString
++=(char)('0'+field
);
2137 U_CAPI
void U_EXPORT2
2138 u_getVersion(UVersionInfo versionArray
) {
2139 (void)copyright
; // Suppress unused variable warning from clang.
2140 u_versionFromString(versionArray
, U_ICU_VERSION
);
2144 * icucfg.h dependent code
2149 #if HAVE_DLOPEN && !U_PLATFORM_USES_ONLY_WIN32_API
2161 U_INTERNAL
void * U_EXPORT2
2162 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2164 if(U_FAILURE(*status
)) return ret
;
2165 ret
= dlopen(libName
, RTLD_NOW
|RTLD_GLOBAL
);
2167 #ifdef U_TRACE_DYLOAD
2168 printf("dlerror on dlopen(%s): %s\n", libName
, dlerror());
2170 *status
= U_MISSING_RESOURCE_ERROR
;
2175 U_INTERNAL
void U_EXPORT2
2176 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2177 if(U_FAILURE(*status
)) return;
2181 U_INTERNAL UVoidFunction
* U_EXPORT2
2182 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2188 if(U_FAILURE(*status
)) return uret
.fp
;
2189 uret
.vp
= dlsym(lib
, sym
);
2190 if(uret
.vp
== NULL
) {
2191 #ifdef U_TRACE_DYLOAD
2192 printf("dlerror on dlsym(%p,%s): %s\n", lib
,sym
, dlerror());
2194 *status
= U_MISSING_RESOURCE_ERROR
;
2201 /* null (nonexistent) implementation. */
2203 U_INTERNAL
void * U_EXPORT2
2204 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2205 if(U_FAILURE(*status
)) return NULL
;
2206 *status
= U_UNSUPPORTED_ERROR
;
2210 U_INTERNAL
void U_EXPORT2
2211 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2212 if(U_FAILURE(*status
)) return;
2213 *status
= U_UNSUPPORTED_ERROR
;
2218 U_INTERNAL UVoidFunction
* U_EXPORT2
2219 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2220 if(U_SUCCESS(*status
)) {
2221 *status
= U_UNSUPPORTED_ERROR
;
2223 return (UVoidFunction
*)NULL
;
2230 #elif U_PLATFORM_USES_ONLY_WIN32_API
2232 U_INTERNAL
void * U_EXPORT2
2233 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2236 if(U_FAILURE(*status
)) return NULL
;
2238 lib
= LoadLibraryA(libName
);
2241 *status
= U_MISSING_RESOURCE_ERROR
;
2247 U_INTERNAL
void U_EXPORT2
2248 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2249 HMODULE handle
= (HMODULE
)lib
;
2250 if(U_FAILURE(*status
)) return;
2252 FreeLibrary(handle
);
2258 U_INTERNAL UVoidFunction
* U_EXPORT2
2259 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2260 HMODULE handle
= (HMODULE
)lib
;
2261 UVoidFunction
* addr
= NULL
;
2263 if(U_FAILURE(*status
) || lib
==NULL
) return NULL
;
2265 addr
= (UVoidFunction
*)GetProcAddress(handle
, sym
);
2268 DWORD lastError
= GetLastError();
2269 if(lastError
== ERROR_PROC_NOT_FOUND
) {
2270 *status
= U_MISSING_RESOURCE_ERROR
;
2272 *status
= U_UNSUPPORTED_ERROR
; /* other unknown error. */
2282 /* No dynamic loading set. */
2284 U_INTERNAL
void * U_EXPORT2
2285 uprv_dl_open(const char *libName
, UErrorCode
*status
) {
2286 if(U_FAILURE(*status
)) return NULL
;
2287 *status
= U_UNSUPPORTED_ERROR
;
2291 U_INTERNAL
void U_EXPORT2
2292 uprv_dl_close(void *lib
, UErrorCode
*status
) {
2293 if(U_FAILURE(*status
)) return;
2294 *status
= U_UNSUPPORTED_ERROR
;
2299 U_INTERNAL UVoidFunction
* U_EXPORT2
2300 uprv_dlsym_func(void *lib
, const char* sym
, UErrorCode
*status
) {
2301 if(U_SUCCESS(*status
)) {
2302 *status
= U_UNSUPPORTED_ERROR
;
2304 return (UVoidFunction
*)NULL
;
2307 #endif /* U_ENABLE_DYLOAD */
2310 * Hey, Emacs, please set the following:
2313 * indent-tabs-mode: nil