#ifndef PTX
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 4
#endif
#ifndef __USE_POSIX
#define __USE_POSIX
#endif
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
#endif
#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "unicode/ustring.h"
#include "putilimp.h"
#include "uassert.h"
#include "umutex.h"
#include "cmemory.h"
#include "cstring.h"
#include "locmap.h"
#include "ucln_cmn.h"
#include "udataswp.h"
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# define VC_EXTRALEAN
# define NOUSER
# define NOSERVICE
# define NOIME
# define NOMCX
# include <windows.h>
#elif defined(U_CYGWIN) && defined(__STRICT_ANSI__)
# undef __STRICT_ANSI__
#elif defined(OS2)
# define INCL_DOSMISC
# define INCL_DOSERRORS
# define INCL_DOSMODULEMGR
# include <os2.h>
#elif defined(OS400)
# include <float.h>
# include <qusec.h>
# include <qusrjobi.h>
# include <qliept.h>
#elif defined(XP_MAC)
# include <Files.h>
# include <IntlResources.h>
# include <Script.h>
# include <Folders.h>
# include <MacTypes.h>
# include <TextUtils.h>
#elif defined(OS390)
#include "unicode/ucnv.h"
#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_QNX)
#include <sys/neutrino.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <locale.h>
#include <float.h>
#include <time.h>
#if U_HAVE_NL_LANGINFO_CODESET
#include <langinfo.h>
#endif
#define DATA_TYPE "dat"
static const char copyright[] = U_COPYRIGHT_STRING;
#define SIGN 0x80000000U
#if defined(__GNUC__)
#define USE_64BIT_DOUBLE_OPTIMIZATION 1
#else
#define USE_64BIT_DOUBLE_OPTIMIZATION 0
#endif
#if USE_64BIT_DOUBLE_OPTIMIZATION
static const int64_t gNan64 = 0x7FF8000000000000LL;
static const int64_t gInf64 = 0x7FF0000000000000LL;
static const double * const fgNan = (const double *)(&gNan64);
static const double * const fgInf = (const double *)(&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
static UBool fgNaNInitialized = FALSE;
static UBool fgInfInitialized = FALSE;
static double gNan;
static double gInf;
static double * const fgNan = &gNan;
static double * const fgInf = &gInf;
#endif
#if defined(_WIN32) || defined(XP_MAC) || defined(OS400) || defined(OS2)
# undef U_POSIX_LOCALE
#else
# define U_POSIX_LOCALE 1
#endif
static char*
u_topNBytesOfDouble(double* d, int n)
{
#if U_IS_BIG_ENDIAN
return (char*)d;
#else
return (char*)(d + 1) - n;
#endif
}
static char*
u_bottomNBytesOfDouble(double* d, int n)
{
#if U_IS_BIG_ENDIAN
return (char*)(d + 1) - n;
#else
return (char*)d;
#endif
}
U_CAPI UDate U_EXPORT2
uprv_getUTCtime()
{
#ifdef XP_MAC
time_t t, t1, t2;
struct tm tmrec;
uprv_memset( &tmrec, 0, sizeof(tmrec) );
tmrec.tm_year = 70;
tmrec.tm_mon = 0;
tmrec.tm_mday = 1;
t1 = mktime(&tmrec);
time(&t);
uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
t2 = mktime(&tmrec);
return (UDate)(t2 - t1) * U_MILLIS_PER_SECOND;
#else
time_t epochtime;
time(&epochtime);
return (UDate)epochtime * U_MILLIS_PER_SECOND;
#endif
}
U_CAPI UBool U_EXPORT2
uprv_isNaN(double number)
{
#if IEEE_754
#if USE_64BIT_DOUBLE_OPTIMIZATION
return (UBool)(((*((int64_t *)&number)) & U_INT64_MAX) > gInf64);
#else
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
#elif defined(OS390)
uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
sizeof(uint32_t));
uint32_t lowBits = *(uint32_t*)u_bottomNBytesOfDouble(&number,
sizeof(uint32_t));
return ((highBits & 0x7F080000L) == 0x7F080000L) &&
(lowBits == 0x00000000L);
#else
return number != number;
#endif
}
U_CAPI UBool U_EXPORT2
uprv_isInfinite(double number)
{
#if IEEE_754
#if USE_64BIT_DOUBLE_OPTIMIZATION
return (UBool)(((*((int64_t *)&number)) & U_INT64_MAX) == gInf64);
#else
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
#elif defined(OS390)
uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
sizeof(uint32_t));
uint32_t lowBits = *(uint32_t*)u_bottomNBytesOfDouble(&number,
sizeof(uint32_t));
return ((highBits & ~SIGN) == 0x70FF0000L) && (lowBits == 0x00000000L);
#else
return number == (2.0 * number);
#endif
}
U_CAPI UBool U_EXPORT2
uprv_isPositiveInfinity(double number)
{
#if IEEE_754 || defined(OS390)
return (UBool)(number > 0 && uprv_isInfinite(number));
#else
return uprv_isInfinite(number);
#endif
}
U_CAPI UBool U_EXPORT2
uprv_isNegativeInfinity(double number)
{
#if IEEE_754 || defined(OS390)
return (UBool)(number < 0 && uprv_isInfinite(number));
#else
uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
sizeof(uint32_t));
return((highBits & SIGN) && uprv_isInfinite(number));
#endif
}
U_CAPI double U_EXPORT2
uprv_getNaN()
{
#if IEEE_754 || defined(OS390)
#if !USE_64BIT_DOUBLE_OPTIMIZATION
if (!fgNaNInitialized) {
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;
#else
return 0.0;
#endif
}
U_CAPI double U_EXPORT2
uprv_getInfinity()
{
#if IEEE_754 || defined(OS390)
#if !USE_64BIT_DOUBLE_OPTIMIZATION
if (!fgInfInitialized)
{
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;
#else
return 0.0;
#endif
}
U_CAPI double U_EXPORT2
uprv_floor(double x)
{
return floor(x);
}
U_CAPI double U_EXPORT2
uprv_ceil(double x)
{
return ceil(x);
}
U_CAPI double U_EXPORT2
uprv_round(double x)
{
return uprv_floor(x + 0.5);
}
U_CAPI double U_EXPORT2
uprv_fabs(double x)
{
return fabs(x);
}
U_CAPI double U_EXPORT2
uprv_modf(double x, double* y)
{
return modf(x, y);
}
U_CAPI double U_EXPORT2
uprv_fmod(double x, double y)
{
return fmod(x, y);
}
U_CAPI double U_EXPORT2
uprv_pow(double x, double y)
{
return pow(x, y);
}
U_CAPI double U_EXPORT2
uprv_pow10(int32_t x)
{
return pow(10.0, (double)x);
}
U_CAPI double U_EXPORT2
uprv_fmax(double x, double y)
{
#if IEEE_754
int32_t lowBits;
if(uprv_isNaN(x) || uprv_isNaN(y))
return uprv_getNaN();
lowBits = *(uint32_t*) u_bottomNBytesOfDouble(&x, sizeof(uint32_t));
if(x == 0.0 && y == 0.0 && (lowBits & SIGN))
return y;
#endif
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)
{
#if IEEE_754
int32_t lowBits;
if(uprv_isNaN(x) || uprv_isNaN(y))
return uprv_getNaN();
lowBits = *(uint32_t*) u_bottomNBytesOfDouble(&y, sizeof(uint32_t));
if(x == 0.0 && y == 0.0 && (lowBits & SIGN))
return y;
#endif
return (x > y ? y : x);
}
U_CAPI int32_t U_EXPORT2
uprv_min(int32_t x, int32_t y)
{
return (x > y ? y : x);
}
U_CAPI double U_EXPORT2
uprv_trunc(double d)
{
#if IEEE_754
int32_t lowBits;
if(uprv_isNaN(d))
return uprv_getNaN();
if(uprv_isInfinite(d))
return uprv_getInfinity();
lowBits = *(uint32_t*) u_bottomNBytesOfDouble(&d, sizeof(uint32_t));
if( (d == 0.0 && (lowBits & SIGN)) || d < 0)
return ceil(d);
else
return floor(d);
#else
return d >= 0 ? floor(d) : ceil(d);
#endif
}
U_CAPI double U_EXPORT2
uprv_maxMantissa(void)
{
return pow(2.0, DBL_MANT_DIG + 1.0) - 1.0;
}
U_CAPI int16_t U_EXPORT2
uprv_log10(double d)
{
#ifdef OS400
return log10(d);
#else
double alog10 = log(d) / log(10.0);
int16_t ailog10 = (int16_t) floor(alog10);
if (alog10 > 0 && d >= pow(10.0, (double)(ailog10 + 1)))
++ailog10;
else if (alog10 < 0 && d < pow(10.0, (double)(ailog10)))
--ailog10;
return ailog10;
#endif
}
U_CAPI double U_EXPORT2
uprv_log(double d)
{
return log(d);
}
#if 0
U_CAPI int32_t U_EXPORT2
uprv_digitsAfterDecimal(double x)
{
char buffer[20];
int32_t numDigits, bytesWritten;
char *p = buffer;
int32_t ptPos, exponent;
bytesWritten = sprintf(buffer, "%+.9g", x);
while (isdigit(*(++p))) {
}
ptPos = (int32_t)(p - buffer);
numDigits = (int32_t)(bytesWritten - ptPos - 1);
exponent = 0;
p = uprv_strchr(buffer, 'e');
if (p != 0) {
int16_t expPos = (int16_t)(p - buffer);
numDigits -= bytesWritten - expPos;
exponent = (int32_t)(atol(p + 1));
}
if (numDigits > 9) {
numDigits = 9;
while (numDigits > 0 && buffer[ptPos + numDigits] == '0')
--numDigits;
}
numDigits -= exponent;
if (numDigits < 0) {
return 0;
}
return numDigits;
}
#endif
#ifdef WIN32
typedef struct {
LONG Bias;
LONG StandardBias;
LONG DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} TZI;
typedef struct {
const char* icuid;
const char* winid;
} WindowsICUMap;
static const WindowsICUMap ZONE_MAP[] = {
"Etc/GMT+12", "Dateline",
"Pacific/Apia", "Samoa",
"Pacific/Honolulu", "Hawaiian",
"America/Anchorage", "Alaskan",
"America/Los_Angeles", "Pacific",
"America/Phoenix", "US Mountain",
"America/Denver", "Mountain",
"America/Chihuahua", "Mexico Standard Time 2",
"America/Managua", "Central America",
"America/Regina", "Canada Central",
"America/Mexico_City", "Mexico",
"America/Chicago", "Central",
"America/Indianapolis", "US Eastern",
"America/Bogota", "SA Pacific",
"America/New_York", "Eastern",
"America/Caracas", "SA Western",
"America/Santiago", "Pacific SA",
"America/Halifax", "Atlantic",
"America/St_Johns", "Newfoundland",
"America/Buenos_Aires", "SA Eastern",
"America/Godthab", "Greenland",
"America/Sao_Paulo", "E. South America",
"America/Noronha", "Mid-Atlantic",
"Atlantic/Cape_Verde", "Cape Verde",
"Atlantic/Azores", "Azores",
"Africa/Casablanca", "Greenwich",
"Europe/London", "GMT",
"Africa/Lagos", "W. Central Africa",
"Europe/Berlin", "W. Europe",
"Europe/Paris", "Romance",
"Europe/Sarajevo", "Central European",
"Europe/Belgrade", "Central Europe",
"Africa/Johannesburg", "South Africa",
"Asia/Jerusalem", "Israel",
"Europe/Istanbul", "GTB",
"Europe/Helsinki", "FLE",
"Africa/Cairo", "Egypt",
"Europe/Bucharest", "E. Europe",
"Africa/Nairobi", "E. Africa",
"Asia/Riyadh", "Arab",
"Europe/Moscow", "Russian",
"Asia/Baghdad", "Arabic",
"Asia/Tehran", "Iran",
"Asia/Muscat", "Arabian",
"Asia/Tbilisi", "Caucasus",
"Asia/Kabul", "Afghanistan",
"Asia/Karachi", "West Asia",
"Asia/Yekaterinburg", "Ekaterinburg",
"Asia/Calcutta", "India",
"Asia/Katmandu", "Nepal",
"Asia/Colombo", "Sri Lanka",
"Asia/Dhaka", "Central Asia",
"Asia/Novosibirsk", "N. Central Asia",
"Asia/Rangoon", "Myanmar",
"Asia/Bangkok", "SE Asia",
"Asia/Krasnoyarsk", "North Asia",
"Australia/Perth", "W. Australia",
"Asia/Taipei", "Taipei",
"Asia/Singapore", "Singapore",
"Asia/Hong_Kong", "China",
"Asia/Irkutsk", "North Asia East",
"Asia/Tokyo", "Tokyo",
"Asia/Seoul", "Korea",
"Asia/Yakutsk", "Yakutsk",
"Australia/Darwin", "AUS Central",
"Australia/Adelaide", "Cen. Australia",
"Pacific/Guam", "West Pacific",
"Australia/Brisbane", "E. Australia",
"Asia/Vladivostok", "Vladivostok",
"Australia/Hobart", "Tasmania",
"Australia/Sydney", "AUS Eastern",
"Asia/Magadan", "Central Pacific",
"Pacific/Fiji", "Fiji",
"Pacific/Auckland", "New Zealand",
"Pacific/Tongatapu", "Tonga",
NULL, NULL
};
typedef struct {
const char* winid;
const char* altwinid;
} WindowsZoneRemap;
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,
};
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";
static const char* const WIN_TYPE_PROBE_REGKEY[] = {
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones",
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT"
};
static const char* const TZ_REGKEY[] = {
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\",
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
};
enum {
WIN_9X_ME_TYPE = 0,
WIN_NT_TYPE = 1,
WIN_2K_XP_TYPE = 2
};
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) {
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) {
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;
}
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;
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;
}
}
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));
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) {
if (firstMatch >= 0 && tziKey.Bias != tziReg.Bias) {
break;
}
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;
}
}
}
if (firstMatch < 0) {
return NULL;
}
if (firstMatch != lastMatch) {
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);
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;
break;
}
}
} else {
RegCloseKey(hkey);
}
}
return ZONE_MAP[firstMatch].icuid;
}
#endif
U_CAPI void U_EXPORT2
uprv_tzset()
{
#ifdef U_TZSET
U_TZSET();
#else
#endif
}
U_CAPI int32_t U_EXPORT2
uprv_timezone()
{
#ifdef U_TIMEZONE
return U_TIMEZONE;
#else
time_t t, t1, t2;
struct tm tmrec;
UBool dst_checked;
int32_t tdiff = 0;
time(&t);
uprv_memcpy( &tmrec, localtime(&t), sizeof(tmrec) );
dst_checked = (tmrec.tm_isdst != 0);
t1 = mktime(&tmrec);
uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
t2 = mktime(&tmrec);
tdiff = t2 - t1;
if (dst_checked)
tdiff += 3600;
return tdiff;
#endif
}
#if defined(U_TZNAME) && (defined(U_IRIX) || defined(U_DARWIN) || defined(U_CYGWIN))
extern U_IMPORT char *U_TZNAME[];
#endif
#if defined(U_DARWIN)
#define TZZONELINK "/etc/localtime"
#define TZZONEINFO "/usr/share/zoneinfo/"
static char *gTimeZoneBuffer = NULL;
#endif
U_CAPI const char* U_EXPORT2
uprv_tzname(int n)
{
#ifdef WIN32
char* id = (char*) detectWindowsTimeZone();
if (id != NULL) {
return id;
}
#endif
#if defined(U_DARWIN)
int ret;
char *tzenv;
tzenv = getenv("TZFILE");
if (tzenv != NULL) {
return tzenv;
}
#if 0
tzenv = getenv("TZ");
if (tzenv != NULL) {
return tzenv;
}
#endif
if (gTimeZoneBuffer == NULL) {
gTimeZoneBuffer = (char *) uprv_malloc(MAXPATHLEN + 2);
ret = readlink(TZZONELINK, gTimeZoneBuffer, MAXPATHLEN + 2);
if (0 < ret) {
gTimeZoneBuffer[ret] = '\0';
if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) {
return (gTimeZoneBuffer += sizeof(TZZONEINFO) - 1);
}
}
uprv_free(gTimeZoneBuffer);
gTimeZoneBuffer = NULL;
}
#endif
#ifdef U_TZNAME
return U_TZNAME[n];
#else
return "";
#endif
}
static char *gDataDirectory = NULL;
#if U_POSIX_LOCALE
static char *gCorrectedPOSIXLocale = NULL;
#endif
static UBool U_CALLCONV putil_cleanup(void)
{
if (gDataDirectory) {
uprv_free(gDataDirectory);
gDataDirectory = NULL;
}
#if U_POSIX_LOCALE
if (gCorrectedPOSIXLocale) {
uprv_free(gCorrectedPOSIXLocale);
gCorrectedPOSIXLocale = NULL;
}
#endif
return TRUE;
}
U_CAPI void U_EXPORT2
u_setDataDirectory(const char *directory) {
char *newDataDir;
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
char *p;
#endif
int32_t length;
if(directory==NULL) {
directory = "";
}
length=(int32_t)uprv_strlen(directory);
newDataDir = (char *)uprv_malloc(length + 2);
uprv_strcpy(newDataDir, directory);
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
while(p = uprv_strchr(newDataDir, U_FILE_ALT_SEP_CHAR)) {
*p = U_FILE_SEP_CHAR;
}
#endif
umtx_lock(NULL);
if (gDataDirectory) {
uprv_free(gDataDirectory);
}
gDataDirectory = newDataDir;
ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
umtx_unlock(NULL);
}
U_CAPI UBool U_EXPORT2
uprv_pathIsAbsolute(const char *path)
{
if(!path || !*path) {
return FALSE;
}
if(*path == U_FILE_SEP_CHAR) {
return TRUE;
}
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
if(*path == U_FILE_ALT_SEP_CHAR) {
return TRUE;
}
#endif
#if defined(WIN32)
if( (((path[0] >= 'A') && (path[0] <= 'Z')) ||
((path[0] >= 'a') && (path[0] <= 'z'))) &&
path[1] == ':' ) {
return TRUE;
}
#endif
return FALSE;
}
U_CAPI const char * U_EXPORT2
u_getDataDirectory(void) {
const char *path = NULL;
char pathBuffer[1024];
const char *dataDir;
umtx_lock(NULL);
dataDir = gDataDirectory;
umtx_unlock(NULL);
if(dataDir) {
return dataDir;
}
pathBuffer[0] = 0;
# if !defined(XP_MAC)
path=getenv("ICU_DATA");
# else
{
OSErr myErr;
short vRef;
long dir,newDir;
int16_t volNum;
Str255 xpath;
FSSpec spec;
short len;
Handle full;
xpath[0]=0;
myErr = HGetVol(xpath, &volNum, &dir);
if(myErr == noErr) {
myErr = FindFolder(volNum, kApplicationSupportFolderType, TRUE, &vRef, &dir);
newDir=-1;
if (myErr == noErr) {
myErr = DirCreate(volNum,
dir,
"\pICU",
&newDir);
if( (myErr == noErr) || (myErr == dupFNErr) ) {
spec.vRefNum = volNum;
spec.parID = dir;
uprv_memcpy(spec.name, "\pICU", 4);
myErr = FSpGetFullPath(&spec, &len, &full);
if(full != NULL)
{
HLock(full);
uprv_memcpy(pathBuffer, ((char*)(*full)), len);
pathBuffer[len] = 0;
path = pathBuffer;
DisposeHandle(full);
}
}
}
}
}
# endif
# if defined WIN32 && defined ICU_ENABLE_DEPRECATED_WIN_REGISTRY
if(path==NULL || *path==0) {
HKEY key;
if(ERROR_SUCCESS==RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\ICU\\Unicode\\Data", 0, KEY_QUERY_VALUE, &key)) {
DWORD type=REG_EXPAND_SZ, size=sizeof(pathBuffer);
if(ERROR_SUCCESS==RegQueryValueEx(key, "Path", NULL, &type, (unsigned char *)pathBuffer, &size) && size>1) {
if(type==REG_EXPAND_SZ) {
char temporaryPath[1024];
uprv_memcpy(temporaryPath, pathBuffer, size);
size=ExpandEnvironmentStrings(temporaryPath, pathBuffer, sizeof(pathBuffer));
if(size>0 && size<sizeof(pathBuffer)) {
path=pathBuffer;
}
} else if(type==REG_SZ) {
path=pathBuffer;
}
}
RegCloseKey(key);
}
}
# endif
# ifdef ICU_DATA_DIR
if(path==NULL || *path==0) {
path=ICU_DATA_DIR;
}
# endif
if(path==NULL) {
path = "";
}
u_setDataDirectory(path);
return gDataDirectory;
}
#ifdef XP_MAC
typedef struct {
int32_t script;
int32_t region;
int32_t lang;
int32_t date_region;
const char* posixID;
} mac_lc_rec;
#define MAC_LC_MAGIC_NUMBER -5
#define MAC_LC_INIT_NUMBER -9
static const mac_lc_rec mac_lc_recs[] = {
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 0, "en_US",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 1, "fr_FR",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 2, "en_GB",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 3, "de_DE",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 4, "it_IT",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 5, "nl_NL",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 6, "fr_BE",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 7, "sv_SE",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 9, "da_DK",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 10, "pt_PT",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 11, "fr_CA",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 13, "is_IS",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 14, "ja_JP",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 15, "en_AU",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 16, "ar_AE",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 17, "fi_FI",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 18, "fr_CH",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 19, "de_CH",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 20, "el_GR",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 21, "is_IS",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 24, "tr_TR",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 25, "sh_YU",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 41, "lt_LT",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 42, "pl_PL",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 43, "hu_HU",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 44, "et_EE",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 45, "lv_LV",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 48, "fa_IR",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 49, "ru_RU",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 50, "en_IE",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 51, "ko_KR",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 52, "zh_CN",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 53, "zh_TW",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 54, "th_TH",
MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER,
MAC_LC_MAGIC_NUMBER, "en_US"
};
#endif
#if U_POSIX_LOCALE
static const char *uprv_getPOSIXID(void)
{
static const char* posixID = NULL;
if (posixID == 0) {
posixID = getenv("LC_ALL");
if (posixID == 0) {
posixID = getenv("LANG");
if (posixID == 0) {
posixID = setlocale(LC_ALL, NULL);
}
}
}
if (posixID==0)
{
posixID = "en_US";
}
else if ((uprv_strcmp("C", posixID) == 0)
|| (uprv_strchr(posixID, ' ') != NULL)
|| (uprv_strchr(posixID, '/') != NULL))
{
posixID = "en_US_POSIX";
}
return posixID;
}
#endif
U_CAPI const char* U_EXPORT2
uprv_getDefaultLocaleID()
{
#if U_POSIX_LOCALE
char *correctedPOSIXLocale = 0;
const char* posixID = uprv_getPOSIXID();
const char *p;
const char *q;
int32_t len;
if (gCorrectedPOSIXLocale != NULL) {
return gCorrectedPOSIXLocale;
}
if ((p = uprv_strchr(posixID, '.')) != NULL) {
correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID));
uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
correctedPOSIXLocale[p-posixID] = 0;
if ((p = uprv_strchr(correctedPOSIXLocale, '@')) != NULL) {
correctedPOSIXLocale[p-correctedPOSIXLocale] = 0;
}
}
if ((p = uprv_strrchr(posixID, '@')) != NULL) {
if (correctedPOSIXLocale == NULL) {
correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID));
uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
correctedPOSIXLocale[p-posixID] = 0;
}
p++;
if (!uprv_strcmp(p, "nynorsk")) {
p = "NY";
}
if (uprv_strchr(correctedPOSIXLocale,'_') == NULL) {
uprv_strcat(correctedPOSIXLocale, "__");
}
else {
uprv_strcat(correctedPOSIXLocale, "_");
}
if ((q = uprv_strchr(p, '.')) != NULL) {
len = (int32_t)(uprv_strlen(correctedPOSIXLocale) + (q-p));
uprv_strncat(correctedPOSIXLocale, p, q-p);
correctedPOSIXLocale[len] = 0;
}
else {
uprv_strcat(correctedPOSIXLocale, p);
}
}
if (correctedPOSIXLocale != NULL) {
posixID = correctedPOSIXLocale;
}
else {
correctedPOSIXLocale = (char *)uprv_malloc(uprv_strlen(posixID) + 1);
posixID = uprv_strcpy(correctedPOSIXLocale, posixID);
}
if (gCorrectedPOSIXLocale == NULL) {
gCorrectedPOSIXLocale = correctedPOSIXLocale;
ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
correctedPOSIXLocale = NULL;
}
if (correctedPOSIXLocale != NULL) {
uprv_free(correctedPOSIXLocale);
}
return posixID;
#elif defined(WIN32)
UErrorCode status = U_ZERO_ERROR;
LCID id = GetThreadLocale();
const char* locID = uprv_convertToPosix(id, &status);
if (U_FAILURE(status)) {
locID = "en_US";
}
return locID;
#elif defined(XP_MAC)
int32_t script = MAC_LC_INIT_NUMBER;
int32_t region = MAC_LC_INIT_NUMBER;
int32_t lang = MAC_LC_INIT_NUMBER;
int32_t date_region = MAC_LC_INIT_NUMBER;
const char* posixID = 0;
int32_t count = sizeof(mac_lc_recs) / sizeof(mac_lc_rec);
int32_t i;
Intl1Hndl ih;
ih = (Intl1Hndl) GetIntlResource(1);
if (ih)
date_region = ((uint16_t)(*ih)->intl1Vers) >> 8;
for (i = 0; i < count; i++) {
if ( ((mac_lc_recs[i].script == MAC_LC_MAGIC_NUMBER)
|| (mac_lc_recs[i].script == script))
&& ((mac_lc_recs[i].region == MAC_LC_MAGIC_NUMBER)
|| (mac_lc_recs[i].region == region))
&& ((mac_lc_recs[i].lang == MAC_LC_MAGIC_NUMBER)
|| (mac_lc_recs[i].lang == lang))
&& ((mac_lc_recs[i].date_region == MAC_LC_MAGIC_NUMBER)
|| (mac_lc_recs[i].date_region == date_region))
)
{
posixID = mac_lc_recs[i].posixID;
break;
}
}
return posixID;
#elif defined(OS2)
char * locID;
locID = getenv("LC_ALL");
if (!locID || !*locID)
locID = getenv("LANG");
if (!locID || !*locID) {
locID = "en_US";
}
if (!stricmp(locID, "c") || !stricmp(locID, "posix") ||
!stricmp(locID, "univ"))
locID = "en_US_POSIX";
return locID;
#elif defined(OS400)
static char correctedLocale[64];
const char *localeID = getenv("LC_ALL");
char *p;
if (localeID == NULL)
localeID = getenv("LANG");
if (localeID == NULL)
localeID = setlocale(LC_ALL, NULL);
if (localeID == NULL)
return "en_US_POSIX";
if((p = uprv_strrchr(localeID, '/')) != NULL)
{
p++;
localeID = p;
}
uprv_strcpy(correctedLocale, localeID);
if((p = uprv_strchr(correctedLocale, '.')) != NULL) {
*p = 0;
}
T_CString_toUpperCase(correctedLocale);
if ((uprv_strcmp("C", correctedLocale) == 0) ||
(uprv_strcmp("POSIX", correctedLocale) == 0) ||
(uprv_strcmp("QLGPGCMA", correctedLocale) == 0))
{
uprv_strcpy(correctedLocale, "en_US_POSIX");
}
else
{
int16_t LocaleLen;
for(p = correctedLocale; *p != 0 && *p != '_'; p++)
{
*p = uprv_tolower(*p);
}
LocaleLen = uprv_strlen(correctedLocale);
if (correctedLocale[LocaleLen - 2] == '_' &&
correctedLocale[LocaleLen - 1] == 'E')
{
uprv_strcat(correctedLocale, "URO");
}
else if (correctedLocale[LocaleLen - 2] == '_' &&
correctedLocale[LocaleLen - 1] == 'L')
{
correctedLocale[LocaleLen - 2] = 0;
}
else if (uprv_strncmp(correctedLocale, "zh_HK", 5) == 0)
{
uprv_strcpy(correctedLocale, "zh_HK");
}
else if (uprv_strcmp(correctedLocale, "zh_CN_GBK") == 0)
{
uprv_strcpy(correctedLocale, "zh_CN");
}
}
return correctedLocale;
#endif
}
static const char*
int_getDefaultCodepage()
{
#if defined(OS400)
uint32_t ccsid = 37;
static char codepage[64];
Qwc_JOBI0400_t jobinfo;
Qus_EC_t error = { sizeof(Qus_EC_t) };
EPT_CALL(QUSRJOBI)(&jobinfo, sizeof(jobinfo), "JOBI0400",
"* ", " ", &error);
if (error.Bytes_Available == 0) {
if (jobinfo.Coded_Char_Set_ID != 0xFFFF) {
ccsid = (uint32_t)jobinfo.Coded_Char_Set_ID;
}
else if (jobinfo.Default_Coded_Char_Set_Id != 0xFFFF) {
ccsid = (uint32_t)jobinfo.Default_Coded_Char_Set_Id;
}
}
sprintf(codepage,"ibm-%d", ccsid);
return codepage;
#elif defined(OS390)
static char codepage[64];
sprintf(codepage,"%s" UCNV_SWAP_LFNL_OPTION_STRING, nl_langinfo(CODESET));
return codepage;
#elif defined(XP_MAC)
return "ibm-1275";
#elif defined(WIN32)
static char codepage[64];
sprintf(codepage, "windows-%d", GetACP());
return codepage;
#elif U_POSIX_LOCALE
static char codesetName[100];
char *name = NULL;
char *euro = NULL;
const char *localeName = NULL;
uprv_memset(codesetName, 0, sizeof(codesetName));
localeName = setlocale(LC_CTYPE, "");
if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
name = uprv_strncpy(codesetName, name+1, sizeof(codesetName));
codesetName[sizeof(codesetName)-1] = 0;
if ((euro = (uprv_strchr(name, '@'))) != NULL) {
*euro = 0;
}
if (*name) {
return name;
}
}
#if U_HAVE_NL_LANGINFO_CODESET
if (*codesetName) {
uprv_memset(codesetName, 0, sizeof(codesetName));
}
{
const char *codeset = nl_langinfo(U_NL_LANGINFO_CODESET);
if (codeset != NULL) {
uprv_strncpy(codesetName, codeset, sizeof(codesetName));
codesetName[sizeof(codesetName)-1] = 0;
return codesetName;
}
}
#endif
if (*codesetName) {
uprv_memset(codesetName, 0, sizeof(codesetName));
}
localeName = uprv_getPOSIXID();
if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
name = uprv_strncpy(codesetName, name+1, sizeof(codesetName));
codesetName[sizeof(codesetName)-1] = 0;
if ((euro = (uprv_strchr(name, '@'))) != NULL) {
*euro = 0;
}
if (*name) {
return name;
}
}
if (*codesetName == 0)
{
uprv_strcpy(codesetName, "US-ASCII");
}
return codesetName;
#else
return "US-ASCII";
#endif
}
U_CAPI const char* U_EXPORT2
uprv_getDefaultCodepage()
{
static char const *name = NULL;
umtx_lock(NULL);
if (name == NULL) {
name = int_getDefaultCodepage();
}
umtx_unlock(NULL);
return name;
}
U_CAPI void U_EXPORT2
u_versionFromString(UVersionInfo versionArray, const char *versionString) {
char *end;
uint16_t part=0;
if(versionArray==NULL) {
return;
}
if(versionString!=NULL) {
for(;;) {
versionArray[part]=(uint8_t)uprv_strtoul(versionString, &end, 10);
if(end==versionString || ++part==U_MAX_VERSION_LENGTH || *end!=U_VERSION_DELIMITER) {
break;
}
versionString=end+1;
}
}
while(part<U_MAX_VERSION_LENGTH) {
versionArray[part++]=0;
}
}
U_CAPI void U_EXPORT2
u_versionToString(UVersionInfo versionArray, char *versionString) {
uint16_t count, part;
uint8_t field;
if(versionString==NULL) {
return;
}
if(versionArray==NULL) {
versionString[0]=0;
return;
}
for(count=4; count>0 && versionArray[count-1]==0; --count) {
}
if(count <= 1) {
count = 2;
}
field=versionArray[0];
if(field>=100) {
*versionString++=(char)('0'+field/100);
field%=100;
}
if(field>=10) {
*versionString++=(char)('0'+field/10);
field%=10;
}
*versionString++=(char)('0'+field);
for(part=1; part<count; ++part) {
*versionString++=U_VERSION_DELIMITER;
field=versionArray[part];
if(field>=100) {
*versionString++=(char)('0'+field/100);
field%=100;
}
if(field>=10) {
*versionString++=(char)('0'+field/10);
field%=10;
}
*versionString++=(char)('0'+field);
}
*versionString=0;
}
U_CAPI void U_EXPORT2
u_getVersion(UVersionInfo versionArray) {
u_versionFromString(versionArray, U_ICU_VERSION);
}