1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 **********************************************************************
5 * Copyright (C) 1997-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
11 * Created by: Richard Gillam
13 * Modification History:
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
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 ******************************************************************************
36 #include "unicode/bytestream.h"
37 #include "unicode/locid.h"
38 #include "unicode/strenum.h"
39 #include "unicode/stringpiece.h"
40 #include "unicode/uloc.h"
42 #include "bytesinkutil.h"
56 static UBool U_CALLCONV
locale_cleanup(void);
61 static Locale
*gLocaleCache
= NULL
;
62 static UInitOnce gLocaleCacheInitOnce
= U_INITONCE_INITIALIZER
;
64 // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
65 static UMutex
*gDefaultLocaleMutex() {
66 static UMutex
*m
= STATIC_NEW(UMutex
);
69 static UHashtable
*gDefaultLocalesHashT
= NULL
;
70 static Locale
*gDefaultLocale
= NULL
;
73 * \def ULOC_STRING_LIMIT
74 * strings beyond this value crash in CharString
76 #define ULOC_STRING_LIMIT 357913941
80 typedef enum ELocalePos
{
94 eCHINA
, /* Alias for PRC */
107 U_CFUNC
int32_t locale_getKeywords(const char *localeID
,
109 char *keywords
, int32_t keywordCapacity
,
110 char *values
, int32_t valuesCapacity
, int32_t *valLen
,
116 // Deleter function for Locales owned by the default Locale hash table/
118 static void U_CALLCONV
119 deleteLocale(void *obj
) {
120 delete (icu::Locale
*) obj
;
123 static UBool U_CALLCONV
locale_cleanup(void)
127 delete [] gLocaleCache
;
129 gLocaleCacheInitOnce
.reset();
131 if (gDefaultLocalesHashT
) {
132 uhash_close(gDefaultLocalesHashT
); // Automatically deletes all elements, using deleter func.
133 gDefaultLocalesHashT
= NULL
;
135 gDefaultLocale
= NULL
;
140 static void U_CALLCONV
locale_init(UErrorCode
&status
) {
143 U_ASSERT(gLocaleCache
== NULL
);
144 gLocaleCache
= new Locale
[(int)eMAX_LOCALES
];
145 if (gLocaleCache
== NULL
) {
146 status
= U_MEMORY_ALLOCATION_ERROR
;
149 ucln_common_registerCleanup(UCLN_COMMON_LOCALE
, locale_cleanup
);
150 gLocaleCache
[eROOT
] = Locale("");
151 gLocaleCache
[eENGLISH
] = Locale("en");
152 gLocaleCache
[eFRENCH
] = Locale("fr");
153 gLocaleCache
[eGERMAN
] = Locale("de");
154 gLocaleCache
[eITALIAN
] = Locale("it");
155 gLocaleCache
[eJAPANESE
] = Locale("ja");
156 gLocaleCache
[eKOREAN
] = Locale("ko");
157 gLocaleCache
[eCHINESE
] = Locale("zh");
158 gLocaleCache
[eFRANCE
] = Locale("fr", "FR");
159 gLocaleCache
[eGERMANY
] = Locale("de", "DE");
160 gLocaleCache
[eITALY
] = Locale("it", "IT");
161 gLocaleCache
[eJAPAN
] = Locale("ja", "JP");
162 gLocaleCache
[eKOREA
] = Locale("ko", "KR");
163 gLocaleCache
[eCHINA
] = Locale("zh", "CN");
164 gLocaleCache
[eTAIWAN
] = Locale("zh", "TW");
165 gLocaleCache
[eUK
] = Locale("en", "GB");
166 gLocaleCache
[eUS
] = Locale("en", "US");
167 gLocaleCache
[eCANADA
] = Locale("en", "CA");
168 gLocaleCache
[eCANADA_FRENCH
] = Locale("fr", "CA");
175 Locale
*locale_set_default_internal(const char *id
, UErrorCode
& status
) {
176 // Synchronize this entire function.
177 Mutex
lock(gDefaultLocaleMutex());
179 UBool canonicalize
= FALSE
;
181 // If given a NULL string for the locale id, grab the default
182 // name from the system.
183 // (Different from most other locale APIs, where a null name means use
184 // the current ICU default locale.)
186 id
= uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify.
187 canonicalize
= TRUE
; // always canonicalize host ID
190 char localeNameBuf
[512];
193 uloc_canonicalize(id
, localeNameBuf
, sizeof(localeNameBuf
)-1, &status
);
195 uloc_getName(id
, localeNameBuf
, sizeof(localeNameBuf
)-1, &status
);
197 localeNameBuf
[sizeof(localeNameBuf
)-1] = 0; // Force null termination in event of
198 // a long name filling the buffer.
199 // (long names are truncated.)
201 if (U_FAILURE(status
)) {
202 return gDefaultLocale
;
205 if (gDefaultLocalesHashT
== NULL
) {
206 gDefaultLocalesHashT
= uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &status
);
207 if (U_FAILURE(status
)) {
208 return gDefaultLocale
;
210 uhash_setValueDeleter(gDefaultLocalesHashT
, deleteLocale
);
211 ucln_common_registerCleanup(UCLN_COMMON_LOCALE
, locale_cleanup
);
214 Locale
*newDefault
= (Locale
*)uhash_get(gDefaultLocalesHashT
, localeNameBuf
);
215 if (newDefault
== NULL
) {
216 newDefault
= new Locale(Locale::eBOGUS
);
217 if (newDefault
== NULL
) {
218 status
= U_MEMORY_ALLOCATION_ERROR
;
219 return gDefaultLocale
;
221 newDefault
->init(localeNameBuf
, FALSE
);
222 uhash_put(gDefaultLocalesHashT
, (char*) newDefault
->getName(), newDefault
, &status
);
223 if (U_FAILURE(status
)) {
224 return gDefaultLocale
;
227 gDefaultLocale
= newDefault
;
228 return gDefaultLocale
;
235 locale_set_default(const char *id
)
238 UErrorCode status
= U_ZERO_ERROR
;
239 locale_set_default_internal(id
, status
);
244 locale_get_default(void)
247 return Locale::getDefault().getName();
253 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale
)
255 /*Character separating the posix id fields*/
257 // In the platform codepage.
262 if (baseName
!= fullName
) {
266 /*if fullName is on the heap, we free it*/
267 if (fullName
!= fullNameBuffer
)
275 : UObject(), fullName(fullNameBuffer
), baseName(NULL
)
281 * Internal constructor to allow construction of a locale object with
282 * NO side effects. (Default constructor tries to get
283 * the default locale.)
285 Locale::Locale(Locale::ELocaleType
)
286 : UObject(), fullName(fullNameBuffer
), baseName(NULL
)
292 Locale::Locale( const char * newLanguage
,
293 const char * newCountry
,
294 const char * newVariant
,
295 const char * newKeywords
)
296 : UObject(), fullName(fullNameBuffer
), baseName(NULL
)
298 if( (newLanguage
==NULL
) && (newCountry
== NULL
) && (newVariant
== NULL
) )
300 init(NULL
, FALSE
); /* shortcut */
304 UErrorCode status
= U_ZERO_ERROR
;
311 // Calculate the size of the resulting string.
314 if ( newLanguage
!= NULL
)
316 lsize
= (int32_t)uprv_strlen(newLanguage
);
317 if ( lsize
< 0 || lsize
> ULOC_STRING_LIMIT
) { // int32 wrap
324 CharString
togo(newLanguage
, lsize
, status
); // start with newLanguage
327 if ( newCountry
!= NULL
)
329 csize
= (int32_t)uprv_strlen(newCountry
);
330 if ( csize
< 0 || csize
> ULOC_STRING_LIMIT
) { // int32 wrap
338 if ( newVariant
!= NULL
)
340 // remove leading _'s
341 while(newVariant
[0] == SEP_CHAR
)
346 // remove trailing _'s
347 vsize
= (int32_t)uprv_strlen(newVariant
);
348 if ( vsize
< 0 || vsize
> ULOC_STRING_LIMIT
) { // int32 wrap
352 while( (vsize
>1) && (newVariant
[vsize
-1] == SEP_CHAR
) )
366 size
+= 2; // at least: __v
368 else if ( csize
> 0 )
370 size
+= 1; // at least: _v
373 if ( newKeywords
!= NULL
)
375 ksize
= (int32_t)uprv_strlen(newKeywords
);
376 if ( ksize
< 0 || ksize
> ULOC_STRING_LIMIT
) {
383 // NOW we have the full locale string..
384 // Now, copy it back.
386 // newLanguage is already copied
388 if ( ( vsize
!= 0 ) || (csize
!= 0) ) // at least: __v
390 togo
.append(SEP_CHAR
, status
);
395 togo
.append(newCountry
, status
);
400 togo
.append(SEP_CHAR
, status
)
401 .append(newVariant
, vsize
, status
);
406 if (uprv_strchr(newKeywords
, '=')) {
407 togo
.append('@', status
); /* keyword parsing */
410 togo
.append('_', status
); /* Variant parsing with a script */
412 togo
.append('_', status
); /* No country found */
415 togo
.append(newKeywords
, status
);
418 if (U_FAILURE(status
)) {
419 // Something went wrong with appending, etc.
423 // Parse it, because for example 'language' might really be a complete
425 init(togo
.data(), FALSE
);
429 Locale::Locale(const Locale
&other
)
430 : UObject(other
), fullName(fullNameBuffer
), baseName(NULL
)
435 Locale::Locale(Locale
&& other
) U_NOEXCEPT
436 : UObject(other
), fullName(fullNameBuffer
), baseName(fullName
) {
437 *this = std::move(other
);
440 Locale
& Locale::operator=(const Locale
& other
) {
441 if (this == &other
) {
447 if (other
.fullName
== other
.fullNameBuffer
) {
448 uprv_strcpy(fullNameBuffer
, other
.fullNameBuffer
);
449 } else if (other
.fullName
== nullptr) {
452 fullName
= uprv_strdup(other
.fullName
);
453 if (fullName
== nullptr) return *this;
456 if (other
.baseName
== other
.fullName
) {
458 } else if (other
.baseName
!= nullptr) {
459 baseName
= uprv_strdup(other
.baseName
);
460 if (baseName
== nullptr) return *this;
463 uprv_strcpy(language
, other
.language
);
464 uprv_strcpy(script
, other
.script
);
465 uprv_strcpy(country
, other
.country
);
467 variantBegin
= other
.variantBegin
;
468 fIsBogus
= other
.fIsBogus
;
473 Locale
& Locale::operator=(Locale
&& other
) U_NOEXCEPT
{
474 if (baseName
!= fullName
) uprv_free(baseName
);
475 if (fullName
!= fullNameBuffer
) uprv_free(fullName
);
477 if (other
.fullName
== other
.fullNameBuffer
) {
478 uprv_strcpy(fullNameBuffer
, other
.fullNameBuffer
);
479 fullName
= fullNameBuffer
;
481 fullName
= other
.fullName
;
484 if (other
.baseName
== other
.fullName
) {
487 baseName
= other
.baseName
;
490 uprv_strcpy(language
, other
.language
);
491 uprv_strcpy(script
, other
.script
);
492 uprv_strcpy(country
, other
.country
);
494 variantBegin
= other
.variantBegin
;
495 fIsBogus
= other
.fIsBogus
;
497 other
.baseName
= other
.fullName
= other
.fullNameBuffer
;
503 Locale::clone() const {
504 return new Locale(*this);
508 Locale::operator==( const Locale
& other
) const
510 return (uprv_strcmp(other
.fullName
, fullName
) == 0);
513 #define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
515 /*This function initializes a Locale from a C locale ID*/
516 Locale
& Locale::init(const char* localeID
, UBool canonicalize
)
519 /* Free our current storage */
520 if (baseName
!= fullName
) {
524 if(fullName
!= fullNameBuffer
) {
526 fullName
= fullNameBuffer
;
530 // just an easy way to have a common error-exit
531 // without goto and without another function
534 char *field
[5] = {0};
535 int32_t fieldLen
[5] = {0};
537 int32_t variantField
;
541 if(localeID
== NULL
) {
542 // not an error, just set the default locale
543 return *this = getDefault();
546 /* preset all fields to empty */
547 language
[0] = script
[0] = country
[0] = 0;
549 // "canonicalize" the locale ID to ICU/Java format
551 length
= canonicalize
?
552 uloc_canonicalize(localeID
, fullName
, sizeof(fullNameBuffer
), &err
) :
553 uloc_getName(localeID
, fullName
, sizeof(fullNameBuffer
), &err
);
555 if(err
== U_BUFFER_OVERFLOW_ERROR
|| length
>= (int32_t)sizeof(fullNameBuffer
)) {
556 /*Go to heap for the fullName if necessary*/
557 fullName
= (char *)uprv_malloc(sizeof(char)*(length
+ 1));
559 fullName
= fullNameBuffer
;
560 break; // error: out of memory
563 length
= canonicalize
?
564 uloc_canonicalize(localeID
, fullName
, length
+1, &err
) :
565 uloc_getName(localeID
, fullName
, length
+1, &err
);
567 if(U_FAILURE(err
) || err
== U_STRING_NOT_TERMINATED_WARNING
) {
568 /* should never occur */
572 variantBegin
= length
;
574 /* after uloc_getName/canonicalize() we know that only '_' are separators */
575 /* But _ could also appeared in timezone such as "en@timezone=America/Los_Angeles" */
576 separator
= field
[0] = fullName
;
578 char* at
= uprv_strchr(fullName
, '@');
579 while ((separator
= uprv_strchr(field
[fieldIdx
-1], SEP_CHAR
)) != 0 &&
580 fieldIdx
< UPRV_LENGTHOF(field
)-1 &&
581 (at
== nullptr || separator
< at
)) {
582 field
[fieldIdx
] = separator
+ 1;
583 fieldLen
[fieldIdx
-1] = (int32_t)(separator
- field
[fieldIdx
-1]);
586 // variant may contain @foo or .foo POSIX cruft; remove it
587 separator
= uprv_strchr(field
[fieldIdx
-1], '@');
588 char* sep2
= uprv_strchr(field
[fieldIdx
-1], '.');
589 if (separator
!=NULL
|| sep2
!=NULL
) {
590 if (separator
==NULL
|| (sep2
!=NULL
&& separator
> sep2
)) {
593 fieldLen
[fieldIdx
-1] = (int32_t)(separator
- field
[fieldIdx
-1]);
595 fieldLen
[fieldIdx
-1] = length
- (int32_t)(field
[fieldIdx
-1] - fullName
);
598 if (fieldLen
[0] >= (int32_t)(sizeof(language
)))
600 break; // error: the language field is too long
603 variantField
= 1; /* Usually the 2nd one, except when a script or country is also used. */
604 if (fieldLen
[0] > 0) {
605 /* We have a language */
606 uprv_memcpy(language
, fullName
, fieldLen
[0]);
607 language
[fieldLen
[0]] = 0;
609 if (fieldLen
[1] == 4 && ISASCIIALPHA(field
[1][0]) &&
610 ISASCIIALPHA(field
[1][1]) && ISASCIIALPHA(field
[1][2]) &&
611 ISASCIIALPHA(field
[1][3])) {
612 /* We have at least a script */
613 uprv_memcpy(script
, field
[1], fieldLen
[1]);
614 script
[fieldLen
[1]] = 0;
618 if (fieldLen
[variantField
] == 2 || fieldLen
[variantField
] == 3) {
619 /* We have a country */
620 uprv_memcpy(country
, field
[variantField
], fieldLen
[variantField
]);
621 country
[fieldLen
[variantField
]] = 0;
623 } else if (fieldLen
[variantField
] == 0) {
624 variantField
++; /* script or country empty but variant in next field (i.e. en__POSIX) */
627 if (fieldLen
[variantField
] > 0) {
628 /* We have a variant */
629 variantBegin
= (int32_t)(field
[variantField
] - fullName
);
634 if (U_FAILURE(err
)) {
638 // successful end of init()
640 } while(0); /*loop doesn't iterate*/
642 // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
649 * Set up the base name.
650 * If there are no key words, it's exactly the full name.
651 * If key words exist, it's the full name truncated at the '@' character.
652 * Need to set up both at init() and after setting a keyword.
655 Locale::initBaseName(UErrorCode
&status
) {
656 if (U_FAILURE(status
)) {
659 U_ASSERT(baseName
==NULL
|| baseName
==fullName
);
660 const char *atPtr
= uprv_strchr(fullName
, '@');
661 const char *eqPtr
= uprv_strchr(fullName
, '=');
662 if (atPtr
&& eqPtr
&& atPtr
< eqPtr
) {
664 int32_t baseNameLength
= (int32_t)(atPtr
- fullName
);
665 baseName
= (char *)uprv_malloc(baseNameLength
+ 1);
666 if (baseName
== NULL
) {
667 status
= U_MEMORY_ALLOCATION_ERROR
;
670 uprv_strncpy(baseName
, fullName
, baseNameLength
);
671 baseName
[baseNameLength
] = 0;
673 // The original computation of variantBegin leaves it equal to the length
674 // of fullName if there is no variant. It should instead be
675 // the length of the baseName.
676 if (variantBegin
> baseNameLength
) {
677 variantBegin
= baseNameLength
;
686 Locale::hashCode() const
688 return ustr_hashCharsN(fullName
, static_cast<int32_t>(uprv_strlen(fullName
)));
692 Locale::setToBogus() {
693 /* Free our current storage */
694 if(baseName
!= fullName
) {
698 if(fullName
!= fullNameBuffer
) {
700 fullName
= fullNameBuffer
;
710 const Locale
& U_EXPORT2
714 Mutex
lock(gDefaultLocaleMutex());
715 if (gDefaultLocale
!= NULL
) {
716 return *gDefaultLocale
;
719 UErrorCode status
= U_ZERO_ERROR
;
720 return *locale_set_default_internal(NULL
, status
);
726 Locale::setDefault( const Locale
& newLocale
,
729 if (U_FAILURE(status
)) {
733 /* Set the default from the full name string of the supplied locale.
734 * This is a convenient way to access the default locale caching mechanisms.
736 const char *localeID
= newLocale
.getName();
737 locale_set_default_internal(localeID
, status
);
741 Locale::addLikelySubtags(UErrorCode
& status
) {
742 if (U_FAILURE(status
)) {
746 CharString maximizedLocaleID
;
748 CharStringByteSink
sink(&maximizedLocaleID
);
749 ulocimp_addLikelySubtags(fullName
, sink
, &status
);
752 if (U_FAILURE(status
)) {
756 init(maximizedLocaleID
.data(), /*canonicalize=*/FALSE
);
758 status
= U_ILLEGAL_ARGUMENT_ERROR
;
763 Locale::minimizeSubtags(UErrorCode
& status
) {
764 if (U_FAILURE(status
)) {
768 CharString minimizedLocaleID
;
770 CharStringByteSink
sink(&minimizedLocaleID
);
771 ulocimp_minimizeSubtags(fullName
, sink
, &status
);
774 if (U_FAILURE(status
)) {
778 init(minimizedLocaleID
.data(), /*canonicalize=*/FALSE
);
780 status
= U_ILLEGAL_ARGUMENT_ERROR
;
785 Locale::forLanguageTag(StringPiece tag
, UErrorCode
& status
)
787 Locale
result(Locale::eBOGUS
);
789 if (U_FAILURE(status
)) {
793 // If a BCP-47 language tag is passed as the language parameter to the
794 // normal Locale constructor, it will actually fall back to invoking
795 // uloc_forLanguageTag() to parse it if it somehow is able to detect that
796 // the string actually is BCP-47. This works well for things like strings
797 // using BCP-47 extensions, but it does not at all work for things like
798 // BCP-47 grandfathered tags (eg. "en-GB-oed") which are possible to also
799 // interpret as ICU locale IDs and because of that won't trigger the BCP-47
800 // parsing. Therefore the code here explicitly calls uloc_forLanguageTag()
801 // and then Locale::init(), instead of just calling the normal constructor.
804 int32_t parsedLength
;
806 CharStringByteSink
sink(&localeID
);
807 ulocimp_forLanguageTag(
815 if (U_FAILURE(status
)) {
819 if (parsedLength
!= tag
.size()) {
820 status
= U_ILLEGAL_ARGUMENT_ERROR
;
824 result
.init(localeID
.data(), /*canonicalize=*/FALSE
);
825 if (result
.isBogus()) {
826 status
= U_ILLEGAL_ARGUMENT_ERROR
;
832 Locale::toLanguageTag(ByteSink
& sink
, UErrorCode
& status
) const
834 if (U_FAILURE(status
)) {
839 status
= U_ILLEGAL_ARGUMENT_ERROR
;
843 ulocimp_toLanguageTag(fullName
, sink
, /*strict=*/FALSE
, &status
);
847 Locale::createFromName (const char *name
)
860 Locale::createCanonical(const char* name
) {
862 loc
.init(name
, TRUE
);
867 Locale::getISO3Language() const
869 return uloc_getISO3Language(fullName
);
874 Locale::getISO3Country() const
876 return uloc_getISO3Country(fullName
);
880 * Return the LCID value as specified in the "LocaleID" resource for this
881 * locale. The LocaleID must be expressed as a hexadecimal number, from
882 * one to four digits. If the LocaleID resource is not present, or is
883 * in an incorrect format, 0 is returned. The LocaleID is for use in
884 * Windows (it is an LCID), but is available on all platforms.
887 Locale::getLCID() const
889 return uloc_getLCID(fullName
);
892 const char* const* U_EXPORT2
Locale::getISOCountries()
894 return uloc_getISOCountries();
897 const char* const* U_EXPORT2
Locale::getISOLanguages()
899 return uloc_getISOLanguages();
902 // Set the locale's data based on a posix id.
903 void Locale::setFromPOSIXID(const char *posixID
)
908 const Locale
& U_EXPORT2
909 Locale::getRoot(void)
911 return getLocale(eROOT
);
914 const Locale
& U_EXPORT2
915 Locale::getEnglish(void)
917 return getLocale(eENGLISH
);
920 const Locale
& U_EXPORT2
921 Locale::getFrench(void)
923 return getLocale(eFRENCH
);
926 const Locale
& U_EXPORT2
927 Locale::getGerman(void)
929 return getLocale(eGERMAN
);
932 const Locale
& U_EXPORT2
933 Locale::getItalian(void)
935 return getLocale(eITALIAN
);
938 const Locale
& U_EXPORT2
939 Locale::getJapanese(void)
941 return getLocale(eJAPANESE
);
944 const Locale
& U_EXPORT2
945 Locale::getKorean(void)
947 return getLocale(eKOREAN
);
950 const Locale
& U_EXPORT2
951 Locale::getChinese(void)
953 return getLocale(eCHINESE
);
956 const Locale
& U_EXPORT2
957 Locale::getSimplifiedChinese(void)
959 return getLocale(eCHINA
);
962 const Locale
& U_EXPORT2
963 Locale::getTraditionalChinese(void)
965 return getLocale(eTAIWAN
);
969 const Locale
& U_EXPORT2
970 Locale::getFrance(void)
972 return getLocale(eFRANCE
);
975 const Locale
& U_EXPORT2
976 Locale::getGermany(void)
978 return getLocale(eGERMANY
);
981 const Locale
& U_EXPORT2
982 Locale::getItaly(void)
984 return getLocale(eITALY
);
987 const Locale
& U_EXPORT2
988 Locale::getJapan(void)
990 return getLocale(eJAPAN
);
993 const Locale
& U_EXPORT2
994 Locale::getKorea(void)
996 return getLocale(eKOREA
);
999 const Locale
& U_EXPORT2
1000 Locale::getChina(void)
1002 return getLocale(eCHINA
);
1005 const Locale
& U_EXPORT2
1006 Locale::getPRC(void)
1008 return getLocale(eCHINA
);
1011 const Locale
& U_EXPORT2
1012 Locale::getTaiwan(void)
1014 return getLocale(eTAIWAN
);
1017 const Locale
& U_EXPORT2
1020 return getLocale(eUK
);
1023 const Locale
& U_EXPORT2
1026 return getLocale(eUS
);
1029 const Locale
& U_EXPORT2
1030 Locale::getCanada(void)
1032 return getLocale(eCANADA
);
1035 const Locale
& U_EXPORT2
1036 Locale::getCanadaFrench(void)
1038 return getLocale(eCANADA_FRENCH
);
1042 Locale::getLocale(int locid
)
1044 Locale
*localeCache
= getLocaleCache();
1045 U_ASSERT((locid
< eMAX_LOCALES
)&&(locid
>=0));
1046 if (localeCache
== NULL
) {
1047 // Failure allocating the locale cache.
1048 // The best we can do is return a NULL reference.
1051 return localeCache
[locid
]; /*operating on NULL*/
1055 This function is defined this way in order to get around static
1056 initialization and static destruction.
1059 Locale::getLocaleCache(void)
1061 UErrorCode status
= U_ZERO_ERROR
;
1062 umtx_initOnce(gLocaleCacheInitOnce
, locale_init
, status
);
1063 return gLocaleCache
;
1066 class KeywordEnumeration
: public StringEnumeration
{
1071 UnicodeString currUSKey
;
1072 static const char fgClassID
;/* Warning this is used beyond the typical RTTI usage. */
1075 static UClassID U_EXPORT2
getStaticClassID(void) { return (UClassID
)&fgClassID
; }
1076 virtual UClassID
getDynamicClassID(void) const { return getStaticClassID(); }
1078 KeywordEnumeration(const char *keys
, int32_t keywordLen
, int32_t currentIndex
, UErrorCode
&status
)
1079 : keywords((char *)&fgClassID
), current((char *)&fgClassID
), length(0) {
1080 if(U_SUCCESS(status
) && keywordLen
!= 0) {
1081 if(keys
== NULL
|| keywordLen
< 0) {
1082 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1084 keywords
= (char *)uprv_malloc(keywordLen
+1);
1085 if (keywords
== NULL
) {
1086 status
= U_MEMORY_ALLOCATION_ERROR
;
1089 uprv_memcpy(keywords
, keys
, keywordLen
);
1090 keywords
[keywordLen
] = 0;
1091 current
= keywords
+ currentIndex
;
1092 length
= keywordLen
;
1098 virtual ~KeywordEnumeration();
1100 virtual StringEnumeration
* clone() const
1102 UErrorCode status
= U_ZERO_ERROR
;
1103 return new KeywordEnumeration(keywords
, length
, (int32_t)(current
- keywords
), status
);
1106 virtual int32_t count(UErrorCode
&/*status*/) const {
1107 char *kw
= keywords
;
1111 kw
+= uprv_strlen(kw
)+1;
1116 virtual const char* next(int32_t* resultLength
, UErrorCode
& status
) {
1119 if(U_SUCCESS(status
) && *current
!= 0) {
1121 len
= (int32_t)uprv_strlen(current
);
1123 if(resultLength
!= NULL
) {
1124 *resultLength
= len
;
1127 if(resultLength
!= NULL
) {
1135 virtual const UnicodeString
* snext(UErrorCode
& status
) {
1136 int32_t resultLength
= 0;
1137 const char *s
= next(&resultLength
, status
);
1138 return setChars(s
, resultLength
, status
);
1141 virtual void reset(UErrorCode
& /*status*/) {
1146 const char KeywordEnumeration::fgClassID
= '\0';
1148 KeywordEnumeration::~KeywordEnumeration() {
1149 uprv_free(keywords
);
1152 // A wrapper around KeywordEnumeration that calls uloc_toUnicodeLocaleKey() in
1153 // the next() method for each keyword before returning it.
1154 class UnicodeKeywordEnumeration
: public KeywordEnumeration
{
1156 using KeywordEnumeration::KeywordEnumeration
;
1157 virtual ~UnicodeKeywordEnumeration();
1159 virtual const char* next(int32_t* resultLength
, UErrorCode
& status
) {
1160 const char* legacy_key
= KeywordEnumeration::next(nullptr, status
);
1161 if (U_SUCCESS(status
) && legacy_key
!= nullptr) {
1162 const char* key
= uloc_toUnicodeLocaleKey(legacy_key
);
1163 if (key
== nullptr) {
1164 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1166 if (resultLength
!= nullptr) {
1167 *resultLength
= static_cast<int32_t>(uprv_strlen(key
));
1172 if (resultLength
!= nullptr) *resultLength
= 0;
1177 // Out-of-line virtual destructor to serve as the "key function".
1178 UnicodeKeywordEnumeration::~UnicodeKeywordEnumeration() = default;
1181 Locale::createKeywords(UErrorCode
&status
) const
1184 int32_t keywordCapacity
= sizeof keywords
;
1185 StringEnumeration
*result
= NULL
;
1187 if (U_FAILURE(status
)) {
1191 const char* variantStart
= uprv_strchr(fullName
, '@');
1192 const char* assignment
= uprv_strchr(fullName
, '=');
1194 if(assignment
> variantStart
) {
1195 int32_t keyLen
= locale_getKeywords(variantStart
+1, '@', keywords
, keywordCapacity
, NULL
, 0, NULL
, FALSE
, &status
);
1196 if(U_SUCCESS(status
) && keyLen
) {
1197 result
= new KeywordEnumeration(keywords
, keyLen
, 0, status
);
1199 status
= U_MEMORY_ALLOCATION_ERROR
;
1203 status
= U_INVALID_FORMAT_ERROR
;
1210 Locale::createUnicodeKeywords(UErrorCode
&status
) const
1213 int32_t keywordCapacity
= sizeof keywords
;
1214 StringEnumeration
*result
= NULL
;
1216 if (U_FAILURE(status
)) {
1220 const char* variantStart
= uprv_strchr(fullName
, '@');
1221 const char* assignment
= uprv_strchr(fullName
, '=');
1223 if(assignment
> variantStart
) {
1224 int32_t keyLen
= locale_getKeywords(variantStart
+1, '@', keywords
, keywordCapacity
, NULL
, 0, NULL
, FALSE
, &status
);
1225 if(U_SUCCESS(status
) && keyLen
) {
1226 result
= new UnicodeKeywordEnumeration(keywords
, keyLen
, 0, status
);
1228 status
= U_MEMORY_ALLOCATION_ERROR
;
1232 status
= U_INVALID_FORMAT_ERROR
;
1239 Locale::getKeywordValue(const char* keywordName
, char *buffer
, int32_t bufLen
, UErrorCode
&status
) const
1241 return uloc_getKeywordValue(fullName
, keywordName
, buffer
, bufLen
, &status
);
1245 Locale::getKeywordValue(StringPiece keywordName
, ByteSink
& sink
, UErrorCode
& status
) const {
1246 if (U_FAILURE(status
)) {
1251 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1255 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1256 const CharString
keywordName_nul(keywordName
, status
);
1257 if (U_FAILURE(status
)) {
1261 LocalMemory
<char> scratch
;
1262 int32_t scratch_capacity
= 16; // Arbitrarily chosen default size.
1265 int32_t result_capacity
, reslen
;
1268 if (scratch
.allocateInsteadAndReset(scratch_capacity
) == nullptr) {
1269 status
= U_MEMORY_ALLOCATION_ERROR
;
1273 buffer
= sink
.GetAppendBuffer(
1274 /*min_capacity=*/scratch_capacity
,
1275 /*desired_capacity_hint=*/scratch_capacity
,
1280 reslen
= uloc_getKeywordValue(
1282 keywordName_nul
.data(),
1287 if (status
!= U_BUFFER_OVERFLOW_ERROR
) {
1291 scratch_capacity
= reslen
;
1292 status
= U_ZERO_ERROR
;
1295 if (U_FAILURE(status
)) {
1299 sink
.Append(buffer
, reslen
);
1300 if (status
== U_STRING_NOT_TERMINATED_WARNING
) {
1301 status
= U_ZERO_ERROR
; // Terminators not used.
1306 Locale::getUnicodeKeywordValue(StringPiece keywordName
,
1308 UErrorCode
& status
) const {
1309 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1310 const CharString
keywordName_nul(keywordName
, status
);
1311 if (U_FAILURE(status
)) {
1315 const char* legacy_key
= uloc_toLegacyKey(keywordName_nul
.data());
1317 if (legacy_key
== nullptr) {
1318 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1322 CharString legacy_value
;
1324 CharStringByteSink
sink(&legacy_value
);
1325 getKeywordValue(legacy_key
, sink
, status
);
1328 if (U_FAILURE(status
)) {
1332 const char* unicode_value
= uloc_toUnicodeLocaleType(
1333 keywordName_nul
.data(), legacy_value
.data());
1335 if (unicode_value
== nullptr) {
1336 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1340 sink
.Append(unicode_value
, static_cast<int32_t>(uprv_strlen(unicode_value
)));
1344 Locale::setKeywordValue(const char* keywordName
, const char* keywordValue
, UErrorCode
&status
)
1346 uloc_setKeywordValue(keywordName
, keywordValue
, fullName
, ULOC_FULLNAME_CAPACITY
, &status
);
1347 if (U_SUCCESS(status
) && baseName
== fullName
) {
1348 // May have added the first keyword, meaning that the fullName is no longer also the baseName.
1349 initBaseName(status
);
1354 Locale::setKeywordValue(StringPiece keywordName
,
1355 StringPiece keywordValue
,
1356 UErrorCode
& status
) {
1357 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1358 const CharString
keywordName_nul(keywordName
, status
);
1359 const CharString
keywordValue_nul(keywordValue
, status
);
1360 setKeywordValue(keywordName_nul
.data(), keywordValue_nul
.data(), status
);
1364 Locale::setUnicodeKeywordValue(StringPiece keywordName
,
1365 StringPiece keywordValue
,
1366 UErrorCode
& status
) {
1367 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1368 const CharString
keywordName_nul(keywordName
, status
);
1369 const CharString
keywordValue_nul(keywordValue
, status
);
1371 if (U_FAILURE(status
)) {
1375 const char* legacy_key
= uloc_toLegacyKey(keywordName_nul
.data());
1377 if (legacy_key
== nullptr) {
1378 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1382 const char* legacy_value
= nullptr;
1384 if (!keywordValue_nul
.isEmpty()) {
1386 uloc_toLegacyType(keywordName_nul
.data(), keywordValue_nul
.data());
1388 if (legacy_value
== nullptr) {
1389 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1394 setKeywordValue(legacy_key
, legacy_value
, status
);
1398 Locale::getBaseName() const {