2 *****************************************************************************************
3 * Copyright (C) 2014 Apple Inc. All Rights Reserved.
4 *****************************************************************************************
7 #include "unicode/utypes.h"
8 #include "unicode/ualoc.h"
9 #include "unicode/uloc.h"
10 #include "unicode/ures.h"
11 #include "unicode/putil.h"
14 // the following has replacements for some math.h funcs etc
18 // The numeric values in territoryInfo are in "IntF" format from LDML2ICUConverter.
19 // From its docs (adapted): [IntF is] a special integer that represents the number in
20 // normalized scientific notation.
21 // Resultant integers are in the form -?xxyyyyyy, where xx is the exponent
22 // offset by 50 and yyyyyy is the coefficient to 5 decimal places (range 1.0 to 9.99999), e.g.
23 // 14660000000000 -> 1.46600E13 -> 63146600
24 // 0.0001 -> 1.00000E-4 -> 46100000
25 // -123.456 -> -1.23456E-2 -> -48123456
27 // Here to avoid an extra division we have the max coefficient as 999999 (instead of
28 // 9.99999) and instead offset the exponent by -55.
30 static double doubleFromIntF(int32_t intF
) {
31 double coefficient
= (double)(intF
% 1000000);
32 int32_t exponent
= (intF
/ 1000000) - 55;
33 return coefficient
* uprv_pow10(exponent
);
36 static int compareLangEntries(const void * entry1
, const void * entry2
) {
37 double fraction1
= ((const UALanguageEntry
*)entry1
)->userFraction
;
38 double fraction2
= ((const UALanguageEntry
*)entry2
)->userFraction
;
39 // want descending order
40 if (fraction1
> fraction2
) return -1;
41 if (fraction1
< fraction2
) return 1;
42 // userFractions the same, sort by languageCode
43 return uprv_strcmp(((const UALanguageEntry
*)entry1
)->languageCode
,((const UALanguageEntry
*)entry2
)->languageCode
);
46 static const UChar ustrLangStatusDefacto
[] = {0x64,0x65,0x5F,0x66,0x61,0x63,0x74,0x6F,0x5F,0x6F,0x66,0x66,0x69,0x63,0x69,0x61,0x6C,0}; //"de_facto_official"
47 static const UChar ustrLangStatusOfficial
[] = {0x6F,0x66,0x66,0x69,0x63,0x69,0x61,0x6C,0}; //"official"
48 static const UChar ustrLangStatusRegional
[] = {0x6F,0x66,0x66,0x69,0x63,0x69,0x61,0x6C,0x5F,0x72,0x65,0x67,0x69,0x6F,0x6E,0x61,0x6C,0}; //"official_regional"
51 kLocalLangEntriesMax
= 26, // enough for most regions to minimumFraction 0.001 except India
52 kLangEntriesFactor
= 3 // if we have to allocate, multiply existing size by this
55 U_CAPI
int32_t U_EXPORT2
56 ualoc_getLanguagesForRegion(const char *regionID
, double minimumFraction
,
57 UALanguageEntry
*entries
, int32_t entriesCapacity
,
60 if (U_FAILURE(*err
)) {
63 if ( regionID
== NULL
|| minimumFraction
< 0.0 || minimumFraction
> 1.0 ||
64 ((entries
==NULL
)? entriesCapacity
!=0: entriesCapacity
<0) ) {
65 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
68 UResourceBundle
*rb
= ures_openDirect(NULL
, "supplementalData", err
);
69 rb
= ures_getByKey(rb
, "territoryInfo", rb
, err
);
70 rb
= ures_getByKey(rb
, regionID
, rb
, err
);
71 if (U_FAILURE(*err
)) {
76 int32_t entryCount
= 0;
77 UResourceBundle
*langBund
= NULL
;
78 int32_t lbIdx
, lbCount
= ures_getSize(rb
);
79 UALanguageEntry localLangEntries
[kLocalLangEntriesMax
];
80 UALanguageEntry
* langEntries
= localLangEntries
;
81 int32_t langEntriesMax
= kLocalLangEntriesMax
;
83 for (lbIdx
= 0; lbIdx
< lbCount
; lbIdx
++) {
84 langBund
= ures_getByIndex(rb
, lbIdx
, langBund
, err
);
85 if (U_FAILURE(*err
)) {
88 const char * langCode
= ures_getKey(langBund
);
89 if (uprv_strcmp(langCode
,"territoryF") == 0) {
92 if (strnlen(langCode
, UALANGDATA_CODELEN
+1) > UALANGDATA_CODELEN
) { // no uprv_strnlen
93 continue; // a code we cannot handle
96 UErrorCode localErr
= U_ZERO_ERROR
;
97 double userFraction
= 0.0;
98 UResourceBundle
*itemBund
= ures_getByKey(langBund
, "populationShareF", NULL
, &localErr
);
99 if (U_SUCCESS(localErr
)) {
100 int32_t intF
= ures_getInt(itemBund
, &localErr
);
101 if (U_SUCCESS(localErr
)) {
102 userFraction
= doubleFromIntF(intF
);
104 ures_close(itemBund
);
106 if (userFraction
< minimumFraction
) {
109 if (entries
!= NULL
) {
110 localErr
= U_ZERO_ERROR
;
111 UALanguageStatus langStatus
= UALANGSTATUS_UNSPECIFIED
;
113 const UChar
* ustrLangStatus
= ures_getStringByKey(langBund
, "officialStatus", &ulen
, &localErr
);
114 if (U_SUCCESS(localErr
)) {
115 int32_t cmp
= u_strcmp(ustrLangStatus
, ustrLangStatusOfficial
);
117 langStatus
= UALANGSTATUS_OFFICIAL
;
118 } else if (cmp
< 0 && u_strcmp(ustrLangStatus
, ustrLangStatusDefacto
) == 0) {
119 langStatus
= UALANGSTATUS_DEFACTO_OFFICIAL
;
120 } else if (u_strcmp(ustrLangStatus
, ustrLangStatusRegional
) == 0) {
121 langStatus
= UALANGSTATUS_REGIONAL_OFFICIAL
;
124 // Now we have all of the info for our next entry
125 if (entryCount
>= langEntriesMax
) {
126 int32_t newMax
= langEntriesMax
* kLangEntriesFactor
;
127 if (langEntries
== localLangEntries
) {
128 // first allocation, copy from local buf
129 langEntries
= (UALanguageEntry
*)uprv_malloc(newMax
*sizeof(UALanguageEntry
));
130 if (langEntries
== NULL
) {
131 *err
= U_MEMORY_ALLOCATION_ERROR
;
134 uprv_memcpy(langEntries
, localLangEntries
, entryCount
*sizeof(UALanguageEntry
));
136 langEntries
= (UALanguageEntry
*)uprv_realloc(langEntries
, newMax
*sizeof(UALanguageEntry
));
137 if (langEntries
== NULL
) {
138 *err
= U_MEMORY_ALLOCATION_ERROR
;
142 langEntriesMax
= newMax
;
144 uprv_strcpy(langEntries
[entryCount
].languageCode
, langCode
);
145 langEntries
[entryCount
].userFraction
= userFraction
;
146 langEntries
[entryCount
].status
= langStatus
;
150 ures_close(langBund
);
152 if (U_FAILURE(*err
)) {
153 if (langEntries
!= localLangEntries
) {
158 if (entries
!= NULL
) {
159 // sort langEntries, copy entries that fit to provided array
160 qsort(langEntries
, entryCount
, sizeof(UALanguageEntry
), compareLangEntries
);
161 if (entryCount
> entriesCapacity
) {
162 entryCount
= entriesCapacity
;
164 uprv_memcpy(entries
, langEntries
, entryCount
*sizeof(UALanguageEntry
));
165 if (langEntries
!= localLangEntries
) {
173 static const char * forceParent
[] = {
181 U_CAPI
int32_t U_EXPORT2
182 ualoc_getAppleParent(const char* localeID
,
184 int32_t parentCapacity
,
189 UErrorCode tempStatus
;
190 char locbuf
[ULOC_FULLNAME_CAPACITY
+1];
192 if (U_FAILURE(*err
)) {
195 if ( (parent
==NULL
)? parentCapacity
!=0: parentCapacity
<0 ) {
196 *err
= U_ILLEGAL_ARGUMENT_ERROR
;
199 len
= uloc_canonicalize(localeID
, locbuf
, ULOC_FULLNAME_CAPACITY
, err
);
200 if (U_FAILURE(*err
)) {
203 if (*err
== U_STRING_NOT_TERMINATED_WARNING
) {
204 locbuf
[ULOC_FULLNAME_CAPACITY
] = 0;
207 if (len
>= 2 && uprv_strncmp(locbuf
, "zh", 2) == 0) {
208 const char ** forceParentPtr
= forceParent
;
209 const char * testCurLoc
;
210 while ( (testCurLoc
= *forceParentPtr
++) != NULL
) {
211 int cmp
= uprv_strcmp(locbuf
, testCurLoc
);
214 len
= uprv_strlen(*forceParentPtr
);
215 if (len
< parentCapacity
) {
216 uprv_strcpy(parent
, *forceParentPtr
);
218 *err
= U_BUFFER_OVERFLOW_ERROR
;
227 tempStatus
= U_ZERO_ERROR
;
228 rb
= ures_openDirect(NULL
, locbuf
, &tempStatus
);
229 if (U_SUCCESS(tempStatus
)) {
230 const char * actualLocale
= ures_getLocaleByType(rb
, ULOC_ACTUAL_LOCALE
, &tempStatus
);
231 if (U_SUCCESS(tempStatus
) && uprv_strcmp(locbuf
, actualLocale
) != 0) {
232 // we have followed an alias
233 len
= uprv_strlen(actualLocale
);
234 if (len
< parentCapacity
) {
235 uprv_strcpy(parent
, actualLocale
);
237 *err
= U_BUFFER_OVERFLOW_ERROR
;
242 tempStatus
= U_ZERO_ERROR
;
243 const UChar
* parentUName
= ures_getStringByKey(rb
, "%%Parent", &len
, &tempStatus
);
244 if (U_SUCCESS(tempStatus
) && tempStatus
!= U_USING_FALLBACK_WARNING
) {
245 if (len
< parentCapacity
) {
246 u_UCharsToChars(parentUName
, parent
, len
+ 1);
248 *err
= U_BUFFER_OVERFLOW_ERROR
;
255 len
= uloc_getParent(locbuf
, parent
, parentCapacity
, err
);
256 if (U_SUCCESS(*err
) && len
== 0) {
258 if (len
< parentCapacity
) {
259 uprv_strcpy(parent
, "root");
261 *err
= U_BUFFER_OVERFLOW_ERROR
;