1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: loclikely.cpp
12 * tab size: 8 (not used)
15 * created on: 2010feb25
16 * created by: Markus W. Scherer
18 * Code for likely and minimized locale subtags, separated out from other .cpp files
19 * that then do not depend on resource bundle code and likely-subtags data.
22 #include "unicode/bytestream.h"
23 #include "unicode/utypes.h"
24 #include "unicode/locid.h"
25 #include "unicode/putil.h"
26 #include "unicode/uchar.h"
27 #include "unicode/uloc.h"
28 #include "unicode/ures.h"
29 #include "unicode/uscript.h"
30 #include "bytesinkutil.h"
38 * These are the canonical strings for unknown languages, scripts and regions.
40 static const char* const unknownLanguage
= "und";
41 static const char* const unknownScript
= "Zzzz";
42 static const char* const unknownRegion
= "ZZ";
45 * This function looks for the localeID in the likelySubtags resource.
47 * @param localeID The tag to find.
48 * @param buffer A buffer to hold the matching entry
49 * @param bufferLength The length of the output buffer
50 * @return A pointer to "buffer" if found, or a null pointer if not.
52 static const char* U_CALLCONV
53 findLikelySubtags(const char* localeID
,
57 const char* result
= NULL
;
59 if (!U_FAILURE(*err
)) {
61 const UChar
* s
= NULL
;
62 UErrorCode tmpErr
= U_ZERO_ERROR
;
63 icu::LocalUResourceBundlePointer
subtags(ures_openDirect(NULL
, "likelySubtags", &tmpErr
));
64 if (U_SUCCESS(tmpErr
)) {
66 if (localeID
!= NULL
) {
67 if (*localeID
== '\0') {
68 localeID
= unknownLanguage
;
69 } else if (*localeID
== '_') {
70 und
.append(unknownLanguage
, *err
);
71 und
.append(localeID
, *err
);
72 if (U_FAILURE(*err
)) {
75 localeID
= und
.data();
78 s
= ures_getStringByKey(subtags
.getAlias(), localeID
, &resLen
, &tmpErr
);
80 if (U_FAILURE(tmpErr
)) {
82 * If a resource is missing, it's not really an error, it's
83 * just that we don't have any data for that particular locale ID.
85 if (tmpErr
!= U_MISSING_RESOURCE_ERROR
) {
89 else if (resLen
>= bufferLength
) {
90 /* The buffer should never overflow. */
91 *err
= U_INTERNAL_PROGRAM_ERROR
;
94 u_UCharsToChars(s
, buffer
, resLen
+ 1);
106 * Append a tag to a buffer, adding the separator if necessary. The buffer
107 * must be large enough to contain the resulting tag plus any separator
108 * necessary. The tag must not be a zero-length string.
110 * @param tag The tag to add.
111 * @param tagLength The length of the tag.
112 * @param buffer The output buffer.
113 * @param bufferLength The length of the output buffer. This is an input/ouput parameter.
115 static void U_CALLCONV
120 int32_t* bufferLength
) {
122 if (*bufferLength
> 0) {
123 buffer
[*bufferLength
] = '_';
128 &buffer
[*bufferLength
],
132 *bufferLength
+= tagLength
;
136 * Create a tag string from the supplied parameters. The lang, script and region
137 * parameters may be NULL pointers. If they are, their corresponding length parameters
138 * must be less than or equal to 0.
140 * If any of the language, script or region parameters are empty, and the alternateTags
141 * parameter is not NULL, it will be parsed for potential language, script and region tags
142 * to be used when constructing the new tag. If the alternateTags parameter is NULL, or
143 * it contains no language tag, the default tag for the unknown language is used.
145 * If the length of the new string exceeds the capacity of the output buffer,
146 * the function copies as many bytes to the output buffer as it can, and returns
147 * the error U_BUFFER_OVERFLOW_ERROR.
149 * If an illegal argument is provided, the function returns the error
150 * U_ILLEGAL_ARGUMENT_ERROR.
152 * Note that this function can return the warning U_STRING_NOT_TERMINATED_WARNING if
153 * the tag string fits in the output buffer, but the null terminator doesn't.
155 * @param lang The language tag to use.
156 * @param langLength The length of the language tag.
157 * @param script The script tag to use.
158 * @param scriptLength The length of the script tag.
159 * @param region The region tag to use.
160 * @param regionLength The length of the region tag.
161 * @param trailing Any trailing data to append to the new tag.
162 * @param trailingLength The length of the trailing data.
163 * @param alternateTags A string containing any alternate tags.
164 * @param sink The output sink receiving the tag string.
165 * @param err A pointer to a UErrorCode for error reporting.
167 static void U_CALLCONV
168 createTagStringWithAlternates(
172 int32_t scriptLength
,
174 int32_t regionLength
,
175 const char* trailing
,
176 int32_t trailingLength
,
177 const char* alternateTags
,
181 if (U_FAILURE(*err
)) {
184 else if (langLength
>= ULOC_LANG_CAPACITY
||
185 scriptLength
>= ULOC_SCRIPT_CAPACITY
||
186 regionLength
>= ULOC_COUNTRY_CAPACITY
) {
191 * ULOC_FULLNAME_CAPACITY will provide enough capacity
192 * that we can build a string that contains the language,
193 * script and region code without worrying about overrunning
194 * the user-supplied buffer.
196 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
197 int32_t tagLength
= 0;
198 UBool regionAppended
= FALSE
;
200 if (langLength
> 0) {
207 else if (alternateTags
== NULL
) {
209 * Append the value for an unknown language, if
210 * we found no language.
214 (int32_t)uprv_strlen(unknownLanguage
),
220 * Parse the alternateTags string for the language.
222 char alternateLang
[ULOC_LANG_CAPACITY
];
223 int32_t alternateLangLength
= sizeof(alternateLang
);
225 alternateLangLength
=
231 if(U_FAILURE(*err
) ||
232 alternateLangLength
>= ULOC_LANG_CAPACITY
) {
235 else if (alternateLangLength
== 0) {
237 * Append the value for an unknown language, if
238 * we found no language.
242 (int32_t)uprv_strlen(unknownLanguage
),
255 if (scriptLength
> 0) {
262 else if (alternateTags
!= NULL
) {
264 * Parse the alternateTags string for the script.
266 char alternateScript
[ULOC_SCRIPT_CAPACITY
];
268 const int32_t alternateScriptLength
=
272 sizeof(alternateScript
),
275 if (U_FAILURE(*err
) ||
276 alternateScriptLength
>= ULOC_SCRIPT_CAPACITY
) {
279 else if (alternateScriptLength
> 0) {
282 alternateScriptLength
,
288 if (regionLength
> 0) {
295 regionAppended
= TRUE
;
297 else if (alternateTags
!= NULL
) {
299 * Parse the alternateTags string for the region.
301 char alternateRegion
[ULOC_COUNTRY_CAPACITY
];
303 const int32_t alternateRegionLength
=
307 sizeof(alternateRegion
),
309 if (U_FAILURE(*err
) ||
310 alternateRegionLength
>= ULOC_COUNTRY_CAPACITY
) {
313 else if (alternateRegionLength
> 0) {
316 alternateRegionLength
,
320 regionAppended
= TRUE
;
325 * Copy the partial tag from our internal buffer to the supplied
328 sink
.Append(tagBuffer
, tagLength
);
330 if (trailingLength
> 0) {
331 if (*trailing
!= '@') {
333 if (!regionAppended
) {
334 /* extra separator is required */
340 * Copy the trailing data into the supplied buffer.
342 sink
.Append(trailing
, trailingLength
);
351 * An overflow indicates the locale ID passed in
352 * is ill-formed. If we got here, and there was
353 * no previous error, it's an implicit overflow.
355 if (*err
== U_BUFFER_OVERFLOW_ERROR
||
357 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
362 * Create a tag string from the supplied parameters. The lang, script and region
363 * parameters may be NULL pointers. If they are, their corresponding length parameters
364 * must be less than or equal to 0. If the lang parameter is an empty string, the
365 * default value for an unknown language is written to the output buffer.
367 * If the length of the new string exceeds the capacity of the output buffer,
368 * the function copies as many bytes to the output buffer as it can, and returns
369 * the error U_BUFFER_OVERFLOW_ERROR.
371 * If an illegal argument is provided, the function returns the error
372 * U_ILLEGAL_ARGUMENT_ERROR.
374 * @param lang The language tag to use.
375 * @param langLength The length of the language tag.
376 * @param script The script tag to use.
377 * @param scriptLength The length of the script tag.
378 * @param region The region tag to use.
379 * @param regionLength The length of the region tag.
380 * @param trailing Any trailing data to append to the new tag.
381 * @param trailingLength The length of the trailing data.
382 * @param sink The output sink receiving the tag string.
383 * @param err A pointer to a UErrorCode for error reporting.
385 static void U_CALLCONV
390 int32_t scriptLength
,
392 int32_t regionLength
,
393 const char* trailing
,
394 int32_t trailingLength
,
398 createTagStringWithAlternates(
413 * Parse the language, script, and region subtags from a tag string, and copy the
414 * results into the corresponding output parameters. The buffers are null-terminated,
415 * unless overflow occurs.
417 * The langLength, scriptLength, and regionLength parameters are input/output
418 * parameters, and must contain the capacity of their corresponding buffers on
419 * input. On output, they will contain the actual length of the buffers, not
420 * including the null terminator.
422 * If the length of any of the output subtags exceeds the capacity of the corresponding
423 * buffer, the function copies as many bytes to the output buffer as it can, and returns
424 * the error U_BUFFER_OVERFLOW_ERROR. It will not parse any more subtags once overflow
427 * If an illegal argument is provided, the function returns the error
428 * U_ILLEGAL_ARGUMENT_ERROR.
430 * @param localeID The locale ID to parse.
431 * @param lang The language tag buffer.
432 * @param langLength The length of the language tag.
433 * @param script The script tag buffer.
434 * @param scriptLength The length of the script tag.
435 * @param region The region tag buffer.
436 * @param regionLength The length of the region tag.
437 * @param err A pointer to a UErrorCode for error reporting.
438 * @return The number of chars of the localeID parameter consumed.
440 static int32_t U_CALLCONV
442 const char* localeID
,
446 int32_t* scriptLength
,
448 int32_t* regionLength
,
451 const char* position
= localeID
;
452 int32_t subtagLength
= 0;
454 if(U_FAILURE(*err
) ||
457 langLength
== NULL
||
459 scriptLength
== NULL
||
461 regionLength
== NULL
) {
465 subtagLength
= ulocimp_getLanguage(position
, lang
, *langLength
, &position
);
466 u_terminateChars(lang
, *langLength
, subtagLength
, err
);
469 * Note that we explicit consider U_STRING_NOT_TERMINATED_WARNING
470 * to be an error, because it indicates the user-supplied tag is
473 if(U_FAILURE(*err
)) {
477 *langLength
= subtagLength
;
480 * If no language was present, use the value of unknownLanguage
481 * instead. Otherwise, move past any separator.
483 if (*langLength
== 0) {
487 *langLength
= (int32_t)uprv_strlen(lang
);
489 if (_isIDSeparator(*position
)) {
493 subtagLength
= ulocimp_getScript(position
, script
, *scriptLength
, &position
);
494 u_terminateChars(script
, *scriptLength
, subtagLength
, err
);
496 if(U_FAILURE(*err
)) {
500 *scriptLength
= subtagLength
;
502 if (*scriptLength
> 0) {
503 if (uprv_strnicmp(script
, unknownScript
, *scriptLength
) == 0) {
505 * If the script part is the "unknown" script, then don't return it.
511 * Move past any separator.
513 if (_isIDSeparator(*position
)) {
518 subtagLength
= ulocimp_getCountry(position
, region
, *regionLength
, &position
);
519 u_terminateChars(region
, *regionLength
, subtagLength
, err
);
521 if(U_FAILURE(*err
)) {
525 *regionLength
= subtagLength
;
527 if (*regionLength
> 0) {
528 if (uprv_strnicmp(region
, unknownRegion
, *regionLength
) == 0) {
530 * If the region part is the "unknown" region, then don't return it.
534 } else if (*position
!= 0 && *position
!= '@') {
535 /* back up over consumed trailing separator */
541 return (int32_t)(position
- localeID
);
546 * If we get here, we have no explicit error, it's the result of an
549 if (!U_FAILURE(*err
)) {
550 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
556 static UBool U_CALLCONV
557 createLikelySubtagsString(
561 int32_t scriptLength
,
563 int32_t regionLength
,
564 const char* variants
,
565 int32_t variantsLength
,
569 * ULOC_FULLNAME_CAPACITY will provide enough capacity
570 * that we can build a string that contains the language,
571 * script and region code without worrying about overrunning
572 * the user-supplied buffer.
574 char likelySubtagsBuffer
[ULOC_FULLNAME_CAPACITY
];
576 if(U_FAILURE(*err
)) {
581 * Try the language with the script and region first.
583 if (scriptLength
> 0 && regionLength
> 0) {
585 const char* likelySubtags
= NULL
;
587 icu::CharString tagBuffer
;
589 icu::CharStringByteSink
sink(&tagBuffer
);
602 if(U_FAILURE(*err
)) {
610 sizeof(likelySubtagsBuffer
),
612 if(U_FAILURE(*err
)) {
616 if (likelySubtags
!= NULL
) {
617 /* Always use the language tag from the
618 maximal string, since it may be more
619 specific than the one provided. */
620 createTagStringWithAlternates(
637 * Try the language with just the script.
639 if (scriptLength
> 0) {
641 const char* likelySubtags
= NULL
;
643 icu::CharString tagBuffer
;
645 icu::CharStringByteSink
sink(&tagBuffer
);
658 if(U_FAILURE(*err
)) {
666 sizeof(likelySubtagsBuffer
),
668 if(U_FAILURE(*err
)) {
672 if (likelySubtags
!= NULL
) {
673 /* Always use the language tag from the
674 maximal string, since it may be more
675 specific than the one provided. */
676 createTagStringWithAlternates(
693 * Try the language with just the region.
695 if (regionLength
> 0) {
697 const char* likelySubtags
= NULL
;
699 icu::CharString tagBuffer
;
701 icu::CharStringByteSink
sink(&tagBuffer
);
714 if(U_FAILURE(*err
)) {
722 sizeof(likelySubtagsBuffer
),
724 if(U_FAILURE(*err
)) {
728 if (likelySubtags
!= NULL
) {
729 /* Always use the language tag from the
730 maximal string, since it may be more
731 specific than the one provided. */
732 createTagStringWithAlternates(
749 * Finally, try just the language.
752 const char* likelySubtags
= NULL
;
754 icu::CharString tagBuffer
;
756 icu::CharStringByteSink
sink(&tagBuffer
);
769 if(U_FAILURE(*err
)) {
777 sizeof(likelySubtagsBuffer
),
779 if(U_FAILURE(*err
)) {
783 if (likelySubtags
!= NULL
) {
784 /* Always use the language tag from the
785 maximal string, since it may be more
786 specific than the one provided. */
787 createTagStringWithAlternates(
807 if (!U_FAILURE(*err
)) {
808 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
814 #define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) \
815 { int32_t count = 0; \
817 for (i = 0; i < trailingLength; i++) { \
818 if (trailing[i] == '-' || trailing[i] == '_') { \
823 } else if (trailing[i] == '@') { \
825 } else if (count > 8) { \
834 _uloc_addLikelySubtags(const char* localeID
,
837 char lang
[ULOC_LANG_CAPACITY
];
838 int32_t langLength
= sizeof(lang
);
839 char script
[ULOC_SCRIPT_CAPACITY
];
840 int32_t scriptLength
= sizeof(script
);
841 char region
[ULOC_COUNTRY_CAPACITY
];
842 int32_t regionLength
= sizeof(region
);
843 const char* trailing
= "";
844 int32_t trailingLength
= 0;
845 int32_t trailingIndex
= 0;
846 UBool success
= FALSE
;
848 if(U_FAILURE(*err
)) {
851 if (localeID
== NULL
) {
855 trailingIndex
= parseTagString(
864 if(U_FAILURE(*err
)) {
865 /* Overflow indicates an illegal argument error */
866 if (*err
== U_BUFFER_OVERFLOW_ERROR
) {
867 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
873 /* Find the length of the trailing portion. */
874 while (_isIDSeparator(localeID
[trailingIndex
])) {
877 trailing
= &localeID
[trailingIndex
];
878 trailingLength
= (int32_t)uprv_strlen(trailing
);
880 CHECK_TRAILING_VARIANT_SIZE(trailing
, trailingLength
);
883 createLikelySubtagsString(
896 const int32_t localIDLength
= (int32_t)uprv_strlen(localeID
);
899 * If we get here, we need to return localeID.
901 sink
.Append(localeID
, localIDLength
);
908 if (!U_FAILURE(*err
)) {
909 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
914 _uloc_minimizeSubtags(const char* localeID
,
917 icu::CharString maximizedTagBuffer
;
919 char lang
[ULOC_LANG_CAPACITY
];
920 int32_t langLength
= sizeof(lang
);
921 char script
[ULOC_SCRIPT_CAPACITY
];
922 int32_t scriptLength
= sizeof(script
);
923 char region
[ULOC_COUNTRY_CAPACITY
];
924 int32_t regionLength
= sizeof(region
);
925 const char* trailing
= "";
926 int32_t trailingLength
= 0;
927 int32_t trailingIndex
= 0;
929 if(U_FAILURE(*err
)) {
932 else if (localeID
== NULL
) {
946 if(U_FAILURE(*err
)) {
948 /* Overflow indicates an illegal argument error */
949 if (*err
== U_BUFFER_OVERFLOW_ERROR
) {
950 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
956 /* Find the spot where the variants or the keywords begin, if any. */
957 while (_isIDSeparator(localeID
[trailingIndex
])) {
960 trailing
= &localeID
[trailingIndex
];
961 trailingLength
= (int32_t)uprv_strlen(trailing
);
963 CHECK_TRAILING_VARIANT_SIZE(trailing
, trailingLength
);
966 icu::CharString base
;
968 icu::CharStringByteSink
sink(&base
);
983 * First, we need to first get the maximization
984 * from AddLikelySubtags.
987 icu::CharStringByteSink
sink(&maximizedTagBuffer
);
988 ulocimp_addLikelySubtags(base
.data(), sink
, err
);
992 if(U_FAILURE(*err
)) {
997 * Start first with just the language.
1000 icu::CharString tagBuffer
;
1002 icu::CharStringByteSink
sink(&tagBuffer
);
1003 createLikelySubtagsString(
1016 if(U_FAILURE(*err
)) {
1019 else if (uprv_strnicmp(
1020 maximizedTagBuffer
.data(),
1022 tagBuffer
.length()) == 0) {
1040 * Next, try the language and region.
1042 if (regionLength
> 0) {
1044 icu::CharString tagBuffer
;
1046 icu::CharStringByteSink
sink(&tagBuffer
);
1047 createLikelySubtagsString(
1060 if(U_FAILURE(*err
)) {
1063 else if (uprv_strnicmp(
1064 maximizedTagBuffer
.data(),
1066 tagBuffer
.length()) == 0) {
1084 * Finally, try the language and script. This is our last chance,
1085 * since trying with all three subtags would only yield the
1086 * maximal version that we already have.
1088 if (scriptLength
> 0 && regionLength
> 0) {
1089 icu::CharString tagBuffer
;
1091 icu::CharStringByteSink
sink(&tagBuffer
);
1092 createLikelySubtagsString(
1105 if(U_FAILURE(*err
)) {
1108 else if (uprv_strnicmp(
1109 maximizedTagBuffer
.data(),
1111 tagBuffer
.length()) == 0) {
1130 * If we got here, return the locale ID parameter.
1132 const int32_t localeIDLength
= (int32_t)uprv_strlen(localeID
);
1133 sink
.Append(localeID
, localeIDLength
);
1139 if (!U_FAILURE(*err
)) {
1140 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1145 do_canonicalize(const char* localeID
,
1147 int32_t bufferCapacity
,
1156 if (*err
== U_STRING_NOT_TERMINATED_WARNING
||
1157 *err
== U_BUFFER_OVERFLOW_ERROR
) {
1158 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1162 else if (U_FAILURE(*err
)) {
1171 U_CAPI
int32_t U_EXPORT2
1172 uloc_addLikelySubtags(const char* localeID
,
1173 char* maximizedLocaleID
,
1174 int32_t maximizedLocaleIDCapacity
,
1175 UErrorCode
* status
) {
1176 if (U_FAILURE(*status
)) {
1180 icu::CheckedArrayByteSink
sink(
1181 maximizedLocaleID
, maximizedLocaleIDCapacity
);
1183 ulocimp_addLikelySubtags(localeID
, sink
, status
);
1184 int32_t reslen
= sink
.NumberOfBytesAppended();
1186 if (U_FAILURE(*status
)) {
1187 return sink
.Overflowed() ? reslen
: -1;
1190 if (sink
.Overflowed()) {
1191 *status
= U_BUFFER_OVERFLOW_ERROR
;
1194 maximizedLocaleID
, maximizedLocaleIDCapacity
, reslen
, status
);
1200 U_CAPI
void U_EXPORT2
1201 ulocimp_addLikelySubtags(const char* localeID
,
1202 icu::ByteSink
& sink
,
1203 UErrorCode
* status
) {
1204 char localeBuffer
[ULOC_FULLNAME_CAPACITY
];
1206 if (do_canonicalize(localeID
, localeBuffer
, sizeof localeBuffer
, status
)) {
1207 _uloc_addLikelySubtags(localeBuffer
, sink
, status
);
1211 U_CAPI
int32_t U_EXPORT2
1212 uloc_minimizeSubtags(const char* localeID
,
1213 char* minimizedLocaleID
,
1214 int32_t minimizedLocaleIDCapacity
,
1215 UErrorCode
* status
) {
1216 if (U_FAILURE(*status
)) {
1220 icu::CheckedArrayByteSink
sink(
1221 minimizedLocaleID
, minimizedLocaleIDCapacity
);
1223 ulocimp_minimizeSubtags(localeID
, sink
, status
);
1224 int32_t reslen
= sink
.NumberOfBytesAppended();
1226 if (U_FAILURE(*status
)) {
1227 return sink
.Overflowed() ? reslen
: -1;
1230 if (sink
.Overflowed()) {
1231 *status
= U_BUFFER_OVERFLOW_ERROR
;
1234 minimizedLocaleID
, minimizedLocaleIDCapacity
, reslen
, status
);
1240 U_CAPI
void U_EXPORT2
1241 ulocimp_minimizeSubtags(const char* localeID
,
1242 icu::ByteSink
& sink
,
1243 UErrorCode
* status
) {
1244 char localeBuffer
[ULOC_FULLNAME_CAPACITY
];
1246 if (do_canonicalize(localeID
, localeBuffer
, sizeof localeBuffer
, status
)) {
1247 _uloc_minimizeSubtags(localeBuffer
, sink
, status
);
1251 // Pairs of (language subtag, + or -) for finding out fast if common languages
1252 // are LTR (minus) or RTL (plus).
1253 static const char LANG_DIR_STRING
[] =
1254 "root-en-es-pt-zh-ja-ko-de-fr-it-ar+he+fa+ru-nl-pl-th-tr-";
1256 // Implemented here because this calls ulocimp_addLikelySubtags().
1257 U_CAPI UBool U_EXPORT2
1258 uloc_isRightToLeft(const char *locale
) {
1259 UErrorCode errorCode
= U_ZERO_ERROR
;
1261 int32_t scriptLength
= uloc_getScript(locale
, script
, UPRV_LENGTHOF(script
), &errorCode
);
1262 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1263 scriptLength
== 0) {
1264 // Fastpath: We know the likely scripts and their writing direction
1265 // for some common languages.
1266 errorCode
= U_ZERO_ERROR
;
1268 int32_t langLength
= uloc_getLanguage(locale
, lang
, UPRV_LENGTHOF(lang
), &errorCode
);
1269 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
) {
1272 if (langLength
> 0) {
1273 const char* langPtr
= uprv_strstr(LANG_DIR_STRING
, lang
);
1274 if (langPtr
!= NULL
) {
1275 switch (langPtr
[langLength
]) {
1276 case '-': return FALSE
;
1277 case '+': return TRUE
;
1278 default: break; // partial match of a longer code
1282 // Otherwise, find the likely script.
1283 errorCode
= U_ZERO_ERROR
;
1284 icu::CharString likely
;
1286 icu::CharStringByteSink
sink(&likely
);
1287 ulocimp_addLikelySubtags(locale
, sink
, &errorCode
);
1289 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
) {
1292 scriptLength
= uloc_getScript(likely
.data(), script
, UPRV_LENGTHOF(script
), &errorCode
);
1293 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1294 scriptLength
== 0) {
1298 if (uprv_strcmp(script
,"Aran")==0) {
1299 uprv_strcpy(script
,"Arab"); // The properties functions do not understand Aran
1301 UScriptCode scriptCode
= (UScriptCode
)u_getPropertyValueEnum(UCHAR_SCRIPT
, script
);
1302 return uscript_isRightToLeft(scriptCode
);
1308 Locale::isRightToLeft() const {
1309 return uloc_isRightToLeft(getBaseName());
1314 // The following must at least allow for rg key value (6) plus terminator (1).
1315 #define ULOC_RG_BUFLEN 8
1317 U_CAPI
int32_t U_EXPORT2
1318 ulocimp_getRegionForSupplementalData(const char *localeID
, UBool inferRegion
,
1319 char *region
, int32_t regionCapacity
, UErrorCode
* status
) {
1320 if (U_FAILURE(*status
)) {
1323 char rgBuf
[ULOC_RG_BUFLEN
];
1324 UErrorCode rgStatus
= U_ZERO_ERROR
;
1326 // First check for rg keyword value
1327 int32_t rgLen
= uloc_getKeywordValue(localeID
, "rg", rgBuf
, ULOC_RG_BUFLEN
, &rgStatus
);
1328 if (U_FAILURE(rgStatus
) || rgLen
!= 6) {
1331 // rgBuf guaranteed to be zero terminated here, with text len 6
1332 char *rgPtr
= rgBuf
;
1333 for (; *rgPtr
!= 0; rgPtr
++) {
1334 *rgPtr
= uprv_toupper(*rgPtr
);
1336 rgLen
= (uprv_strcmp(rgBuf
+2, "ZZZZ") == 0)? 2: 0;
1340 // No valid rg keyword value, try for unicode_region_subtag
1341 rgLen
= uloc_getCountry(localeID
, rgBuf
, ULOC_RG_BUFLEN
, status
);
1342 if (U_FAILURE(*status
)) {
1344 } else if (rgLen
== 0 && inferRegion
) {
1345 // no unicode_region_subtag but inferRegion TRUE, try likely subtags
1346 rgStatus
= U_ZERO_ERROR
;
1347 icu::CharString locBuf
;
1349 icu::CharStringByteSink
sink(&locBuf
);
1350 ulocimp_addLikelySubtags(localeID
, sink
, &rgStatus
);
1352 if (U_SUCCESS(rgStatus
)) {
1353 rgLen
= uloc_getCountry(locBuf
.data(), rgBuf
, ULOC_RG_BUFLEN
, status
);
1354 if (U_FAILURE(*status
)) {
1362 uprv_strncpy(region
, rgBuf
, regionCapacity
);
1363 return u_terminateChars(region
, regionCapacity
, rgLen
, status
);