aa0b0a88e8
X-SVN-Rev: 2
1198 lines
32 KiB
C
1198 lines
32 KiB
C
/*
|
|
*******************************************************************************
|
|
* *
|
|
* COPYRIGHT: *
|
|
* (C) Copyright Taligent, Inc., 1997 *
|
|
* (C) Copyright International Business Machines Corporation, 1997-1998 *
|
|
* Licensed Material - Program-Property of IBM - All Rights Reserved. *
|
|
* US Government Users Restricted Rights - Use, duplication, or disclosure *
|
|
* restricted by GSA ADP Schedule Contract with IBM Corp. *
|
|
* *
|
|
*******************************************************************************
|
|
*
|
|
* File ULOC.CPP
|
|
*
|
|
* Modification History:
|
|
*
|
|
* Date Name Description
|
|
* 04/01/97 aliu Creation.
|
|
* 08/21/98 stephen JDK 1.2 sync
|
|
* 12/08/98 rtg New Locale implementation and C API
|
|
* 03/15/99 damiba overhaul.
|
|
* 04/06/99 stephen changed setDefault() to realloc and copy
|
|
* 06/14/99 stephen Changed calls to ures_open for new params
|
|
* 07/21/99 stephen Modified setDefault() to propagate to C++
|
|
******************************************************************************/
|
|
|
|
|
|
#include "uloc.h"
|
|
|
|
#include "utypes.h"
|
|
#include "ures.h"
|
|
#include "uchar.h"
|
|
#include "umutex.h"
|
|
#include "cstring.h"
|
|
#include "ustring.h"
|
|
#include "cmemory.h"
|
|
|
|
/****************************************************************************
|
|
Global variable and type definitions
|
|
******************************************************************************/
|
|
|
|
/* UnicodeString stuff */
|
|
typedef struct UnicodeString UnicodeString;
|
|
|
|
CAPI const UChar* T_UnicodeString_getUChars(const UnicodeString *s);
|
|
/* Locale stuff */
|
|
CAPI void locale_set_default(const char *id);
|
|
|
|
/* These strings describe the resources we attempt to load from
|
|
the locale ResourceBundle data file.*/
|
|
static const char* _kLocaleString = "LocaleString";
|
|
static const char* _kShortLanguage = "ShortLanguage";
|
|
static const char* _kShortCountry = "ShortCountry";
|
|
static const char* _kLocaleID = "LocaleID";
|
|
static const char* _kLanguages = "Languages";
|
|
static const char* _kCountries = "Countries";
|
|
|
|
|
|
#define TEMPBUFSIZE 8
|
|
|
|
/*Some static strings needed in the getDisplay* functions*/
|
|
static const UChar openParen[] = { (UChar)0x0020 /* space */, (UChar)0x0028 /* ( */, (UChar)0x0000};
|
|
static const UChar comma[] = { (UChar)0x002C /* space */, (UChar)0x0020 /* , */, (UChar)0x0000};
|
|
static const UChar closeParen[] = { (UChar)0x0029 /* ( */, (UChar)0x0000};
|
|
|
|
|
|
static char* _defaultLocale = NULL;
|
|
static char* _dataDirectory = NULL;
|
|
|
|
static char** _installedLocales = NULL;
|
|
static int32_t _installedLocalesCount = 0;
|
|
|
|
|
|
static const char _languages[] =
|
|
"aa\0ab\0af\0am\0ar\0as\0ay\0az\0"
|
|
"ba\0be\0bg\0bh\0bi\0bn\0bo\0br\0"
|
|
"ca\0co\0cs\0cy\0da\0de\0dz\0"
|
|
"el\0en\0eo\0es\0et\0eu\0fa\0fi\0fj\0fo\0fr\0fy\0"
|
|
"ga\0gd\0gl\0gn\0gu\0ha\0he\0hi\0hr\0hu\0hy\0"
|
|
"ia\0id\0ie\0ik\0in\0is\0it\0iu\0iw\0"
|
|
"ja\0ji\0jw\0ka\0kk\0kl\0km\0kn\0ko\0ks\0ku\0ky\0"
|
|
"la\0ln\0lo\0lt\0lv\0"
|
|
"mg\0mi\0mk\0ml\0mn\0mo\0mr\0ms\0mt\0my\0"
|
|
"na\0ne\0nl\0no\0oc\0om\0or\0"
|
|
"pa\0pl\0ps\0pt\0qu\0rm\0rn\0ro\0ru\0rw\0"
|
|
"sa\0sd\0sg\0sh\0si\0sk\0sl\0sm\0sn\0so\0sq\0sr\0ss\0st\0su\0sv\0sw\0"
|
|
"ta\0te\0tg\0th\0ti\0tk\0tl\0tn\0to\0tr\0ts\0tt\0tw\0"
|
|
"ug\0uk\0ur\0uz\0vi\0vo\0wo\0xh\0yi\0yo\0za\0zh\0zu";
|
|
/* This list MUST be in sorted order, and MUST contain only two-letter codes! */
|
|
|
|
static const char _languages3[] =
|
|
"aar\0abk\0afr\0amh\0ara\0asm\0aym\0aze\0"
|
|
"bak\0bel\0bul\0bih\0bis\0ben\0bod\0bre\0"
|
|
"cat\0cos\0ces\0cym\0dan\0deu\0dzo\0"
|
|
"ell\0eng\0epo\0spa\0est\0eus\0fas\0fin\0fij\0fao\0fra\0fry\0"
|
|
"gai\0gdh\0glg\0grn\0guj\0hau\0heb\0hin\0hrv\0hun\0hye\0"
|
|
"ina\0ind\0ile\0ipk\0ind\0isl\0ita\0iku\0heb\0"
|
|
"jpn\0yid\0jaw\0kat\0kaz\0kal\0khm\0kan\0kor\0kas\0kur\0kir\0"
|
|
"lat\0lin\0lao\0lit\0lav\0"
|
|
"mlg\0mri\0mkd\0mal\0mon\0mol\0mar\0msa\0mlt\0mya\0"
|
|
"nau\0nep\0nld\0nor\0oci\0orm\0ori\0"
|
|
"pan\0pol\0pus\0por\0que\0roh\0run\0ron\0rus\0kin\0"
|
|
"san\0snd\0sag\0srp\0sin\0slk\0slv\0smo\0sna\0som\0sqi\0srp\0ssw\0sot\0sun\0swe\0swa\0"
|
|
"tat\0tel\0tgk\0tha\0tir\0tuk\0tgl\0tsn\0ton\0tur\0tsn\0tat\0twi\0"
|
|
"uig\0ukr\0urd\0uzb\0vie\0vol\0wol\0xho\0yid\0yor\0zha\0zho\0zul";
|
|
/* This list MUST contain a three-letter code for every two-letter code in the
|
|
list above, and they MUST ne in the same order (i.e., the same language must
|
|
be in the same place in both lists)! */
|
|
|
|
static const char _countries[] =
|
|
"AD\0AE\0AF\0AG\0AI\0AL\0AM\0AN\0AO\0AQ\0AR\0AS\0AT\0AU\0AW\0AZ\0"
|
|
"BA\0BB\0BD\0BE\0BF\0BG\0BH\0BI\0BJ\0BM\0BN\0BO\0BR\0BS\0BT\0BV\0BW\0BY\0BZ\0"
|
|
"CA\0CC\0CF\0CG\0CH\0CI\0CK\0CL\0CM\0CN\0CO\0CR\0CU\0CV\0CX\0CY\0CZ\0"
|
|
"DE\0DJ\0DK\0DM\0DO\0DZ\0EC\0EE\0EG\0EH\0ER\0ES\0ET\0"
|
|
"FI\0FJ\0FK\0FM\0FO\0FR\0FX\0"
|
|
"GA\0GB\0GD\0GE\0GF\0GH\0GI\0GL\0GM\0GN\0GP\0GQ\0GR\0GS\0GT\0GU\0GW\0GY\0"
|
|
"HK\0HM\0HN\0HR\0HT\0HU\0ID\0IE\0IL\0IN\0IO\0IQ\0IR\0IS\0IT\0"
|
|
"JM\0JO\0JP\0KE\0KG\0KH\0KI\0KM\0KN\0KP\0KR\0KW\0KY\0KZ\0"
|
|
"LA\0LB\0LC\0LI\0LK\0LR\0LS\0LT\0LU\0LV\0LY\0"
|
|
"MA\0MC\0MD\0MG\0MH\0MK\0ML\0MM\0MN\0MO\0MP\0MQ\0MR\0MS\0MT\0MU\0MV\0MW\0MX\0MY\0MZ\0"
|
|
"NA\0NC\0NE\0NF\0NG\0NI\0NL\0NO\0NP\0NR\0NU\0NZ\0OM\0"
|
|
"PA\0PE\0PF\0PG\0PH\0PK\0PL\0PM\0PN\0PR\0PT\0PW\0PY\0QA\0RE\0RO\0RU\0RW\0"
|
|
"SA\0SB\0SC\0SD\0SE\0SG\0SH\0SI\0SJ\0SK\0SL\0SM\0SN\0SO\0SR\0ST\0SV\0SY\0SZ\0"
|
|
"TC\0TD\0TF\0TG\0TH\0TJ\0TK\0TM\0TN\0TO\0TP\0TR\0TT\0TV\0TW\0TZ\0"
|
|
"UA\0UG\0UM\0US\0UY\0UZ\0VA\0VC\0VE\0VG\0VI\0VN\0VU\0"
|
|
"WF\0WS\0YE\0YT\0YU\0ZA\0ZM\0ZR\0ZW";
|
|
/* This list MUST be in sorted order, and MUST contain only two-letter codes! */
|
|
|
|
static const char _countries3[] =
|
|
"AND\0ARE\0AFG\0ATG\0AIA\0ALB\0ARM\0ANT\0AGO\0ATA\0ARG\0ASM\0AUT\0AUS\0ABW\0AZE\0"
|
|
"BIH\0BRB\0BGD\0BEL\0BFA\0BGR\0BHR\0BDI\0BEN\0BMU\0BRN\0BOL\0BRA\0BHS\0BTN\0BVT\0BWA"
|
|
"\0BLR\0BLZ\0"
|
|
"CAN\0CCK\0CAF\0COG\0CHE\0CIV\0COK\0CHL\0CMR\0CHN\0COL\0CRI\0CUB\0CPV\0CXR\0CYP\0CZE\0"
|
|
"DEU\0DJI\0DNK\0DMA\0DOM\0DZA\0ECU\0EST\0EGY\0ESH\0ERI\0ESP\0ETH\0"
|
|
"FIN\0FJI\0FLK\0FSM\0FRO\0FRA\0FXX\0"
|
|
"GAB\0GBR\0GRD\0GEO\0GUF\0GHA\0GIB\0GRL\0GMB\0GIN\0GLP\0GNQ\0GRC\0SGS\0GTM\0GUM"
|
|
"\0GNB\0GUY\0"
|
|
"HKG\0HMD\0HND\0HRV\0HTI\0HUN\0IDN\0IRL\0ISR\0IND\0IOT\0IRQ\0IRN\0ISL\0ITA\0"
|
|
"JAM\0JOR\0JPN\0KEN\0KGZ\0KHM\0KIR\0COM\0KNA\0PRK\0KOR\0KWT\0CYM\0KAZ\0"
|
|
"LAO\0LBN\0LCA\0LIE\0LKA\0LBR\0LSO\0LTU\0LUX\0LVA\0LBY\0"
|
|
"MAR\0MCO\0MDA\0MDG\0MHL\0MKD\0MLI\0MMR\0MNG\0MAC\0MNP\0MTQ\0MRT\0MSR\0MLT\0MUS\0"
|
|
"MDV\0MWI\0MEX\0MYS\0MOZ\0"
|
|
"NAM\0NCL\0NER\0NFK\0NGA\0NIC\0NLD\0NOR\0NPL\0NRU\0NIU\0NZL\0OMN\0"
|
|
"PAN\0PER\0PYF\0PNG\0PHL\0PAK\0POL\0SPM\0PCN\0PRI\0PRT\0PLW\0PRY\0QAT\0REU\0ROM"
|
|
"\0RUS\0RWA\0"
|
|
"SAU\0SLB\0SYC\0SDN\0SWE\0SGP\0SHN\0SVN\0SJM\0SVK\0SLE\0SMR\0SEN\0SOM\0SUR\0STP"
|
|
"\0SLV\0SYR\0SWZ\0"
|
|
"TCA\0TCD\0ATF\0TGO\0THA\0TJK\0TKL\0TKM\0TUN\0TON\0TMP\0TUR\0TTO\0TUV\0TWN\0TZA\0"
|
|
"UKR\0UGA\0UMI\0USA\0URY\0UZB\0VAT\0VCT\0VEN\0VGB\0VIR\0VNM\0VUT\0"
|
|
"WLF\0WSM\0YEM\0MYT\0YUG\0ZAF\0ZMB\0ZAR\0ZWE";
|
|
/* This list MUST contain a three-letter code for every two-letter code in
|
|
the above list, and they MUST be listed in the same order! */
|
|
|
|
static char** _isoLanguages = NULL;
|
|
static char** _isoCountries = NULL;
|
|
|
|
/*******************************************************************************
|
|
Implementation function definitions
|
|
*******************************************************************************/
|
|
|
|
static int16_t _findIndex(const char* list, int32_t listLength, const char* key);
|
|
|
|
/*Works like strchr with '_' pr '-'*/
|
|
static const char* _findCharSeparator(const char* string);
|
|
|
|
/*Lazy evaluated the list of installed locales*/
|
|
static void _lazyEvaluate_installedLocales();
|
|
|
|
/*returns TRUE if a is an ID separator FALSE otherwise*/
|
|
#define _isIDSeparator(a) (a == '_' || a == '-')
|
|
|
|
|
|
/*******************************************************************************
|
|
API function definitions
|
|
*******************************************************************************/
|
|
|
|
|
|
const char* _findCharSeparator(const char* string)
|
|
{
|
|
if (string == NULL) return NULL;
|
|
/*Keeps iterating until an ID separator is found*/
|
|
while (*string && !_isIDSeparator(*string)) string++;
|
|
if (*string) return string;
|
|
else return NULL;
|
|
}
|
|
|
|
|
|
int16_t _findIndex(const char* list, int32_t listLength, const char* key)
|
|
{
|
|
const char* anchor = list;
|
|
const char* listEnd = anchor + listLength;
|
|
bool_t found = FALSE;
|
|
int index = 0;
|
|
int tokenSize = icu_strlen(list)+1; /*gets the size of the tokens*/
|
|
|
|
while (!found && list<listEnd)
|
|
{
|
|
if (icu_strcmp(key, list) == 0)
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
list += tokenSize;
|
|
}
|
|
if (found == TRUE) return ((list - anchor)/tokenSize);
|
|
else return -1;
|
|
}
|
|
|
|
const char* uloc_getDefault()
|
|
{
|
|
const char* result = _defaultLocale;
|
|
UErrorCode err = ZERO_ERROR;
|
|
|
|
/*lazy evaluates _defaultLocale*/
|
|
if (result == NULL)
|
|
{
|
|
uloc_setDefault(NULL, &err);
|
|
result = _defaultLocale;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void uloc_setDefault(const char* newDefaultLocale,
|
|
UErrorCode* err)
|
|
{
|
|
|
|
if (FAILURE(*err)) return;
|
|
/* the error code isn't currently used for anything by this function*/
|
|
|
|
if (newDefaultLocale == NULL)
|
|
{
|
|
newDefaultLocale = icu_getDefaultLocaleID();
|
|
}
|
|
|
|
umtx_lock(NULL);
|
|
if(_defaultLocale == NULL)
|
|
_defaultLocale = (char*)icu_malloc(sizeof(char) * (icu_strlen(newDefaultLocale) + 1));
|
|
else
|
|
_defaultLocale = (char*)icu_realloc(_defaultLocale,
|
|
sizeof(char) * (icu_strlen(newDefaultLocale) + 1));
|
|
icu_strcpy(_defaultLocale, newDefaultLocale);
|
|
umtx_unlock(NULL);
|
|
|
|
/* propagate change to C++ */
|
|
locale_set_default(newDefaultLocale);
|
|
}
|
|
|
|
|
|
int32_t uloc_getParent(const char* localeID,
|
|
char* parent,
|
|
int32_t parentCapacity,
|
|
UErrorCode* err)
|
|
{
|
|
int i=0;
|
|
int offset = 0;
|
|
int count = 0;
|
|
|
|
if (FAILURE(*err)) return 0;
|
|
|
|
if (localeID == NULL) localeID = uloc_getDefault();
|
|
|
|
|
|
while (localeID[offset]&&(count < 2))
|
|
{
|
|
if (_isIDSeparator(localeID[offset++])) count++;
|
|
}
|
|
|
|
/*finds the second IDSeparator*/
|
|
while (offset && !_isIDSeparator(localeID[offset])) offset--;
|
|
|
|
|
|
/*Loop updates i to the size of the parent
|
|
but only copies into the buffer as much as the buffer can bare*/
|
|
while (i < offset)
|
|
{
|
|
if (parentCapacity > i) parent[i] = localeID[i];
|
|
i++;
|
|
}
|
|
|
|
/*Sets the error code on case of need*/
|
|
if (i >= parentCapacity )
|
|
{
|
|
*err = BUFFER_OVERFLOW_ERROR;
|
|
}
|
|
|
|
if (parentCapacity>0) parent[icu_min(i,parentCapacity-1)] = '\0';
|
|
|
|
|
|
return i+1;
|
|
}
|
|
|
|
int32_t
|
|
uloc_getLanguage(const char* localeID,
|
|
char* language,
|
|
int32_t languageCapacity,
|
|
UErrorCode* err)
|
|
{
|
|
int i=0;
|
|
|
|
|
|
if (FAILURE(*err)) return 0;
|
|
|
|
if (localeID == NULL) localeID = uloc_getDefault();
|
|
|
|
/*Loop updates i to the size of the language
|
|
but only copies into the buffer as much as the buffer can bare*/
|
|
while ((*localeID != '\0') && !_isIDSeparator(*localeID))
|
|
{
|
|
if (languageCapacity > i) language[i] = tolower(*localeID);
|
|
i++;
|
|
localeID++;
|
|
}
|
|
|
|
if (i >= languageCapacity )
|
|
{
|
|
*err = BUFFER_OVERFLOW_ERROR;
|
|
}
|
|
|
|
if (languageCapacity > 0)
|
|
{
|
|
language[icu_min(i,languageCapacity-1)] = '\0';
|
|
/*We need to normalize for changes in ISO language names,
|
|
We special case out the recent ISO changes, translating them
|
|
internally to the old iso codes.*/
|
|
if (SUCCESS(*err))
|
|
{
|
|
if (icu_strcmp("he", language) == 0) icu_strcpy(language, "iw");
|
|
else if (icu_strcmp("yi", language) == 0) icu_strcpy(language, "ji");
|
|
else if (icu_strcmp("id", language) == 0) icu_strcpy(language, "in");
|
|
}
|
|
}
|
|
|
|
return i+1;
|
|
}
|
|
|
|
|
|
int32_t uloc_getCountry(const char* localeID,
|
|
char* country,
|
|
int32_t countryCapacity,
|
|
UErrorCode* err)
|
|
{
|
|
int i=0;
|
|
|
|
if (FAILURE(*err)) return 0;
|
|
if (localeID == NULL) localeID = uloc_getDefault();
|
|
|
|
localeID = _findCharSeparator(localeID);
|
|
|
|
/*Loop updates i to the size of the language
|
|
but only copies into the buffer as much as the buffer can bare*/
|
|
if (localeID)
|
|
{
|
|
++localeID;
|
|
while ((*localeID != '\0') && !_isIDSeparator(*localeID))
|
|
{
|
|
if (countryCapacity > i) country[i] = toupper(*localeID);
|
|
i++;
|
|
localeID++;
|
|
}
|
|
}
|
|
|
|
if (i >= countryCapacity )
|
|
{
|
|
*err = BUFFER_OVERFLOW_ERROR;
|
|
}
|
|
|
|
if (countryCapacity > 0) {country[icu_min(i,countryCapacity-1)] = '\0';}
|
|
return i+1;
|
|
}
|
|
|
|
int32_t uloc_getVariant(const char* localeID,
|
|
char* variant,
|
|
int32_t variantCapacity,
|
|
UErrorCode* err)
|
|
{
|
|
int i=0;
|
|
|
|
if (FAILURE(*err)) return 0;
|
|
if (localeID == NULL) localeID = uloc_getDefault();
|
|
|
|
localeID = _findCharSeparator(localeID);
|
|
if (localeID) localeID = _findCharSeparator(++localeID);
|
|
|
|
if (localeID)
|
|
{
|
|
++localeID;
|
|
/*Loop updates i to the size of the language
|
|
but only copies into the buffer as much as the buffer can bare*/
|
|
while (*localeID != '\0')
|
|
{
|
|
if (variantCapacity > i) variant[i] = toupper(*localeID);
|
|
i++;
|
|
localeID++;
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= variantCapacity )
|
|
{
|
|
*err = BUFFER_OVERFLOW_ERROR;
|
|
}
|
|
|
|
|
|
if (variantCapacity>0) {variant[icu_min(i,variantCapacity-1)] = '\0';}
|
|
return i+1;
|
|
}
|
|
|
|
int32_t uloc_getName(const char* localeID,
|
|
char* name,
|
|
int32_t nameCapacity,
|
|
UErrorCode* err)
|
|
{
|
|
int i= 0;
|
|
int varSze = 0;
|
|
int cntSze = 0;
|
|
UErrorCode int_err = ZERO_ERROR;
|
|
|
|
if (FAILURE(*err)) return 0;
|
|
/*First we preflight the components in order to ensure a valid return value*/
|
|
if (localeID == NULL) localeID = uloc_getDefault();
|
|
|
|
cntSze = uloc_getCountry(localeID,
|
|
NULL ,
|
|
0,
|
|
&int_err);
|
|
int_err = ZERO_ERROR;
|
|
varSze = uloc_getVariant(localeID,
|
|
NULL ,
|
|
0,
|
|
&int_err);
|
|
|
|
int_err = ZERO_ERROR;
|
|
i = uloc_getLanguage(localeID,
|
|
NULL,
|
|
0,
|
|
&int_err);
|
|
/*Adjust for the zero terminators*/
|
|
--varSze;
|
|
--cntSze;
|
|
|
|
if (cntSze) i++;
|
|
if (varSze) i++;
|
|
i += cntSze + varSze;
|
|
|
|
int_err = ZERO_ERROR;
|
|
|
|
uloc_getLanguage(localeID,
|
|
name,
|
|
nameCapacity,
|
|
&int_err);
|
|
|
|
/*We fill in the users buffer*/
|
|
if ((nameCapacity>0) && cntSze)
|
|
{
|
|
if (SUCCESS(int_err)) icu_strcat(name, "_");
|
|
|
|
uloc_getCountry(localeID,
|
|
name + icu_strlen(name),
|
|
nameCapacity - icu_strlen(name),
|
|
&int_err);
|
|
|
|
if (varSze)
|
|
{
|
|
if (SUCCESS(int_err)) icu_strcat(name, "_");
|
|
|
|
uloc_getVariant(localeID,
|
|
name + icu_strlen(name),
|
|
nameCapacity - icu_strlen(name),
|
|
&int_err);
|
|
}
|
|
|
|
}
|
|
*err = int_err;
|
|
|
|
return i;
|
|
}
|
|
|
|
const char* uloc_getISO3Language(const char* localeID)
|
|
{
|
|
int16_t index;
|
|
char lang[TEMPBUFSIZE];
|
|
UErrorCode err = ZERO_ERROR;
|
|
|
|
if (localeID == NULL) localeID = uloc_getDefault();
|
|
uloc_getLanguage(localeID, lang, TEMPBUFSIZE, &err);
|
|
if (FAILURE(err)) return "";
|
|
index = _findIndex(_languages, sizeof(_languages),lang);
|
|
if (index < 0) return "";
|
|
return &(_languages3[index * 4]);
|
|
}
|
|
|
|
const char* uloc_getISO3Country(const char* localeID)
|
|
{
|
|
int16_t index;
|
|
char cntry[TEMPBUFSIZE];
|
|
UErrorCode err = ZERO_ERROR;
|
|
|
|
if (localeID == NULL) localeID = uloc_getDefault();
|
|
uloc_getCountry(localeID, cntry, TEMPBUFSIZE, &err);
|
|
if (FAILURE(err)) return "";
|
|
index = _findIndex(_countries, sizeof(_countries), cntry);
|
|
if (index < 0) return "";
|
|
|
|
return &(_countries3[index * 4]);
|
|
}
|
|
|
|
uint32_t uloc_getLCID(const char* localeID)
|
|
{
|
|
UErrorCode err = ZERO_ERROR;
|
|
char temp[30];
|
|
const UChar* lcid = NULL;
|
|
uint32_t result = 0;
|
|
UResourceBundle* bundle = ures_open(uloc_getDataDirectory(), localeID, &err);
|
|
|
|
if (SUCCESS(err))
|
|
{
|
|
lcid = ures_get(bundle, _kLocaleID, &err);
|
|
ures_close(bundle);
|
|
if (FAILURE(err) || !lcid || u_strlen(lcid) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
u_austrcpy(temp, lcid);
|
|
result = (uint32_t)T_CString_stringToInteger(temp, 16);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int32_t uloc_getDisplayLanguage(const char* locale,
|
|
const char* inLocale,
|
|
UChar* language,
|
|
int32_t languageCapacity,
|
|
UErrorCode* status)
|
|
{
|
|
const UChar* result = NULL;
|
|
int32_t i = 0;
|
|
int langBufSize;
|
|
bool_t doneDefaultLocale = FALSE;
|
|
char inLanguageBuffer[TEMPBUFSIZE];
|
|
char inLocaleBuffer[TEMPBUFSIZE];
|
|
UErrorCode err = ZERO_ERROR;
|
|
UResourceBundle* bundle;
|
|
const UChar* temp = NULL;
|
|
bool_t isDefaultLocale = FALSE;
|
|
const char* dataDir = uloc_getDataDirectory();
|
|
bool_t done = FALSE;
|
|
|
|
if (FAILURE(*status)) return 0;
|
|
|
|
if (inLocale == NULL)
|
|
{
|
|
inLocale = uloc_getDefault();
|
|
isDefaultLocale = TRUE;
|
|
}
|
|
else if (icu_strcmp(inLocale, uloc_getDefault()) == 0) isDefaultLocale = TRUE;
|
|
/*truncates the fallback mechanism if we start out with a defaultLocale*/
|
|
|
|
if (locale == NULL) locale = uloc_getDefault();
|
|
|
|
/*extracts the language*/
|
|
langBufSize = uloc_getLanguage(locale,
|
|
inLanguageBuffer,
|
|
TEMPBUFSIZE,
|
|
&err);
|
|
|
|
|
|
|
|
/*We need to implement a fallback mechanism here because we are getting keys out of a
|
|
tagged array, there is no capability of doing this with fallback through the resource
|
|
bundle API*/
|
|
|
|
if (langBufSize > 1)
|
|
{
|
|
do
|
|
{
|
|
/*
|
|
If we are at the root locale ("")
|
|
The first time we fall back to the full default locale
|
|
As we iterate down the latter, if we hit the root locale ("")
|
|
we pass it to the resource bundle api so it checks default.txt
|
|
*/
|
|
|
|
if (inLocale[0] == '\0')
|
|
{
|
|
if (!isDefaultLocale)
|
|
{
|
|
isDefaultLocale = TRUE;
|
|
inLocale = uloc_getDefault();
|
|
}
|
|
else done = TRUE;
|
|
}
|
|
|
|
|
|
bundle = ures_open(dataDir, inLocale, &err);
|
|
|
|
if (SUCCESS(err))
|
|
{
|
|
UErrorCode err = ZERO_ERROR;
|
|
temp = ures_getTaggedArrayItem(bundle,
|
|
_kLanguages,
|
|
inLanguageBuffer,
|
|
&err);
|
|
if (SUCCESS(err)) result = temp;
|
|
ures_close(bundle);
|
|
}
|
|
|
|
|
|
err = ZERO_ERROR;
|
|
|
|
/*Iterates down the Locale ID*/
|
|
|
|
uloc_getParent(inLocale, inLocaleBuffer, TEMPBUFSIZE, &err);
|
|
inLocale = inLocaleBuffer;
|
|
|
|
} while ((result == NULL) && !done);
|
|
}
|
|
|
|
|
|
if (result)
|
|
{
|
|
i = u_strlen(result)+1;
|
|
if (i > languageCapacity)
|
|
{
|
|
*status = BUFFER_OVERFLOW_ERROR;
|
|
|
|
if (languageCapacity >= 1)
|
|
{
|
|
u_strncpy(language, result, languageCapacity-1);
|
|
language[languageCapacity-1] = (UChar)0x0000;
|
|
}
|
|
}
|
|
else u_strcpy(language, result);
|
|
}
|
|
else
|
|
{
|
|
/*Falls back to ISO Name*/
|
|
i = langBufSize;
|
|
if (i > languageCapacity)
|
|
{
|
|
*status = BUFFER_OVERFLOW_ERROR;
|
|
|
|
if (languageCapacity >= 1)
|
|
{
|
|
|
|
language[languageCapacity-1] = (UChar)0x0000;
|
|
u_uastrncpy(language, inLanguageBuffer, languageCapacity-1);
|
|
}
|
|
}
|
|
else u_uastrcpy(language, inLanguageBuffer);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int32_t uloc_getDisplayCountry(const char* locale,
|
|
const char* inLocale,
|
|
UChar* country,
|
|
int32_t countryCapacity,
|
|
UErrorCode* status)
|
|
{
|
|
/* NULL may be used to specify the default */
|
|
const UChar* result = NULL;
|
|
int32_t i = 0;
|
|
int cntryBufSize;
|
|
bool_t doneDefaultLocale = FALSE;
|
|
char inCountryBuffer[TEMPBUFSIZE];
|
|
UErrorCode err = ZERO_ERROR;
|
|
UResourceBundle* bundle = NULL;
|
|
char inLocaleBuffer[TEMPBUFSIZE];
|
|
bool_t isDefaultLocale = FALSE;
|
|
const char* dataDir = uloc_getDataDirectory();
|
|
bool_t done = FALSE;
|
|
|
|
if (FAILURE(*status)) return 0;
|
|
|
|
|
|
|
|
if (inLocale == NULL)
|
|
{
|
|
inLocale = uloc_getDefault();
|
|
isDefaultLocale = TRUE;
|
|
}
|
|
else if (icu_strcmp(inLocale, uloc_getDefault()) == 0) isDefaultLocale = TRUE;
|
|
/*truncates the fallback mechanism if we start out with a defaultLocale*/
|
|
|
|
if (locale == NULL) locale = uloc_getDefault();
|
|
|
|
/*extracts the country*/
|
|
cntryBufSize = uloc_getCountry(locale, inCountryBuffer, TEMPBUFSIZE, &err);
|
|
|
|
|
|
|
|
if (cntryBufSize > 1)
|
|
{
|
|
/*
|
|
We need to implement a fallback mechanism here because we are getting keys out of a
|
|
tagged array, there is no capability of doing this with fallback through the resource
|
|
bundle API
|
|
*/
|
|
do
|
|
{
|
|
/*
|
|
If we are at the root locale ("")
|
|
The first time we fall back to the full default locale
|
|
As we iterate down the latter, if we hit the root locale ("")
|
|
we pass it to the resource bundle api so it checks default.txt
|
|
*/
|
|
|
|
if (inLocale[0] == '\0')
|
|
{
|
|
if (!isDefaultLocale)
|
|
{
|
|
isDefaultLocale = TRUE;
|
|
inLocale = uloc_getDefault();
|
|
}
|
|
else done = TRUE;
|
|
}
|
|
|
|
|
|
bundle = ures_open(dataDir, inLocale, &err);
|
|
|
|
if (SUCCESS(err))
|
|
{
|
|
const UChar* temp;
|
|
|
|
temp = ures_getTaggedArrayItem(bundle,
|
|
_kCountries,
|
|
inCountryBuffer,
|
|
&err);
|
|
if (SUCCESS(err))
|
|
result = temp;
|
|
ures_close(bundle);
|
|
}
|
|
|
|
err = ZERO_ERROR;
|
|
uloc_getParent(inLocale, inLocaleBuffer, TEMPBUFSIZE, &err);
|
|
|
|
inLocale = inLocaleBuffer;
|
|
} while ((result == NULL) && !done);
|
|
}
|
|
|
|
if (result)
|
|
{
|
|
i = u_strlen(result)+1;
|
|
if (i > countryCapacity)
|
|
{
|
|
*status = BUFFER_OVERFLOW_ERROR;
|
|
|
|
if (countryCapacity >= 1)
|
|
{
|
|
country[countryCapacity-1] = (UChar)0x0000;
|
|
u_strncpy(country, result, countryCapacity-1);
|
|
}
|
|
}
|
|
else u_strcpy(country, result);
|
|
}
|
|
else
|
|
{
|
|
/*Falls back to ISO Name*/
|
|
i = cntryBufSize;
|
|
if (i > countryCapacity)
|
|
{
|
|
*status = BUFFER_OVERFLOW_ERROR;
|
|
|
|
if (countryCapacity >= 1)
|
|
{
|
|
u_uastrncpy(country, inCountryBuffer, countryCapacity-1);
|
|
country[countryCapacity-1] = (UChar)0x0000;
|
|
}
|
|
}
|
|
else u_uastrcpy(country, inCountryBuffer);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
int32_t uloc_getDisplayVariant(const char* locale,
|
|
const char* inLocale,
|
|
UChar* variant,
|
|
int32_t variantCapacity,
|
|
UErrorCode* status)
|
|
{
|
|
const UChar* result = NULL;
|
|
int32_t i = 0;
|
|
int varBufSize;
|
|
bool_t doneDefaultLocale = FALSE;
|
|
char inVariantBuffer[TEMPBUFSIZE];
|
|
char* inVariant = inVariantBuffer;
|
|
UErrorCode err = ZERO_ERROR;
|
|
UResourceBundle* bundle;
|
|
char inLocaleBuffer[TEMPBUFSIZE];
|
|
bool_t isDefaultLocale = FALSE;
|
|
char inVariantTagBuffer[TEMPBUFSIZE+2];
|
|
char* inVariantTag = inVariantTagBuffer;
|
|
const char* dataDir = uloc_getDataDirectory();
|
|
bool_t done = FALSE;
|
|
|
|
if (FAILURE(*status)) return 0;
|
|
|
|
inVariantTagBuffer[0] = '\0';
|
|
|
|
if (inLocale == NULL)
|
|
{
|
|
inLocale = uloc_getDefault();
|
|
isDefaultLocale = TRUE;
|
|
}
|
|
else if (icu_strcmp(inLocale, uloc_getDefault()) == 0) isDefaultLocale = TRUE;
|
|
/*truncates the fallback mechanism if we start out with a defaultLocale*/
|
|
|
|
if (locale == NULL) locale = uloc_getDefault();
|
|
|
|
/*extracts the variant*/
|
|
varBufSize = uloc_getVariant(locale, inVariant, TEMPBUFSIZE, &err);
|
|
|
|
if (varBufSize > 1)
|
|
{
|
|
/*In case the variant is longer than our stack buffers*/
|
|
if (err == BUFFER_OVERFLOW_ERROR)
|
|
{
|
|
inVariant = (char*)icu_malloc(varBufSize*sizeof(char)+1);
|
|
if (inVariant == NULL) goto NO_MEMORY;
|
|
inVariantTag = (char*)icu_malloc(varBufSize*sizeof(char)+icu_strlen("%%")+1);
|
|
if (inVariantTag == NULL)
|
|
{
|
|
icu_free(inVariant);
|
|
goto NO_MEMORY;
|
|
}
|
|
err = ZERO_ERROR;
|
|
uloc_getVariant(locale, inVariant, varBufSize, &err);
|
|
}
|
|
|
|
icu_strcpy(inVariantTag,"%%");
|
|
icu_strcat(inVariantTag, inVariant);
|
|
|
|
/*We need to implement a fallback mechanism here because we are getting keys out of a
|
|
tagged array, there is no capability of doing this with fallback through the resource
|
|
bundle API*/
|
|
do {
|
|
/*
|
|
If we are at the root locale ("")
|
|
The first time we fall back to the full default locale
|
|
As we iterate down the latter, if we hit the root locale ("")
|
|
we pass it to the resource bundle api so it checks default.txt
|
|
*/
|
|
|
|
if (inLocale[0] == '\0')
|
|
{
|
|
if (!isDefaultLocale)
|
|
{
|
|
isDefaultLocale = TRUE;
|
|
inLocale = uloc_getDefault();
|
|
}
|
|
else done = TRUE;
|
|
}
|
|
|
|
|
|
bundle = ures_open(dataDir, inLocale, &err);
|
|
|
|
if (SUCCESS(err))
|
|
{
|
|
const UChar* temp;
|
|
|
|
temp = ures_get(bundle,
|
|
inVariantTag,
|
|
&err);
|
|
if (SUCCESS(err)) result = temp;
|
|
ures_close(bundle);
|
|
}
|
|
|
|
err = ZERO_ERROR;
|
|
uloc_getParent(inLocale, inLocaleBuffer, TEMPBUFSIZE, &err);
|
|
|
|
inLocale = inLocaleBuffer;
|
|
} while ((result == NULL) && !done);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
if (result)
|
|
{
|
|
i = u_strlen(result)+1;
|
|
if (i > variantCapacity)
|
|
{
|
|
*status = BUFFER_OVERFLOW_ERROR;
|
|
|
|
if (variantCapacity >= 1)
|
|
{
|
|
variant[variantCapacity-1] = (UChar)0x0000;
|
|
u_strncpy(variant, result, variantCapacity-1);
|
|
}
|
|
}
|
|
else u_strcpy(variant, result);
|
|
}
|
|
else
|
|
{
|
|
/*Falls back to user's Name*/
|
|
i = varBufSize;
|
|
if (i > variantCapacity)
|
|
{
|
|
*status = BUFFER_OVERFLOW_ERROR;
|
|
|
|
if (variantCapacity >= 1)
|
|
{
|
|
u_uastrncpy(variant, inVariant, variantCapacity-1);
|
|
variant[variantCapacity-1] = (UChar)0x0000;
|
|
}
|
|
}
|
|
else u_uastrcpy(variant, inVariant);
|
|
}
|
|
|
|
/*Clean up memory*/
|
|
if (inVariant != inVariantBuffer)
|
|
{
|
|
icu_free(inVariant);
|
|
icu_free(inVariantTag);
|
|
}
|
|
return i;
|
|
|
|
NO_MEMORY:
|
|
*status = MEMORY_ALLOCATION_ERROR;
|
|
return 0;
|
|
}
|
|
|
|
int32_t uloc_getDisplayName(const char* locale,
|
|
const char* inLocale,
|
|
UChar* result,
|
|
int32_t nameCapacity,
|
|
UErrorCode* err)
|
|
{
|
|
UErrorCode int_err = ZERO_ERROR;
|
|
int i = 0;
|
|
int cntSze, varSze;
|
|
bool_t has_lang = TRUE;
|
|
int result_size;
|
|
|
|
int_err = ZERO_ERROR;
|
|
|
|
/*Preflights all the components*/
|
|
cntSze = uloc_getDisplayCountry(locale,
|
|
inLocale,
|
|
NULL ,
|
|
0,
|
|
&int_err);
|
|
int_err = ZERO_ERROR;
|
|
varSze = uloc_getDisplayVariant(locale,
|
|
inLocale,
|
|
NULL ,
|
|
0,
|
|
&int_err);
|
|
|
|
int_err = ZERO_ERROR;
|
|
i = uloc_getDisplayLanguage(locale,
|
|
inLocale,
|
|
NULL,
|
|
0,
|
|
&int_err);
|
|
/*Decrement duplicative zero-terminators*/
|
|
--varSze;
|
|
--cntSze;
|
|
|
|
/*Logic below adjusts pre-flight information with additional characters "(", ",", " ", ")"
|
|
when neeed be*/
|
|
if ((i-1 == 0) && (varSze == 0)) /*No language field*/
|
|
{
|
|
has_lang = FALSE;
|
|
i = cntSze+1;
|
|
}
|
|
else if (cntSze)
|
|
{
|
|
if (varSze) i += cntSze + varSze + 5;
|
|
else i += cntSze + 3;
|
|
}
|
|
|
|
int_err = ZERO_ERROR;
|
|
|
|
result_size = uloc_getDisplayLanguage(locale,
|
|
inLocale,
|
|
result,
|
|
nameCapacity,
|
|
&int_err) - 1;
|
|
|
|
if (SUCCESS(int_err)&&cntSze)
|
|
{
|
|
if (SUCCESS(int_err))
|
|
{
|
|
if (has_lang)
|
|
{
|
|
u_strcat(result, openParen);
|
|
result_size += 2;
|
|
}
|
|
|
|
result_size += uloc_getDisplayCountry(locale,
|
|
inLocale,
|
|
result + result_size,
|
|
nameCapacity - result_size,
|
|
&int_err) - 1;
|
|
}
|
|
|
|
if (varSze)
|
|
{
|
|
if (SUCCESS(int_err))
|
|
{
|
|
u_strcat(result, comma);
|
|
result_size += 2;
|
|
|
|
result_size += uloc_getDisplayVariant(locale,
|
|
inLocale,
|
|
result + result_size,
|
|
nameCapacity - result_size,
|
|
&int_err) - 1;
|
|
}
|
|
}
|
|
|
|
if (SUCCESS(int_err)&&has_lang) u_strcat(result, closeParen);
|
|
}
|
|
|
|
*err = int_err;
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a list of all available locales. The return value is a pointer to
|
|
* an array of pointers to ULocale objects. Both this array and the pointers
|
|
* it contains are owned by ICU and should not be deleted or written through
|
|
* by the caller. The array is terminated by a null pointer. RTG
|
|
*/
|
|
CAPI UnicodeString** T_ResourceBundle_listInstalledLocales(const char* path, int32_t* numInstalledLocales);
|
|
|
|
const char*
|
|
uloc_getAvailable(int32_t index)
|
|
{
|
|
|
|
if (_installedLocales == NULL) _lazyEvaluate_installedLocales();
|
|
|
|
if (index > _installedLocalesCount) return NULL;
|
|
else return _installedLocales[index];
|
|
|
|
}
|
|
|
|
int32_t uloc_countAvailable()
|
|
{
|
|
if (_installedLocales == NULL) _lazyEvaluate_installedLocales();
|
|
|
|
return _installedLocalesCount;
|
|
}
|
|
|
|
void _lazyEvaluate_installedLocales()
|
|
{
|
|
UnicodeString** temp;
|
|
char ** temp2;
|
|
int i;
|
|
if (_installedLocales == NULL)
|
|
{
|
|
temp = T_ResourceBundle_listInstalledLocales(uloc_getDataDirectory(),
|
|
&_installedLocalesCount);
|
|
temp2 = (char **) icu_malloc(sizeof(char*) * (_installedLocalesCount+1));
|
|
|
|
for (i = 0; i < _installedLocalesCount; i++)
|
|
{
|
|
temp2[i] = (char*) icu_malloc(sizeof(char) *
|
|
(u_strlen(T_UnicodeString_getUChars(temp[i])) + 1));
|
|
temp2[i] = u_austrcpy(temp2[i], T_UnicodeString_getUChars(temp[i]));
|
|
}
|
|
{
|
|
umtx_lock(NULL);
|
|
if (_installedLocales == NULL)
|
|
{
|
|
_installedLocales = temp2;
|
|
temp2 = NULL;
|
|
}
|
|
else {
|
|
for (i = 0; i < _installedLocalesCount; i++) icu_free(temp2[i]);
|
|
icu_free(temp2);
|
|
}
|
|
umtx_unlock(NULL);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all language codes defined in ISO 639. This is a pointer
|
|
* to an array of pointers to arrays of char. All of these pointers are owned
|
|
* by ICU-- do not delete them, and do not write through them. The array is
|
|
* terminated with a null pointer.
|
|
*/
|
|
const char* const* uloc_getISOLanguages()
|
|
{
|
|
const char *from, *end;
|
|
char **to;
|
|
|
|
if (_isoLanguages == NULL)
|
|
{
|
|
|
|
{
|
|
umtx_lock(NULL);
|
|
|
|
if (_isoLanguages == NULL)
|
|
{
|
|
_isoLanguages = (char**) icu_malloc(sizeof(char*)*(1+(sizeof(_languages) / 3)));
|
|
|
|
end = _languages + (sizeof(_languages));
|
|
from = _languages;
|
|
to = _isoLanguages;
|
|
|
|
while (from < end)
|
|
{
|
|
*to = (char*)from;
|
|
++to;
|
|
from += 3;
|
|
}
|
|
*to = NULL;
|
|
}
|
|
umtx_unlock(NULL);
|
|
}
|
|
}
|
|
return (const char* const*)_isoLanguages;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all 2-letter country codes defined in ISO 639. This is a
|
|
* pointer to an array of pointers to arrays of char. All of these pointers are
|
|
* owned by ICU-- do not delete them, and do not write through them. The array is
|
|
* terminated with a null pointer.
|
|
*/
|
|
const char* const* uloc_getISOCountries()
|
|
{
|
|
if (_isoCountries == NULL)
|
|
{
|
|
const char *from, *end;
|
|
char **to;
|
|
{
|
|
umtx_lock(NULL);
|
|
|
|
if (_isoCountries == NULL)
|
|
{
|
|
_isoCountries = (char**) icu_malloc(sizeof(char*)*(1+(sizeof(_countries) / 3)));
|
|
|
|
end = _countries + (sizeof(_countries));
|
|
from = _countries;
|
|
to = _isoCountries;
|
|
|
|
while (from < end)
|
|
{
|
|
*to = (char*)from;
|
|
++to;
|
|
from += 3;
|
|
}
|
|
*to = NULL;
|
|
}
|
|
umtx_unlock(NULL);
|
|
}
|
|
}
|
|
return (const char* const*)_isoCountries;
|
|
}
|
|
|
|
/**
|
|
* Functions to get and set the directory containing the locale data files.
|
|
*/
|
|
|
|
const char*
|
|
uloc_getDataDirectory()
|
|
{
|
|
if (_dataDirectory == NULL)
|
|
{
|
|
uloc_setDataDirectory(icu_getDefaultDataDirectory());
|
|
}
|
|
return _dataDirectory;
|
|
}
|
|
|
|
void
|
|
uloc_setDataDirectory(const char* newDirectory)
|
|
{
|
|
char* newDataDirectory = (char*) icu_malloc(sizeof(char)*(icu_strlen(newDirectory) + 1));
|
|
icu_strcpy(newDataDirectory, newDirectory);
|
|
|
|
{
|
|
umtx_lock(NULL);
|
|
|
|
if(_dataDirectory != NULL)
|
|
icu_free(_dataDirectory);
|
|
_dataDirectory = newDataDirectory;
|
|
if(_installedLocales != NULL)
|
|
icu_free(_installedLocales);
|
|
_installedLocales = NULL;
|
|
umtx_unlock(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|