| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
| 3 | // See the LICENSE file in the project root for more information. | 
| 4 | // | 
| 5 |  | 
| 6 | #include <assert.h> | 
| 7 | #include <string.h> | 
| 8 | #include <vector> | 
| 9 |  | 
| 10 | #include "icushim.h" | 
| 11 | #include "locale.hpp" | 
| 12 | #include "holders.h" | 
| 13 |  | 
| 14 | // invariant character definitions used by ICU | 
| 15 | #define UCHAR_CURRENCY ((UChar)0x00A4)   // international currency | 
| 16 | #define UCHAR_SPACE ((UChar)0x0020)      // space | 
| 17 | #define UCHAR_NBSPACE ((UChar)0x00A0)    // space | 
| 18 | #define UCHAR_DIGIT ((UChar)0x0023)      // '#' | 
| 19 | #define UCHAR_SEMICOLON ((UChar)0x003B)  // ';' | 
| 20 | #define UCHAR_MINUS ((UChar)0x002D)      // '-' | 
| 21 | #define UCHAR_PERCENT ((UChar)0x0025)    // '%' | 
| 22 | #define UCHAR_OPENPAREN ((UChar)0x0028)  // '(' | 
| 23 | #define UCHAR_CLOSEPAREN ((UChar)0x0029) // ')' | 
| 24 |  | 
| 25 | #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) | 
| 26 |  | 
| 27 | // Enum that corresponds to managed enum CultureData.LocaleNumberData. | 
| 28 | // The numeric values of the enum members match their Win32 counterparts. | 
| 29 | enum LocaleNumberData : int32_t | 
| 30 | { | 
| 31 |     LanguageId = 0x00000001, | 
| 32 |     MeasurementSystem = 0x0000000D, | 
| 33 |     FractionalDigitsCount = 0x00000011, | 
| 34 |     NegativeNumberFormat = 0x00001010, | 
| 35 |     MonetaryFractionalDigitsCount = 0x00000019, | 
| 36 |     PositiveMonetaryNumberFormat = 0x0000001B, | 
| 37 |     NegativeMonetaryNumberFormat = 0x0000001C, | 
| 38 |     FirstDayofWeek = 0x0000100C, | 
| 39 |     FirstWeekOfYear = 0x0000100D, | 
| 40 |     ReadingLayout = 0x00000070, | 
| 41 |     NegativePercentFormat = 0x00000074, | 
| 42 |     PositivePercentFormat = 0x00000075, | 
| 43 |     Digit = 0x00000010, | 
| 44 |     Monetary = 0x00000018 | 
| 45 | }; | 
| 46 |  | 
| 47 | // Enum that corresponds to managed enum System.Globalization.CalendarWeekRule | 
| 48 | enum CalendarWeekRule : int32_t | 
| 49 | { | 
| 50 |     FirstDay = 0, | 
| 51 |     FirstFullWeek = 1, | 
| 52 |     FirstFourDayWeek = 2 | 
| 53 | }; | 
| 54 |  | 
| 55 | /* | 
| 56 | Function: | 
| 57 | NormalizeNumericPattern | 
| 58 |  | 
| 59 | Returns a numeric string pattern in a format that we can match against the | 
| 60 | appropriate managed pattern. | 
| 61 | */ | 
| 62 | std::string NormalizeNumericPattern(const UChar* srcPattern, bool isNegative) | 
| 63 | { | 
| 64 |     // A srcPattern example: "#,##0.00 C;(#,##0.00 C)" but where C is the | 
| 65 |     // international currency symbol (UCHAR_CURRENCY) | 
| 66 |     // The positive pattern comes first, then an optional negative pattern | 
| 67 |     // separated by a semicolon | 
| 68 |     // A destPattern example: "(C n)" where C represents the currency symbol, and | 
| 69 |     // n is the number | 
| 70 |     std::string destPattern; | 
| 71 |  | 
| 72 |     int iStart = 0; | 
| 73 |     int iEnd = u_strlen(srcPattern); | 
| 74 |     int32_t iNegativePatternStart = -1; | 
| 75 |  | 
| 76 |     for (int i = iStart; i < iEnd; i++) | 
| 77 |     { | 
| 78 |         if (srcPattern[i] == ';') | 
| 79 |         { | 
| 80 |             iNegativePatternStart = i; | 
| 81 |         } | 
| 82 |     } | 
| 83 |  | 
| 84 |     if (iNegativePatternStart >= 0) | 
| 85 |     { | 
| 86 |         if (isNegative) | 
| 87 |         { | 
| 88 |             iStart = iNegativePatternStart + 1; | 
| 89 |         } | 
| 90 |         else | 
| 91 |         { | 
| 92 |             iEnd = iNegativePatternStart - 1; | 
| 93 |         } | 
| 94 |     } | 
| 95 |  | 
| 96 |     bool minusAdded = false; | 
| 97 |     bool digitAdded = false; | 
| 98 |     bool currencyAdded = false; | 
| 99 |     bool spaceAdded = false; | 
| 100 |  | 
| 101 |     for (int i = iStart; i <= iEnd; i++) | 
| 102 |     { | 
| 103 |         UChar ch = srcPattern[i]; | 
| 104 |         switch (ch) | 
| 105 |         { | 
| 106 |             case UCHAR_DIGIT: | 
| 107 |                 if (!digitAdded) | 
| 108 |                 { | 
| 109 |                     digitAdded = true; | 
| 110 |                     destPattern.push_back('n'); | 
| 111 |                 } | 
| 112 |                 break; | 
| 113 |  | 
| 114 |             case UCHAR_CURRENCY: | 
| 115 |                 if (!currencyAdded) | 
| 116 |                 { | 
| 117 |                     currencyAdded = true; | 
| 118 |                     destPattern.push_back('C'); | 
| 119 |                 } | 
| 120 |                 break; | 
| 121 |  | 
| 122 |             case UCHAR_SPACE: | 
| 123 |             case UCHAR_NBSPACE: | 
| 124 |                 if (!spaceAdded) | 
| 125 |                 { | 
| 126 |                     spaceAdded = true; | 
| 127 |                     destPattern.push_back(' '); | 
| 128 |                 } | 
| 129 |                 else | 
| 130 |                 { | 
| 131 |                     assert(false); | 
| 132 |                 } | 
| 133 |                 break; | 
| 134 |  | 
| 135 |             case UCHAR_MINUS: | 
| 136 |             case UCHAR_OPENPAREN: | 
| 137 |             case UCHAR_CLOSEPAREN: | 
| 138 |                 minusAdded = true; | 
| 139 |                 destPattern.push_back(static_cast<char>(ch)); | 
| 140 |                 break; | 
| 141 |  | 
| 142 |             case UCHAR_PERCENT: | 
| 143 |                 destPattern.push_back('%'); | 
| 144 |                 break; | 
| 145 |         } | 
| 146 |     } | 
| 147 |  | 
| 148 |     // if there is no negative subpattern, the ICU convention is to prefix the | 
| 149 |     // minus sign | 
| 150 |     if (isNegative && !minusAdded) | 
| 151 |     { | 
| 152 |         destPattern.insert(destPattern.begin(), '-'); | 
| 153 |     } | 
| 154 |  | 
| 155 |     return destPattern; | 
| 156 | } | 
| 157 |  | 
| 158 | /* | 
| 159 | Function: | 
| 160 | GetNumericPattern | 
| 161 |  | 
| 162 | Determines the pattern from the decimalFormat and returns the matching pattern's | 
| 163 | index from patterns[]. | 
| 164 | Returns index -1 if no pattern is found. | 
| 165 | */ | 
| 166 | int GetNumericPattern(const UNumberFormat* pNumberFormat, const char* patterns[], int patternsCount, bool isNegative) | 
| 167 | { | 
| 168 |     const int INVALID_FORMAT = -1; | 
| 169 |     const int MAX_DOTNET_NUMERIC_PATTERN_LENGTH = 6; // example: "(C n)" plus terminator | 
| 170 |  | 
| 171 |     UErrorCode ignore = U_ZERO_ERROR; | 
| 172 |     int32_t icuPatternLength = unum_toPattern(pNumberFormat, false, nullptr, 0, &ignore); | 
| 173 |  | 
| 174 |     std::vector<UChar> icuPattern(icuPatternLength + 1, '\0'); | 
| 175 |  | 
| 176 |     UErrorCode err = U_ZERO_ERROR; | 
| 177 |  | 
| 178 |     unum_toPattern(pNumberFormat, false, icuPattern.data(), icuPattern.size(), &err); | 
| 179 |  | 
| 180 |     assert(U_SUCCESS(err)); | 
| 181 |  | 
| 182 |     std::string normalizedPattern = NormalizeNumericPattern(icuPattern.data(), isNegative); | 
| 183 |  | 
| 184 |     assert(normalizedPattern.length() > 0); | 
| 185 |     assert(normalizedPattern.length() < MAX_DOTNET_NUMERIC_PATTERN_LENGTH); | 
| 186 |  | 
| 187 |     if (normalizedPattern.length() == 0 || normalizedPattern.length() >= MAX_DOTNET_NUMERIC_PATTERN_LENGTH) | 
| 188 |     { | 
| 189 |         return INVALID_FORMAT; | 
| 190 |     } | 
| 191 |  | 
| 192 |     for (int i = 0; i < patternsCount; i++) | 
| 193 |     { | 
| 194 |         if (strcmp(normalizedPattern.c_str(), patterns[i]) == 0) | 
| 195 |         { | 
| 196 |             return i; | 
| 197 |         } | 
| 198 |     }; | 
| 199 |  | 
| 200 |     assert(false); // should have found a valid pattern | 
| 201 |     return INVALID_FORMAT; | 
| 202 | } | 
| 203 |  | 
| 204 | /* | 
| 205 | Function: | 
| 206 | GetCurrencyNegativePattern | 
| 207 |  | 
| 208 | Implementation of NumberFormatInfo.CurrencyNegativePattern. | 
| 209 | Returns the pattern index. | 
| 210 | */ | 
| 211 | int GetCurrencyNegativePattern(const char* locale) | 
| 212 | { | 
| 213 |     const int DEFAULT_VALUE = 0; | 
| 214 |     static const char* Patterns[] = {"(Cn)" , | 
| 215 |                                      "-Cn" , | 
| 216 |                                      "C-n" , | 
| 217 |                                      "Cn-" , | 
| 218 |                                      "(nC)" , | 
| 219 |                                      "-nC" , | 
| 220 |                                      "n-C" , | 
| 221 |                                      "nC-" , | 
| 222 |                                      "-n C" , | 
| 223 |                                      "-C n" , | 
| 224 |                                      "n C-" , | 
| 225 |                                      "C n-" , | 
| 226 |                                      "C -n" , | 
| 227 |                                      "n- C" , | 
| 228 |                                      "(C n)" , | 
| 229 |                                      "(n C)" }; | 
| 230 |     UErrorCode status = U_ZERO_ERROR; | 
| 231 |  | 
| 232 |     UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); | 
| 233 |     UNumberFormatHolder formatHolder(pFormat, status); | 
| 234 |  | 
| 235 |     assert(U_SUCCESS(status)); | 
| 236 |  | 
| 237 |     if (U_SUCCESS(status)) | 
| 238 |     { | 
| 239 |         int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); | 
| 240 |         if (value >= 0) | 
| 241 |         { | 
| 242 |             return value; | 
| 243 |         } | 
| 244 |     } | 
| 245 |  | 
| 246 |     return DEFAULT_VALUE; | 
| 247 | } | 
| 248 |  | 
| 249 | /* | 
| 250 | Function: | 
| 251 | GetCurrencyPositivePattern | 
| 252 |  | 
| 253 | Implementation of NumberFormatInfo.CurrencyPositivePattern. | 
| 254 | Returns the pattern index. | 
| 255 | */ | 
| 256 | int GetCurrencyPositivePattern(const char* locale) | 
| 257 | { | 
| 258 |     const int DEFAULT_VALUE = 0; | 
| 259 |     static const char* Patterns[] = {"Cn" , "nC" , "C n" , "n C" }; | 
| 260 |     UErrorCode status = U_ZERO_ERROR; | 
| 261 |  | 
| 262 |     UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); | 
| 263 |     UNumberFormatHolder formatHolder(pFormat, status); | 
| 264 |  | 
| 265 |     assert(U_SUCCESS(status)); | 
| 266 |  | 
| 267 |     if (U_SUCCESS(status)) | 
| 268 |     { | 
| 269 |         int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); | 
| 270 |         if (value >= 0) | 
| 271 |         { | 
| 272 |             return value; | 
| 273 |         } | 
| 274 |     } | 
| 275 |  | 
| 276 |     return DEFAULT_VALUE; | 
| 277 | } | 
| 278 |  | 
| 279 | /* | 
| 280 | Function: | 
| 281 | GetNumberNegativePattern | 
| 282 |  | 
| 283 | Implementation of NumberFormatInfo.NumberNegativePattern. | 
| 284 | Returns the pattern index. | 
| 285 | */ | 
| 286 | int GetNumberNegativePattern(const char* locale) | 
| 287 | { | 
| 288 |     const int DEFAULT_VALUE = 1; | 
| 289 |     static const char* Patterns[] = {"(n)" , "-n" , "- n" , "n-" , "n -" }; | 
| 290 |     UErrorCode status = U_ZERO_ERROR; | 
| 291 |  | 
| 292 |     UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); | 
| 293 |     UNumberFormatHolder formatHolder(pFormat, status); | 
| 294 |  | 
| 295 |     assert(U_SUCCESS(status)); | 
| 296 |  | 
| 297 |     if (U_SUCCESS(status)) | 
| 298 |     { | 
| 299 |         int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); | 
| 300 |         if (value >= 0) | 
| 301 |         { | 
| 302 |             return value; | 
| 303 |         } | 
| 304 |     } | 
| 305 |  | 
| 306 |     return DEFAULT_VALUE; | 
| 307 | } | 
| 308 |  | 
| 309 | /* | 
| 310 | Function: | 
| 311 | GetPercentNegativePattern | 
| 312 |  | 
| 313 | Implementation of NumberFormatInfo.PercentNegativePattern. | 
| 314 | Returns the pattern index. | 
| 315 | */ | 
| 316 | int GetPercentNegativePattern(const char* locale) | 
| 317 | { | 
| 318 |     const int DEFAULT_VALUE = 0; | 
| 319 |     static const char* Patterns[] = { | 
| 320 |         "-n %" , "-n%" , "-%n" , "%-n" , "%n-" , "n-%" , "n%-" , "-% n" , "n %-" , "% n-" , "% -n" , "n- %" }; | 
| 321 |     UErrorCode status = U_ZERO_ERROR; | 
| 322 |  | 
| 323 |     UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); | 
| 324 |     UNumberFormatHolder formatHolder(pFormat, status); | 
| 325 |  | 
| 326 |     assert(U_SUCCESS(status)); | 
| 327 |  | 
| 328 |     if (U_SUCCESS(status)) | 
| 329 |     { | 
| 330 |         int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); | 
| 331 |         if (value >= 0) | 
| 332 |         { | 
| 333 |             return value; | 
| 334 |         } | 
| 335 |     } | 
| 336 |  | 
| 337 |     return DEFAULT_VALUE; | 
| 338 | } | 
| 339 |  | 
| 340 | /* | 
| 341 | Function: | 
| 342 | GetPercentPositivePattern | 
| 343 |  | 
| 344 | Implementation of NumberFormatInfo.PercentPositivePattern. | 
| 345 | Returns the pattern index. | 
| 346 | */ | 
| 347 | int GetPercentPositivePattern(const char* locale) | 
| 348 | { | 
| 349 |     const int DEFAULT_VALUE = 0; | 
| 350 |     static const char* Patterns[] = {"n %" , "n%" , "%n" , "% n" }; | 
| 351 |     UErrorCode status = U_ZERO_ERROR; | 
| 352 |  | 
| 353 |     UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); | 
| 354 |     UNumberFormatHolder formatHolder(pFormat, status); | 
| 355 |  | 
| 356 |     assert(U_SUCCESS(status)); | 
| 357 |  | 
| 358 |     if (U_SUCCESS(status)) | 
| 359 |     { | 
| 360 |         int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); | 
| 361 |         if (value >= 0) | 
| 362 |         { | 
| 363 |             return value; | 
| 364 |         } | 
| 365 |     } | 
| 366 |  | 
| 367 |     return DEFAULT_VALUE; | 
| 368 | } | 
| 369 |  | 
| 370 | /* | 
| 371 | Function: | 
| 372 | GetMeasurementSystem | 
| 373 |  | 
| 374 | Obtains the measurement system for the local, determining if US or metric. | 
| 375 | Returns 1 for US, 0 otherwise. | 
| 376 | */ | 
| 377 | UErrorCode GetMeasurementSystem(const char* locale, int32_t* value) | 
| 378 | { | 
| 379 |     UErrorCode status = U_ZERO_ERROR; | 
| 380 |  | 
| 381 |     UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(locale, &status); | 
| 382 |     if (U_SUCCESS(status)) | 
| 383 |     { | 
| 384 |         *value = (measurementSystem == UMeasurementSystem::UMS_US) ? 1 : 0; | 
| 385 |     } | 
| 386 |  | 
| 387 |     return status; | 
| 388 | } | 
| 389 |  | 
| 390 | /* | 
| 391 | PAL Function: | 
| 392 | GetLocaleInfoInt | 
| 393 |  | 
| 394 | Obtains integer locale information | 
| 395 | Returns 1 for success, 0 otherwise | 
| 396 | */ | 
| 397 | extern "C"  int32_t GlobalizationNative_GetLocaleInfoInt( | 
| 398 |     const UChar* localeName, LocaleNumberData localeNumberData, int32_t* value) | 
| 399 | { | 
| 400 |     UErrorCode status = U_ZERO_ERROR; | 
| 401 |     char locale[ULOC_FULLNAME_CAPACITY]; | 
| 402 |     GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); | 
| 403 |  | 
| 404 |     if (U_FAILURE(status)) | 
| 405 |     { | 
| 406 |         return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); | 
| 407 |     } | 
| 408 |  | 
| 409 |     switch (localeNumberData) | 
| 410 |     { | 
| 411 |         case LanguageId: | 
| 412 |             *value = uloc_getLCID(locale); | 
| 413 |             break; | 
| 414 |         case MeasurementSystem: | 
| 415 |             status = GetMeasurementSystem(locale, value); | 
| 416 |             break; | 
| 417 |         case FractionalDigitsCount: | 
| 418 |         { | 
| 419 |             UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); | 
| 420 |             if (U_SUCCESS(status)) | 
| 421 |             { | 
| 422 |                 *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); | 
| 423 |                 unum_close(numformat); | 
| 424 |             } | 
| 425 |             break; | 
| 426 |         } | 
| 427 |         case NegativeNumberFormat: | 
| 428 |             *value = GetNumberNegativePattern(locale); | 
| 429 |             break; | 
| 430 |         case MonetaryFractionalDigitsCount: | 
| 431 |         { | 
| 432 |             UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); | 
| 433 |             if (U_SUCCESS(status)) | 
| 434 |             { | 
| 435 |                 *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); | 
| 436 |                 unum_close(numformat); | 
| 437 |             } | 
| 438 |             break; | 
| 439 |         } | 
| 440 |         case PositiveMonetaryNumberFormat: | 
| 441 |             *value = GetCurrencyPositivePattern(locale); | 
| 442 |             break; | 
| 443 |         case NegativeMonetaryNumberFormat: | 
| 444 |             *value = GetCurrencyNegativePattern(locale); | 
| 445 |             break; | 
| 446 |         case FirstWeekOfYear: | 
| 447 |         { | 
| 448 |             // corresponds to DateTimeFormat.CalendarWeekRule | 
| 449 |             UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); | 
| 450 |             UCalendarHolder calHolder(pCal, status); | 
| 451 |  | 
| 452 |             if (U_SUCCESS(status)) | 
| 453 |             { | 
| 454 |                 // values correspond to LOCALE_IFIRSTWEEKOFYEAR | 
| 455 |                 int minDaysInWeek = ucal_getAttribute(pCal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK); | 
| 456 |                 if (minDaysInWeek == 1) | 
| 457 |                 { | 
| 458 |                     *value = CalendarWeekRule::FirstDay; | 
| 459 |                 } | 
| 460 |                 else if (minDaysInWeek == 7) | 
| 461 |                 { | 
| 462 |                     *value = CalendarWeekRule::FirstFullWeek; | 
| 463 |                 } | 
| 464 |                 else if (minDaysInWeek >= 4) | 
| 465 |                 { | 
| 466 |                     *value = CalendarWeekRule::FirstFourDayWeek; | 
| 467 |                 } | 
| 468 |                 else | 
| 469 |                 { | 
| 470 |                     status = U_UNSUPPORTED_ERROR; | 
| 471 |                 } | 
| 472 |             } | 
| 473 |             break; | 
| 474 |         } | 
| 475 |         case ReadingLayout: | 
| 476 |         { | 
| 477 |             // coresponds to values 0 and 1 in LOCALE_IREADINGLAYOUT (values 2 and 3 not | 
| 478 |             // used in coreclr) | 
| 479 |             //  0 - Left to right (such as en-US) | 
| 480 |             //  1 - Right to left (such as arabic locales) | 
| 481 |             ULayoutType orientation = uloc_getCharacterOrientation(locale, &status); | 
| 482 |             // alternative implementation in ICU 54+ is uloc_isRightToLeft() which | 
| 483 |             // also supports script tags in locale | 
| 484 |             if (U_SUCCESS(status)) | 
| 485 |             { | 
| 486 |                 *value = (orientation == ULOC_LAYOUT_RTL) ? 1 : 0; | 
| 487 |             } | 
| 488 |             break; | 
| 489 |         } | 
| 490 |         case FirstDayofWeek: | 
| 491 |         { | 
| 492 |             UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); | 
| 493 |             UCalendarHolder calHolder(pCal, status); | 
| 494 |  | 
| 495 |             if (U_SUCCESS(status)) | 
| 496 |             { | 
| 497 |                 *value = ucal_getAttribute(pCal, UCAL_FIRST_DAY_OF_WEEK) - 1; // .NET is 0-based and ICU is 1-based | 
| 498 |             } | 
| 499 |             break; | 
| 500 |         } | 
| 501 |         case NegativePercentFormat: | 
| 502 |             *value = GetPercentNegativePattern(locale); | 
| 503 |             break; | 
| 504 |         case PositivePercentFormat: | 
| 505 |             *value = GetPercentPositivePattern(locale); | 
| 506 |             break; | 
| 507 |         default: | 
| 508 |             status = U_UNSUPPORTED_ERROR; | 
| 509 |             assert(false); | 
| 510 |             break; | 
| 511 |     } | 
| 512 |  | 
| 513 |     return UErrorCodeToBool(status); | 
| 514 | } | 
| 515 |  | 
| 516 | /* | 
| 517 | PAL Function: | 
| 518 | GetLocaleInfoGroupingSizes | 
| 519 |  | 
| 520 | Obtains grouping sizes for decimal and currency | 
| 521 | Returns 1 for success, 0 otherwise | 
| 522 | */ | 
| 523 | extern "C"  int32_t GlobalizationNative_GetLocaleInfoGroupingSizes( | 
| 524 |     const UChar* localeName, LocaleNumberData localeGroupingData, int32_t* primaryGroupSize, int32_t* secondaryGroupSize) | 
| 525 | { | 
| 526 |     UErrorCode status = U_ZERO_ERROR; | 
| 527 |     char locale[ULOC_FULLNAME_CAPACITY]; | 
| 528 |     GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); | 
| 529 |  | 
| 530 |     if (U_FAILURE(status)) | 
| 531 |     { | 
| 532 |         return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); | 
| 533 |     } | 
| 534 |  | 
| 535 |     UNumberFormatStyle style; | 
| 536 |     switch (localeGroupingData) | 
| 537 |     { | 
| 538 |         case Digit: | 
| 539 |             style = UNUM_DECIMAL; | 
| 540 |             break; | 
| 541 |         case Monetary: | 
| 542 |             style = UNUM_CURRENCY; | 
| 543 |             break; | 
| 544 |         default: | 
| 545 |             return UErrorCodeToBool(U_UNSUPPORTED_ERROR); | 
| 546 |     } | 
| 547 |  | 
| 548 |     UNumberFormat* numformat = unum_open(style, NULL, 0, locale, NULL, &status); | 
| 549 |     if (U_SUCCESS(status)) | 
| 550 |     { | 
| 551 |         *primaryGroupSize = unum_getAttribute(numformat, UNUM_GROUPING_SIZE); | 
| 552 |         *secondaryGroupSize = unum_getAttribute(numformat, UNUM_SECONDARY_GROUPING_SIZE); | 
| 553 |         unum_close(numformat); | 
| 554 |     } | 
| 555 |  | 
| 556 |     return UErrorCodeToBool(status); | 
| 557 | } | 
| 558 |  |