2 *******************************************************************************
4 * Copyright (C) 1997-2016, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: loclikely.cpp
10 * tab size: 8 (not used)
13 * created on: 2010feb25
14 * created by: Markus W. Scherer
16 * Code for likely and minimized locale subtags, separated out from other .cpp files
17 * that then do not depend on resource bundle code and likely-subtags data.
20 #include "unicode/utypes.h"
21 #include "unicode/locid.h"
22 #include "unicode/putil.h"
23 #include "unicode/uloc.h"
24 #include "unicode/ures.h"
25 #include "unicode/uscript.h"
32 * This function looks for the localeID in the likelySubtags resource.
34 * @param localeID The tag to find.
35 * @param buffer A buffer to hold the matching entry
36 * @param bufferLength The length of the output buffer
37 * @return A pointer to "buffer" if found, or a null pointer if not.
39 static const char* U_CALLCONV
40 findLikelySubtags(const char* localeID
,
44 const char* result
= NULL
;
46 if (!U_FAILURE(*err
)) {
48 const UChar
* s
= NULL
;
49 UErrorCode tmpErr
= U_ZERO_ERROR
;
50 UResourceBundle
* subtags
= ures_openDirect(NULL
, "likelySubtags", &tmpErr
);
51 if (U_SUCCESS(tmpErr
)) {
52 s
= ures_getStringByKey(subtags
, localeID
, &resLen
, &tmpErr
);
54 if (U_FAILURE(tmpErr
)) {
56 * If a resource is missing, it's not really an error, it's
57 * just that we don't have any data for that particular locale ID.
59 if (tmpErr
!= U_MISSING_RESOURCE_ERROR
) {
63 else if (resLen
>= bufferLength
) {
64 /* The buffer should never overflow. */
65 *err
= U_INTERNAL_PROGRAM_ERROR
;
68 u_UCharsToChars(s
, buffer
, resLen
+ 1);
82 * Append a tag to a buffer, adding the separator if necessary. The buffer
83 * must be large enough to contain the resulting tag plus any separator
84 * necessary. The tag must not be a zero-length string.
86 * @param tag The tag to add.
87 * @param tagLength The length of the tag.
88 * @param buffer The output buffer.
89 * @param bufferLength The length of the output buffer. This is an input/ouput parameter.
91 static void U_CALLCONV
96 int32_t* bufferLength
) {
98 if (*bufferLength
> 0) {
99 buffer
[*bufferLength
] = '_';
104 &buffer
[*bufferLength
],
108 *bufferLength
+= tagLength
;
112 * These are the canonical strings for unknown languages, scripts and regions.
114 static const char* const unknownLanguage
= "und";
115 static const char* const unknownScript
= "Zzzz";
116 static const char* const unknownRegion
= "ZZ";
119 * Create a tag string from the supplied parameters. The lang, script and region
120 * parameters may be NULL pointers. If they are, their corresponding length parameters
121 * must be less than or equal to 0.
123 * If any of the language, script or region parameters are empty, and the alternateTags
124 * parameter is not NULL, it will be parsed for potential language, script and region tags
125 * to be used when constructing the new tag. If the alternateTags parameter is NULL, or
126 * it contains no language tag, the default tag for the unknown language is used.
128 * If the length of the new string exceeds the capacity of the output buffer,
129 * the function copies as many bytes to the output buffer as it can, and returns
130 * the error U_BUFFER_OVERFLOW_ERROR.
132 * If an illegal argument is provided, the function returns the error
133 * U_ILLEGAL_ARGUMENT_ERROR.
135 * Note that this function can return the warning U_STRING_NOT_TERMINATED_WARNING if
136 * the tag string fits in the output buffer, but the null terminator doesn't.
138 * @param lang The language tag to use.
139 * @param langLength The length of the language tag.
140 * @param script The script tag to use.
141 * @param scriptLength The length of the script tag.
142 * @param region The region tag to use.
143 * @param regionLength The length of the region tag.
144 * @param trailing Any trailing data to append to the new tag.
145 * @param trailingLength The length of the trailing data.
146 * @param alternateTags A string containing any alternate tags.
147 * @param tag The output buffer.
148 * @param tagCapacity The capacity of the output buffer.
149 * @param err A pointer to a UErrorCode for error reporting.
150 * @return The length of the tag string, which may be greater than tagCapacity, or -1 on error.
152 static int32_t U_CALLCONV
153 createTagStringWithAlternates(
157 int32_t scriptLength
,
159 int32_t regionLength
,
160 const char* trailing
,
161 int32_t trailingLength
,
162 const char* alternateTags
,
167 if (U_FAILURE(*err
)) {
170 else if (tag
== NULL
||
172 langLength
>= ULOC_LANG_CAPACITY
||
173 scriptLength
>= ULOC_SCRIPT_CAPACITY
||
174 regionLength
>= ULOC_COUNTRY_CAPACITY
) {
179 * ULOC_FULLNAME_CAPACITY will provide enough capacity
180 * that we can build a string that contains the language,
181 * script and region code without worrying about overrunning
182 * the user-supplied buffer.
184 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
185 int32_t tagLength
= 0;
186 int32_t capacityRemaining
= tagCapacity
;
187 UBool regionAppended
= FALSE
;
189 if (langLength
> 0) {
196 else if (alternateTags
== NULL
) {
198 * Append the value for an unknown language, if
199 * we found no language.
203 (int32_t)uprv_strlen(unknownLanguage
),
209 * Parse the alternateTags string for the language.
211 char alternateLang
[ULOC_LANG_CAPACITY
];
212 int32_t alternateLangLength
= sizeof(alternateLang
);
214 alternateLangLength
=
220 if(U_FAILURE(*err
) ||
221 alternateLangLength
>= ULOC_LANG_CAPACITY
) {
224 else if (alternateLangLength
== 0) {
226 * Append the value for an unknown language, if
227 * we found no language.
231 (int32_t)uprv_strlen(unknownLanguage
),
244 if (scriptLength
> 0) {
251 else if (alternateTags
!= NULL
) {
253 * Parse the alternateTags string for the script.
255 char alternateScript
[ULOC_SCRIPT_CAPACITY
];
257 const int32_t alternateScriptLength
=
261 sizeof(alternateScript
),
264 if (U_FAILURE(*err
) ||
265 alternateScriptLength
>= ULOC_SCRIPT_CAPACITY
) {
268 else if (alternateScriptLength
> 0) {
271 alternateScriptLength
,
277 if (regionLength
> 0) {
284 regionAppended
= TRUE
;
286 else if (alternateTags
!= NULL
) {
288 * Parse the alternateTags string for the region.
290 char alternateRegion
[ULOC_COUNTRY_CAPACITY
];
292 const int32_t alternateRegionLength
=
296 sizeof(alternateRegion
),
298 if (U_FAILURE(*err
) ||
299 alternateRegionLength
>= ULOC_COUNTRY_CAPACITY
) {
302 else if (alternateRegionLength
> 0) {
305 alternateRegionLength
,
309 regionAppended
= TRUE
;
314 const int32_t toCopy
=
315 tagLength
>= tagCapacity
? tagCapacity
: tagLength
;
318 * Copy the partial tag from our internal buffer to the supplied
326 capacityRemaining
-= toCopy
;
329 if (trailingLength
> 0) {
330 if (*trailing
!= '@' && capacityRemaining
> 0) {
331 tag
[tagLength
++] = '_';
333 if (capacityRemaining
> 0 && !regionAppended
) {
334 /* extra separator is required */
335 tag
[tagLength
++] = '_';
340 if (capacityRemaining
> 0) {
342 * Copy the trailing data into the supplied buffer. Use uprv_memmove, since we
343 * don't know if the user-supplied buffers overlap.
345 const int32_t toCopy
=
346 trailingLength
>= capacityRemaining
? capacityRemaining
: trailingLength
;
355 tagLength
+= trailingLength
;
357 return u_terminateChars(
367 * An overflow indicates the locale ID passed in
368 * is ill-formed. If we got here, and there was
369 * no previous error, it's an implicit overflow.
371 if (*err
== U_BUFFER_OVERFLOW_ERROR
||
373 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
380 * Create a tag string from the supplied parameters. The lang, script and region
381 * parameters may be NULL pointers. If they are, their corresponding length parameters
382 * must be less than or equal to 0. If the lang parameter is an empty string, the
383 * default value for an unknown language is written to the output buffer.
385 * If the length of the new string exceeds the capacity of the output buffer,
386 * the function copies as many bytes to the output buffer as it can, and returns
387 * the error U_BUFFER_OVERFLOW_ERROR.
389 * If an illegal argument is provided, the function returns the error
390 * U_ILLEGAL_ARGUMENT_ERROR.
392 * @param lang The language tag to use.
393 * @param langLength The length of the language tag.
394 * @param script The script tag to use.
395 * @param scriptLength The length of the script tag.
396 * @param region The region tag to use.
397 * @param regionLength The length of the region tag.
398 * @param trailing Any trailing data to append to the new tag.
399 * @param trailingLength The length of the trailing data.
400 * @param tag The output buffer.
401 * @param tagCapacity The capacity of the output buffer.
402 * @param err A pointer to a UErrorCode for error reporting.
403 * @return The length of the tag string, which may be greater than tagCapacity.
405 static int32_t U_CALLCONV
410 int32_t scriptLength
,
412 int32_t regionLength
,
413 const char* trailing
,
414 int32_t trailingLength
,
419 return createTagStringWithAlternates(
435 * Parse the language, script, and region subtags from a tag string, and copy the
436 * results into the corresponding output parameters. The buffers are null-terminated,
437 * unless overflow occurs.
439 * The langLength, scriptLength, and regionLength parameters are input/output
440 * parameters, and must contain the capacity of their corresponding buffers on
441 * input. On output, they will contain the actual length of the buffers, not
442 * including the null terminator.
444 * If the length of any of the output subtags exceeds the capacity of the corresponding
445 * buffer, the function copies as many bytes to the output buffer as it can, and returns
446 * the error U_BUFFER_OVERFLOW_ERROR. It will not parse any more subtags once overflow
449 * If an illegal argument is provided, the function returns the error
450 * U_ILLEGAL_ARGUMENT_ERROR.
452 * @param localeID The locale ID to parse.
453 * @param lang The language tag buffer.
454 * @param langLength The length of the language tag.
455 * @param script The script tag buffer.
456 * @param scriptLength The length of the script tag.
457 * @param region The region tag buffer.
458 * @param regionLength The length of the region tag.
459 * @param err A pointer to a UErrorCode for error reporting.
460 * @return The number of chars of the localeID parameter consumed.
462 static int32_t U_CALLCONV
464 const char* localeID
,
468 int32_t* scriptLength
,
470 int32_t* regionLength
,
473 const char* position
= localeID
;
474 int32_t subtagLength
= 0;
476 if(U_FAILURE(*err
) ||
479 langLength
== NULL
||
481 scriptLength
== NULL
||
483 regionLength
== NULL
) {
487 subtagLength
= ulocimp_getLanguage(position
, lang
, *langLength
, &position
);
488 u_terminateChars(lang
, *langLength
, subtagLength
, err
);
491 * Note that we explicit consider U_STRING_NOT_TERMINATED_WARNING
492 * to be an error, because it indicates the user-supplied tag is
495 if(U_FAILURE(*err
)) {
499 *langLength
= subtagLength
;
502 * If no language was present, use the value of unknownLanguage
503 * instead. Otherwise, move past any separator.
505 if (*langLength
== 0) {
509 *langLength
= (int32_t)uprv_strlen(lang
);
511 else if (_isIDSeparator(*position
)) {
515 subtagLength
= ulocimp_getScript(position
, script
, *scriptLength
, &position
);
516 u_terminateChars(script
, *scriptLength
, subtagLength
, err
);
518 if(U_FAILURE(*err
)) {
522 *scriptLength
= subtagLength
;
524 if (*scriptLength
> 0) {
525 if (uprv_strnicmp(script
, unknownScript
, *scriptLength
) == 0) {
527 * If the script part is the "unknown" script, then don't return it.
533 * Move past any separator.
535 if (_isIDSeparator(*position
)) {
540 subtagLength
= ulocimp_getCountry(position
, region
, *regionLength
, &position
);
541 u_terminateChars(region
, *regionLength
, subtagLength
, err
);
543 if(U_FAILURE(*err
)) {
547 *regionLength
= subtagLength
;
549 if (*regionLength
> 0) {
550 if (uprv_strnicmp(region
, unknownRegion
, *regionLength
) == 0) {
552 * If the region part is the "unknown" region, then don't return it.
556 } else if (*position
!= 0 && *position
!= '@') {
557 /* back up over consumed trailing separator */
563 return (int32_t)(position
- localeID
);
568 * If we get here, we have no explicit error, it's the result of an
571 if (!U_FAILURE(*err
)) {
572 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
578 static int32_t U_CALLCONV
579 createLikelySubtagsString(
583 int32_t scriptLength
,
585 int32_t regionLength
,
586 const char* variants
,
587 int32_t variantsLength
,
593 * ULOC_FULLNAME_CAPACITY will provide enough capacity
594 * that we can build a string that contains the language,
595 * script and region code without worrying about overrunning
596 * the user-supplied buffer.
598 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
599 char likelySubtagsBuffer
[ULOC_FULLNAME_CAPACITY
];
601 if(U_FAILURE(*err
)) {
606 * Try the language with the script and region first.
608 if (scriptLength
> 0 && regionLength
> 0) {
610 const char* likelySubtags
= NULL
;
624 if(U_FAILURE(*err
)) {
632 sizeof(likelySubtagsBuffer
),
634 if(U_FAILURE(*err
)) {
638 if (likelySubtags
!= NULL
) {
639 /* Always use the language tag from the
640 maximal string, since it may be more
641 specific than the one provided. */
642 return createTagStringWithAlternates(
659 * Try the language with just the script.
661 if (scriptLength
> 0) {
663 const char* likelySubtags
= NULL
;
677 if(U_FAILURE(*err
)) {
685 sizeof(likelySubtagsBuffer
),
687 if(U_FAILURE(*err
)) {
691 if (likelySubtags
!= NULL
) {
692 /* Always use the language tag from the
693 maximal string, since it may be more
694 specific than the one provided. */
695 return createTagStringWithAlternates(
712 * Try the language with just the region.
714 if (regionLength
> 0) {
716 const char* likelySubtags
= NULL
;
730 if(U_FAILURE(*err
)) {
738 sizeof(likelySubtagsBuffer
),
740 if(U_FAILURE(*err
)) {
744 if (likelySubtags
!= NULL
) {
745 /* Always use the language tag from the
746 maximal string, since it may be more
747 specific than the one provided. */
748 return createTagStringWithAlternates(
765 * Finally, try just the language.
768 const char* likelySubtags
= NULL
;
782 if(U_FAILURE(*err
)) {
790 sizeof(likelySubtagsBuffer
),
792 if(U_FAILURE(*err
)) {
796 if (likelySubtags
!= NULL
) {
797 /* Always use the language tag from the
798 maximal string, since it may be more
799 specific than the one provided. */
800 return createTagStringWithAlternates(
816 return u_terminateChars(
824 if (!U_FAILURE(*err
)) {
825 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
831 #define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) \
832 { int32_t count = 0; \
834 for (i = 0; i < trailingLength; i++) { \
835 if (trailing[i] == '-' || trailing[i] == '_') { \
840 } else if (trailing[i] == '@') { \
842 } else if (count > 8) { \
851 _uloc_addLikelySubtags(const char* localeID
,
852 char* maximizedLocaleID
,
853 int32_t maximizedLocaleIDCapacity
,
856 char lang
[ULOC_LANG_CAPACITY
];
857 int32_t langLength
= sizeof(lang
);
858 char script
[ULOC_SCRIPT_CAPACITY
];
859 int32_t scriptLength
= sizeof(script
);
860 char region
[ULOC_COUNTRY_CAPACITY
];
861 int32_t regionLength
= sizeof(region
);
862 const char* trailing
= "";
863 int32_t trailingLength
= 0;
864 int32_t trailingIndex
= 0;
865 int32_t resultLength
= 0;
867 if(U_FAILURE(*err
)) {
870 else if (localeID
== NULL
||
871 maximizedLocaleID
== NULL
||
872 maximizedLocaleIDCapacity
<= 0) {
876 trailingIndex
= parseTagString(
885 if(U_FAILURE(*err
)) {
886 /* Overflow indicates an illegal argument error */
887 if (*err
== U_BUFFER_OVERFLOW_ERROR
) {
888 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
894 /* Find the length of the trailing portion. */
895 while (_isIDSeparator(localeID
[trailingIndex
])) {
898 trailing
= &localeID
[trailingIndex
];
899 trailingLength
= (int32_t)uprv_strlen(trailing
);
901 CHECK_TRAILING_VARIANT_SIZE(trailing
, trailingLength
);
904 createLikelySubtagsString(
914 maximizedLocaleIDCapacity
,
917 if (resultLength
== 0) {
918 const int32_t localIDLength
= (int32_t)uprv_strlen(localeID
);
921 * If we get here, we need to return localeID.
926 localIDLength
<= maximizedLocaleIDCapacity
?
927 localIDLength
: maximizedLocaleIDCapacity
);
932 maximizedLocaleIDCapacity
,
941 if (!U_FAILURE(*err
)) {
942 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
949 _uloc_minimizeSubtags(const char* localeID
,
950 char* minimizedLocaleID
,
951 int32_t minimizedLocaleIDCapacity
,
955 * ULOC_FULLNAME_CAPACITY will provide enough capacity
956 * that we can build a string that contains the language,
957 * script and region code without worrying about overrunning
958 * the user-supplied buffer.
960 char maximizedTagBuffer
[ULOC_FULLNAME_CAPACITY
];
961 int32_t maximizedTagBufferLength
= sizeof(maximizedTagBuffer
);
963 char lang
[ULOC_LANG_CAPACITY
];
964 int32_t langLength
= sizeof(lang
);
965 char script
[ULOC_SCRIPT_CAPACITY
];
966 int32_t scriptLength
= sizeof(script
);
967 char region
[ULOC_COUNTRY_CAPACITY
];
968 int32_t regionLength
= sizeof(region
);
969 const char* trailing
= "";
970 int32_t trailingLength
= 0;
971 int32_t trailingIndex
= 0;
973 if(U_FAILURE(*err
)) {
976 else if (localeID
== NULL
||
977 minimizedLocaleID
== NULL
||
978 minimizedLocaleIDCapacity
<= 0) {
992 if(U_FAILURE(*err
)) {
994 /* Overflow indicates an illegal argument error */
995 if (*err
== U_BUFFER_OVERFLOW_ERROR
) {
996 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1002 /* Find the spot where the variants or the keywords begin, if any. */
1003 while (_isIDSeparator(localeID
[trailingIndex
])) {
1006 trailing
= &localeID
[trailingIndex
];
1007 trailingLength
= (int32_t)uprv_strlen(trailing
);
1009 CHECK_TRAILING_VARIANT_SIZE(trailing
, trailingLength
);
1021 maximizedTagBufferLength
,
1023 if(U_FAILURE(*err
)) {
1028 * First, we need to first get the maximization
1029 * from AddLikelySubtags.
1031 maximizedTagBufferLength
=
1032 uloc_addLikelySubtags(
1035 maximizedTagBufferLength
,
1038 if(U_FAILURE(*err
)) {
1043 * Start first with just the language.
1046 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
1048 const int32_t tagBufferLength
=
1049 createLikelySubtagsString(
1062 if(U_FAILURE(*err
)) {
1065 else if (uprv_strnicmp(
1068 tagBufferLength
) == 0) {
1070 return createTagString(
1080 minimizedLocaleIDCapacity
,
1086 * Next, try the language and region.
1088 if (regionLength
> 0) {
1090 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
1092 const int32_t tagBufferLength
=
1093 createLikelySubtagsString(
1106 if(U_FAILURE(*err
)) {
1109 else if (uprv_strnicmp(
1112 tagBufferLength
) == 0) {
1114 return createTagString(
1124 minimizedLocaleIDCapacity
,
1130 * Finally, try the language and script. This is our last chance,
1131 * since trying with all three subtags would only yield the
1132 * maximal version that we already have.
1134 if (scriptLength
> 0 && regionLength
> 0) {
1135 char tagBuffer
[ULOC_FULLNAME_CAPACITY
];
1137 const int32_t tagBufferLength
=
1138 createLikelySubtagsString(
1151 if(U_FAILURE(*err
)) {
1154 else if (uprv_strnicmp(
1157 tagBufferLength
) == 0) {
1159 return createTagString(
1169 minimizedLocaleIDCapacity
,
1176 * If we got here, return the locale ID parameter.
1178 const int32_t localeIDLength
= (int32_t)uprv_strlen(localeID
);
1183 localeIDLength
<= minimizedLocaleIDCapacity
?
1184 localeIDLength
: minimizedLocaleIDCapacity
);
1186 return u_terminateChars(
1188 minimizedLocaleIDCapacity
,
1195 if (!U_FAILURE(*err
)) {
1196 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1205 do_canonicalize(const char* localeID
,
1207 int32_t bufferCapacity
,
1216 if (*err
== U_STRING_NOT_TERMINATED_WARNING
||
1217 *err
== U_BUFFER_OVERFLOW_ERROR
) {
1218 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
1222 else if (U_FAILURE(*err
)) {
1231 U_CAPI
int32_t U_EXPORT2
1232 uloc_addLikelySubtags(const char* localeID
,
1233 char* maximizedLocaleID
,
1234 int32_t maximizedLocaleIDCapacity
,
1237 char localeBuffer
[ULOC_FULLNAME_CAPACITY
];
1239 if (!do_canonicalize(
1242 sizeof(localeBuffer
),
1247 return _uloc_addLikelySubtags(
1250 maximizedLocaleIDCapacity
,
1255 U_CAPI
int32_t U_EXPORT2
1256 uloc_minimizeSubtags(const char* localeID
,
1257 char* minimizedLocaleID
,
1258 int32_t minimizedLocaleIDCapacity
,
1261 char localeBuffer
[ULOC_FULLNAME_CAPACITY
];
1263 if (!do_canonicalize(
1266 sizeof(localeBuffer
),
1271 return _uloc_minimizeSubtags(
1274 minimizedLocaleIDCapacity
,
1279 // Pairs of (language subtag, + or -) for finding out fast if common languages
1280 // are LTR (minus) or RTL (plus).
1281 static const char* LANG_DIR_STRING
=
1282 "root-en-es-pt-zh-ja-ko-de-fr-it-ar+he+fa+ru-nl-pl-th-tr-";
1284 // Implemented here because this calls uloc_addLikelySubtags().
1285 U_CAPI UBool U_EXPORT2
1286 uloc_isRightToLeft(const char *locale
) {
1287 UErrorCode errorCode
= U_ZERO_ERROR
;
1289 int32_t scriptLength
= uloc_getScript(locale
, script
, UPRV_LENGTHOF(script
), &errorCode
);
1290 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1291 scriptLength
== 0) {
1292 // Fastpath: We know the likely scripts and their writing direction
1293 // for some common languages.
1294 errorCode
= U_ZERO_ERROR
;
1296 int32_t langLength
= uloc_getLanguage(locale
, lang
, UPRV_LENGTHOF(lang
), &errorCode
);
1297 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1301 const char* langPtr
= uprv_strstr(LANG_DIR_STRING
, lang
);
1302 if (langPtr
!= NULL
) {
1303 switch (langPtr
[langLength
]) {
1304 case '-': return FALSE
;
1305 case '+': return TRUE
;
1306 default: break; // partial match of a longer code
1309 // Otherwise, find the likely script.
1310 errorCode
= U_ZERO_ERROR
;
1311 char likely
[ULOC_FULLNAME_CAPACITY
];
1312 (void)uloc_addLikelySubtags(locale
, likely
, UPRV_LENGTHOF(likely
), &errorCode
);
1313 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
) {
1316 scriptLength
= uloc_getScript(likely
, script
, UPRV_LENGTHOF(script
), &errorCode
);
1317 if (U_FAILURE(errorCode
) || errorCode
== U_STRING_NOT_TERMINATED_WARNING
||
1318 scriptLength
== 0) {
1322 UScriptCode scriptCode
= (UScriptCode
)u_getPropertyValueEnum(UCHAR_SCRIPT
, script
);
1323 return uscript_isRightToLeft(scriptCode
);
1329 Locale::isRightToLeft() const {
1330 return uloc_isRightToLeft(getBaseName());
1333 // The following must at least allow for rg key value (6) plus terminator (1).
1334 #define ULOC_RG_BUFLEN 8
1336 U_CAPI
int32_t U_EXPORT2
1337 ulocimp_getRegionForSupplementalData(const char *localeID
, UBool inferRegion
,
1338 char *region
, int32_t regionCapacity
, UErrorCode
* status
) {
1339 if (U_FAILURE(*status
)) {
1342 char rgBuf
[ULOC_RG_BUFLEN
];
1343 UErrorCode rgStatus
= U_ZERO_ERROR
;
1345 // First check for rg keyword value
1346 int32_t rgLen
= uloc_getKeywordValue(localeID
, "rg", rgBuf
, ULOC_RG_BUFLEN
, &rgStatus
);
1347 if (U_FAILURE(rgStatus
) || rgLen
!= 6) {
1350 // rgBuf guaranteed to be zero terminated here, with text len 6
1351 char *rgPtr
= rgBuf
;
1352 for (; *rgPtr
!= 0; rgPtr
++) {
1353 *rgPtr
= uprv_toupper(*rgPtr
);
1355 rgLen
= (uprv_strcmp(rgBuf
+2, "ZZZZ") == 0)? 2: 0;
1359 // No valid rg keyword value, try for unicode_region_subtag
1360 rgLen
= uloc_getCountry(localeID
, rgBuf
, ULOC_RG_BUFLEN
, status
);
1361 if (U_FAILURE(*status
)) {
1363 } else if (rgLen
== 0 && inferRegion
) {
1364 // no unicode_region_subtag but inferRegion TRUE, try likely subtags
1365 char locBuf
[ULOC_FULLNAME_CAPACITY
];
1366 rgStatus
= U_ZERO_ERROR
;
1367 (void)uloc_addLikelySubtags(localeID
, locBuf
, ULOC_FULLNAME_CAPACITY
, &rgStatus
);
1368 if (U_SUCCESS(rgStatus
)) {
1369 rgLen
= uloc_getCountry(locBuf
, rgBuf
, ULOC_RG_BUFLEN
, status
);
1370 if (U_FAILURE(*status
)) {
1378 uprv_strncpy(region
, rgBuf
, regionCapacity
);
1379 return u_terminateChars(region
, regionCapacity
, rgLen
, status
);