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/utypes.h"
23 #include "unicode/locid.h"
24 #include "unicode/putil.h"
25 #include "unicode/uchar.h"
26 #include "unicode/uloc.h"
27 #include "unicode/ures.h"
28 #include "unicode/uscript.h"
35 * This function looks for the localeID in the likelySubtags resource.
37 * @param localeID The tag to find.
38 * @param buffer A buffer to hold the matching entry
39 * @param bufferLength The length of the output buffer
40 * @return A pointer to "buffer" if found, or a null pointer if not.
42 static const char* U_CALLCONV
43 findLikelySubtags(const char* localeID
,
47 const char* result
= NULL
;
49 if (!U_FAILURE(*err
)) {
51 const UChar
* s
= NULL
;
52 UErrorCode tmpErr
= U_ZERO_ERROR
;
53 UResourceBundle
* subtags
= ures_openDirect(NULL
, "likelySubtags", &tmpErr
);
54 if (U_SUCCESS(tmpErr
)) {
55 s
= ures_getStringByKey(subtags
, localeID
, &resLen
, &tmpErr
);
57 if (U_FAILURE(tmpErr
)) {
59 * If a resource is missing, it's not really an error, it's
60 * just that we don't have any data for that particular locale ID.
62 if (tmpErr
!= U_MISSING_RESOURCE_ERROR
) {
66 else if (resLen
>= bufferLength
) {
67 /* The buffer should never overflow. */
68 *err
= U_INTERNAL_PROGRAM_ERROR
;
71 u_UCharsToChars(s
, buffer
, resLen
+ 1);
85 * Append a tag to a buffer, adding the separator if necessary. The buffer
86 * must be large enough to contain the resulting tag plus any separator
87 * necessary. The tag must not be a zero-length string.
89 * @param tag The tag to add.
90 * @param tagLength The length of the tag.
91 * @param buffer The output buffer.
92 * @param bufferLength The length of the output buffer. This is an input/ouput parameter.
94 static void U_CALLCONV
99 int32_t* bufferLength
) {
101 if (*bufferLength
> 0) {
102 buffer
[*bufferLength
] = '_';
107 &buffer
[*bufferLength
],
111 *bufferLength
+= tagLength
;
115 * These are the canonical strings for unknown languages, scripts and regions.
117 static const char* const unknownLanguage
= "und";
118 static const char* const unknownScript
= "Zzzz";
119 static const char* const unknownRegion
= "ZZ";
122 * Create a tag string from the supplied parameters. The lang, script and region
123 * parameters may be NULL pointers. If they are, their corresponding length parameters
124 * must be less than or equal to 0.
126 * If any of the language, script or region parameters are empty, and the alternateTags
127 * parameter is not NULL, it will be parsed for potential language, script and region tags
128 * to be used when constructing the new tag. If the alternateTags parameter is NULL, or
129 * it contains no language tag, the default tag for the unknown language is used.
131 * If the length of the new string exceeds the capacity of the output buffer,
132 * the function copies as many bytes to the output buffer as it can, and returns
133 * the error U_BUFFER_OVERFLOW_ERROR.
135 * If an illegal argument is provided, the function returns the error
136 * U_ILLEGAL_ARGUMENT_ERROR.
138 * Note that this function can return the warning U_STRING_NOT_TERMINATED_WARNING if
139 * the tag string fits in the output buffer, but the null terminator doesn't.
141 * @param lang The language tag to use.
142 * @param langLength The length of the language tag.
143 * @param script The script tag to use.
144 * @param scriptLength The length of the script tag.
145 * @param region The region tag to use.
146 * @param regionLength The length of the region tag.
147 * @param trailing Any trailing data to append to the new tag.
148 * @param trailingLength The length of the trailing data.
149 * @param alternateTags A string containing any alternate tags.
150 * @param tag The output buffer.
151 * @param tagCapacity The capacity of the output buffer.
152 * @param err A pointer to a UErrorCode for error reporting.
153 * @return The length of the tag string, which may be greater than tagCapacity, or -1 on error.
155 static int32_t U_CALLCONV
156 createTagStringWithAlternates(
160 int32_t scriptLength
,
162 int32_t regionLength
,
163 const char* trailing
,
164 int32_t trailingLength
,
165 const char* alternateTags
,
170 if (U_FAILURE(*err
)) {
173 else if (tag
== NULL
||
175 langLength
>= ULOC_LANG_CAPACITY
||
176 scriptLength
>= ULOC_SCRIPT_CAPACITY
||
177 regionLength
>= ULOC_COUNTRY_CAPACITY
) {
182 * ULOC_FULLNAME_CAPACITY will provide enough capacity
183 * that we can build a string that contains the language,
184 * script and region code without worrying about overrunning
185 * the user-supplied buffer.
187 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
188 int32_t tagLength
= 0;
189 int32_t capacityRemaining
= tagCapacity
;
190 UBool regionAppended
= FALSE
;
192 if (langLength
> 0) {
199 else if (alternateTags
== NULL
) {
201 * Append the value for an unknown language, if
202 * we found no language.
206 (int32_t)uprv_strlen(unknownLanguage
),
212 * Parse the alternateTags string for the language.
214 char alternateLang
[ULOC_LANG_CAPACITY
];
215 int32_t alternateLangLength
= sizeof(alternateLang
);
217 alternateLangLength
=
223 if(U_FAILURE(*err
) ||
224 alternateLangLength
>= ULOC_LANG_CAPACITY
) {
227 else if (alternateLangLength
== 0) {
229 * Append the value for an unknown language, if
230 * we found no language.
234 (int32_t)uprv_strlen(unknownLanguage
),
247 if (scriptLength
> 0) {
254 else if (alternateTags
!= NULL
) {
256 * Parse the alternateTags string for the script.
258 char alternateScript
[ULOC_SCRIPT_CAPACITY
];
260 const int32_t alternateScriptLength
=
264 sizeof(alternateScript
),
267 if (U_FAILURE(*err
) ||
268 alternateScriptLength
>= ULOC_SCRIPT_CAPACITY
) {
271 else if (alternateScriptLength
> 0) {
274 alternateScriptLength
,
280 if (regionLength
> 0) {
287 regionAppended
= TRUE
;
289 else if (alternateTags
!= NULL
) {
291 * Parse the alternateTags string for the region.
293 char alternateRegion
[ULOC_COUNTRY_CAPACITY
];
295 const int32_t alternateRegionLength
=
299 sizeof(alternateRegion
),
301 if (U_FAILURE(*err
) ||
302 alternateRegionLength
>= ULOC_COUNTRY_CAPACITY
) {
305 else if (alternateRegionLength
> 0) {
308 alternateRegionLength
,
312 regionAppended
= TRUE
;
317 const int32_t toCopy
=
318 tagLength
>= tagCapacity
? tagCapacity
: tagLength
;
321 * Copy the partial tag from our internal buffer to the supplied
329 capacityRemaining
-= toCopy
;
332 if (trailingLength
> 0) {
333 if (*trailing
!= '@' && capacityRemaining
> 0) {
334 tag
[tagLength
++] = '_';
336 if (capacityRemaining
> 0 && !regionAppended
) {
337 /* extra separator is required */
338 tag
[tagLength
++] = '_';
343 if (capacityRemaining
> 0) {
345 * Copy the trailing data into the supplied buffer. Use uprv_memmove, since we
346 * don't know if the user-supplied buffers overlap.
348 const int32_t toCopy
=
349 trailingLength
>= capacityRemaining
? capacityRemaining
: trailingLength
;
358 tagLength
+= trailingLength
;
360 return u_terminateChars(
370 * An overflow indicates the locale ID passed in
371 * is ill-formed. If we got here, and there was
372 * no previous error, it's an implicit overflow.
374 if (*err
== U_BUFFER_OVERFLOW_ERROR
||
376 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
383 * Create a tag string from the supplied parameters. The lang, script and region
384 * parameters may be NULL pointers. If they are, their corresponding length parameters
385 * must be less than or equal to 0. If the lang parameter is an empty string, the
386 * default value for an unknown language is written to the output buffer.
388 * If the length of the new string exceeds the capacity of the output buffer,
389 * the function copies as many bytes to the output buffer as it can, and returns
390 * the error U_BUFFER_OVERFLOW_ERROR.
392 * If an illegal argument is provided, the function returns the error
393 * U_ILLEGAL_ARGUMENT_ERROR.
395 * @param lang The language tag to use.
396 * @param langLength The length of the language tag.
397 * @param script The script tag to use.
398 * @param scriptLength The length of the script tag.
399 * @param region The region tag to use.
400 * @param regionLength The length of the region tag.
401 * @param trailing Any trailing data to append to the new tag.
402 * @param trailingLength The length of the trailing data.
403 * @param tag The output buffer.
404 * @param tagCapacity The capacity of the output buffer.
405 * @param err A pointer to a UErrorCode for error reporting.
406 * @return The length of the tag string, which may be greater than tagCapacity.
408 static int32_t U_CALLCONV
413 int32_t scriptLength
,
415 int32_t regionLength
,
416 const char* trailing
,
417 int32_t trailingLength
,
422 return createTagStringWithAlternates(
438 * Parse the language, script, and region subtags from a tag string, and copy the
439 * results into the corresponding output parameters. The buffers are null-terminated,
440 * unless overflow occurs.
442 * The langLength, scriptLength, and regionLength parameters are input/output
443 * parameters, and must contain the capacity of their corresponding buffers on
444 * input. On output, they will contain the actual length of the buffers, not
445 * including the null terminator.
447 * If the length of any of the output subtags exceeds the capacity of the corresponding
448 * buffer, the function copies as many bytes to the output buffer as it can, and returns
449 * the error U_BUFFER_OVERFLOW_ERROR. It will not parse any more subtags once overflow
452 * If an illegal argument is provided, the function returns the error
453 * U_ILLEGAL_ARGUMENT_ERROR.
455 * @param localeID The locale ID to parse.
456 * @param lang The language tag buffer.
457 * @param langLength The length of the language tag.
458 * @param script The script tag buffer.
459 * @param scriptLength The length of the script tag.
460 * @param region The region tag buffer.
461 * @param regionLength The length of the region tag.
462 * @param err A pointer to a UErrorCode for error reporting.
463 * @return The number of chars of the localeID parameter consumed.
465 static int32_t U_CALLCONV
467 const char* localeID
,
471 int32_t* scriptLength
,
473 int32_t* regionLength
,
476 const char* position
= localeID
;
477 int32_t subtagLength
= 0;
479 if(U_FAILURE(*err
) ||
482 langLength
== NULL
||
484 scriptLength
== NULL
||
486 regionLength
== NULL
) {
490 subtagLength
= ulocimp_getLanguage(position
, lang
, *langLength
, &position
);
491 u_terminateChars(lang
, *langLength
, subtagLength
, err
);
494 * Note that we explicit consider U_STRING_NOT_TERMINATED_WARNING
495 * to be an error, because it indicates the user-supplied tag is
498 if(U_FAILURE(*err
)) {
502 *langLength
= subtagLength
;
505 * If no language was present, use the value of unknownLanguage
506 * instead. Otherwise, move past any separator.
508 if (*langLength
== 0) {
512 *langLength
= (int32_t)uprv_strlen(lang
);
514 else if (_isIDSeparator(*position
)) {
518 subtagLength
= ulocimp_getScript(position
, script
, *scriptLength
, &position
);
519 u_terminateChars(script
, *scriptLength
, subtagLength
, err
);
521 if(U_FAILURE(*err
)) {
525 *scriptLength
= subtagLength
;
527 if (*scriptLength
> 0) {
528 if (uprv_strnicmp(script
, unknownScript
, *scriptLength
) == 0) {
530 * If the script part is the "unknown" script, then don't return it.
536 * Move past any separator.
538 if (_isIDSeparator(*position
)) {
543 subtagLength
= ulocimp_getCountry(position
, region
, *regionLength
, &position
);
544 u_terminateChars(region
, *regionLength
, subtagLength
, err
);
546 if(U_FAILURE(*err
)) {
550 *regionLength
= subtagLength
;
552 if (*regionLength
> 0) {
553 if (uprv_strnicmp(region
, unknownRegion
, *regionLength
) == 0) {
555 * If the region part is the "unknown" region, then don't return it.
559 } else if (*position
!= 0 && *position
!= '@') {
560 /* back up over consumed trailing separator */
566 return (int32_t)(position
- localeID
);
571 * If we get here, we have no explicit error, it's the result of an
574 if (!U_FAILURE(*err
)) {
575 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
581 static int32_t U_CALLCONV
582 createLikelySubtagsString(
586 int32_t scriptLength
,
588 int32_t regionLength
,
589 const char* variants
,
590 int32_t variantsLength
,
596 * ULOC_FULLNAME_CAPACITY will provide enough capacity
597 * that we can build a string that contains the language,
598 * script and region code without worrying about overrunning
599 * the user-supplied buffer.
601 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
602 char likelySubtagsBuffer
[ULOC_FULLNAME_CAPACITY
];
604 if(U_FAILURE(*err
)) {
609 * Try the language with the script and region first.
611 if (scriptLength
> 0 && regionLength
> 0) {
613 const char* likelySubtags
= NULL
;
627 if(U_FAILURE(*err
)) {
635 sizeof(likelySubtagsBuffer
),
637 if(U_FAILURE(*err
)) {
641 if (likelySubtags
!= NULL
) {
642 /* Always use the language tag from the
643 maximal string, since it may be more
644 specific than the one provided. */
645 return createTagStringWithAlternates(
662 * Try the language with just the script.
664 if (scriptLength
> 0) {
666 const char* likelySubtags
= NULL
;
680 if(U_FAILURE(*err
)) {
688 sizeof(likelySubtagsBuffer
),
690 if(U_FAILURE(*err
)) {
694 if (likelySubtags
!= NULL
) {
695 /* Always use the language tag from the
696 maximal string, since it may be more
697 specific than the one provided. */
698 return createTagStringWithAlternates(
715 * Try the language with just the region.
717 if (regionLength
> 0) {
719 const char* likelySubtags
= NULL
;
733 if(U_FAILURE(*err
)) {
741 sizeof(likelySubtagsBuffer
),
743 if(U_FAILURE(*err
)) {
747 if (likelySubtags
!= NULL
) {
748 /* Always use the language tag from the
749 maximal string, since it may be more
750 specific than the one provided. */
751 return createTagStringWithAlternates(
768 * Finally, try just the language.
771 const char* likelySubtags
= NULL
;
785 if(U_FAILURE(*err
)) {
793 sizeof(likelySubtagsBuffer
),
795 if(U_FAILURE(*err
)) {
799 if (likelySubtags
!= NULL
) {
800 /* Always use the language tag from the
801 maximal string, since it may be more
802 specific than the one provided. */
803 return createTagStringWithAlternates(
819 return u_terminateChars(
827 if (!U_FAILURE(*err
)) {
828 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
834 #define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) \
835 { int32_t count = 0; \
837 for (i = 0; i < trailingLength; i++) { \
838 if (trailing[i] == '-' || trailing[i] == '_') { \
843 } else if (trailing[i] == '@') { \
845 } else if (count > 8) { \
854 _uloc_addLikelySubtags(const char* localeID
,
855 char* maximizedLocaleID
,
856 int32_t maximizedLocaleIDCapacity
,
859 char lang
[ULOC_LANG_CAPACITY
];
860 int32_t langLength
= sizeof(lang
);
861 char script
[ULOC_SCRIPT_CAPACITY
];
862 int32_t scriptLength
= sizeof(script
);
863 char region
[ULOC_COUNTRY_CAPACITY
];
864 int32_t regionLength
= sizeof(region
);
865 const char* trailing
= "";
866 int32_t trailingLength
= 0;
867 int32_t trailingIndex
= 0;
868 int32_t resultLength
= 0;
870 if(U_FAILURE(*err
)) {
873 else if (localeID
== NULL
||
874 maximizedLocaleID
== NULL
||
875 maximizedLocaleIDCapacity
<= 0) {
879 trailingIndex
= parseTagString(
888 if(U_FAILURE(*err
)) {
889 /* Overflow indicates an illegal argument error */
890 if (*err
== U_BUFFER_OVERFLOW_ERROR
) {
891 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
897 /* Find the length of the trailing portion. */
898 while (_isIDSeparator(localeID
[trailingIndex
])) {
901 trailing
= &localeID
[trailingIndex
];
902 trailingLength
= (int32_t)uprv_strlen(trailing
);
904 CHECK_TRAILING_VARIANT_SIZE(trailing
, trailingLength
);
907 createLikelySubtagsString(
917 maximizedLocaleIDCapacity
,
920 if (resultLength
== 0) {
921 const int32_t localIDLength
= (int32_t)uprv_strlen(localeID
);
924 * If we get here, we need to return localeID.
929 localIDLength
<= maximizedLocaleIDCapacity
?
930 localIDLength
: maximizedLocaleIDCapacity
);
935 maximizedLocaleIDCapacity
,
944 if (!U_FAILURE(*err
)) {
945 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
952 _uloc_minimizeSubtags(const char* localeID
,
953 char* minimizedLocaleID
,
954 int32_t minimizedLocaleIDCapacity
,
958 * ULOC_FULLNAME_CAPACITY will provide enough capacity
959 * that we can build a string that contains the language,
960 * script and region code without worrying about overrunning
961 * the user-supplied buffer.
963 char maximizedTagBuffer
[ULOC_FULLNAME_CAPACITY
];
964 int32_t maximizedTagBufferLength
= sizeof(maximizedTagBuffer
);
966 char lang
[ULOC_LANG_CAPACITY
];
967 int32_t langLength
= sizeof(lang
);
968 char script
[ULOC_SCRIPT_CAPACITY
];
969 int32_t scriptLength
= sizeof(script
);
970 char region
[ULOC_COUNTRY_CAPACITY
];
971 int32_t regionLength
= sizeof(region
);
972 const char* trailing
= "";
973 int32_t trailingLength
= 0;
974 int32_t trailingIndex
= 0;
976 if(U_FAILURE(*err
)) {
979 else if (localeID
== NULL
||
980 minimizedLocaleID
== NULL
||
981 minimizedLocaleIDCapacity
<= 0) {
995 if(U_FAILURE(*err
)) {
997 /* Overflow indicates an illegal argument error */
998 if (*err
== U_BUFFER_OVERFLOW_ERROR
) {
999 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1005 /* Find the spot where the variants or the keywords begin, if any. */
1006 while (_isIDSeparator(localeID
[trailingIndex
])) {
1009 trailing
= &localeID
[trailingIndex
];
1010 trailingLength
= (int32_t)uprv_strlen(trailing
);
1012 CHECK_TRAILING_VARIANT_SIZE(trailing
, trailingLength
);
1024 maximizedTagBufferLength
,
1026 if(U_FAILURE(*err
)) {
1031 * First, we need to first get the maximization
1032 * from AddLikelySubtags.
1034 maximizedTagBufferLength
=
1035 uloc_addLikelySubtags(
1038 maximizedTagBufferLength
,
1041 if(U_FAILURE(*err
)) {
1046 * Start first with just the language.
1049 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
1051 const int32_t tagBufferLength
=
1052 createLikelySubtagsString(
1065 if(U_FAILURE(*err
)) {
1068 else if (uprv_strnicmp(
1071 tagBufferLength
) == 0) {
1073 return createTagString(
1083 minimizedLocaleIDCapacity
,
1089 * Next, try the language and region.
1091 if (regionLength
> 0) {
1093 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
1095 const int32_t tagBufferLength
=
1096 createLikelySubtagsString(
1109 if(U_FAILURE(*err
)) {
1112 else if (uprv_strnicmp(
1115 tagBufferLength
) == 0) {
1117 return createTagString(
1127 minimizedLocaleIDCapacity
,
1133 * Finally, try the language and script. This is our last chance,
1134 * since trying with all three subtags would only yield the
1135 * maximal version that we already have.
1137 if (scriptLength
> 0 && regionLength
> 0) {
1138 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
1140 const int32_t tagBufferLength
=
1141 createLikelySubtagsString(
1154 if(U_FAILURE(*err
)) {
1157 else if (uprv_strnicmp(
1160 tagBufferLength
) == 0) {
1162 return createTagString(
1172 minimizedLocaleIDCapacity
,
1179 * If we got here, return the locale ID parameter.
1181 const int32_t localeIDLength
= (int32_t)uprv_strlen(localeID
);
1186 localeIDLength
<= minimizedLocaleIDCapacity
?
1187 localeIDLength
: minimizedLocaleIDCapacity
);
1189 return u_terminateChars(
1191 minimizedLocaleIDCapacity
,
1198 if (!U_FAILURE(*err
)) {
1199 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1208 do_canonicalize(const char* localeID
,
1210 int32_t bufferCapacity
,
1219 if (*err
== U_STRING_NOT_TERMINATED_WARNING
||
1220 *err
== U_BUFFER_OVERFLOW_ERROR
) {
1221 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1225 else if (U_FAILURE(*err
)) {
1234 U_CAPI
int32_t U_EXPORT2
1235 uloc_addLikelySubtags(const char* localeID
,
1236 char* maximizedLocaleID
,
1237 int32_t maximizedLocaleIDCapacity
,
1240 char localeBuffer
[ULOC_FULLNAME_CAPACITY
];
1242 if (!do_canonicalize(
1245 sizeof(localeBuffer
),
1250 return _uloc_addLikelySubtags(
1253 maximizedLocaleIDCapacity
,
1258 U_CAPI
int32_t U_EXPORT2
1259 uloc_minimizeSubtags(const char* localeID
,
1260 char* minimizedLocaleID
,
1261 int32_t minimizedLocaleIDCapacity
,
1264 char localeBuffer
[ULOC_FULLNAME_CAPACITY
];
1266 if (!do_canonicalize(
1269 sizeof(localeBuffer
),
1274 return _uloc_minimizeSubtags(
1277 minimizedLocaleIDCapacity
,
1282 // Pairs of (language subtag, + or -) for finding out fast if common languages
1283 // are LTR (minus) or RTL (plus).
1284 static const char* LANG_DIR_STRING
=
1285 "root-en-es-pt-zh-ja-ko-de-fr-it-ar+he+fa+ru-nl-pl-th-tr-";
1287 // Implemented here because this calls uloc_addLikelySubtags().
1288 U_CAPI UBool U_EXPORT2
1289 uloc_isRightToLeft(const char *locale
) {
1290 UErrorCode errorCode
= U_ZERO_ERROR
;
1292 int32_t scriptLength
= uloc_getScript(locale
, script
, UPRV_LENGTHOF(script
), &errorCode
);
1293 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1294 scriptLength
== 0) {
1295 // Fastpath: We know the likely scripts and their writing direction
1296 // for some common languages.
1297 errorCode
= U_ZERO_ERROR
;
1299 int32_t langLength
= uloc_getLanguage(locale
, lang
, UPRV_LENGTHOF(lang
), &errorCode
);
1300 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1304 const char* langPtr
= uprv_strstr(LANG_DIR_STRING
, lang
);
1305 if (langPtr
!= NULL
) {
1306 switch (langPtr
[langLength
]) {
1307 case '-': return FALSE
;
1308 case '+': return TRUE
;
1309 default: break; // partial match of a longer code
1312 // Otherwise, find the likely script.
1313 errorCode
= U_ZERO_ERROR
;
1314 char likely
[ULOC_FULLNAME_CAPACITY
];
1315 (void)uloc_addLikelySubtags(locale
, likely
, UPRV_LENGTHOF(likely
), &errorCode
);
1316 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
) {
1319 scriptLength
= uloc_getScript(likely
, script
, UPRV_LENGTHOF(script
), &errorCode
);
1320 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1321 scriptLength
== 0) {
1325 UScriptCode scriptCode
= (UScriptCode
)u_getPropertyValueEnum(UCHAR_SCRIPT
, script
);
1326 return uscript_isRightToLeft(scriptCode
);
1332 Locale::isRightToLeft() const {
1333 return uloc_isRightToLeft(getBaseName());
1338 // The following must at least allow for rg key value (6) plus terminator (1).
1339 #define ULOC_RG_BUFLEN 8
1341 U_CAPI
int32_t U_EXPORT2
1342 ulocimp_getRegionForSupplementalData(const char *localeID
, UBool inferRegion
,
1343 char *region
, int32_t regionCapacity
, UErrorCode
* status
) {
1344 if (U_FAILURE(*status
)) {
1347 char rgBuf
[ULOC_RG_BUFLEN
];
1348 UErrorCode rgStatus
= U_ZERO_ERROR
;
1350 // First check for rg keyword value
1351 int32_t rgLen
= uloc_getKeywordValue(localeID
, "rg", rgBuf
, ULOC_RG_BUFLEN
, &rgStatus
);
1352 if (U_FAILURE(rgStatus
) || rgLen
!= 6) {
1355 // rgBuf guaranteed to be zero terminated here, with text len 6
1356 char *rgPtr
= rgBuf
;
1357 for (; *rgPtr
!= 0; rgPtr
++) {
1358 *rgPtr
= uprv_toupper(*rgPtr
);
1360 rgLen
= (uprv_strcmp(rgBuf
+2, "ZZZZ") == 0)? 2: 0;
1364 // No valid rg keyword value, try for unicode_region_subtag
1365 rgLen
= uloc_getCountry(localeID
, rgBuf
, ULOC_RG_BUFLEN
, status
);
1366 if (U_FAILURE(*status
)) {
1368 } else if (rgLen
== 0 && inferRegion
) {
1369 // no unicode_region_subtag but inferRegion TRUE, try likely subtags
1370 char locBuf
[ULOC_FULLNAME_CAPACITY
];
1371 rgStatus
= U_ZERO_ERROR
;
1372 (void)uloc_addLikelySubtags(localeID
, locBuf
, ULOC_FULLNAME_CAPACITY
, &rgStatus
);
1373 if (U_SUCCESS(rgStatus
)) {
1374 rgLen
= uloc_getCountry(locBuf
, rgBuf
, ULOC_RG_BUFLEN
, status
);
1375 if (U_FAILURE(*status
)) {
1383 uprv_strncpy(region
, rgBuf
, regionCapacity
);
1384 return u_terminateChars(region
, regionCapacity
, rgLen
, status
);