Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* |
michael@0 | 2 | ********************************************************************** |
michael@0 | 3 | * Copyright (C) 1997-2012, International Business Machines |
michael@0 | 4 | * Corporation and others. All Rights Reserved. |
michael@0 | 5 | ********************************************************************** |
michael@0 | 6 | * |
michael@0 | 7 | * File locid.cpp |
michael@0 | 8 | * |
michael@0 | 9 | * Created by: Richard Gillam |
michael@0 | 10 | * |
michael@0 | 11 | * Modification History: |
michael@0 | 12 | * |
michael@0 | 13 | * Date Name Description |
michael@0 | 14 | * 02/11/97 aliu Changed gLocPath to fgDataDirectory and added |
michael@0 | 15 | * methods to get and set it. |
michael@0 | 16 | * 04/02/97 aliu Made operator!= inline; fixed return value |
michael@0 | 17 | * of getName(). |
michael@0 | 18 | * 04/15/97 aliu Cleanup for AIX/Win32. |
michael@0 | 19 | * 04/24/97 aliu Numerous changes per code review. |
michael@0 | 20 | * 08/18/98 stephen Changed getDisplayName() |
michael@0 | 21 | * Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE |
michael@0 | 22 | * Added getISOCountries(), getISOLanguages(), |
michael@0 | 23 | * getLanguagesForCountry() |
michael@0 | 24 | * 03/16/99 bertrand rehaul. |
michael@0 | 25 | * 07/21/99 stephen Added U_CFUNC setDefault |
michael@0 | 26 | * 11/09/99 weiv Added const char * getName() const; |
michael@0 | 27 | * 04/12/00 srl removing unicodestring api's and cached hash code |
michael@0 | 28 | * 08/10/01 grhoten Change the static Locales to accessor functions |
michael@0 | 29 | ****************************************************************************** |
michael@0 | 30 | */ |
michael@0 | 31 | |
michael@0 | 32 | |
michael@0 | 33 | #include "unicode/locid.h" |
michael@0 | 34 | #include "unicode/uloc.h" |
michael@0 | 35 | #include "putilimp.h" |
michael@0 | 36 | #include "mutex.h" |
michael@0 | 37 | #include "umutex.h" |
michael@0 | 38 | #include "uassert.h" |
michael@0 | 39 | #include "cmemory.h" |
michael@0 | 40 | #include "cstring.h" |
michael@0 | 41 | #include "uhash.h" |
michael@0 | 42 | #include "ucln_cmn.h" |
michael@0 | 43 | #include "ustr_imp.h" |
michael@0 | 44 | |
michael@0 | 45 | #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) |
michael@0 | 46 | |
michael@0 | 47 | U_CDECL_BEGIN |
michael@0 | 48 | static UBool U_CALLCONV locale_cleanup(void); |
michael@0 | 49 | U_CDECL_END |
michael@0 | 50 | |
michael@0 | 51 | U_NAMESPACE_BEGIN |
michael@0 | 52 | |
michael@0 | 53 | static Locale *gLocaleCache = NULL; |
michael@0 | 54 | |
michael@0 | 55 | // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale. |
michael@0 | 56 | static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER; |
michael@0 | 57 | static UHashtable *gDefaultLocalesHashT = NULL; |
michael@0 | 58 | static Locale *gDefaultLocale = NULL; |
michael@0 | 59 | |
michael@0 | 60 | U_NAMESPACE_END |
michael@0 | 61 | |
michael@0 | 62 | typedef enum ELocalePos { |
michael@0 | 63 | eENGLISH, |
michael@0 | 64 | eFRENCH, |
michael@0 | 65 | eGERMAN, |
michael@0 | 66 | eITALIAN, |
michael@0 | 67 | eJAPANESE, |
michael@0 | 68 | eKOREAN, |
michael@0 | 69 | eCHINESE, |
michael@0 | 70 | |
michael@0 | 71 | eFRANCE, |
michael@0 | 72 | eGERMANY, |
michael@0 | 73 | eITALY, |
michael@0 | 74 | eJAPAN, |
michael@0 | 75 | eKOREA, |
michael@0 | 76 | eCHINA, /* Alias for PRC */ |
michael@0 | 77 | eTAIWAN, |
michael@0 | 78 | eUK, |
michael@0 | 79 | eUS, |
michael@0 | 80 | eCANADA, |
michael@0 | 81 | eCANADA_FRENCH, |
michael@0 | 82 | eROOT, |
michael@0 | 83 | |
michael@0 | 84 | |
michael@0 | 85 | //eDEFAULT, |
michael@0 | 86 | eMAX_LOCALES |
michael@0 | 87 | } ELocalePos; |
michael@0 | 88 | |
michael@0 | 89 | U_CFUNC int32_t locale_getKeywords(const char *localeID, |
michael@0 | 90 | char prev, |
michael@0 | 91 | char *keywords, int32_t keywordCapacity, |
michael@0 | 92 | char *values, int32_t valuesCapacity, int32_t *valLen, |
michael@0 | 93 | UBool valuesToo, |
michael@0 | 94 | UErrorCode *status); |
michael@0 | 95 | |
michael@0 | 96 | U_CDECL_BEGIN |
michael@0 | 97 | // |
michael@0 | 98 | // Deleter function for Locales owned by the default Locale hash table/ |
michael@0 | 99 | // |
michael@0 | 100 | static void U_CALLCONV |
michael@0 | 101 | deleteLocale(void *obj) { |
michael@0 | 102 | delete (icu::Locale *) obj; |
michael@0 | 103 | } |
michael@0 | 104 | |
michael@0 | 105 | static UBool U_CALLCONV locale_cleanup(void) |
michael@0 | 106 | { |
michael@0 | 107 | U_NAMESPACE_USE |
michael@0 | 108 | |
michael@0 | 109 | if (gLocaleCache) { |
michael@0 | 110 | delete [] gLocaleCache; |
michael@0 | 111 | gLocaleCache = NULL; |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | if (gDefaultLocalesHashT) { |
michael@0 | 115 | uhash_close(gDefaultLocalesHashT); // Automatically deletes all elements, using deleter func. |
michael@0 | 116 | gDefaultLocalesHashT = NULL; |
michael@0 | 117 | gDefaultLocale = NULL; |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | return TRUE; |
michael@0 | 121 | } |
michael@0 | 122 | U_CDECL_END |
michael@0 | 123 | |
michael@0 | 124 | U_NAMESPACE_BEGIN |
michael@0 | 125 | |
michael@0 | 126 | Locale *locale_set_default_internal(const char *id, UErrorCode& status) { |
michael@0 | 127 | // Synchronize this entire function. |
michael@0 | 128 | Mutex lock(&gDefaultLocaleMutex); |
michael@0 | 129 | |
michael@0 | 130 | UBool canonicalize = FALSE; |
michael@0 | 131 | |
michael@0 | 132 | // If given a NULL string for the locale id, grab the default |
michael@0 | 133 | // name from the system. |
michael@0 | 134 | // (Different from most other locale APIs, where a null name means use |
michael@0 | 135 | // the current ICU default locale.) |
michael@0 | 136 | if (id == NULL) { |
michael@0 | 137 | id = uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify. |
michael@0 | 138 | canonicalize = TRUE; // always canonicalize host ID |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | char localeNameBuf[512]; |
michael@0 | 142 | |
michael@0 | 143 | if (canonicalize) { |
michael@0 | 144 | uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status); |
michael@0 | 145 | } else { |
michael@0 | 146 | uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status); |
michael@0 | 147 | } |
michael@0 | 148 | localeNameBuf[sizeof(localeNameBuf)-1] = 0; // Force null termination in event of |
michael@0 | 149 | // a long name filling the buffer. |
michael@0 | 150 | // (long names are truncated.) |
michael@0 | 151 | // |
michael@0 | 152 | if (U_FAILURE(status)) { |
michael@0 | 153 | return gDefaultLocale; |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | if (gDefaultLocalesHashT == NULL) { |
michael@0 | 157 | gDefaultLocalesHashT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); |
michael@0 | 158 | if (U_FAILURE(status)) { |
michael@0 | 159 | return gDefaultLocale; |
michael@0 | 160 | } |
michael@0 | 161 | uhash_setValueDeleter(gDefaultLocalesHashT, deleteLocale); |
michael@0 | 162 | ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf); |
michael@0 | 166 | if (newDefault == NULL) { |
michael@0 | 167 | newDefault = new Locale(Locale::eBOGUS); |
michael@0 | 168 | if (newDefault == NULL) { |
michael@0 | 169 | status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 170 | return gDefaultLocale; |
michael@0 | 171 | } |
michael@0 | 172 | newDefault->init(localeNameBuf, FALSE); |
michael@0 | 173 | uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status); |
michael@0 | 174 | if (U_FAILURE(status)) { |
michael@0 | 175 | return gDefaultLocale; |
michael@0 | 176 | } |
michael@0 | 177 | } |
michael@0 | 178 | gDefaultLocale = newDefault; |
michael@0 | 179 | return gDefaultLocale; |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | U_NAMESPACE_END |
michael@0 | 183 | |
michael@0 | 184 | /* sfb 07/21/99 */ |
michael@0 | 185 | U_CFUNC void |
michael@0 | 186 | locale_set_default(const char *id) |
michael@0 | 187 | { |
michael@0 | 188 | U_NAMESPACE_USE |
michael@0 | 189 | UErrorCode status = U_ZERO_ERROR; |
michael@0 | 190 | locale_set_default_internal(id, status); |
michael@0 | 191 | } |
michael@0 | 192 | /* end */ |
michael@0 | 193 | |
michael@0 | 194 | U_CFUNC const char * |
michael@0 | 195 | locale_get_default(void) |
michael@0 | 196 | { |
michael@0 | 197 | U_NAMESPACE_USE |
michael@0 | 198 | return Locale::getDefault().getName(); |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | |
michael@0 | 202 | U_NAMESPACE_BEGIN |
michael@0 | 203 | |
michael@0 | 204 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale) |
michael@0 | 205 | |
michael@0 | 206 | /*Character separating the posix id fields*/ |
michael@0 | 207 | // '_' |
michael@0 | 208 | // In the platform codepage. |
michael@0 | 209 | #define SEP_CHAR '_' |
michael@0 | 210 | |
michael@0 | 211 | Locale::~Locale() |
michael@0 | 212 | { |
michael@0 | 213 | /*if fullName is on the heap, we free it*/ |
michael@0 | 214 | if (fullName != fullNameBuffer) |
michael@0 | 215 | { |
michael@0 | 216 | uprv_free(fullName); |
michael@0 | 217 | fullName = NULL; |
michael@0 | 218 | } |
michael@0 | 219 | if (baseName && baseName != baseNameBuffer) { |
michael@0 | 220 | uprv_free(baseName); |
michael@0 | 221 | baseName = NULL; |
michael@0 | 222 | } |
michael@0 | 223 | } |
michael@0 | 224 | |
michael@0 | 225 | Locale::Locale() |
michael@0 | 226 | : UObject(), fullName(fullNameBuffer), baseName(NULL) |
michael@0 | 227 | { |
michael@0 | 228 | init(NULL, FALSE); |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | /* |
michael@0 | 232 | * Internal constructor to allow construction of a locale object with |
michael@0 | 233 | * NO side effects. (Default constructor tries to get |
michael@0 | 234 | * the default locale.) |
michael@0 | 235 | */ |
michael@0 | 236 | Locale::Locale(Locale::ELocaleType) |
michael@0 | 237 | : UObject(), fullName(fullNameBuffer), baseName(NULL) |
michael@0 | 238 | { |
michael@0 | 239 | setToBogus(); |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | |
michael@0 | 243 | Locale::Locale( const char * newLanguage, |
michael@0 | 244 | const char * newCountry, |
michael@0 | 245 | const char * newVariant, |
michael@0 | 246 | const char * newKeywords) |
michael@0 | 247 | : UObject(), fullName(fullNameBuffer), baseName(NULL) |
michael@0 | 248 | { |
michael@0 | 249 | if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) ) |
michael@0 | 250 | { |
michael@0 | 251 | init(NULL, FALSE); /* shortcut */ |
michael@0 | 252 | } |
michael@0 | 253 | else |
michael@0 | 254 | { |
michael@0 | 255 | MaybeStackArray<char, ULOC_FULLNAME_CAPACITY> togo; |
michael@0 | 256 | int32_t size = 0; |
michael@0 | 257 | int32_t lsize = 0; |
michael@0 | 258 | int32_t csize = 0; |
michael@0 | 259 | int32_t vsize = 0; |
michael@0 | 260 | int32_t ksize = 0; |
michael@0 | 261 | char *p; |
michael@0 | 262 | |
michael@0 | 263 | // Calculate the size of the resulting string. |
michael@0 | 264 | |
michael@0 | 265 | // Language |
michael@0 | 266 | if ( newLanguage != NULL ) |
michael@0 | 267 | { |
michael@0 | 268 | lsize = (int32_t)uprv_strlen(newLanguage); |
michael@0 | 269 | size = lsize; |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | // _Country |
michael@0 | 273 | if ( newCountry != NULL ) |
michael@0 | 274 | { |
michael@0 | 275 | csize = (int32_t)uprv_strlen(newCountry); |
michael@0 | 276 | size += csize; |
michael@0 | 277 | } |
michael@0 | 278 | |
michael@0 | 279 | // _Variant |
michael@0 | 280 | if ( newVariant != NULL ) |
michael@0 | 281 | { |
michael@0 | 282 | // remove leading _'s |
michael@0 | 283 | while(newVariant[0] == SEP_CHAR) |
michael@0 | 284 | { |
michael@0 | 285 | newVariant++; |
michael@0 | 286 | } |
michael@0 | 287 | |
michael@0 | 288 | // remove trailing _'s |
michael@0 | 289 | vsize = (int32_t)uprv_strlen(newVariant); |
michael@0 | 290 | while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) ) |
michael@0 | 291 | { |
michael@0 | 292 | vsize--; |
michael@0 | 293 | } |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | if( vsize > 0 ) |
michael@0 | 297 | { |
michael@0 | 298 | size += vsize; |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | // Separator rules: |
michael@0 | 302 | if ( vsize > 0 ) |
michael@0 | 303 | { |
michael@0 | 304 | size += 2; // at least: __v |
michael@0 | 305 | } |
michael@0 | 306 | else if ( csize > 0 ) |
michael@0 | 307 | { |
michael@0 | 308 | size += 1; // at least: _v |
michael@0 | 309 | } |
michael@0 | 310 | |
michael@0 | 311 | if ( newKeywords != NULL) |
michael@0 | 312 | { |
michael@0 | 313 | ksize = (int32_t)uprv_strlen(newKeywords); |
michael@0 | 314 | size += ksize + 1; |
michael@0 | 315 | } |
michael@0 | 316 | |
michael@0 | 317 | |
michael@0 | 318 | // NOW we have the full locale string.. |
michael@0 | 319 | |
michael@0 | 320 | /*if the whole string is longer than our internal limit, we need |
michael@0 | 321 | to go to the heap for temporary buffers*/ |
michael@0 | 322 | if (size >= togo.getCapacity()) |
michael@0 | 323 | { |
michael@0 | 324 | // If togo_heap could not be created, initialize with default settings. |
michael@0 | 325 | if (togo.resize(size+1) == NULL) { |
michael@0 | 326 | init(NULL, FALSE); |
michael@0 | 327 | } |
michael@0 | 328 | } |
michael@0 | 329 | |
michael@0 | 330 | togo[0] = 0; |
michael@0 | 331 | |
michael@0 | 332 | // Now, copy it back. |
michael@0 | 333 | p = togo.getAlias(); |
michael@0 | 334 | if ( lsize != 0 ) |
michael@0 | 335 | { |
michael@0 | 336 | uprv_strcpy(p, newLanguage); |
michael@0 | 337 | p += lsize; |
michael@0 | 338 | } |
michael@0 | 339 | |
michael@0 | 340 | if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v |
michael@0 | 341 | { // ^ |
michael@0 | 342 | *p++ = SEP_CHAR; |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | if ( csize != 0 ) |
michael@0 | 346 | { |
michael@0 | 347 | uprv_strcpy(p, newCountry); |
michael@0 | 348 | p += csize; |
michael@0 | 349 | } |
michael@0 | 350 | |
michael@0 | 351 | if ( vsize != 0) |
michael@0 | 352 | { |
michael@0 | 353 | *p++ = SEP_CHAR; // at least: __v |
michael@0 | 354 | |
michael@0 | 355 | uprv_strncpy(p, newVariant, vsize); // Must use strncpy because |
michael@0 | 356 | p += vsize; // of trimming (above). |
michael@0 | 357 | *p = 0; // terminate |
michael@0 | 358 | } |
michael@0 | 359 | |
michael@0 | 360 | if ( ksize != 0) |
michael@0 | 361 | { |
michael@0 | 362 | if (uprv_strchr(newKeywords, '=')) { |
michael@0 | 363 | *p++ = '@'; /* keyword parsing */ |
michael@0 | 364 | } |
michael@0 | 365 | else { |
michael@0 | 366 | *p++ = '_'; /* Variant parsing with a script */ |
michael@0 | 367 | if ( vsize == 0) { |
michael@0 | 368 | *p++ = '_'; /* No country found */ |
michael@0 | 369 | } |
michael@0 | 370 | } |
michael@0 | 371 | uprv_strcpy(p, newKeywords); |
michael@0 | 372 | p += ksize; |
michael@0 | 373 | } |
michael@0 | 374 | |
michael@0 | 375 | // Parse it, because for example 'language' might really be a complete |
michael@0 | 376 | // string. |
michael@0 | 377 | init(togo.getAlias(), FALSE); |
michael@0 | 378 | } |
michael@0 | 379 | } |
michael@0 | 380 | |
michael@0 | 381 | Locale::Locale(const Locale &other) |
michael@0 | 382 | : UObject(other), fullName(fullNameBuffer), baseName(NULL) |
michael@0 | 383 | { |
michael@0 | 384 | *this = other; |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | Locale &Locale::operator=(const Locale &other) |
michael@0 | 388 | { |
michael@0 | 389 | if (this == &other) { |
michael@0 | 390 | return *this; |
michael@0 | 391 | } |
michael@0 | 392 | |
michael@0 | 393 | if (&other == NULL) { |
michael@0 | 394 | this->setToBogus(); |
michael@0 | 395 | return *this; |
michael@0 | 396 | } |
michael@0 | 397 | |
michael@0 | 398 | /* Free our current storage */ |
michael@0 | 399 | if(fullName != fullNameBuffer) { |
michael@0 | 400 | uprv_free(fullName); |
michael@0 | 401 | fullName = fullNameBuffer; |
michael@0 | 402 | } |
michael@0 | 403 | |
michael@0 | 404 | /* Allocate the full name if necessary */ |
michael@0 | 405 | if(other.fullName != other.fullNameBuffer) { |
michael@0 | 406 | fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1)); |
michael@0 | 407 | if (fullName == NULL) { |
michael@0 | 408 | return *this; |
michael@0 | 409 | } |
michael@0 | 410 | } |
michael@0 | 411 | /* Copy the full name */ |
michael@0 | 412 | uprv_strcpy(fullName, other.fullName); |
michael@0 | 413 | |
michael@0 | 414 | /* baseName is the cached result of getBaseName. if 'other' has a |
michael@0 | 415 | baseName and it fits in baseNameBuffer, then copy it. otherwise set |
michael@0 | 416 | it to NULL, and let the user lazy-create it (in getBaseName) if they |
michael@0 | 417 | want it. */ |
michael@0 | 418 | if(baseName && baseName != baseNameBuffer) { |
michael@0 | 419 | uprv_free(baseName); |
michael@0 | 420 | } |
michael@0 | 421 | baseName = NULL; |
michael@0 | 422 | |
michael@0 | 423 | if(other.baseName == other.baseNameBuffer) { |
michael@0 | 424 | uprv_strcpy(baseNameBuffer, other.baseNameBuffer); |
michael@0 | 425 | baseName = baseNameBuffer; |
michael@0 | 426 | } |
michael@0 | 427 | |
michael@0 | 428 | /* Copy the language and country fields */ |
michael@0 | 429 | uprv_strcpy(language, other.language); |
michael@0 | 430 | uprv_strcpy(script, other.script); |
michael@0 | 431 | uprv_strcpy(country, other.country); |
michael@0 | 432 | |
michael@0 | 433 | /* The variantBegin is an offset, just copy it */ |
michael@0 | 434 | variantBegin = other.variantBegin; |
michael@0 | 435 | fIsBogus = other.fIsBogus; |
michael@0 | 436 | return *this; |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | Locale * |
michael@0 | 440 | Locale::clone() const { |
michael@0 | 441 | return new Locale(*this); |
michael@0 | 442 | } |
michael@0 | 443 | |
michael@0 | 444 | UBool |
michael@0 | 445 | Locale::operator==( const Locale& other) const |
michael@0 | 446 | { |
michael@0 | 447 | return (uprv_strcmp(other.fullName, fullName) == 0); |
michael@0 | 448 | } |
michael@0 | 449 | |
michael@0 | 450 | #define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) |
michael@0 | 451 | |
michael@0 | 452 | /*This function initializes a Locale from a C locale ID*/ |
michael@0 | 453 | Locale& Locale::init(const char* localeID, UBool canonicalize) |
michael@0 | 454 | { |
michael@0 | 455 | fIsBogus = FALSE; |
michael@0 | 456 | /* Free our current storage */ |
michael@0 | 457 | if(fullName != fullNameBuffer) { |
michael@0 | 458 | uprv_free(fullName); |
michael@0 | 459 | fullName = fullNameBuffer; |
michael@0 | 460 | } |
michael@0 | 461 | |
michael@0 | 462 | if(baseName && baseName != baseNameBuffer) { |
michael@0 | 463 | uprv_free(baseName); |
michael@0 | 464 | baseName = NULL; |
michael@0 | 465 | } |
michael@0 | 466 | |
michael@0 | 467 | // not a loop: |
michael@0 | 468 | // just an easy way to have a common error-exit |
michael@0 | 469 | // without goto and without another function |
michael@0 | 470 | do { |
michael@0 | 471 | char *separator; |
michael@0 | 472 | char *field[5] = {0}; |
michael@0 | 473 | int32_t fieldLen[5] = {0}; |
michael@0 | 474 | int32_t fieldIdx; |
michael@0 | 475 | int32_t variantField; |
michael@0 | 476 | int32_t length; |
michael@0 | 477 | UErrorCode err; |
michael@0 | 478 | |
michael@0 | 479 | if(localeID == NULL) { |
michael@0 | 480 | // not an error, just set the default locale |
michael@0 | 481 | return *this = getDefault(); |
michael@0 | 482 | } |
michael@0 | 483 | |
michael@0 | 484 | /* preset all fields to empty */ |
michael@0 | 485 | language[0] = script[0] = country[0] = 0; |
michael@0 | 486 | |
michael@0 | 487 | // "canonicalize" the locale ID to ICU/Java format |
michael@0 | 488 | err = U_ZERO_ERROR; |
michael@0 | 489 | length = canonicalize ? |
michael@0 | 490 | uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) : |
michael@0 | 491 | uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err); |
michael@0 | 492 | |
michael@0 | 493 | if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) { |
michael@0 | 494 | /*Go to heap for the fullName if necessary*/ |
michael@0 | 495 | fullName = (char *)uprv_malloc(sizeof(char)*(length + 1)); |
michael@0 | 496 | if(fullName == 0) { |
michael@0 | 497 | fullName = fullNameBuffer; |
michael@0 | 498 | break; // error: out of memory |
michael@0 | 499 | } |
michael@0 | 500 | err = U_ZERO_ERROR; |
michael@0 | 501 | length = canonicalize ? |
michael@0 | 502 | uloc_canonicalize(localeID, fullName, length+1, &err) : |
michael@0 | 503 | uloc_getName(localeID, fullName, length+1, &err); |
michael@0 | 504 | } |
michael@0 | 505 | if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) { |
michael@0 | 506 | /* should never occur */ |
michael@0 | 507 | break; |
michael@0 | 508 | } |
michael@0 | 509 | |
michael@0 | 510 | variantBegin = length; |
michael@0 | 511 | |
michael@0 | 512 | /* after uloc_getName/canonicalize() we know that only '_' are separators */ |
michael@0 | 513 | separator = field[0] = fullName; |
michael@0 | 514 | fieldIdx = 1; |
michael@0 | 515 | while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < (int32_t)(sizeof(field)/sizeof(field[0]))-1) { |
michael@0 | 516 | field[fieldIdx] = separator + 1; |
michael@0 | 517 | fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]); |
michael@0 | 518 | fieldIdx++; |
michael@0 | 519 | } |
michael@0 | 520 | // variant may contain @foo or .foo POSIX cruft; remove it |
michael@0 | 521 | separator = uprv_strchr(field[fieldIdx-1], '@'); |
michael@0 | 522 | char* sep2 = uprv_strchr(field[fieldIdx-1], '.'); |
michael@0 | 523 | if (separator!=NULL || sep2!=NULL) { |
michael@0 | 524 | if (separator==NULL || (sep2!=NULL && separator > sep2)) { |
michael@0 | 525 | separator = sep2; |
michael@0 | 526 | } |
michael@0 | 527 | fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]); |
michael@0 | 528 | } else { |
michael@0 | 529 | fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName); |
michael@0 | 530 | } |
michael@0 | 531 | |
michael@0 | 532 | if (fieldLen[0] >= (int32_t)(sizeof(language))) |
michael@0 | 533 | { |
michael@0 | 534 | break; // error: the language field is too long |
michael@0 | 535 | } |
michael@0 | 536 | |
michael@0 | 537 | variantField = 1; /* Usually the 2nd one, except when a script or country is also used. */ |
michael@0 | 538 | if (fieldLen[0] > 0) { |
michael@0 | 539 | /* We have a language */ |
michael@0 | 540 | uprv_memcpy(language, fullName, fieldLen[0]); |
michael@0 | 541 | language[fieldLen[0]] = 0; |
michael@0 | 542 | } |
michael@0 | 543 | if (fieldLen[1] == 4 && ISASCIIALPHA(field[1][0]) && |
michael@0 | 544 | ISASCIIALPHA(field[1][1]) && ISASCIIALPHA(field[1][2]) && |
michael@0 | 545 | ISASCIIALPHA(field[1][3])) { |
michael@0 | 546 | /* We have at least a script */ |
michael@0 | 547 | uprv_memcpy(script, field[1], fieldLen[1]); |
michael@0 | 548 | script[fieldLen[1]] = 0; |
michael@0 | 549 | variantField++; |
michael@0 | 550 | } |
michael@0 | 551 | |
michael@0 | 552 | if (fieldLen[variantField] == 2 || fieldLen[variantField] == 3) { |
michael@0 | 553 | /* We have a country */ |
michael@0 | 554 | uprv_memcpy(country, field[variantField], fieldLen[variantField]); |
michael@0 | 555 | country[fieldLen[variantField]] = 0; |
michael@0 | 556 | variantField++; |
michael@0 | 557 | } else if (fieldLen[variantField] == 0) { |
michael@0 | 558 | variantField++; /* script or country empty but variant in next field (i.e. en__POSIX) */ |
michael@0 | 559 | } |
michael@0 | 560 | |
michael@0 | 561 | if (fieldLen[variantField] > 0) { |
michael@0 | 562 | /* We have a variant */ |
michael@0 | 563 | variantBegin = (int32_t)(field[variantField] - fullName); |
michael@0 | 564 | } |
michael@0 | 565 | |
michael@0 | 566 | // successful end of init() |
michael@0 | 567 | return *this; |
michael@0 | 568 | } while(0); /*loop doesn't iterate*/ |
michael@0 | 569 | |
michael@0 | 570 | // when an error occurs, then set this object to "bogus" (there is no UErrorCode here) |
michael@0 | 571 | setToBogus(); |
michael@0 | 572 | |
michael@0 | 573 | return *this; |
michael@0 | 574 | } |
michael@0 | 575 | |
michael@0 | 576 | int32_t |
michael@0 | 577 | Locale::hashCode() const |
michael@0 | 578 | { |
michael@0 | 579 | return ustr_hashCharsN(fullName, uprv_strlen(fullName)); |
michael@0 | 580 | } |
michael@0 | 581 | |
michael@0 | 582 | void |
michael@0 | 583 | Locale::setToBogus() { |
michael@0 | 584 | /* Free our current storage */ |
michael@0 | 585 | if(fullName != fullNameBuffer) { |
michael@0 | 586 | uprv_free(fullName); |
michael@0 | 587 | fullName = fullNameBuffer; |
michael@0 | 588 | } |
michael@0 | 589 | if(baseName && baseName != baseNameBuffer) { |
michael@0 | 590 | uprv_free(baseName); |
michael@0 | 591 | baseName = NULL; |
michael@0 | 592 | } |
michael@0 | 593 | *fullNameBuffer = 0; |
michael@0 | 594 | *language = 0; |
michael@0 | 595 | *script = 0; |
michael@0 | 596 | *country = 0; |
michael@0 | 597 | fIsBogus = TRUE; |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | const Locale& U_EXPORT2 |
michael@0 | 601 | Locale::getDefault() |
michael@0 | 602 | { |
michael@0 | 603 | { |
michael@0 | 604 | Mutex lock(&gDefaultLocaleMutex); |
michael@0 | 605 | if (gDefaultLocale != NULL) { |
michael@0 | 606 | return *gDefaultLocale; |
michael@0 | 607 | } |
michael@0 | 608 | } |
michael@0 | 609 | UErrorCode status = U_ZERO_ERROR; |
michael@0 | 610 | return *locale_set_default_internal(NULL, status); |
michael@0 | 611 | } |
michael@0 | 612 | |
michael@0 | 613 | |
michael@0 | 614 | |
michael@0 | 615 | void U_EXPORT2 |
michael@0 | 616 | Locale::setDefault( const Locale& newLocale, |
michael@0 | 617 | UErrorCode& status) |
michael@0 | 618 | { |
michael@0 | 619 | if (U_FAILURE(status)) { |
michael@0 | 620 | return; |
michael@0 | 621 | } |
michael@0 | 622 | |
michael@0 | 623 | /* Set the default from the full name string of the supplied locale. |
michael@0 | 624 | * This is a convenient way to access the default locale caching mechanisms. |
michael@0 | 625 | */ |
michael@0 | 626 | const char *localeID = newLocale.getName(); |
michael@0 | 627 | locale_set_default_internal(localeID, status); |
michael@0 | 628 | } |
michael@0 | 629 | |
michael@0 | 630 | Locale U_EXPORT2 |
michael@0 | 631 | Locale::createFromName (const char *name) |
michael@0 | 632 | { |
michael@0 | 633 | if (name) { |
michael@0 | 634 | Locale l(""); |
michael@0 | 635 | l.init(name, FALSE); |
michael@0 | 636 | return l; |
michael@0 | 637 | } |
michael@0 | 638 | else { |
michael@0 | 639 | return getDefault(); |
michael@0 | 640 | } |
michael@0 | 641 | } |
michael@0 | 642 | |
michael@0 | 643 | Locale U_EXPORT2 |
michael@0 | 644 | Locale::createCanonical(const char* name) { |
michael@0 | 645 | Locale loc(""); |
michael@0 | 646 | loc.init(name, TRUE); |
michael@0 | 647 | return loc; |
michael@0 | 648 | } |
michael@0 | 649 | |
michael@0 | 650 | const char * |
michael@0 | 651 | Locale::getISO3Language() const |
michael@0 | 652 | { |
michael@0 | 653 | return uloc_getISO3Language(fullName); |
michael@0 | 654 | } |
michael@0 | 655 | |
michael@0 | 656 | |
michael@0 | 657 | const char * |
michael@0 | 658 | Locale::getISO3Country() const |
michael@0 | 659 | { |
michael@0 | 660 | return uloc_getISO3Country(fullName); |
michael@0 | 661 | } |
michael@0 | 662 | |
michael@0 | 663 | /** |
michael@0 | 664 | * Return the LCID value as specified in the "LocaleID" resource for this |
michael@0 | 665 | * locale. The LocaleID must be expressed as a hexadecimal number, from |
michael@0 | 666 | * one to four digits. If the LocaleID resource is not present, or is |
michael@0 | 667 | * in an incorrect format, 0 is returned. The LocaleID is for use in |
michael@0 | 668 | * Windows (it is an LCID), but is available on all platforms. |
michael@0 | 669 | */ |
michael@0 | 670 | uint32_t |
michael@0 | 671 | Locale::getLCID() const |
michael@0 | 672 | { |
michael@0 | 673 | return uloc_getLCID(fullName); |
michael@0 | 674 | } |
michael@0 | 675 | |
michael@0 | 676 | const char* const* U_EXPORT2 Locale::getISOCountries() |
michael@0 | 677 | { |
michael@0 | 678 | return uloc_getISOCountries(); |
michael@0 | 679 | } |
michael@0 | 680 | |
michael@0 | 681 | const char* const* U_EXPORT2 Locale::getISOLanguages() |
michael@0 | 682 | { |
michael@0 | 683 | return uloc_getISOLanguages(); |
michael@0 | 684 | } |
michael@0 | 685 | |
michael@0 | 686 | // Set the locale's data based on a posix id. |
michael@0 | 687 | void Locale::setFromPOSIXID(const char *posixID) |
michael@0 | 688 | { |
michael@0 | 689 | init(posixID, TRUE); |
michael@0 | 690 | } |
michael@0 | 691 | |
michael@0 | 692 | const Locale & U_EXPORT2 |
michael@0 | 693 | Locale::getRoot(void) |
michael@0 | 694 | { |
michael@0 | 695 | return getLocale(eROOT); |
michael@0 | 696 | } |
michael@0 | 697 | |
michael@0 | 698 | const Locale & U_EXPORT2 |
michael@0 | 699 | Locale::getEnglish(void) |
michael@0 | 700 | { |
michael@0 | 701 | return getLocale(eENGLISH); |
michael@0 | 702 | } |
michael@0 | 703 | |
michael@0 | 704 | const Locale & U_EXPORT2 |
michael@0 | 705 | Locale::getFrench(void) |
michael@0 | 706 | { |
michael@0 | 707 | return getLocale(eFRENCH); |
michael@0 | 708 | } |
michael@0 | 709 | |
michael@0 | 710 | const Locale & U_EXPORT2 |
michael@0 | 711 | Locale::getGerman(void) |
michael@0 | 712 | { |
michael@0 | 713 | return getLocale(eGERMAN); |
michael@0 | 714 | } |
michael@0 | 715 | |
michael@0 | 716 | const Locale & U_EXPORT2 |
michael@0 | 717 | Locale::getItalian(void) |
michael@0 | 718 | { |
michael@0 | 719 | return getLocale(eITALIAN); |
michael@0 | 720 | } |
michael@0 | 721 | |
michael@0 | 722 | const Locale & U_EXPORT2 |
michael@0 | 723 | Locale::getJapanese(void) |
michael@0 | 724 | { |
michael@0 | 725 | return getLocale(eJAPANESE); |
michael@0 | 726 | } |
michael@0 | 727 | |
michael@0 | 728 | const Locale & U_EXPORT2 |
michael@0 | 729 | Locale::getKorean(void) |
michael@0 | 730 | { |
michael@0 | 731 | return getLocale(eKOREAN); |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | const Locale & U_EXPORT2 |
michael@0 | 735 | Locale::getChinese(void) |
michael@0 | 736 | { |
michael@0 | 737 | return getLocale(eCHINESE); |
michael@0 | 738 | } |
michael@0 | 739 | |
michael@0 | 740 | const Locale & U_EXPORT2 |
michael@0 | 741 | Locale::getSimplifiedChinese(void) |
michael@0 | 742 | { |
michael@0 | 743 | return getLocale(eCHINA); |
michael@0 | 744 | } |
michael@0 | 745 | |
michael@0 | 746 | const Locale & U_EXPORT2 |
michael@0 | 747 | Locale::getTraditionalChinese(void) |
michael@0 | 748 | { |
michael@0 | 749 | return getLocale(eTAIWAN); |
michael@0 | 750 | } |
michael@0 | 751 | |
michael@0 | 752 | |
michael@0 | 753 | const Locale & U_EXPORT2 |
michael@0 | 754 | Locale::getFrance(void) |
michael@0 | 755 | { |
michael@0 | 756 | return getLocale(eFRANCE); |
michael@0 | 757 | } |
michael@0 | 758 | |
michael@0 | 759 | const Locale & U_EXPORT2 |
michael@0 | 760 | Locale::getGermany(void) |
michael@0 | 761 | { |
michael@0 | 762 | return getLocale(eGERMANY); |
michael@0 | 763 | } |
michael@0 | 764 | |
michael@0 | 765 | const Locale & U_EXPORT2 |
michael@0 | 766 | Locale::getItaly(void) |
michael@0 | 767 | { |
michael@0 | 768 | return getLocale(eITALY); |
michael@0 | 769 | } |
michael@0 | 770 | |
michael@0 | 771 | const Locale & U_EXPORT2 |
michael@0 | 772 | Locale::getJapan(void) |
michael@0 | 773 | { |
michael@0 | 774 | return getLocale(eJAPAN); |
michael@0 | 775 | } |
michael@0 | 776 | |
michael@0 | 777 | const Locale & U_EXPORT2 |
michael@0 | 778 | Locale::getKorea(void) |
michael@0 | 779 | { |
michael@0 | 780 | return getLocale(eKOREA); |
michael@0 | 781 | } |
michael@0 | 782 | |
michael@0 | 783 | const Locale & U_EXPORT2 |
michael@0 | 784 | Locale::getChina(void) |
michael@0 | 785 | { |
michael@0 | 786 | return getLocale(eCHINA); |
michael@0 | 787 | } |
michael@0 | 788 | |
michael@0 | 789 | const Locale & U_EXPORT2 |
michael@0 | 790 | Locale::getPRC(void) |
michael@0 | 791 | { |
michael@0 | 792 | return getLocale(eCHINA); |
michael@0 | 793 | } |
michael@0 | 794 | |
michael@0 | 795 | const Locale & U_EXPORT2 |
michael@0 | 796 | Locale::getTaiwan(void) |
michael@0 | 797 | { |
michael@0 | 798 | return getLocale(eTAIWAN); |
michael@0 | 799 | } |
michael@0 | 800 | |
michael@0 | 801 | const Locale & U_EXPORT2 |
michael@0 | 802 | Locale::getUK(void) |
michael@0 | 803 | { |
michael@0 | 804 | return getLocale(eUK); |
michael@0 | 805 | } |
michael@0 | 806 | |
michael@0 | 807 | const Locale & U_EXPORT2 |
michael@0 | 808 | Locale::getUS(void) |
michael@0 | 809 | { |
michael@0 | 810 | return getLocale(eUS); |
michael@0 | 811 | } |
michael@0 | 812 | |
michael@0 | 813 | const Locale & U_EXPORT2 |
michael@0 | 814 | Locale::getCanada(void) |
michael@0 | 815 | { |
michael@0 | 816 | return getLocale(eCANADA); |
michael@0 | 817 | } |
michael@0 | 818 | |
michael@0 | 819 | const Locale & U_EXPORT2 |
michael@0 | 820 | Locale::getCanadaFrench(void) |
michael@0 | 821 | { |
michael@0 | 822 | return getLocale(eCANADA_FRENCH); |
michael@0 | 823 | } |
michael@0 | 824 | |
michael@0 | 825 | const Locale & |
michael@0 | 826 | Locale::getLocale(int locid) |
michael@0 | 827 | { |
michael@0 | 828 | Locale *localeCache = getLocaleCache(); |
michael@0 | 829 | U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0)); |
michael@0 | 830 | if (localeCache == NULL) { |
michael@0 | 831 | // Failure allocating the locale cache. |
michael@0 | 832 | // The best we can do is return a NULL reference. |
michael@0 | 833 | locid = 0; |
michael@0 | 834 | } |
michael@0 | 835 | return localeCache[locid]; /*operating on NULL*/ |
michael@0 | 836 | } |
michael@0 | 837 | |
michael@0 | 838 | /* |
michael@0 | 839 | This function is defined this way in order to get around static |
michael@0 | 840 | initialization and static destruction. |
michael@0 | 841 | */ |
michael@0 | 842 | Locale * |
michael@0 | 843 | Locale::getLocaleCache(void) |
michael@0 | 844 | { |
michael@0 | 845 | umtx_lock(NULL); |
michael@0 | 846 | UBool needInit = (gLocaleCache == NULL); |
michael@0 | 847 | umtx_unlock(NULL); |
michael@0 | 848 | |
michael@0 | 849 | if (needInit) { |
michael@0 | 850 | Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES]; |
michael@0 | 851 | if (tLocaleCache == NULL) { |
michael@0 | 852 | return NULL; |
michael@0 | 853 | } |
michael@0 | 854 | tLocaleCache[eROOT] = Locale(""); |
michael@0 | 855 | tLocaleCache[eENGLISH] = Locale("en"); |
michael@0 | 856 | tLocaleCache[eFRENCH] = Locale("fr"); |
michael@0 | 857 | tLocaleCache[eGERMAN] = Locale("de"); |
michael@0 | 858 | tLocaleCache[eITALIAN] = Locale("it"); |
michael@0 | 859 | tLocaleCache[eJAPANESE] = Locale("ja"); |
michael@0 | 860 | tLocaleCache[eKOREAN] = Locale("ko"); |
michael@0 | 861 | tLocaleCache[eCHINESE] = Locale("zh"); |
michael@0 | 862 | tLocaleCache[eFRANCE] = Locale("fr", "FR"); |
michael@0 | 863 | tLocaleCache[eGERMANY] = Locale("de", "DE"); |
michael@0 | 864 | tLocaleCache[eITALY] = Locale("it", "IT"); |
michael@0 | 865 | tLocaleCache[eJAPAN] = Locale("ja", "JP"); |
michael@0 | 866 | tLocaleCache[eKOREA] = Locale("ko", "KR"); |
michael@0 | 867 | tLocaleCache[eCHINA] = Locale("zh", "CN"); |
michael@0 | 868 | tLocaleCache[eTAIWAN] = Locale("zh", "TW"); |
michael@0 | 869 | tLocaleCache[eUK] = Locale("en", "GB"); |
michael@0 | 870 | tLocaleCache[eUS] = Locale("en", "US"); |
michael@0 | 871 | tLocaleCache[eCANADA] = Locale("en", "CA"); |
michael@0 | 872 | tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA"); |
michael@0 | 873 | |
michael@0 | 874 | umtx_lock(NULL); |
michael@0 | 875 | if (gLocaleCache == NULL) { |
michael@0 | 876 | gLocaleCache = tLocaleCache; |
michael@0 | 877 | tLocaleCache = NULL; |
michael@0 | 878 | ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); |
michael@0 | 879 | } |
michael@0 | 880 | umtx_unlock(NULL); |
michael@0 | 881 | if (tLocaleCache) { |
michael@0 | 882 | delete [] tLocaleCache; // Fancy array delete will destruct each member. |
michael@0 | 883 | } |
michael@0 | 884 | } |
michael@0 | 885 | return gLocaleCache; |
michael@0 | 886 | } |
michael@0 | 887 | |
michael@0 | 888 | class KeywordEnumeration : public StringEnumeration { |
michael@0 | 889 | private: |
michael@0 | 890 | char *keywords; |
michael@0 | 891 | char *current; |
michael@0 | 892 | int32_t length; |
michael@0 | 893 | UnicodeString currUSKey; |
michael@0 | 894 | static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */ |
michael@0 | 895 | |
michael@0 | 896 | public: |
michael@0 | 897 | static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; } |
michael@0 | 898 | virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); } |
michael@0 | 899 | public: |
michael@0 | 900 | KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status) |
michael@0 | 901 | : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) { |
michael@0 | 902 | if(U_SUCCESS(status) && keywordLen != 0) { |
michael@0 | 903 | if(keys == NULL || keywordLen < 0) { |
michael@0 | 904 | status = U_ILLEGAL_ARGUMENT_ERROR; |
michael@0 | 905 | } else { |
michael@0 | 906 | keywords = (char *)uprv_malloc(keywordLen+1); |
michael@0 | 907 | if (keywords == NULL) { |
michael@0 | 908 | status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 909 | } |
michael@0 | 910 | else { |
michael@0 | 911 | uprv_memcpy(keywords, keys, keywordLen); |
michael@0 | 912 | keywords[keywordLen] = 0; |
michael@0 | 913 | current = keywords + currentIndex; |
michael@0 | 914 | length = keywordLen; |
michael@0 | 915 | } |
michael@0 | 916 | } |
michael@0 | 917 | } |
michael@0 | 918 | } |
michael@0 | 919 | |
michael@0 | 920 | virtual ~KeywordEnumeration(); |
michael@0 | 921 | |
michael@0 | 922 | virtual StringEnumeration * clone() const |
michael@0 | 923 | { |
michael@0 | 924 | UErrorCode status = U_ZERO_ERROR; |
michael@0 | 925 | return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status); |
michael@0 | 926 | } |
michael@0 | 927 | |
michael@0 | 928 | virtual int32_t count(UErrorCode &/*status*/) const { |
michael@0 | 929 | char *kw = keywords; |
michael@0 | 930 | int32_t result = 0; |
michael@0 | 931 | while(*kw) { |
michael@0 | 932 | result++; |
michael@0 | 933 | kw += uprv_strlen(kw)+1; |
michael@0 | 934 | } |
michael@0 | 935 | return result; |
michael@0 | 936 | } |
michael@0 | 937 | |
michael@0 | 938 | virtual const char* next(int32_t* resultLength, UErrorCode& status) { |
michael@0 | 939 | const char* result; |
michael@0 | 940 | int32_t len; |
michael@0 | 941 | if(U_SUCCESS(status) && *current != 0) { |
michael@0 | 942 | result = current; |
michael@0 | 943 | len = (int32_t)uprv_strlen(current); |
michael@0 | 944 | current += len+1; |
michael@0 | 945 | if(resultLength != NULL) { |
michael@0 | 946 | *resultLength = len; |
michael@0 | 947 | } |
michael@0 | 948 | } else { |
michael@0 | 949 | if(resultLength != NULL) { |
michael@0 | 950 | *resultLength = 0; |
michael@0 | 951 | } |
michael@0 | 952 | result = NULL; |
michael@0 | 953 | } |
michael@0 | 954 | return result; |
michael@0 | 955 | } |
michael@0 | 956 | |
michael@0 | 957 | virtual const UnicodeString* snext(UErrorCode& status) { |
michael@0 | 958 | int32_t resultLength = 0; |
michael@0 | 959 | const char *s = next(&resultLength, status); |
michael@0 | 960 | return setChars(s, resultLength, status); |
michael@0 | 961 | } |
michael@0 | 962 | |
michael@0 | 963 | virtual void reset(UErrorCode& /*status*/) { |
michael@0 | 964 | current = keywords; |
michael@0 | 965 | } |
michael@0 | 966 | }; |
michael@0 | 967 | |
michael@0 | 968 | const char KeywordEnumeration::fgClassID = '\0'; |
michael@0 | 969 | |
michael@0 | 970 | KeywordEnumeration::~KeywordEnumeration() { |
michael@0 | 971 | uprv_free(keywords); |
michael@0 | 972 | } |
michael@0 | 973 | |
michael@0 | 974 | StringEnumeration * |
michael@0 | 975 | Locale::createKeywords(UErrorCode &status) const |
michael@0 | 976 | { |
michael@0 | 977 | char keywords[256]; |
michael@0 | 978 | int32_t keywordCapacity = 256; |
michael@0 | 979 | StringEnumeration *result = NULL; |
michael@0 | 980 | |
michael@0 | 981 | const char* variantStart = uprv_strchr(fullName, '@'); |
michael@0 | 982 | const char* assignment = uprv_strchr(fullName, '='); |
michael@0 | 983 | if(variantStart) { |
michael@0 | 984 | if(assignment > variantStart) { |
michael@0 | 985 | int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status); |
michael@0 | 986 | if(keyLen) { |
michael@0 | 987 | result = new KeywordEnumeration(keywords, keyLen, 0, status); |
michael@0 | 988 | } |
michael@0 | 989 | } else { |
michael@0 | 990 | status = U_INVALID_FORMAT_ERROR; |
michael@0 | 991 | } |
michael@0 | 992 | } |
michael@0 | 993 | return result; |
michael@0 | 994 | } |
michael@0 | 995 | |
michael@0 | 996 | int32_t |
michael@0 | 997 | Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const |
michael@0 | 998 | { |
michael@0 | 999 | return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status); |
michael@0 | 1000 | } |
michael@0 | 1001 | |
michael@0 | 1002 | void |
michael@0 | 1003 | Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status) |
michael@0 | 1004 | { |
michael@0 | 1005 | uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status); |
michael@0 | 1006 | } |
michael@0 | 1007 | |
michael@0 | 1008 | const char * |
michael@0 | 1009 | Locale::getBaseName() const |
michael@0 | 1010 | { |
michael@0 | 1011 | // lazy init |
michael@0 | 1012 | UErrorCode status = U_ZERO_ERROR; |
michael@0 | 1013 | // semantically const |
michael@0 | 1014 | if(baseName == 0) { |
michael@0 | 1015 | ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer; |
michael@0 | 1016 | int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNAME_CAPACITY, &status); |
michael@0 | 1017 | if(baseNameSize >= ULOC_FULLNAME_CAPACITY) { |
michael@0 | 1018 | ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * baseNameSize + 1); |
michael@0 | 1019 | if (baseName == NULL) { |
michael@0 | 1020 | return baseName; |
michael@0 | 1021 | } |
michael@0 | 1022 | uloc_getBaseName(fullName, baseName, baseNameSize+1, &status); |
michael@0 | 1023 | } |
michael@0 | 1024 | baseName[baseNameSize] = 0; |
michael@0 | 1025 | |
michael@0 | 1026 | // the computation of variantBegin leaves it equal to the length |
michael@0 | 1027 | // of fullName if there is no variant. It should instead be |
michael@0 | 1028 | // the length of the baseName. Patch around this for now. |
michael@0 | 1029 | if (variantBegin == (int32_t)uprv_strlen(fullName)) { |
michael@0 | 1030 | ((Locale*)this)->variantBegin = baseNameSize; |
michael@0 | 1031 | } |
michael@0 | 1032 | } |
michael@0 | 1033 | return baseName; |
michael@0 | 1034 | } |
michael@0 | 1035 | |
michael@0 | 1036 | //eof |
michael@0 | 1037 | U_NAMESPACE_END |