]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ********************************************************************** | |
3 | * Copyright (C) 1997-2003, International Business Machines | |
4 | * Corporation and others. All Rights Reserved. | |
5 | ********************************************************************** | |
6 | * | |
7 | * File locid.cpp | |
8 | * | |
9 | * Created by: Richard Gillam | |
10 | * | |
11 | * Modification History: | |
12 | * | |
13 | * Date Name Description | |
14 | * 02/11/97 aliu Changed gLocPath to fgDataDirectory and added | |
15 | * methods to get and set it. | |
16 | * 04/02/97 aliu Made operator!= inline; fixed return value | |
17 | * of getName(). | |
18 | * 04/15/97 aliu Cleanup for AIX/Win32. | |
19 | * 04/24/97 aliu Numerous changes per code review. | |
20 | * 08/18/98 stephen Changed getDisplayName() | |
21 | * Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE | |
22 | * Added getISOCountries(), getISOLanguages(), | |
23 | * getLanguagesForCountry() | |
24 | * 03/16/99 bertrand rehaul. | |
25 | * 07/21/99 stephen Added U_CFUNC setDefault | |
26 | * 11/09/99 weiv Added const char * getName() const; | |
27 | * 04/12/00 srl removing unicodestring api's and cached hash code | |
28 | * 08/10/01 grhoten Change the static Locales to accessor functions | |
29 | ****************************************************************************** | |
30 | */ | |
31 | ||
32 | ||
33 | #include "unicode/locid.h" | |
34 | #include "unicode/uloc.h" | |
35 | #include "umutex.h" | |
36 | #include "uassert.h" | |
37 | #include "cmemory.h" | |
38 | #include "cstring.h" | |
39 | #include "uhash.h" | |
40 | #include "ucln_cmn.h" | |
41 | ||
42 | static Locale* availableLocaleList = NULL; | |
43 | static int32_t availableLocaleListCount; | |
44 | typedef enum ELocalePos { | |
45 | eENGLISH, | |
46 | eFRENCH, | |
47 | eGERMAN, | |
48 | eITALIAN, | |
49 | eJAPANESE, | |
50 | eKOREAN, | |
51 | eCHINESE, | |
52 | ||
53 | eFRANCE, | |
54 | eGERMANY, | |
55 | eITALY, | |
56 | eJAPAN, | |
57 | eKOREA, | |
58 | eCHINA, /* Alias for PRC */ | |
59 | eTAIWAN, | |
60 | eUK, | |
61 | eUS, | |
62 | eCANADA, | |
63 | eCANADA_FRENCH, | |
64 | ||
65 | ||
66 | //eDEFAULT, | |
67 | eMAX_LOCALES | |
68 | } ELocalePos; | |
69 | ||
70 | /* Use void * to make it properly aligned */ | |
71 | /* Add 1 for rounding */ | |
72 | // static void *gByteLocaleCache[(eMAX_LOCALES + 1) * sizeof(Locale) / sizeof(void*)]; | |
73 | ||
74 | static Locale *gLocaleCache = NULL; | |
75 | static Locale *gDefaultLocale = NULL; | |
76 | ||
77 | UBool | |
78 | locale_cleanup(void) | |
79 | { | |
80 | U_NAMESPACE_USE | |
81 | ||
82 | if (availableLocaleList) { | |
83 | delete []availableLocaleList; | |
84 | availableLocaleList = NULL; | |
85 | } | |
86 | availableLocaleListCount = 0; | |
87 | ||
88 | if (gLocaleCache) { | |
89 | delete [] gLocaleCache; | |
90 | gLocaleCache = NULL; | |
91 | } | |
92 | if (gDefaultLocale) { | |
93 | delete gDefaultLocale; | |
94 | gDefaultLocale = NULL; | |
95 | } | |
96 | return TRUE; | |
97 | } | |
98 | ||
99 | U_NAMESPACE_BEGIN | |
100 | const char Locale::fgClassID=0; | |
101 | ||
102 | void locale_set_default_internal(const char *id) | |
103 | { | |
104 | U_NAMESPACE_USE | |
105 | Locale tempLocale(Locale::eBOGUS); | |
106 | ||
107 | if (id == NULL) | |
108 | { | |
109 | umtx_lock(NULL); | |
110 | id = uprv_getDefaultLocaleID(); | |
111 | umtx_unlock(NULL); | |
112 | } | |
113 | ||
114 | tempLocale.init(id); // Note: we do not want to hold the mutex through init(), | |
115 | // which is a relatively large, complex function. | |
116 | // Hence, the use of a temporary locale. | |
117 | const Locale *defLocale = &Locale::getDefault(); | |
118 | ||
119 | umtx_lock(NULL); | |
120 | Locale *ncDefLocale = (Locale *)defLocale; | |
121 | *ncDefLocale = tempLocale; | |
122 | umtx_unlock(NULL); | |
123 | } | |
124 | U_NAMESPACE_END | |
125 | ||
126 | /* sfb 07/21/99 */ | |
127 | U_CFUNC void | |
128 | locale_set_default(const char *id) | |
129 | { | |
130 | U_NAMESPACE_USE | |
131 | locale_set_default_internal(id); | |
132 | } | |
133 | /* end */ | |
134 | ||
135 | U_CFUNC const char * | |
136 | locale_get_default(void) | |
137 | { | |
138 | U_NAMESPACE_USE | |
139 | ||
140 | return Locale::getDefault().getName(); | |
141 | } | |
142 | ||
143 | ||
144 | U_NAMESPACE_BEGIN | |
145 | ||
146 | /*Character separating the posix id fields*/ | |
147 | // '_' | |
148 | // In the platform codepage. | |
149 | #define SEP_CHAR '_' | |
150 | ||
151 | Locale::~Locale() | |
152 | { | |
153 | /*if fullName is on the heap, we free it*/ | |
154 | if (fullName != fullNameBuffer) | |
155 | { | |
156 | uprv_free(fullName); | |
157 | fullName = NULL; | |
158 | } | |
159 | } | |
160 | ||
161 | Locale::Locale() | |
162 | : UObject(), fullName(fullNameBuffer) | |
163 | { | |
164 | init(NULL); | |
165 | } | |
166 | ||
167 | Locale::Locale(Locale::ELocaleType t) | |
168 | : UObject(), fullName(fullNameBuffer) | |
169 | { | |
170 | setToBogus(); | |
171 | } | |
172 | ||
173 | ||
174 | Locale::Locale( const char * newLanguage, | |
175 | const char * newCountry, | |
176 | const char * newVariant) | |
177 | : UObject(), fullName(fullNameBuffer) | |
178 | { | |
179 | if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) ) | |
180 | { | |
181 | init(NULL); /* shortcut */ | |
182 | } | |
183 | else | |
184 | { | |
185 | char togo_stack[ULOC_FULLNAME_CAPACITY]; | |
186 | char *togo; | |
187 | char *togo_heap = NULL; | |
188 | int32_t size = 0; | |
189 | int32_t lsize = 0; | |
190 | int32_t csize = 0; | |
191 | int32_t vsize = 0; | |
192 | char *p; | |
193 | ||
194 | // Calculate the size of the resulting string. | |
195 | ||
196 | // Language | |
197 | if ( newLanguage != NULL ) | |
198 | { | |
199 | lsize = (int32_t)uprv_strlen(newLanguage); | |
200 | size = lsize; | |
201 | } | |
202 | ||
203 | // _Country | |
204 | if ( newCountry != NULL ) | |
205 | { | |
206 | csize = (int32_t)uprv_strlen(newCountry); | |
207 | size += csize; | |
208 | } | |
209 | ||
210 | // _Variant | |
211 | if ( newVariant != NULL ) | |
212 | { | |
213 | // remove leading _'s | |
214 | while(newVariant[0] == SEP_CHAR) | |
215 | { | |
216 | newVariant++; | |
217 | } | |
218 | ||
219 | // remove trailing _'s | |
220 | vsize = (int32_t)uprv_strlen(newVariant); | |
221 | while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) ) | |
222 | { | |
223 | vsize--; | |
224 | } | |
225 | } | |
226 | ||
227 | if( vsize > 0 ) | |
228 | { | |
229 | size += vsize; | |
230 | } | |
231 | ||
232 | // Separator rules: | |
233 | if ( vsize > 0 ) | |
234 | { | |
235 | size += 2; // at least: __v | |
236 | } | |
237 | else if ( csize > 0 ) | |
238 | { | |
239 | size += 1; // at least: _v | |
240 | } | |
241 | ||
242 | // NOW we have the full locale string.. | |
243 | ||
244 | /*if the whole string is longer than our internal limit, we need | |
245 | to go to the heap for temporary buffers*/ | |
246 | if (size > ULOC_FULLNAME_CAPACITY) | |
247 | { | |
248 | togo_heap = (char *)uprv_malloc(sizeof(char)*(size+1)); | |
249 | togo = togo_heap; | |
250 | } | |
251 | else | |
252 | { | |
253 | togo = togo_stack; | |
254 | } | |
255 | ||
256 | togo[0] = 0; | |
257 | ||
258 | // Now, copy it back. | |
259 | p = togo; | |
260 | if ( lsize != 0 ) | |
261 | { | |
262 | uprv_strcpy(p, newLanguage); | |
263 | p += lsize; | |
264 | } | |
265 | ||
266 | if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v | |
267 | { // ^ | |
268 | *p++ = SEP_CHAR; | |
269 | } | |
270 | ||
271 | if ( csize != 0 ) | |
272 | { | |
273 | uprv_strcpy(p, newCountry); | |
274 | p += csize; | |
275 | } | |
276 | ||
277 | if ( vsize != 0) | |
278 | { | |
279 | *p++ = SEP_CHAR; // at least: __v | |
280 | ||
281 | uprv_strncpy(p, newVariant, vsize); // Must use strncpy because | |
282 | p += vsize; // of trimming (above). | |
283 | *p = 0; // terminate | |
284 | } | |
285 | ||
286 | // Parse it, because for example 'language' might really be a complete | |
287 | // string. | |
288 | init(togo); | |
289 | ||
290 | if (togo_heap) { | |
291 | uprv_free(togo_heap); | |
292 | } | |
293 | } | |
294 | } | |
295 | ||
296 | Locale::Locale(const Locale &other) | |
297 | : UObject(other), fullName(fullNameBuffer) | |
298 | { | |
299 | *this = other; | |
300 | } | |
301 | ||
302 | Locale &Locale::operator=(const Locale &other) | |
303 | { | |
304 | if (this == &other) { | |
305 | return *this; | |
306 | } | |
307 | ||
308 | if (&other == NULL) { | |
309 | this->setToBogus(); | |
310 | return *this; | |
311 | } | |
312 | ||
313 | /* Free our current storage */ | |
314 | if(fullName != fullNameBuffer) { | |
315 | uprv_free(fullName); | |
316 | fullName = fullNameBuffer; | |
317 | } | |
318 | ||
319 | /* Allocate the full name if necessary */ | |
320 | if(other.fullName != other.fullNameBuffer) { | |
321 | fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1)); | |
322 | } | |
323 | ||
324 | /* Copy the full name */ | |
325 | uprv_strcpy(fullName, other.fullName); | |
326 | ||
327 | /* Copy the language and country fields */ | |
328 | uprv_strcpy(language, other.language); | |
329 | uprv_strcpy(country, other.country); | |
330 | ||
331 | /* The variantBegin is an offset into fullName, just copy it */ | |
332 | variantBegin = other.variantBegin; | |
333 | fIsBogus = other.fIsBogus; | |
334 | return *this; | |
335 | } | |
336 | ||
337 | UBool | |
338 | Locale::operator==( const Locale& other) const | |
339 | { | |
340 | return (uprv_strcmp(other.fullName, fullName) == 0); | |
341 | } | |
342 | ||
343 | /*This function initializes a Locale from a C locale ID*/ | |
344 | Locale& Locale::init(const char* localeID) | |
345 | { | |
346 | fIsBogus = FALSE; | |
347 | /* Free our current storage */ | |
348 | if(fullName != fullNameBuffer) { | |
349 | uprv_free(fullName); | |
350 | fullName = fullNameBuffer; | |
351 | } | |
352 | ||
353 | // not a loop: | |
354 | // just an easy way to have a common error-exit | |
355 | // without goto and without another function | |
356 | do { | |
357 | char *separator, *prev; | |
358 | int32_t length; | |
359 | UErrorCode err; | |
360 | ||
361 | if(localeID == NULL) { | |
362 | // not an error, just set the default locale | |
363 | return *this = getDefault(); | |
364 | } | |
365 | ||
366 | // "canonicalize" the locale ID to ICU/Java format | |
367 | err = U_ZERO_ERROR; | |
368 | length = uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err); | |
369 | if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) { | |
370 | /*Go to heap for the fullName if necessary*/ | |
371 | fullName = (char *)uprv_malloc(sizeof(char)*(length + 1)); | |
372 | if(fullName == 0) { | |
373 | fullName = fullNameBuffer; | |
374 | break; // error: out of memory | |
375 | } | |
376 | err = U_ZERO_ERROR; | |
377 | length = uloc_getName(localeID, fullName, length + 1, &err); | |
378 | } | |
379 | if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) { | |
380 | /* should never occur */ | |
381 | break; | |
382 | } | |
383 | ||
384 | /* preset all fields to empty */ | |
385 | language[0] = country[0] = 0; | |
386 | variantBegin = (int32_t)uprv_strlen(fullName); | |
387 | ||
388 | /* after uloc_getName() we know that only '_' are separators */ | |
389 | separator = uprv_strchr(fullName, SEP_CHAR); | |
390 | if(separator != 0) { | |
391 | /* there is a country field */ | |
392 | length = (int32_t)(separator - fullName); | |
393 | if(length > 0) { | |
394 | if(length >= (int32_t)sizeof(language)) { | |
395 | break; // error: language code too long | |
396 | } | |
397 | uprv_memcpy(language, fullName, length); | |
398 | } | |
399 | language[length] = 0; | |
400 | ||
401 | prev = separator + 1; | |
402 | separator = uprv_strchr(prev, SEP_CHAR); | |
403 | if(separator != 0) { | |
404 | /* there is a variant field */ | |
405 | length = (int32_t)(separator - prev); | |
406 | if(length > 0) { | |
407 | if(length >= (int32_t)sizeof(country)) { | |
408 | break; // error: country code too long | |
409 | } | |
410 | uprv_memcpy(country, prev, length); | |
411 | } | |
412 | country[length] = 0; | |
413 | ||
414 | variantBegin = (int32_t)((separator + 1) - fullName); | |
415 | } else { | |
416 | /* variantBegin==strlen(fullName), length==strlen(language)==prev-1-fullName */ | |
417 | if((variantBegin - length - 1) >= (int32_t)sizeof(country)) { | |
418 | break; // error: country code too long | |
419 | } | |
420 | uprv_strcpy(country, prev); | |
421 | } | |
422 | } else { | |
423 | /* variantBegin==strlen(fullName) */ | |
424 | if(variantBegin >= (int32_t)sizeof(language)) { | |
425 | break; // error: language code too long | |
426 | } | |
427 | uprv_strcpy(language, fullName); | |
428 | } | |
429 | ||
430 | // successful end of init() | |
431 | return *this; | |
432 | } while(0); | |
433 | ||
434 | // when an error occurs, then set this object to "bogus" (there is no UErrorCode here) | |
435 | setToBogus(); | |
436 | ||
437 | return *this; | |
438 | } | |
439 | ||
440 | int32_t | |
441 | Locale::hashCode() const | |
442 | { | |
443 | UHashTok hashKey; | |
444 | hashKey.pointer = fullName; | |
445 | return uhash_hashChars(hashKey); | |
446 | } | |
447 | ||
448 | void | |
449 | Locale::setToBogus() { | |
450 | /* Free our current storage */ | |
451 | if(fullName != fullNameBuffer) { | |
452 | uprv_free(fullName); | |
453 | fullName = fullNameBuffer; | |
454 | } | |
455 | *fullNameBuffer = 0; | |
456 | *language = 0; | |
457 | *country = 0; | |
458 | fIsBogus = TRUE; | |
459 | } | |
460 | ||
461 | const Locale& | |
462 | Locale::getDefault() | |
463 | { | |
464 | umtx_lock(NULL); | |
465 | UBool needInit = (gDefaultLocale == NULL); | |
466 | umtx_unlock(NULL); | |
467 | if (needInit) { | |
468 | Locale *tLocale = new Locale(Locale::eBOGUS); | |
469 | if (tLocale != NULL) { | |
470 | const char *cLocale; | |
471 | ||
472 | umtx_lock(NULL); | |
473 | /* uprv_getDefaultLocaleID is not thread safe, so we surround it with a mutex */ | |
474 | cLocale = uprv_getDefaultLocaleID(); | |
475 | umtx_unlock(NULL); | |
476 | ||
477 | tLocale->init(cLocale); | |
478 | umtx_lock(NULL); | |
479 | if (gDefaultLocale == NULL) { | |
480 | gDefaultLocale = tLocale; | |
481 | tLocale = NULL; | |
482 | } | |
483 | umtx_unlock(NULL); | |
484 | delete tLocale; | |
485 | } | |
486 | } | |
487 | return *gDefaultLocale; | |
488 | } | |
489 | ||
490 | void | |
491 | Locale::setDefault( const Locale& newLocale, | |
492 | UErrorCode& status) | |
493 | { | |
494 | if (U_FAILURE(status)) | |
495 | return; | |
496 | ||
497 | const Locale *defLocale = &Locale::getDefault(); | |
498 | umtx_lock(NULL); | |
499 | Locale *ncDefLocale = (Locale *)defLocale; | |
500 | *ncDefLocale = newLocale; | |
501 | umtx_unlock(NULL); | |
502 | } | |
503 | ||
504 | Locale | |
505 | Locale::createFromName (const char *name) | |
506 | { | |
507 | if (name) { | |
508 | Locale l; | |
509 | l.init(name); | |
510 | return l; | |
511 | } | |
512 | else { | |
513 | return getDefault(); | |
514 | } | |
515 | } | |
516 | ||
517 | ||
518 | const char * | |
519 | Locale::getISO3Language() const | |
520 | { | |
521 | return uloc_getISO3Language(fullName); | |
522 | } | |
523 | ||
524 | ||
525 | const char * | |
526 | Locale::getISO3Country() const | |
527 | { | |
528 | return uloc_getISO3Country(fullName); | |
529 | } | |
530 | ||
531 | /** | |
532 | * Return the LCID value as specified in the "LocaleID" resource for this | |
533 | * locale. The LocaleID must be expressed as a hexadecimal number, from | |
534 | * one to four digits. If the LocaleID resource is not present, or is | |
535 | * in an incorrect format, 0 is returned. The LocaleID is for use in | |
536 | * Windows (it is an LCID), but is available on all platforms. | |
537 | */ | |
538 | uint32_t | |
539 | Locale::getLCID() const | |
540 | { | |
541 | return uloc_getLCID(fullName); | |
542 | } | |
543 | ||
544 | UnicodeString& | |
545 | Locale::getDisplayLanguage(UnicodeString& dispLang) const | |
546 | { | |
547 | return this->getDisplayLanguage(getDefault(), dispLang); | |
548 | } | |
549 | ||
550 | /*We cannot make any assumptions on the size of the output display strings | |
551 | * Yet, since we are calling through to a C API, we need to set limits on | |
552 | * buffer size. For all the following getDisplay functions we first attempt | |
553 | * to fill up a stack allocated buffer. If it is to small we heap allocated | |
554 | * the exact buffer we need copy it to the UnicodeString and delete it*/ | |
555 | ||
556 | UnicodeString& | |
557 | Locale::getDisplayLanguage(const Locale &displayLocale, | |
558 | UnicodeString &result) const { | |
559 | UChar *buffer; | |
560 | UErrorCode errorCode=U_ZERO_ERROR; | |
561 | int32_t length; | |
562 | ||
563 | buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); | |
564 | if(buffer==0) { | |
565 | result.truncate(0); | |
566 | return result; | |
567 | } | |
568 | ||
569 | length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, | |
570 | buffer, result.getCapacity(), | |
571 | &errorCode); | |
572 | result.releaseBuffer(length); | |
573 | ||
574 | if(errorCode==U_BUFFER_OVERFLOW_ERROR) { | |
575 | buffer=result.getBuffer(length); | |
576 | if(buffer==0) { | |
577 | result.truncate(0); | |
578 | return result; | |
579 | } | |
580 | errorCode=U_ZERO_ERROR; | |
581 | length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, | |
582 | buffer, result.getCapacity(), | |
583 | &errorCode); | |
584 | result.releaseBuffer(length); | |
585 | } | |
586 | ||
587 | if(U_FAILURE(errorCode)) { | |
588 | result.truncate(0); | |
589 | } | |
590 | ||
591 | return result; | |
592 | } | |
593 | ||
594 | UnicodeString& | |
595 | Locale::getDisplayCountry(UnicodeString& dispCntry) const | |
596 | { | |
597 | return this->getDisplayCountry(getDefault(), dispCntry); | |
598 | } | |
599 | ||
600 | UnicodeString& | |
601 | Locale::getDisplayCountry(const Locale &displayLocale, | |
602 | UnicodeString &result) const { | |
603 | UChar *buffer; | |
604 | UErrorCode errorCode=U_ZERO_ERROR; | |
605 | int32_t length; | |
606 | ||
607 | buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); | |
608 | if(buffer==0) { | |
609 | result.truncate(0); | |
610 | return result; | |
611 | } | |
612 | ||
613 | length=uloc_getDisplayCountry(fullName, displayLocale.fullName, | |
614 | buffer, result.getCapacity(), | |
615 | &errorCode); | |
616 | result.releaseBuffer(length); | |
617 | ||
618 | if(errorCode==U_BUFFER_OVERFLOW_ERROR) { | |
619 | buffer=result.getBuffer(length); | |
620 | if(buffer==0) { | |
621 | result.truncate(0); | |
622 | return result; | |
623 | } | |
624 | errorCode=U_ZERO_ERROR; | |
625 | length=uloc_getDisplayCountry(fullName, displayLocale.fullName, | |
626 | buffer, result.getCapacity(), | |
627 | &errorCode); | |
628 | result.releaseBuffer(length); | |
629 | } | |
630 | ||
631 | if(U_FAILURE(errorCode)) { | |
632 | result.truncate(0); | |
633 | } | |
634 | ||
635 | return result; | |
636 | } | |
637 | ||
638 | UnicodeString& | |
639 | Locale::getDisplayVariant(UnicodeString& dispVar) const | |
640 | { | |
641 | return this->getDisplayVariant(getDefault(), dispVar); | |
642 | } | |
643 | ||
644 | UnicodeString& | |
645 | Locale::getDisplayVariant(const Locale &displayLocale, | |
646 | UnicodeString &result) const { | |
647 | UChar *buffer; | |
648 | UErrorCode errorCode=U_ZERO_ERROR; | |
649 | int32_t length; | |
650 | ||
651 | buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); | |
652 | if(buffer==0) { | |
653 | result.truncate(0); | |
654 | return result; | |
655 | } | |
656 | ||
657 | length=uloc_getDisplayVariant(fullName, displayLocale.fullName, | |
658 | buffer, result.getCapacity(), | |
659 | &errorCode); | |
660 | result.releaseBuffer(length); | |
661 | ||
662 | if(errorCode==U_BUFFER_OVERFLOW_ERROR) { | |
663 | buffer=result.getBuffer(length); | |
664 | if(buffer==0) { | |
665 | result.truncate(0); | |
666 | return result; | |
667 | } | |
668 | errorCode=U_ZERO_ERROR; | |
669 | length=uloc_getDisplayVariant(fullName, displayLocale.fullName, | |
670 | buffer, result.getCapacity(), | |
671 | &errorCode); | |
672 | result.releaseBuffer(length); | |
673 | } | |
674 | ||
675 | if(U_FAILURE(errorCode)) { | |
676 | result.truncate(0); | |
677 | } | |
678 | ||
679 | return result; | |
680 | } | |
681 | ||
682 | UnicodeString& | |
683 | Locale::getDisplayName( UnicodeString& name ) const | |
684 | { | |
685 | return this->getDisplayName(getDefault(), name); | |
686 | } | |
687 | ||
688 | UnicodeString& | |
689 | Locale::getDisplayName(const Locale &displayLocale, | |
690 | UnicodeString &result) const { | |
691 | UChar *buffer; | |
692 | UErrorCode errorCode=U_ZERO_ERROR; | |
693 | int32_t length; | |
694 | ||
695 | buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); | |
696 | if(buffer==0) { | |
697 | result.truncate(0); | |
698 | return result; | |
699 | } | |
700 | ||
701 | length=uloc_getDisplayName(fullName, displayLocale.fullName, | |
702 | buffer, result.getCapacity(), | |
703 | &errorCode); | |
704 | result.releaseBuffer(length); | |
705 | ||
706 | if(errorCode==U_BUFFER_OVERFLOW_ERROR) { | |
707 | buffer=result.getBuffer(length); | |
708 | if(buffer==0) { | |
709 | result.truncate(0); | |
710 | return result; | |
711 | } | |
712 | errorCode=U_ZERO_ERROR; | |
713 | length=uloc_getDisplayName(fullName, displayLocale.fullName, | |
714 | buffer, result.getCapacity(), | |
715 | &errorCode); | |
716 | result.releaseBuffer(length); | |
717 | } | |
718 | ||
719 | if(U_FAILURE(errorCode)) { | |
720 | result.truncate(0); | |
721 | } | |
722 | ||
723 | return result; | |
724 | } | |
725 | const Locale* | |
726 | Locale::getAvailableLocales(int32_t& count) | |
727 | { | |
728 | // for now, there is a hardcoded list, so just walk through that list and set it up. | |
729 | umtx_lock(NULL); | |
730 | UBool needInit = availableLocaleList == 0; | |
731 | umtx_unlock(NULL); | |
732 | ||
733 | if (needInit) { | |
734 | int32_t locCount = uloc_countAvailable(); | |
735 | Locale *newLocaleList = 0; | |
736 | if(locCount) { | |
737 | newLocaleList = new Locale[locCount]; | |
738 | } | |
739 | if (newLocaleList == NULL) { | |
740 | return NULL; | |
741 | } | |
742 | ||
743 | count = locCount; | |
744 | ||
745 | while(--locCount >= 0) { | |
746 | newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount)); | |
747 | } | |
748 | ||
749 | umtx_lock(NULL); | |
750 | if(availableLocaleList == 0) { | |
751 | availableLocaleListCount = count; | |
752 | availableLocaleList = newLocaleList; | |
753 | newLocaleList = NULL; | |
754 | } | |
755 | umtx_unlock(NULL); | |
756 | delete []newLocaleList; | |
757 | } | |
758 | count = availableLocaleListCount; | |
759 | return availableLocaleList; | |
760 | } | |
761 | ||
762 | const char* const* Locale::getISOCountries() | |
763 | { | |
764 | return uloc_getISOCountries(); | |
765 | } | |
766 | ||
767 | const char* const* Locale::getISOLanguages() | |
768 | { | |
769 | return uloc_getISOLanguages(); | |
770 | } | |
771 | ||
772 | // Set the locale's data based on a posix id. | |
773 | void Locale::setFromPOSIXID(const char *posixID) | |
774 | { | |
775 | init(posixID); | |
776 | } | |
777 | ||
778 | const Locale & | |
779 | Locale::getEnglish(void) | |
780 | { | |
781 | return getLocale(eENGLISH); | |
782 | } | |
783 | ||
784 | const Locale & | |
785 | Locale::getFrench(void) | |
786 | { | |
787 | return getLocale(eFRENCH); | |
788 | } | |
789 | ||
790 | const Locale & | |
791 | Locale::getGerman(void) | |
792 | { | |
793 | return getLocale(eGERMAN); | |
794 | } | |
795 | ||
796 | const Locale & | |
797 | Locale::getItalian(void) | |
798 | { | |
799 | return getLocale(eITALIAN); | |
800 | } | |
801 | ||
802 | const Locale & | |
803 | Locale::getJapanese(void) | |
804 | { | |
805 | return getLocale(eJAPANESE); | |
806 | } | |
807 | ||
808 | const Locale & | |
809 | Locale::getKorean(void) | |
810 | { | |
811 | return getLocale(eKOREAN); | |
812 | } | |
813 | ||
814 | const Locale & | |
815 | Locale::getChinese(void) | |
816 | { | |
817 | return getLocale(eCHINESE); | |
818 | } | |
819 | ||
820 | const Locale & | |
821 | Locale::getSimplifiedChinese(void) | |
822 | { | |
823 | return getLocale(eCHINA); | |
824 | } | |
825 | ||
826 | const Locale & | |
827 | Locale::getTraditionalChinese(void) | |
828 | { | |
829 | return getLocale(eTAIWAN); | |
830 | } | |
831 | ||
832 | ||
833 | const Locale & | |
834 | Locale::getFrance(void) | |
835 | { | |
836 | return getLocale(eFRANCE); | |
837 | } | |
838 | ||
839 | const Locale & | |
840 | Locale::getGermany(void) | |
841 | { | |
842 | return getLocale(eGERMANY); | |
843 | } | |
844 | ||
845 | const Locale & | |
846 | Locale::getItaly(void) | |
847 | { | |
848 | return getLocale(eITALY); | |
849 | } | |
850 | ||
851 | const Locale & | |
852 | Locale::getJapan(void) | |
853 | { | |
854 | return getLocale(eJAPAN); | |
855 | } | |
856 | ||
857 | const Locale & | |
858 | Locale::getKorea(void) | |
859 | { | |
860 | return getLocale(eKOREA); | |
861 | } | |
862 | ||
863 | const Locale & | |
864 | Locale::getChina(void) | |
865 | { | |
866 | return getLocale(eCHINA); | |
867 | } | |
868 | ||
869 | const Locale & | |
870 | Locale::getPRC(void) | |
871 | { | |
872 | return getLocale(eCHINA); | |
873 | } | |
874 | ||
875 | const Locale & | |
876 | Locale::getTaiwan(void) | |
877 | { | |
878 | return getLocale(eTAIWAN); | |
879 | } | |
880 | ||
881 | const Locale & | |
882 | Locale::getUK(void) | |
883 | { | |
884 | return getLocale(eUK); | |
885 | } | |
886 | ||
887 | const Locale & | |
888 | Locale::getUS(void) | |
889 | { | |
890 | return getLocale(eUS); | |
891 | } | |
892 | ||
893 | const Locale & | |
894 | Locale::getCanada(void) | |
895 | { | |
896 | return getLocale(eCANADA); | |
897 | } | |
898 | ||
899 | const Locale & | |
900 | Locale::getCanadaFrench(void) | |
901 | { | |
902 | return getLocale(eCANADA_FRENCH); | |
903 | } | |
904 | ||
905 | const Locale & | |
906 | Locale::getLocale(int locid) | |
907 | { | |
908 | Locale *localeCache = getLocaleCache(); | |
909 | U_ASSERT(locid < eMAX_LOCALES); | |
910 | if (localeCache == NULL) { | |
911 | // Failure allocating the locale cache. | |
912 | // The best we can do is return a NULL reference. | |
913 | locid = 0; | |
914 | } | |
915 | return localeCache[locid]; | |
916 | } | |
917 | ||
918 | /* | |
919 | This function is defined this way in order to get around static | |
920 | initialization and static destruction. | |
921 | */ | |
922 | Locale * | |
923 | Locale::getLocaleCache(void) | |
924 | { | |
925 | umtx_lock(NULL); | |
926 | UBool needInit = (gLocaleCache == NULL); | |
927 | umtx_unlock(NULL); | |
928 | ||
929 | if (needInit) { | |
930 | Locale *tLocaleCache = new Locale[eMAX_LOCALES]; | |
931 | if (tLocaleCache == NULL) { | |
932 | return NULL; | |
933 | } | |
934 | tLocaleCache[eENGLISH] = Locale("en"); | |
935 | tLocaleCache[eFRENCH] = Locale("fr"); | |
936 | tLocaleCache[eGERMAN] = Locale("de"); | |
937 | tLocaleCache[eITALIAN] = Locale("it"); | |
938 | tLocaleCache[eJAPANESE] = Locale("ja"); | |
939 | tLocaleCache[eKOREAN] = Locale("ko"); | |
940 | tLocaleCache[eCHINESE] = Locale("zh"); | |
941 | tLocaleCache[eFRANCE] = Locale("fr", "FR"); | |
942 | tLocaleCache[eGERMANY] = Locale("de", "DE"); | |
943 | tLocaleCache[eITALY] = Locale("it", "IT"); | |
944 | tLocaleCache[eJAPAN] = Locale("ja", "JP"); | |
945 | tLocaleCache[eKOREA] = Locale("ko", "KR"); | |
946 | tLocaleCache[eCHINA] = Locale("zh", "CN"); | |
947 | tLocaleCache[eTAIWAN] = Locale("zh", "TW"); | |
948 | tLocaleCache[eUK] = Locale("en", "GB"); | |
949 | tLocaleCache[eUS] = Locale("en", "US"); | |
950 | tLocaleCache[eCANADA] = Locale("en", "CA"); | |
951 | tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA"); | |
952 | ||
953 | umtx_lock(NULL); | |
954 | if (gLocaleCache == NULL) { | |
955 | gLocaleCache = tLocaleCache; | |
956 | tLocaleCache = NULL; | |
957 | } | |
958 | umtx_unlock(NULL); | |
959 | if (tLocaleCache) { | |
960 | delete [] tLocaleCache; // Fancy array delete will destruct each member. | |
961 | } | |
962 | } | |
963 | return gLocaleCache; | |
964 | } | |
965 | ||
966 | //eof | |
967 | U_NAMESPACE_END |