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 ******************************************************************************
35 #include "unicode/locid.h"
36 #include "unicode/strenum.h"
37 #include "unicode/uloc.h"
51 static UBool U_CALLCONV
locale_cleanup(void);
56 static Locale
*gLocaleCache
= NULL
;
57 static UInitOnce gLocaleCacheInitOnce
= U_INITONCE_INITIALIZER
;
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
;
65 * \def ULOC_STRING_LIMIT
66 * strings beyond this value crash in CharString
68 #define ULOC_STRING_LIMIT 357913941
72 typedef enum ELocalePos
{
86 eCHINA
, /* Alias for PRC */
99 U_CFUNC
int32_t locale_getKeywords(const char *localeID
,
101 char *keywords
, int32_t keywordCapacity
,
102 char *values
, int32_t valuesCapacity
, int32_t *valLen
,
108 // Deleter function for Locales owned by the default Locale hash table/
110 static void U_CALLCONV
111 deleteLocale(void *obj
) {
112 delete (icu::Locale
*) obj
;
115 static UBool U_CALLCONV
locale_cleanup(void)
119 delete [] gLocaleCache
;
121 gLocaleCacheInitOnce
.reset();
123 if (gDefaultLocalesHashT
) {
124 uhash_close(gDefaultLocalesHashT
); // Automatically deletes all elements, using deleter func.
125 gDefaultLocalesHashT
= NULL
;
127 gDefaultLocale
= NULL
;
132 static void U_CALLCONV
locale_init(UErrorCode
&status
) {
135 U_ASSERT(gLocaleCache
== NULL
);
136 gLocaleCache
= new Locale
[(int)eMAX_LOCALES
];
137 if (gLocaleCache
== NULL
) {
138 status
= U_MEMORY_ALLOCATION_ERROR
;
141 ucln_common_registerCleanup(UCLN_COMMON_LOCALE
, locale_cleanup
);
142 gLocaleCache
[eROOT
] = Locale("");
143 gLocaleCache
[eENGLISH
] = Locale("en");
144 gLocaleCache
[eFRENCH
] = Locale("fr");
145 gLocaleCache
[eGERMAN
] = Locale("de");
146 gLocaleCache
[eITALIAN
] = Locale("it");
147 gLocaleCache
[eJAPANESE
] = Locale("ja");
148 gLocaleCache
[eKOREAN
] = Locale("ko");
149 gLocaleCache
[eCHINESE
] = Locale("zh");
150 gLocaleCache
[eFRANCE
] = Locale("fr", "FR");
151 gLocaleCache
[eGERMANY
] = Locale("de", "DE");
152 gLocaleCache
[eITALY
] = Locale("it", "IT");
153 gLocaleCache
[eJAPAN
] = Locale("ja", "JP");
154 gLocaleCache
[eKOREA
] = Locale("ko", "KR");
155 gLocaleCache
[eCHINA
] = Locale("zh", "CN");
156 gLocaleCache
[eTAIWAN
] = Locale("zh", "TW");
157 gLocaleCache
[eUK
] = Locale("en", "GB");
158 gLocaleCache
[eUS
] = Locale("en", "US");
159 gLocaleCache
[eCANADA
] = Locale("en", "CA");
160 gLocaleCache
[eCANADA_FRENCH
] = Locale("fr", "CA");
167 Locale
*locale_set_default_internal(const char *id
, UErrorCode
& status
) {
168 // Synchronize this entire function.
169 Mutex
lock(&gDefaultLocaleMutex
);
171 UBool canonicalize
= FALSE
;
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.)
178 id
= uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify.
179 canonicalize
= TRUE
; // always canonicalize host ID
182 char localeNameBuf
[512];
185 uloc_canonicalize(id
, localeNameBuf
, sizeof(localeNameBuf
)-1, &status
);
187 uloc_getName(id
, localeNameBuf
, sizeof(localeNameBuf
)-1, &status
);
189 localeNameBuf
[sizeof(localeNameBuf
)-1] = 0; // Force null termination in event of
190 // a long name filling the buffer.
191 // (long names are truncated.)
193 if (U_FAILURE(status
)) {
194 return gDefaultLocale
;
197 if (gDefaultLocalesHashT
== NULL
) {
198 gDefaultLocalesHashT
= uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &status
);
199 if (U_FAILURE(status
)) {
200 return gDefaultLocale
;
202 uhash_setValueDeleter(gDefaultLocalesHashT
, deleteLocale
);
203 ucln_common_registerCleanup(UCLN_COMMON_LOCALE
, locale_cleanup
);
206 Locale
*newDefault
= (Locale
*)uhash_get(gDefaultLocalesHashT
, localeNameBuf
);
207 if (newDefault
== NULL
) {
208 newDefault
= new Locale(Locale::eBOGUS
);
209 if (newDefault
== NULL
) {
210 status
= U_MEMORY_ALLOCATION_ERROR
;
211 return gDefaultLocale
;
213 newDefault
->init(localeNameBuf
, FALSE
);
214 uhash_put(gDefaultLocalesHashT
, (char*) newDefault
->getName(), newDefault
, &status
);
215 if (U_FAILURE(status
)) {
216 return gDefaultLocale
;
219 gDefaultLocale
= newDefault
;
220 return gDefaultLocale
;
227 locale_set_default(const char *id
)
230 UErrorCode status
= U_ZERO_ERROR
;
231 locale_set_default_internal(id
, status
);
236 locale_get_default(void)
239 return Locale::getDefault().getName();
245 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale
)
247 /*Character separating the posix id fields*/
249 // In the platform codepage.
254 if (baseName
!= fullName
) {
258 /*if fullName is on the heap, we free it*/
259 if (fullName
!= fullNameBuffer
)
267 : UObject(), fullName(fullNameBuffer
), baseName(NULL
)
273 * Internal constructor to allow construction of a locale object with
274 * NO side effects. (Default constructor tries to get
275 * the default locale.)
277 Locale::Locale(Locale::ELocaleType
)
278 : UObject(), fullName(fullNameBuffer
), baseName(NULL
)
284 Locale::Locale( const char * newLanguage
,
285 const char * newCountry
,
286 const char * newVariant
,
287 const char * newKeywords
)
288 : UObject(), fullName(fullNameBuffer
), baseName(NULL
)
290 if( (newLanguage
==NULL
) && (newCountry
== NULL
) && (newVariant
== NULL
) )
292 init(NULL
, FALSE
); /* shortcut */
296 UErrorCode status
= U_ZERO_ERROR
;
303 // Calculate the size of the resulting string.
306 if ( newLanguage
!= NULL
)
308 lsize
= (int32_t)uprv_strlen(newLanguage
);
309 if ( lsize
< 0 || lsize
> ULOC_STRING_LIMIT
) { // int32 wrap
316 CharString
togo(newLanguage
, lsize
, status
); // start with newLanguage
319 if ( newCountry
!= NULL
)
321 csize
= (int32_t)uprv_strlen(newCountry
);
322 if ( csize
< 0 || csize
> ULOC_STRING_LIMIT
) { // int32 wrap
330 if ( newVariant
!= NULL
)
332 // remove leading _'s
333 while(newVariant
[0] == SEP_CHAR
)
338 // remove trailing _'s
339 vsize
= (int32_t)uprv_strlen(newVariant
);
340 if ( vsize
< 0 || vsize
> ULOC_STRING_LIMIT
) { // int32 wrap
344 while( (vsize
>1) && (newVariant
[vsize
-1] == SEP_CHAR
) )
358 size
+= 2; // at least: __v
360 else if ( csize
> 0 )
362 size
+= 1; // at least: _v
365 if ( newKeywords
!= NULL
)
367 ksize
= (int32_t)uprv_strlen(newKeywords
);
368 if ( ksize
< 0 || ksize
> ULOC_STRING_LIMIT
) {
375 // NOW we have the full locale string..
376 // Now, copy it back.
378 // newLanguage is already copied
380 if ( ( vsize
!= 0 ) || (csize
!= 0) ) // at least: __v
382 togo
.append(SEP_CHAR
, status
);
387 togo
.append(newCountry
, status
);
392 togo
.append(SEP_CHAR
, status
)
393 .append(newVariant
, vsize
, status
);
398 if (uprv_strchr(newKeywords
, '=')) {
399 togo
.append('@', status
); /* keyword parsing */
402 togo
.append('_', status
); /* Variant parsing with a script */
404 togo
.append('_', status
); /* No country found */
407 togo
.append(newKeywords
, status
);
410 if (U_FAILURE(status
)) {
411 // Something went wrong with appending, etc.
415 // Parse it, because for example 'language' might really be a complete
417 init(togo
.data(), FALSE
);
421 Locale::Locale(const Locale
&other
)
422 : UObject(other
), fullName(fullNameBuffer
), baseName(NULL
)
427 Locale
&Locale::operator=(const Locale
&other
)
429 if (this == &other
) {
433 /* Free our current storage */
434 if (baseName
!= fullName
) {
438 if(fullName
!= fullNameBuffer
) {
440 fullName
= fullNameBuffer
;
443 /* Allocate the full name if necessary */
444 if(other
.fullName
!= other
.fullNameBuffer
) {
445 fullName
= (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other
.fullName
)+1));
446 if (fullName
== NULL
) {
450 /* Copy the full name */
451 uprv_strcpy(fullName
, other
.fullName
);
453 /* Copy the baseName if it differs from fullName. */
454 if (other
.baseName
== other
.fullName
) {
457 if (other
.baseName
) {
458 baseName
= uprv_strdup(other
.baseName
);
462 /* Copy the language and country fields */
463 uprv_strcpy(language
, other
.language
);
464 uprv_strcpy(script
, other
.script
);
465 uprv_strcpy(country
, other
.country
);
467 /* The variantBegin is an offset, just copy it */
468 variantBegin
= other
.variantBegin
;
469 fIsBogus
= other
.fIsBogus
;
474 Locale::clone() const {
475 return new Locale(*this);
479 Locale::operator==( const Locale
& other
) const
481 return (uprv_strcmp(other
.fullName
, fullName
) == 0);
484 #define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
486 /*This function initializes a Locale from a C locale ID*/
487 Locale
& Locale::init(const char* localeID
, UBool canonicalize
)
490 /* Free our current storage */
491 if (baseName
!= fullName
) {
495 if(fullName
!= fullNameBuffer
) {
497 fullName
= fullNameBuffer
;
501 // just an easy way to have a common error-exit
502 // without goto and without another function
505 char *field
[5] = {0};
506 int32_t fieldLen
[5] = {0};
508 int32_t variantField
;
512 if(localeID
== NULL
) {
513 // not an error, just set the default locale
514 return *this = getDefault();
517 /* preset all fields to empty */
518 language
[0] = script
[0] = country
[0] = 0;
520 // "canonicalize" the locale ID to ICU/Java format
522 length
= canonicalize
?
523 uloc_canonicalize(localeID
, fullName
, sizeof(fullNameBuffer
), &err
) :
524 uloc_getName(localeID
, fullName
, sizeof(fullNameBuffer
), &err
);
526 if(err
== U_BUFFER_OVERFLOW_ERROR
|| length
>= (int32_t)sizeof(fullNameBuffer
)) {
527 /*Go to heap for the fullName if necessary*/
528 fullName
= (char *)uprv_malloc(sizeof(char)*(length
+ 1));
530 fullName
= fullNameBuffer
;
531 break; // error: out of memory
534 length
= canonicalize
?
535 uloc_canonicalize(localeID
, fullName
, length
+1, &err
) :
536 uloc_getName(localeID
, fullName
, length
+1, &err
);
538 if(U_FAILURE(err
) || err
== U_STRING_NOT_TERMINATED_WARNING
) {
539 /* should never occur */
543 variantBegin
= length
;
545 /* after uloc_getName/canonicalize() we know that only '_' are separators */
546 separator
= field
[0] = fullName
;
548 while ((separator
= uprv_strchr(field
[fieldIdx
-1], SEP_CHAR
)) && fieldIdx
< UPRV_LENGTHOF(field
)-1) {
549 field
[fieldIdx
] = separator
+ 1;
550 fieldLen
[fieldIdx
-1] = (int32_t)(separator
- field
[fieldIdx
-1]);
553 // variant may contain @foo or .foo POSIX cruft; remove it
554 separator
= uprv_strchr(field
[fieldIdx
-1], '@');
555 char* sep2
= uprv_strchr(field
[fieldIdx
-1], '.');
556 if (separator
!=NULL
|| sep2
!=NULL
) {
557 if (separator
==NULL
|| (sep2
!=NULL
&& separator
> sep2
)) {
560 fieldLen
[fieldIdx
-1] = (int32_t)(separator
- field
[fieldIdx
-1]);
562 fieldLen
[fieldIdx
-1] = length
- (int32_t)(field
[fieldIdx
-1] - fullName
);
565 if (fieldLen
[0] >= (int32_t)(sizeof(language
)))
567 break; // error: the language field is too long
570 variantField
= 1; /* Usually the 2nd one, except when a script or country is also used. */
571 if (fieldLen
[0] > 0) {
572 /* We have a language */
573 uprv_memcpy(language
, fullName
, fieldLen
[0]);
574 language
[fieldLen
[0]] = 0;
576 if (fieldLen
[1] == 4 && ISASCIIALPHA(field
[1][0]) &&
577 ISASCIIALPHA(field
[1][1]) && ISASCIIALPHA(field
[1][2]) &&
578 ISASCIIALPHA(field
[1][3])) {
579 /* We have at least a script */
580 uprv_memcpy(script
, field
[1], fieldLen
[1]);
581 script
[fieldLen
[1]] = 0;
585 if (fieldLen
[variantField
] == 2 || fieldLen
[variantField
] == 3) {
586 /* We have a country */
587 uprv_memcpy(country
, field
[variantField
], fieldLen
[variantField
]);
588 country
[fieldLen
[variantField
]] = 0;
590 } else if (fieldLen
[variantField
] == 0) {
591 variantField
++; /* script or country empty but variant in next field (i.e. en__POSIX) */
594 if (fieldLen
[variantField
] > 0) {
595 /* We have a variant */
596 variantBegin
= (int32_t)(field
[variantField
] - fullName
);
601 if (U_FAILURE(err
)) {
605 // successful end of init()
607 } while(0); /*loop doesn't iterate*/
609 // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
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.
622 Locale::initBaseName(UErrorCode
&status
) {
623 if (U_FAILURE(status
)) {
626 U_ASSERT(baseName
==NULL
|| baseName
==fullName
);
627 const char *atPtr
= uprv_strchr(fullName
, '@');
628 const char *eqPtr
= uprv_strchr(fullName
, '=');
629 if (atPtr
&& eqPtr
&& atPtr
< eqPtr
) {
631 int32_t baseNameLength
= (int32_t)(atPtr
- fullName
);
632 baseName
= (char *)uprv_malloc(baseNameLength
+ 1);
633 if (baseName
== NULL
) {
634 status
= U_MEMORY_ALLOCATION_ERROR
;
637 uprv_strncpy(baseName
, fullName
, baseNameLength
);
638 baseName
[baseNameLength
] = 0;
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 if (variantBegin
> baseNameLength
) {
644 variantBegin
= baseNameLength
;
653 Locale::hashCode() const
655 return ustr_hashCharsN(fullName
, uprv_strlen(fullName
));
659 Locale::setToBogus() {
660 /* Free our current storage */
661 if(baseName
!= fullName
) {
665 if(fullName
!= fullNameBuffer
) {
667 fullName
= fullNameBuffer
;
677 const Locale
& U_EXPORT2
681 Mutex
lock(&gDefaultLocaleMutex
);
682 if (gDefaultLocale
!= NULL
) {
683 return *gDefaultLocale
;
686 UErrorCode status
= U_ZERO_ERROR
;
687 return *locale_set_default_internal(NULL
, status
);
693 Locale::setDefault( const Locale
& newLocale
,
696 if (U_FAILURE(status
)) {
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.
703 const char *localeID
= newLocale
.getName();
704 locale_set_default_internal(localeID
, status
);
708 Locale::createFromName (const char *name
)
721 Locale::createCanonical(const char* name
) {
723 loc
.init(name
, TRUE
);
728 Locale::getISO3Language() const
730 return uloc_getISO3Language(fullName
);
735 Locale::getISO3Country() const
737 return uloc_getISO3Country(fullName
);
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.
748 Locale::getLCID() const
750 return uloc_getLCID(fullName
);
753 const char* const* U_EXPORT2
Locale::getISOCountries()
755 return uloc_getISOCountries();
758 const char* const* U_EXPORT2
Locale::getISOLanguages()
760 return uloc_getISOLanguages();
763 // Set the locale's data based on a posix id.
764 void Locale::setFromPOSIXID(const char *posixID
)
769 const Locale
& U_EXPORT2
770 Locale::getRoot(void)
772 return getLocale(eROOT
);
775 const Locale
& U_EXPORT2
776 Locale::getEnglish(void)
778 return getLocale(eENGLISH
);
781 const Locale
& U_EXPORT2
782 Locale::getFrench(void)
784 return getLocale(eFRENCH
);
787 const Locale
& U_EXPORT2
788 Locale::getGerman(void)
790 return getLocale(eGERMAN
);
793 const Locale
& U_EXPORT2
794 Locale::getItalian(void)
796 return getLocale(eITALIAN
);
799 const Locale
& U_EXPORT2
800 Locale::getJapanese(void)
802 return getLocale(eJAPANESE
);
805 const Locale
& U_EXPORT2
806 Locale::getKorean(void)
808 return getLocale(eKOREAN
);
811 const Locale
& U_EXPORT2
812 Locale::getChinese(void)
814 return getLocale(eCHINESE
);
817 const Locale
& U_EXPORT2
818 Locale::getSimplifiedChinese(void)
820 return getLocale(eCHINA
);
823 const Locale
& U_EXPORT2
824 Locale::getTraditionalChinese(void)
826 return getLocale(eTAIWAN
);
830 const Locale
& U_EXPORT2
831 Locale::getFrance(void)
833 return getLocale(eFRANCE
);
836 const Locale
& U_EXPORT2
837 Locale::getGermany(void)
839 return getLocale(eGERMANY
);
842 const Locale
& U_EXPORT2
843 Locale::getItaly(void)
845 return getLocale(eITALY
);
848 const Locale
& U_EXPORT2
849 Locale::getJapan(void)
851 return getLocale(eJAPAN
);
854 const Locale
& U_EXPORT2
855 Locale::getKorea(void)
857 return getLocale(eKOREA
);
860 const Locale
& U_EXPORT2
861 Locale::getChina(void)
863 return getLocale(eCHINA
);
866 const Locale
& U_EXPORT2
869 return getLocale(eCHINA
);
872 const Locale
& U_EXPORT2
873 Locale::getTaiwan(void)
875 return getLocale(eTAIWAN
);
878 const Locale
& U_EXPORT2
881 return getLocale(eUK
);
884 const Locale
& U_EXPORT2
887 return getLocale(eUS
);
890 const Locale
& U_EXPORT2
891 Locale::getCanada(void)
893 return getLocale(eCANADA
);
896 const Locale
& U_EXPORT2
897 Locale::getCanadaFrench(void)
899 return getLocale(eCANADA_FRENCH
);
903 Locale::getLocale(int locid
)
905 Locale
*localeCache
= getLocaleCache();
906 U_ASSERT((locid
< eMAX_LOCALES
)&&(locid
>=0));
907 if (localeCache
== NULL
) {
908 // Failure allocating the locale cache.
909 // The best we can do is return a NULL reference.
912 return localeCache
[locid
]; /*operating on NULL*/
916 This function is defined this way in order to get around static
917 initialization and static destruction.
920 Locale::getLocaleCache(void)
922 UErrorCode status
= U_ZERO_ERROR
;
923 umtx_initOnce(gLocaleCacheInitOnce
, locale_init
, status
);
927 class KeywordEnumeration
: public StringEnumeration
{
932 UnicodeString currUSKey
;
933 static const char fgClassID
;/* Warning this is used beyond the typical RTTI usage. */
936 static UClassID U_EXPORT2
getStaticClassID(void) { return (UClassID
)&fgClassID
; }
937 virtual UClassID
getDynamicClassID(void) const { return getStaticClassID(); }
939 KeywordEnumeration(const char *keys
, int32_t keywordLen
, int32_t currentIndex
, UErrorCode
&status
)
940 : keywords((char *)&fgClassID
), current((char *)&fgClassID
), length(0) {
941 if(U_SUCCESS(status
) && keywordLen
!= 0) {
942 if(keys
== NULL
|| keywordLen
< 0) {
943 status
= U_ILLEGAL_ARGUMENT_ERROR
;
945 keywords
= (char *)uprv_malloc(keywordLen
+1);
946 if (keywords
== NULL
) {
947 status
= U_MEMORY_ALLOCATION_ERROR
;
950 uprv_memcpy(keywords
, keys
, keywordLen
);
951 keywords
[keywordLen
] = 0;
952 current
= keywords
+ currentIndex
;
959 virtual ~KeywordEnumeration();
961 virtual StringEnumeration
* clone() const
963 UErrorCode status
= U_ZERO_ERROR
;
964 return new KeywordEnumeration(keywords
, length
, (int32_t)(current
- keywords
), status
);
967 virtual int32_t count(UErrorCode
&/*status*/) const {
972 kw
+= uprv_strlen(kw
)+1;
977 virtual const char* next(int32_t* resultLength
, UErrorCode
& status
) {
980 if(U_SUCCESS(status
) && *current
!= 0) {
982 len
= (int32_t)uprv_strlen(current
);
984 if(resultLength
!= NULL
) {
988 if(resultLength
!= NULL
) {
996 virtual const UnicodeString
* snext(UErrorCode
& status
) {
997 int32_t resultLength
= 0;
998 const char *s
= next(&resultLength
, status
);
999 return setChars(s
, resultLength
, status
);
1002 virtual void reset(UErrorCode
& /*status*/) {
1007 const char KeywordEnumeration::fgClassID
= '\0';
1009 KeywordEnumeration::~KeywordEnumeration() {
1010 uprv_free(keywords
);
1014 Locale::createKeywords(UErrorCode
&status
) const
1017 int32_t keywordCapacity
= 256;
1018 StringEnumeration
*result
= NULL
;
1020 const char* variantStart
= uprv_strchr(fullName
, '@');
1021 const char* assignment
= uprv_strchr(fullName
, '=');
1023 if(assignment
> variantStart
) {
1024 int32_t keyLen
= locale_getKeywords(variantStart
+1, '@', keywords
, keywordCapacity
, NULL
, 0, NULL
, FALSE
, &status
);
1026 result
= new KeywordEnumeration(keywords
, keyLen
, 0, status
);
1029 status
= U_INVALID_FORMAT_ERROR
;
1036 Locale::getKeywordValue(const char* keywordName
, char *buffer
, int32_t bufLen
, UErrorCode
&status
) const
1038 return uloc_getKeywordValue(fullName
, keywordName
, buffer
, bufLen
, &status
);
1042 Locale::setKeywordValue(const char* keywordName
, const char* keywordValue
, UErrorCode
&status
)
1044 uloc_setKeywordValue(keywordName
, keywordValue
, fullName
, ULOC_FULLNAME_CAPACITY
, &status
);
1045 if (U_SUCCESS(status
) && baseName
== fullName
) {
1046 // May have added the first keyword, meaning that the fullName is no longer also the baseName.
1047 initBaseName(status
);
1052 Locale::getBaseName() const {