scuffed-code/icu4c/source/common/uloc.c

1198 lines
32 KiB
C
Raw Normal View History

1999-08-16 21:50:52 +00:00
/*
*******************************************************************************
* *
* 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);
}
}