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