summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu-xetex/common/putil.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu-xetex/common/putil.c')
-rw-r--r--Build/source/libs/icu-xetex/common/putil.c1003
1 files changed, 232 insertions, 771 deletions
diff --git a/Build/source/libs/icu-xetex/common/putil.c b/Build/source/libs/icu-xetex/common/putil.c
index b371284562e..e063a261241 100644
--- a/Build/source/libs/icu-xetex/common/putil.c
+++ b/Build/source/libs/icu-xetex/common/putil.c
@@ -1,7 +1,7 @@
/*
******************************************************************************
*
-* Copyright (C) 1997-2005, International Business Machines
+* Copyright (C) 1997-2006, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
@@ -36,23 +36,21 @@
******************************************************************************
*/
-#ifndef PTX
-
/* Define _XOPEN_SOURCE for Solaris and friends. */
/* NetBSD needs it to be >= 4 */
#ifndef _XOPEN_SOURCE
+#if __STDC_VERSION__ >= 199901L
+/* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 */
+#define _XOPEN_SOURCE 600
+#else
#define _XOPEN_SOURCE 4
#endif
-
-/* Define __USE_POSIX and __USE_XOPEN for Linux and glibc. */
-#ifndef __USE_POSIX
-#define __USE_POSIX
-#endif
-#ifndef __USE_XOPEN
-#define __USE_XOPEN
#endif
-#endif /* PTX */
+/* Make sure things like readlink and such functions work. */
+#ifndef _XOPEN_SOURCE_EXTENDED
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
/* include ICU headers */
#include "unicode/utypes.h"
@@ -84,6 +82,7 @@
# define NOIME
# define NOMCX
# include <windows.h>
+# include "wintz.h"
#elif defined(U_CYGWIN) && defined(__STRICT_ANSI__)
/* tzset isn't defined in strict ANSI on Cygwin. */
# undef __STRICT_ANSI__
@@ -102,12 +101,9 @@
# define ICU_NO_USER_DATA_OVERRIDE 1
#elif defined(OS390)
#include "unicode/ucnv.h" /* Needed for UCNV_SWAP_LFNL_OPTION_STRING */
-#elif defined(U_AIX)
-#elif defined(U_SOLARIS) || defined(U_LINUX)
-#elif defined(U_HPUX)
-#elif defined(U_DARWIN)
-#include <sys/file.h>
-#include <sys/param.h>
+#elif defined(U_DARWIN) || defined(U_LINUX) || defined(U_BSD)
+#include <limits.h>
+#include <unistd.h>
#elif defined(U_QNX)
#include <sys/neutrino.h>
#endif
@@ -136,41 +132,14 @@ static const char copyright[] = U_COPYRIGHT_STRING;
/* We return QNAN rather than SNAN*/
#define SIGN 0x80000000U
-#if defined(__GNUC__) || defined(_MSC_VER)
-/*
- This is an optimization for when u_topNBytesOfDouble
- and u_bottomNBytesOfDouble can't be properly optimized by the compiler
- or when faster infinity and NaN usage is helpful.
-*/
-#define USE_64BIT_DOUBLE_OPTIMIZATION 1
-#else
-#define USE_64BIT_DOUBLE_OPTIMIZATION 0
-#endif
-
-#if USE_64BIT_DOUBLE_OPTIMIZATION
-/* gcc 3.2 has an optimization bug */
-static const int64_t gNan64 = INT64_C(0x7FF8000000000000);
-static const int64_t gInf64 = INT64_C(0x7FF0000000000000);
-static const double * const fgNan = (const double * const)(&gNan64);
-static const double * const fgInf = (const double * const)(&gInf64);
-#else
-
-#if IEEE_754
-#define NAN_TOP ((int16_t)0x7FF8)
-#define INF_TOP ((int16_t)0x7FF0)
-#elif defined(OS390)
-#define NAN_TOP ((int16_t)0x7F08)
-#define INF_TOP ((int16_t)0x3F00)
-#endif
-/* statics */
-static UBool fgNaNInitialized = FALSE;
-static UBool fgInfInitialized = FALSE;
-static double gNan;
-static double gInf;
-static double * fgNan = &gNan;
-static double * fgInf = &gInf;
-#endif
+/* Make it easy to define certain types of constants */
+typedef union {
+ int64_t i64; /* This must be defined first in order to allow the initialization to work. This is a C89 feature. */
+ double d64;
+} BitPatternConversion;
+static const BitPatternConversion gNan = { (int64_t) INT64_C(0x7FF8000000000000) };
+static const BitPatternConversion gInf = { (int64_t) INT64_C(0x7FF0000000000000) };
/*---------------------------------------------------------------------------
Platform utilities
@@ -186,8 +155,11 @@ static double * fgInf = &gInf;
# define U_POSIX_LOCALE 1
#endif
-/* Utilities to get the bits from a double */
-#if !USE_64BIT_DOUBLE_OPTIMIZATION
+/*
+ WARNING! u_topNBytesOfDouble and u_bottomNBytesOfDouble
+ can't be properly optimized by the gcc compiler sometimes (i.e. gcc 3.2).
+*/
+#if !IEEE_754
static char*
u_topNBytesOfDouble(double* d, int n)
{
@@ -277,35 +249,10 @@ U_CAPI UBool U_EXPORT2
uprv_isNaN(double number)
{
#if IEEE_754
-#if USE_64BIT_DOUBLE_OPTIMIZATION
- /* gcc 3.2 has an optimization bug */
+ BitPatternConversion convertedNumber;
+ convertedNumber.d64 = number;
/* Infinity is 0x7FF0000000000000U. Anything greater than that is a NaN */
- return (UBool)(((*((int64_t *)&number)) & U_INT64_MAX) > gInf64);
-
-#else
- /* This should work in theory, but it doesn't, so we resort to the more*/
- /* complicated method below.*/
- /* return number != number;*/
-
- /* You can't return number == getNaN() because, by definition, NaN != x for*/
- /* all x, including NaN (that is, NaN != NaN). So instead, we compare*/
- /* against the known bit pattern. We must be careful of endianism here.*/
- /* The pattern we are looking for id:*/
-
- /* 7FFy yyyy yyyy yyyy (some y non-zero)*/
-
- /* There are two different kinds of NaN, but we ignore the distinction*/
- /* here. Note that the y value must be non-zero; if it is zero, then we*/
- /* have infinity.*/
-
- uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
- sizeof(uint32_t));
- uint32_t lowBits = *(uint32_t*)u_bottomNBytesOfDouble(&number,
- sizeof(uint32_t));
-
- return (UBool)(((highBits & 0x7FF00000L) == 0x7FF00000L) &&
- (((highBits & 0x000FFFFFL) != 0) || (lowBits != 0)));
-#endif
+ return (UBool)((convertedNumber.i64 & U_INT64_MAX) > gInf.i64);
#elif defined(OS390)
uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
@@ -328,32 +275,10 @@ U_CAPI UBool U_EXPORT2
uprv_isInfinite(double number)
{
#if IEEE_754
-#if USE_64BIT_DOUBLE_OPTIMIZATION
- /* gcc 3.2 has an optimization bug */
- return (UBool)(((*((int64_t *)&number)) & U_INT64_MAX) == gInf64);
-#else
-
- /* We know the top bit is the sign bit, so we mask that off in a copy of */
- /* the number and compare against infinity. [LIU]*/
- /* The following approach doesn't work for some reason, so we go ahead and */
- /* scrutinize the pattern itself. */
- /* double a = number; */
- /* *(int8_t*)u_topNBytesOfDouble(&a, 1) &= 0x7F;*/
- /* return a == uprv_getInfinity();*/
- /* Instead, We want to see either:*/
-
- /* 7FF0 0000 0000 0000*/
- /* FFF0 0000 0000 0000*/
-
- uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
- sizeof(uint32_t));
- uint32_t lowBits = *(uint32_t*)u_bottomNBytesOfDouble(&number,
- sizeof(uint32_t));
-
- return (UBool)(((highBits & ~SIGN) == 0x7FF00000U) &&
- (lowBits == 0x00000000U));
-#endif
-
+ BitPatternConversion convertedNumber;
+ convertedNumber.d64 = number;
+ /* Infinity is exactly 0x7FF0000000000000U. */
+ return (UBool)((convertedNumber.i64 & U_INT64_MAX) == gInf.i64);
#elif defined(OS390)
uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
sizeof(uint32_t));
@@ -398,19 +323,7 @@ U_CAPI double U_EXPORT2
uprv_getNaN()
{
#if IEEE_754 || defined(OS390)
-#if !USE_64BIT_DOUBLE_OPTIMIZATION
- if (!fgNaNInitialized) {
- /* This variable is always initialized with the same value,
- so a mutex isn't needed. */
- int i;
- int8_t* p = (int8_t*)fgNan;
- for(i = 0; i < sizeof(double); ++i)
- *p++ = 0;
- *(int16_t*)u_topNBytesOfDouble(fgNan, sizeof(NAN_TOP)) = NAN_TOP;
- fgNaNInitialized = TRUE;
- }
-#endif
- return *fgNan;
+ return gNan.d64;
#else
/* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
/* you'll need to replace this default implementation with what's correct*/
@@ -423,20 +336,7 @@ U_CAPI double U_EXPORT2
uprv_getInfinity()
{
#if IEEE_754 || defined(OS390)
-#if !USE_64BIT_DOUBLE_OPTIMIZATION
- if (!fgInfInitialized)
- {
- /* This variable is always initialized with the same value,
- so a mutex isn't needed. */
- int i;
- int8_t* p = (int8_t*)fgInf;
- for(i = 0; i < sizeof(double); ++i)
- *p++ = 0;
- *(int16_t*)u_topNBytesOfDouble(fgInf, sizeof(INF_TOP)) = INF_TOP;
- fgInfInitialized = TRUE;
- }
-#endif
- return *fgInf;
+ return gInf.d64;
#else
/* If your platform doesn't support IEEE 754 but *does* have an infinity*/
/* value, you'll need to replace this default implementation with what's*/
@@ -515,12 +415,6 @@ uprv_fmax(double x, double y)
return (x > y ? x : y);
}
-U_CAPI int32_t U_EXPORT2
-uprv_max(int32_t x, int32_t y)
-{
- return (x > y ? x : y);
-}
-
U_CAPI double U_EXPORT2
uprv_fmin(double x, double y)
{
@@ -542,12 +436,6 @@ uprv_fmin(double x, double y)
return (x > y ? y : x);
}
-U_CAPI int32_t U_EXPORT2
-uprv_min(int32_t x, int32_t y)
-{
- return (x > y ? y : x);
-}
-
/**
* Truncates the given double.
* trunc(3.3) = 3.0, trunc (-3.3) = -3.0
@@ -589,40 +477,6 @@ uprv_maxMantissa(void)
return pow(2.0, DBL_MANT_DIG + 1.0) - 1.0;
}
-/**
- * Return the floor of the log base 10 of a given double.
- * This method compensates for inaccuracies which arise naturally when
- * computing logs, and always give the correct value. The parameter
- * must be positive and finite.
- * (Thanks to Alan Liu for supplying this function.)
- */
-U_CAPI int16_t U_EXPORT2
-uprv_log10(double d)
-{
-#ifdef OS400
- /* We don't use the normal implementation because you can't underflow */
- /* a double otherwise an underflow exception occurs */
- return log10(d);
-#else
- /* The reason this routine is needed is that simply taking the*/
- /* log and dividing by log10 yields a result which may be off*/
- /* by 1 due to rounding errors. For example, the naive log10*/
- /* of 1.0e300 taken this way is 299, rather than 300.*/
- double alog10 = log(d) / log(10.0);
- int16_t ailog10 = (int16_t) floor(alog10);
-
- /* Positive logs could be too small, e.g. 0.99 instead of 1.0*/
- if (alog10 > 0 && d >= pow(10.0, (double)(ailog10 + 1)))
- ++ailog10;
-
- /* Negative logs could be too big, e.g. -0.99 instead of -1.0*/
- else if (alog10 < 0 && d < pow(10.0, (double)(ailog10)))
- --ailog10;
-
- return ailog10;
-#endif
-}
-
U_CAPI double U_EXPORT2
uprv_log(double d)
{
@@ -681,487 +535,6 @@ uprv_digitsAfterDecimal(double x)
platform with new implementations.
---------------------------------------------------------------------------*/
-/* Win32 time zone detection ------------------------------------------------ */
-
-#ifdef U_WINDOWS
-
-/*
- This code attempts to detect the Windows time zone, as set in the
- Windows Date and Time control panel. It attempts to work on
- multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized
- installs. It works by directly interrogating the registry and
- comparing the data there with the data returned by the
- GetTimeZoneInformation API, along with some other strategies. The
- registry contains time zone data under one of two keys (depending on
- the flavor of Windows):
-
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\
- HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
-
- Under this key are several subkeys, one for each time zone. These
- subkeys are named "Pacific" on Win9x/Me and "Pacific Standard Time"
- on WinNT/2k/XP. There are some other wrinkles; see the code for
- details. The subkey name is NOT LOCALIZED, allowing us to support
- localized installs.
-
- Under the subkey are data values. We care about:
-
- Std Standard time display name, localized
- TZI Binary block of data
-
- The TZI data is of particular interest. It contains the offset, two
- more offsets for standard and daylight time, and the start and end
- rules. This is the same data returned by the GetTimeZoneInformation
- API. The API may modify the data on the way out, so we have to be
- careful, but essentially we do a binary comparison against the TZI
- blocks of various registry keys. When we find a match, we know what
- time zone Windows is set to. Since the registry key is not
- localized, we can then translate the key through a simple table
- lookup into the corresponding ICU time zone.
-
- This strategy doesn't always work because there are zones which
- share an offset and rules, so more than one TZI block will match.
- For example, both Tokyo and Seoul are at GMT+9 with no DST rules;
- their TZI blocks are identical. For these cases, we fall back to a
- name lookup. We attempt to match the display name as stored in the
- registry for the current zone to the display name stored in the
- registry for various Windows zones. By comparing the registry data
- directly we avoid conversion complications.
-
- Author: Alan Liu
- Since: ICU 2.6
- Based on original code by Carl Brown <cbrown@xnetinc.com>
-*/
-
-/**
- * Layout of the binary registry data under the "TZI" key.
- */
-typedef struct {
- LONG Bias;
- LONG StandardBias;
- LONG DaylightBias; /* Tweaked by GetTimeZoneInformation */
- SYSTEMTIME StandardDate;
- SYSTEMTIME DaylightDate;
-} TZI;
-
-typedef struct {
- const char* icuid;
- const char* winid;
-} WindowsICUMap;
-
-/**
- * Mapping between Windows zone IDs and ICU zone IDs. This list has
- * been mechanically checked; all zone offsets match (most important)
- * and city names match the display city names (where possible). The
- * presence or absence of DST differs in some cases, but this is
- * acceptable as long as the zone is semantically the same (which has
- * been manually checked).
- *
- * Windows 9x/Me zone IDs are listed as "Pacific" rather than "Pacific
- * Standard Time", which is seen in NT/2k/XP. This is fixed-up at
- * runtime as needed. The one exception is "Mexico Standard Time 2",
- * which is not present on Windows 9x/Me.
- *
- * Zones that are not unique under Offset+Rules should be grouped
- * together for efficiency (see code below). In addition, rules MUST
- * be grouped so that all zones of a single offset are together.
- *
- * Comments list S(tandard) or D(aylight), as declared by Windows,
- * followed by the display name (data from Windows XP).
- *
- * NOTE: Etc/GMT+12 is CORRECT for offset GMT-12:00. Consult
- * documentation elsewhere for an explanation.
- */
-static const WindowsICUMap ZONE_MAP[] = {
- "Etc/GMT+12", "Dateline", /* S (GMT-12:00) International Date Line West */
-
- "Pacific/Apia", "Samoa", /* S (GMT-11:00) Midway Island, Samoa */
-
- "Pacific/Honolulu", "Hawaiian", /* S (GMT-10:00) Hawaii */
-
- "America/Anchorage", "Alaskan", /* D (GMT-09:00) Alaska */
-
- "America/Los_Angeles", "Pacific", /* D (GMT-08:00) Pacific Time (US & Canada); Tijuana */
-
- "America/Phoenix", "US Mountain", /* S (GMT-07:00) Arizona */
- "America/Denver", "Mountain", /* D (GMT-07:00) Mountain Time (US & Canada) */
- "America/Chihuahua", "Mexico Standard Time 2", /* D (GMT-07:00) Chihuahua, La Paz, Mazatlan */
-
- "America/Managua", "Central America", /* S (GMT-06:00) Central America */
- "America/Regina", "Canada Central", /* S (GMT-06:00) Saskatchewan */
- "America/Mexico_City", "Mexico", /* D (GMT-06:00) Guadalajara, Mexico City, Monterrey */
- "America/Chicago", "Central", /* D (GMT-06:00) Central Time (US & Canada) */
-
- "America/Indianapolis", "US Eastern", /* S (GMT-05:00) Indiana (East) */
- "America/Bogota", "SA Pacific", /* S (GMT-05:00) Bogota, Lima, Quito */
- "America/New_York", "Eastern", /* D (GMT-05:00) Eastern Time (US & Canada) */
-
- "America/Caracas", "SA Western", /* S (GMT-04:00) Caracas, La Paz */
- "America/Santiago", "Pacific SA", /* D (GMT-04:00) Santiago */
- "America/Halifax", "Atlantic", /* D (GMT-04:00) Atlantic Time (Canada) */
-
- "America/St_Johns", "Newfoundland", /* D (GMT-03:30) Newfoundland */
-
- "America/Buenos_Aires", "SA Eastern", /* S (GMT-03:00) Buenos Aires, Georgetown */
- "America/Godthab", "Greenland", /* D (GMT-03:00) Greenland */
- "America/Sao_Paulo", "E. South America", /* D (GMT-03:00) Brasilia */
-
- "America/Noronha", "Mid-Atlantic", /* D (GMT-02:00) Mid-Atlantic */
-
- "Atlantic/Cape_Verde", "Cape Verde", /* S (GMT-01:00) Cape Verde Is. */
- "Atlantic/Azores", "Azores", /* D (GMT-01:00) Azores */
-
- "Africa/Casablanca", "Greenwich", /* S (GMT) Casablanca, Monrovia */
- "Europe/London", "GMT", /* D (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London */
-
- "Africa/Lagos", "W. Central Africa", /* S (GMT+01:00) West Central Africa */
- "Europe/Berlin", "W. Europe", /* D (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */
- "Europe/Paris", "Romance", /* D (GMT+01:00) Brussels, Copenhagen, Madrid, Paris */
- "Europe/Sarajevo", "Central European", /* D (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb */
- "Europe/Belgrade", "Central Europe", /* D (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */
-
- "Africa/Johannesburg", "South Africa", /* S (GMT+02:00) Harare, Pretoria */
- "Asia/Jerusalem", "Israel", /* S (GMT+02:00) Jerusalem */
- "Europe/Istanbul", "GTB", /* D (GMT+02:00) Athens, Istanbul, Minsk */
- "Europe/Helsinki", "FLE", /* D (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */
- "Africa/Cairo", "Egypt", /* D (GMT+02:00) Cairo */
- "Europe/Bucharest", "E. Europe", /* D (GMT+02:00) Bucharest */
-
- "Africa/Nairobi", "E. Africa", /* S (GMT+03:00) Nairobi */
- "Asia/Riyadh", "Arab", /* S (GMT+03:00) Kuwait, Riyadh */
- "Europe/Moscow", "Russian", /* D (GMT+03:00) Moscow, St. Petersburg, Volgograd */
- "Asia/Baghdad", "Arabic", /* D (GMT+03:00) Baghdad */
-
- "Asia/Tehran", "Iran", /* D (GMT+03:30) Tehran */
-
- "Asia/Muscat", "Arabian", /* S (GMT+04:00) Abu Dhabi, Muscat */
- "Asia/Tbilisi", "Caucasus", /* D (GMT+04:00) Baku, Tbilisi, Yerevan */
-
- "Asia/Kabul", "Afghanistan", /* S (GMT+04:30) Kabul */
-
- "Asia/Karachi", "West Asia", /* S (GMT+05:00) Islamabad, Karachi, Tashkent */
- "Asia/Yekaterinburg", "Ekaterinburg", /* D (GMT+05:00) Ekaterinburg */
-
- "Asia/Calcutta", "India", /* S (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi */
-
- "Asia/Katmandu", "Nepal", /* S (GMT+05:45) Kathmandu */
-
- "Asia/Colombo", "Sri Lanka", /* S (GMT+06:00) Sri Jayawardenepura */
- "Asia/Dhaka", "Central Asia", /* S (GMT+06:00) Astana, Dhaka */
- "Asia/Novosibirsk", "N. Central Asia", /* D (GMT+06:00) Almaty, Novosibirsk */
-
- "Asia/Rangoon", "Myanmar", /* S (GMT+06:30) Rangoon */
-
- "Asia/Bangkok", "SE Asia", /* S (GMT+07:00) Bangkok, Hanoi, Jakarta */
- "Asia/Krasnoyarsk", "North Asia", /* D (GMT+07:00) Krasnoyarsk */
-
- "Australia/Perth", "W. Australia", /* S (GMT+08:00) Perth */
- "Asia/Taipei", "Taipei", /* S (GMT+08:00) Taipei */
- "Asia/Singapore", "Singapore", /* S (GMT+08:00) Kuala Lumpur, Singapore */
- "Asia/Hong_Kong", "China", /* S (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi */
- "Asia/Irkutsk", "North Asia East", /* D (GMT+08:00) Irkutsk, Ulaan Bataar */
-
- "Asia/Tokyo", "Tokyo", /* S (GMT+09:00) Osaka, Sapporo, Tokyo */
- "Asia/Seoul", "Korea", /* S (GMT+09:00) Seoul */
- "Asia/Yakutsk", "Yakutsk", /* D (GMT+09:00) Yakutsk */
-
- "Australia/Darwin", "AUS Central", /* S (GMT+09:30) Darwin */
- "Australia/Adelaide", "Cen. Australia", /* D (GMT+09:30) Adelaide */
-
- "Pacific/Guam", "West Pacific", /* S (GMT+10:00) Guam, Port Moresby */
- "Australia/Brisbane", "E. Australia", /* S (GMT+10:00) Brisbane */
- "Asia/Vladivostok", "Vladivostok", /* D (GMT+10:00) Vladivostok */
- "Australia/Hobart", "Tasmania", /* D (GMT+10:00) Hobart */
- "Australia/Sydney", "AUS Eastern", /* D (GMT+10:00) Canberra, Melbourne, Sydney */
-
- "Asia/Magadan", "Central Pacific", /* S (GMT+11:00) Magadan, Solomon Is., New Caledonia */
-
- "Pacific/Fiji", "Fiji", /* S (GMT+12:00) Fiji, Kamchatka, Marshall Is. */
- "Pacific/Auckland", "New Zealand", /* D (GMT+12:00) Auckland, Wellington */
-
- "Pacific/Tongatapu", "Tonga", /* S (GMT+13:00) Nuku'alofa */
- NULL, NULL
-};
-
-typedef struct {
- const char* winid;
- const char* altwinid;
-} WindowsZoneRemap;
-
-/**
- * If a lookup fails, we attempt to remap certain Windows ids to
- * alternate Windows ids. If the alternate listed here begins with
- * '-', we use it as is (without the '-'). If it begins with '+', we
- * append a " Standard Time" if appropriate.
- */
-static const WindowsZoneRemap ZONE_REMAP[] = {
- "Central European", "-Warsaw",
- "Central Europe", "-Prague Bratislava",
- "China", "-Beijing",
-
- "Greenwich", "+GMT",
- "GTB", "+GFT",
- "Arab", "+Saudi Arabia",
- "SE Asia", "+Bangkok",
- "AUS Eastern", "+Sydney",
- NULL, NULL,
-};
-
-/**
- * Various registry keys and key fragments.
- */
-static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
-static const char STANDARD_NAME_REGKEY[] = "StandardName";
-static const char STANDARD_TIME_REGKEY[] = " Standard Time";
-static const char TZI_REGKEY[] = "TZI";
-static const char STD_REGKEY[] = "Std";
-
-/**
- * HKLM subkeys used to probe for the flavor of Windows. Note that we
- * specifically check for the "GMT" zone subkey; this is present on
- * NT, but on XP has become "GMT Standard Time". We need to
- * discriminate between these cases.
- */
-static const char* const WIN_TYPE_PROBE_REGKEY[] = {
- /* WIN_9X_ME_TYPE */
- "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones",
-
- /* WIN_NT_TYPE */
- "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT"
-
- /* otherwise: WIN_2K_XP_TYPE */
-};
-
-/**
- * The time zone root subkeys (under HKLM) for different flavors of
- * Windows.
- */
-static const char* const TZ_REGKEY[] = {
- /* WIN_9X_ME_TYPE */
- "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\",
-
- /* WIN_NT_TYPE | WIN_2K_XP_TYPE */
- "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
-};
-
-/**
- * Flavor of Windows, from our perspective. Not a real OS version,
- * but rather the flavor of the layout of the time zone information in
- * the registry.
- */
-enum {
- WIN_9X_ME_TYPE = 0,
- WIN_NT_TYPE = 1,
- WIN_2K_XP_TYPE = 2
-};
-
-/**
- * Auxiliary Windows time zone function. Attempts to open the given
- * Windows time zone ID as a registry key. Returns ERROR_SUCCESS if
- * successful. Caller must close the registry key. Handles
- * variations in the resource layout in different flavors of Windows.
- *
- * @param hkey output parameter to receive opened registry key
- * @param winid Windows zone ID, e.g., "Pacific", without the
- * " Standard Time" suffix (if any). Special case "Mexico Standard Time 2"
- * allowed.
- * @param winType Windows flavor (WIN_9X_ME_TYPE, etc.)
- * @return ERROR_SUCCESS upon success
- */
-static LONG openTZRegKey(HKEY *hkey, const char* winid, int winType) {
- LONG result;
- char subKeyName[96];
- char* name;
- int i;
-
- uprv_strcpy(subKeyName, TZ_REGKEY[(winType == WIN_9X_ME_TYPE) ? 0 : 1]);
- name = &subKeyName[strlen(subKeyName)];
- uprv_strcat(subKeyName, winid);
- if (winType != WIN_9X_ME_TYPE) {
- /* Don't modify "Mexico Standard Time 2", which does not occur
- on WIN_9X_ME_TYPE. Also, if the type is WIN_NT_TYPE, then
- in practice this means the GMT key is not followed by
- " Standard Time", so don't append in that case. */
- int isMexico2 = (winid[uprv_strlen(winid)- 1] == '2');
- if (!isMexico2 &&
- !(winType == WIN_NT_TYPE && uprv_strcmp(winid, "GMT") == 0)) {
- uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
- }
- }
- result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- subKeyName,
- 0,
- KEY_QUERY_VALUE,
- hkey);
-
- if (result != ERROR_SUCCESS) {
- /* If the primary lookup fails, try to remap the Windows zone
- ID, according to the remapping table. */
- for (i=0; ZONE_REMAP[i].winid; ++i) {
- if (uprv_strcmp(winid, ZONE_REMAP[i].winid) == 0) {
- uprv_strcpy(name, ZONE_REMAP[i].altwinid + 1);
- if (*(ZONE_REMAP[i].altwinid) == '+' &&
- winType != WIN_9X_ME_TYPE) {
- uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
- }
- result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- subKeyName,
- 0,
- KEY_QUERY_VALUE,
- hkey);
- break;
- }
- }
- }
-
- return result;
-}
-
-/**
- * Main Windows time zone detection function. Returns the Windows
- * time zone, translated to an ICU time zone, or NULL upon failure.
- */
-static const char* detectWindowsTimeZone() {
- int winType;
- LONG result;
- HKEY hkey;
- TZI tziKey;
- TZI tziReg;
- DWORD cbData = sizeof(TZI);
- TIME_ZONE_INFORMATION apiTZI;
- char stdName[32];
- DWORD stdNameSize;
- char stdRegName[64];
- DWORD stdRegNameSize;
- int firstMatch, lastMatch;
- int j;
-
- /* Detect the version of windows by trying to open a sequence of
- probe keys. We don't use the OS version API because what we
- really want to know is how the registry is laid out.
- Specifically, is it 9x/Me or not, and is it "GMT" or "GMT
- Standard Time". */
- for (winType=0; winType<2; ++winType) {
- result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- WIN_TYPE_PROBE_REGKEY[winType],
- 0,
- KEY_QUERY_VALUE,
- &hkey);
- RegCloseKey(hkey);
- if (result == ERROR_SUCCESS) {
- break;
- }
- }
-
- /* Obtain TIME_ZONE_INFORMATION from the API, and then convert it
- to TZI. We could also interrogate the registry directly; we do
- this below if needed. */
- uprv_memset(&apiTZI, 0, sizeof(apiTZI));
- GetTimeZoneInformation(&apiTZI);
- tziKey.Bias = apiTZI.Bias;
- uprv_memcpy((char *)&tziKey.StandardDate, (char*)&apiTZI.StandardDate,
- sizeof(apiTZI.StandardDate));
- uprv_memcpy((char *)&tziKey.DaylightDate, (char*)&apiTZI.DaylightDate,
- sizeof(apiTZI.DaylightDate));
-
- /* For each zone that can be identified by Offset+Rules, see if we
- have a match. Continue scanning after finding a match,
- recording the index of the first and the last match. We have
- to do this because some zones are not unique under
- Offset+Rules. */
- firstMatch = lastMatch = -1;
- for (j=0; ZONE_MAP[j].icuid; j++) {
- result = openTZRegKey(&hkey, ZONE_MAP[j].winid, winType);
- if (result == ERROR_SUCCESS) {
- result = RegQueryValueEx(hkey,
- TZI_REGKEY,
- NULL,
- NULL,
- (LPBYTE)&tziReg,
- &cbData);
- }
- RegCloseKey(hkey);
- if (result == ERROR_SUCCESS) {
- /* Assume that offsets are grouped together, and bail out
- when we've scanned everything with a matching
- offset. */
- if (firstMatch >= 0 && tziKey.Bias != tziReg.Bias) {
- break;
- }
- /* Windows alters the DaylightBias in some situations.
- Using the bias and the rules suffices, so overwrite
- these unreliable fields. */
- tziKey.StandardBias = tziReg.StandardBias;
- tziKey.DaylightBias = tziReg.DaylightBias;
- if (uprv_memcmp((char *)&tziKey, (char*)&tziReg,
- sizeof(tziKey)) == 0) {
- if (firstMatch < 0) {
- firstMatch = j;
- }
- lastMatch = j;
- }
- }
- }
-
- /* This should never happen; if it does it means our table doesn't
- match Windows AT ALL, perhaps because this is post-XP? */
- if (firstMatch < 0) {
- return NULL;
- }
-
- if (firstMatch != lastMatch) {
- /* Offset+Rules lookup yielded >= 2 matches. Try to match the
- localized display name. Get the name from the registry
- (not the API). This avoids conversion issues. Use the
- standard name, since Windows modifies the daylight name to
- match the standard name if there is no DST. */
- result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- CURRENT_ZONE_REGKEY,
- 0,
- KEY_QUERY_VALUE,
- &hkey);
- if (result == ERROR_SUCCESS) {
- stdNameSize = sizeof(stdName);
- result = RegQueryValueEx(hkey,
- (LPTSTR)STANDARD_NAME_REGKEY,
- NULL,
- NULL,
- (LPBYTE)stdName,
- &stdNameSize);
- RegCloseKey(hkey);
-
- /* Scan through the Windows time zone data in the registry
- again (just the range of zones with matching TZIs) and
- look for a standard display name match. */
- for (j=firstMatch; j<=lastMatch; j++) {
- result = openTZRegKey(&hkey, ZONE_MAP[j].winid, winType);
- if (result == ERROR_SUCCESS) {
- stdRegNameSize = sizeof(stdRegName);
- result = RegQueryValueEx(hkey,
- (LPTSTR)STD_REGKEY,
- NULL,
- NULL,
- (LPBYTE)stdRegName,
- &stdRegNameSize);
- }
- RegCloseKey(hkey);
- if (result == ERROR_SUCCESS &&
- stdRegNameSize == stdNameSize &&
- uprv_memcmp(stdName, stdRegName, stdNameSize) == 0) {
- firstMatch = j; /* record the match */
- break;
- }
- }
- } else {
- RegCloseKey(hkey); /* should never get here */
- }
- }
-
- return ZONE_MAP[firstMatch].icuid;
-}
-
-#endif /*U_WINDOWS*/
-
/* Generic time zone layer -------------------------------------------------- */
/* Time zone utilities */
@@ -1209,58 +582,103 @@ uprv_timezone()
extern U_IMPORT char *U_TZNAME[];
#endif
-#if defined(U_DARWIN) /* For Mac OS X */
+#if !UCONFIG_NO_FILE_IO && (defined(U_DARWIN) || defined(U_LINUX) || defined(U_BSD))
+/* These platforms are likely to use Olson timezone IDs. */
+#define CHECK_LOCALTIME_LINK 1
#define TZZONELINK "/etc/localtime"
#define TZZONEINFO "/usr/share/zoneinfo/"
-static char *gTimeZoneBuffer = NULL; /* Heap allocated */
+static char gTimeZoneBuffer[PATH_MAX];
+static char *gTimeZoneBufferPtr = NULL;
+#endif
+
+#ifndef U_WINDOWS
+#define isNonDigit(ch) (ch < '0' || '9' < ch)
+static UBool isValidOlsonID(const char *id) {
+ int32_t idx = 0;
+
+ /* Determine if this is something like Iceland (Olson ID)
+ or AST4ADT (non-Olson ID) */
+ while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') {
+ idx++;
+ }
+
+ /* If we went through the whole string, then it might be okay.
+ The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
+ "GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
+ The rest of the time it could be an Olson ID. George */
+ return (UBool)(id[idx] == 0
+ || uprv_strcmp(id, "PST8PDT") == 0
+ || uprv_strcmp(id, "MST7MDT") == 0
+ || uprv_strcmp(id, "CST6CDT") == 0
+ || uprv_strcmp(id, "EST5EDT") == 0);
+}
#endif
U_CAPI const char* U_EXPORT2
uprv_tzname(int n)
{
#ifdef U_WINDOWS
- char* id = (char*) detectWindowsTimeZone();
+ const char *id = uprv_detectWindowsTimeZone();
+
if (id != NULL) {
return id;
}
-#endif
+#else
+ const char *tzenv = NULL;
-#if defined(U_DARWIN)
+/*#if defined(U_DARWIN)
int ret;
- char *tzenv;
-
tzenv = getenv("TZFILE");
if (tzenv != NULL) {
return tzenv;
}
+#endif*/
-#if 0
- /* TZ is often set to "PST8PDT" or similar, so we cannot use it. Alan */
tzenv = getenv("TZ");
- if (tzenv != NULL) {
+ if (tzenv != NULL && isValidOlsonID(tzenv))
+ {
+ /* This might be a good Olson ID. */
+ if (uprv_strncmp(tzenv, "posix/", 6) == 0
+ || uprv_strncmp(tzenv, "right/", 6) == 0)
+ {
+ /* Remove the posix/ or right/ prefix. */
+ tzenv += 6;
+ }
return tzenv;
}
-#endif
-
- /* Caller must handle threading issues */
- if (gTimeZoneBuffer == NULL) {
- gTimeZoneBuffer = (char *) uprv_malloc(MAXPATHLEN + 2);
+ /* else U_TZNAME will give a better result. */
- ret = readlink(TZZONELINK, gTimeZoneBuffer, MAXPATHLEN + 2);
+#if defined(CHECK_LOCALTIME_LINK)
+ /* Caller must handle threading issues */
+ if (gTimeZoneBufferPtr == NULL) {
+ /*
+ This is a trick to look at the name of the link to get the Olson ID
+ because the tzfile contents is underspecified.
+ This isn't guaranteed to work because it may not be a symlink.
+ */
+ int32_t ret = (int32_t)readlink(TZZONELINK, gTimeZoneBuffer, sizeof(gTimeZoneBuffer));
if (0 < ret) {
- gTimeZoneBuffer[ret] = '\0';
- if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) {
- return (gTimeZoneBuffer += sizeof(TZZONEINFO) - 1);
+ int32_t tzZoneInfoLen = uprv_strlen(TZZONEINFO);
+ gTimeZoneBuffer[ret] = 0;
+ if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, tzZoneInfoLen) == 0
+ && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
+ {
+ return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
}
}
-
- uprv_free(gTimeZoneBuffer);
- gTimeZoneBuffer = NULL;
}
+ else {
+ return gTimeZoneBufferPtr;
+ }
+#endif
#endif
#ifdef U_TZNAME
+ /*
+ U_TZNAME is usually a non-unique abbreviation,
+ which isn't normally usable.
+ */
return U_TZNAME[n];
#else
return "";
@@ -1384,7 +802,7 @@ u_getDataDirectory(void) {
There may also be some platforms where environment variables
are not allowed.
*/
-# if !defined(ICU_NO_USER_DATA_OVERRIDE) && (!defined(UCONFIG_NO_FILE_IO) || !UCONFIG_NO_FILE_IO)
+# if !defined(ICU_NO_USER_DATA_OVERRIDE) && !UCONFIG_NO_FILE_IO
/* First try to get the environment variable */
path=getenv("ICU_DATA");
# endif
@@ -1520,32 +938,48 @@ static const char *uprv_getPOSIXID(void)
{
static const char* posixID = NULL;
if (posixID == 0) {
- posixID = getenv("LC_ALL");
- if (posixID == 0) {
- posixID = getenv("LANG");
+ /*
+ * On Solaris two different calls to setlocale can result in
+ * different values. Only get this value once.
+ *
+ * We must check this first because an application can set this.
+ *
+ * LC_ALL can't be used because it's platform dependent. The LANG
+ * environment variable seems to affect LC_CTYPE variable by default.
+ * Here is what setlocale(LC_ALL, NULL) can return.
+ * HPUX can return 'C C C C C C C'
+ * Solaris can return /en_US/C/C/C/C/C on the second try.
+ * Linux can return LC_CTYPE=C;LC_NUMERIC=C;...
+ *
+ * The default codepage detection also needs to use LC_CTYPE.
+ *
+ * Do not call setlocale(LC_*, "")! Using an empty string instead
+ * of NULL, will modify the libc behavior.
+ */
+ posixID = setlocale(LC_CTYPE, NULL);
+ if ((posixID == 0)
+ || (uprv_strcmp("C", posixID) == 0)
+ || (uprv_strcmp("POSIX", posixID) == 0))
+ {
+ /* Maybe we got some garbage. Try something more reasonable */
+ posixID = getenv("LC_ALL");
if (posixID == 0) {
- /*
- * On Solaris two different calls to setlocale can result in
- * different values. Only get this value once.
- */
- posixID = setlocale(LC_ALL, NULL);
+ posixID = getenv("LC_CTYPE");
+ if (posixID == 0) {
+ posixID = getenv("LANG");
+ }
}
}
- }
- if (posixID==0)
- {
- /* Nothing worked. Give it a nice value. */
- posixID = "en_US";
- }
- else if ((uprv_strcmp("C", posixID) == 0)
- || (uprv_strchr(posixID, ' ') != NULL)
- || (uprv_strchr(posixID, '/') != NULL))
- { /* HPUX returns 'C C C C C C C' */
- /* Solaris can return /en_US/C/C/C/C/C on the second try. */
- /* Maybe we got some garbage. Give it a nice value. */
- posixID = "en_US_POSIX";
+ if ((posixID==0)
+ || (uprv_strcmp("C", posixID) == 0)
+ || (uprv_strcmp("POSIX", posixID) == 0))
+ {
+ /* Nothing worked. Give it a nice POSIX default value. */
+ posixID = "en_US_POSIX";
+ }
}
+
return posixID;
}
#endif
@@ -1595,7 +1029,7 @@ The leftmost codepage (.xxx) wins.
if ((p = uprv_strchr(posixID, '.')) != NULL) {
/* assume new locale can't be larger than old one? */
- correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID));
+ correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID)+1);
uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
correctedPOSIXLocale[p-posixID] = 0;
@@ -1608,7 +1042,7 @@ The leftmost codepage (.xxx) wins.
/* Note that we scan the *uncorrected* ID. */
if ((p = uprv_strrchr(posixID, '@')) != NULL) {
if (correctedPOSIXLocale == NULL) {
- correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID));
+ correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID)+1);
uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
correctedPOSIXLocale[p-posixID] = 0;
}
@@ -1617,12 +1051,7 @@ The leftmost codepage (.xxx) wins.
/* Take care of any special cases here.. */
if (!uprv_strcmp(p, "nynorsk")) {
p = "NY";
-
- /* Should we assume no_NO_NY instead of possible no__NY?
- * if (!uprv_strcmp(correctedPOSIXLocale, "no")) {
- * uprv_strcpy(correctedPOSIXLocale, "no_NO");
- * }
- */
+ /* Don't worry about no__NY. In practice, it won't appear. */
}
if (uprv_strchr(correctedPOSIXLocale,'_') == NULL) {
@@ -1645,6 +1074,8 @@ The leftmost codepage (.xxx) wins.
/* Should there be a map from 'no@nynorsk' -> no_NO_NY here?
* How about 'russian' -> 'ru'?
+ * Many of the other locales using ISO codes will be handled by the
+ * canonicalization functions in uloc_getDefault.
*/
}
@@ -1810,6 +1241,81 @@ The leftmost codepage (.xxx) wins.
}
+#if U_POSIX_LOCALE
+/*
+Due to various platform differences, one platform may specify a charset,
+when they really mean a different charset. Remap the names so that they are
+compatible with ICU.
+*/
+static const char*
+remapPlatformDependentCodepage(const char *locale, const char *name) {
+ if (locale != NULL && *locale == 0) {
+ /* Make sure that an empty locale is handled the same way. */
+ locale = NULL;
+ }
+ if (name == NULL) {
+ return NULL;
+ }
+#if defined(U_AIX)
+ if (uprv_strcmp(name, "IBM-943") == 0) {
+ /* Use the ASCII compatible ibm-943 */
+ name = "Shift-JIS";
+ }
+ else if (uprv_strcmp(name, "IBM-1252") == 0) {
+ /* Use the windows-1252 that contains the Euro */
+ name = "IBM-5348";
+ }
+#elif defined(U_SOLARIS)
+ if (locale != NULL && uprv_strcmp(name, "EUC") == 0) {
+ /* Solaris underspecifies the "EUC" name. */
+ if (uprv_strcmp(locale, "zh_CN") == 0) {
+ name = "EUC-CN";
+ }
+ else if (uprv_strcmp(locale, "zh_TW") == 0) {
+ name = "EUC-TW";
+ }
+ else if (uprv_strcmp(locale, "ko_KR") == 0) {
+ name = "EUC-KR";
+ }
+ }
+#elif defined(U_DARWIN)
+ if (locale == NULL && *name == 0) {
+ /*
+ No locale was specified, and an empty name was passed in.
+ This usually indicates that nl_langinfo didn't return valid information.
+ Mac OS X uses UTF-8 by default (especially the locale data and console).
+ */
+ name = "UTF-8";
+ }
+#endif
+ /* return NULL when "" is passed in */
+ if (*name == 0) {
+ name = NULL;
+ }
+ return name;
+}
+
+static const char*
+getCodepageFromPOSIXID(const char *localeName, char * buffer, int32_t buffCapacity)
+{
+ char localeBuf[100];
+ const char *name = NULL;
+ char *variant = NULL;
+
+ if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
+ size_t localeCapacity = uprv_min(sizeof(localeBuf), (name-localeName)+1);
+ uprv_strncpy(localeBuf, localeName, localeCapacity);
+ localeBuf[localeCapacity-1] = 0; /* ensure NULL termination */
+ name = uprv_strncpy(buffer, name+1, buffCapacity);
+ buffer[buffCapacity-1] = 0; /* ensure NULL termination */
+ if ((variant = (uprv_strchr(name, '@'))) != NULL) {
+ *variant = 0;
+ }
+ name = remapPlatformDependentCodepage(localeBuf, name);
+ }
+ return name;
+}
+#endif
static const char*
int_getDefaultCodepage()
@@ -1850,58 +1356,32 @@ int_getDefaultCodepage()
#elif U_POSIX_LOCALE
static char codesetName[100];
- char *name = NULL;
- char *euro = NULL;
const char *localeName = NULL;
+ const char *name = NULL;
uprv_memset(codesetName, 0, sizeof(codesetName));
- /* Check setlocale before the environment variables
- because the application may have set it first */
-
- /* Use setlocale in a nice way.
+ /* Use setlocale in a nice way, and then check some environment variables.
Maybe the application used setlocale already.
- Normally this won't work. */
- localeName = setlocale(LC_CTYPE, NULL);
- if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
- /* strip the locale name and look at the suffix only */
- name = uprv_strncpy(codesetName, name+1, sizeof(codesetName));
- codesetName[sizeof(codesetName)-1] = 0;
- if ((euro = (uprv_strchr(name, '@'))) != NULL) {
- *euro = 0;
- }
- /* if we can find the codset name from setlocale, return that. */
- if (*name) {
- return name;
- }
+ */
+ localeName = uprv_getPOSIXID();
+ name = getCodepageFromPOSIXID(localeName, codesetName, sizeof(codesetName));
+ if (name) {
+ /* if we can find the codeset name from setlocale, return that. */
+ return name;
}
/* else "C" was probably returned. That's underspecified. */
- /* Use setlocale a little more forcefully.
- The application didn't use setlocale */
- localeName = setlocale(LC_CTYPE, "");
- if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
- /* strip the locale name and look at the suffix only */
- name = uprv_strncpy(codesetName, name+1, sizeof(codesetName));
- codesetName[sizeof(codesetName)-1] = 0;
- if ((euro = (uprv_strchr(name, '@'))) != NULL) {
- *euro = 0;
- }
- /* if we can find the codset name from setlocale, return that. */
- if (*name) {
- return name;
- }
- }
- /* else "C" or something like it was returned. That's still underspecified. */
-
#if U_HAVE_NL_LANGINFO_CODESET
if (*codesetName) {
uprv_memset(codesetName, 0, sizeof(codesetName));
}
- /* When available, check nl_langinfo first because it usually gives more
- useful names. It depends on LC_CTYPE and not LANG or LC_ALL */
+ /* When available, check nl_langinfo because it usually gives more
+ useful names. It depends on LC_CTYPE and not LANG or LC_ALL.
+ nl_langinfo may use the same buffer as setlocale. */
{
const char *codeset = nl_langinfo(U_NL_LANGINFO_CODESET);
+ codeset = remapPlatformDependentCodepage(NULL, codeset);
if (codeset != NULL) {
uprv_strncpy(codesetName, codeset, sizeof(codesetName));
codesetName[sizeof(codesetName)-1] = 0;
@@ -1910,28 +1390,9 @@ int_getDefaultCodepage()
}
#endif
- /* Try a locale specified by the user.
- This is usually underspecified and usually checked by setlocale already. */
- if (*codesetName) {
- uprv_memset(codesetName, 0, sizeof(codesetName));
- }
- localeName = uprv_getPOSIXID();
- if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
- /* strip the locale name and look at the suffix only */
- name = uprv_strncpy(codesetName, name+1, sizeof(codesetName));
- codesetName[sizeof(codesetName)-1] = 0;
- if ((euro = (uprv_strchr(name, '@'))) != NULL) {
- *euro = 0;
- }
- /* if we can find the codset name, return that. */
- if (*name) {
- return name;
- }
- }
-
if (*codesetName == 0)
{
- /* if the table lookup failed, return US ASCII (ISO 646). */
+ /* Everything failed. Return US ASCII (ISO 646). */
uprv_strcpy(codesetName, "US-ASCII");
}
return codesetName;