unum.cpp (30317B)
1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ******************************************************************************* 5 * Copyright (C) 1996-2015, International Business Machines 6 * Corporation and others. All Rights Reserved. 7 ******************************************************************************* 8 * Modification History: 9 * 10 * Date Name Description 11 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes 12 ******************************************************************************* 13 */ 14 15 #include "unicode/utypes.h" 16 17 #if !UCONFIG_NO_FORMATTING 18 19 #include "unicode/unum.h" 20 21 #include "unicode/uloc.h" 22 #include "unicode/numfmt.h" 23 #include "unicode/decimfmt.h" 24 #include "unicode/rbnf.h" 25 #include "unicode/compactdecimalformat.h" 26 #include "unicode/ustring.h" 27 #include "unicode/fmtable.h" 28 #include "unicode/dcfmtsym.h" 29 #include "unicode/curramt.h" 30 #include "unicode/localpointer.h" 31 #include "unicode/measfmt.h" 32 #include "unicode/udisplaycontext.h" 33 #include "uassert.h" 34 #include "cpputils.h" 35 #include "cstring.h" 36 #include "putilimp.h" 37 38 39 U_NAMESPACE_USE 40 41 42 U_CAPI UNumberFormat* U_EXPORT2 43 unum_open( UNumberFormatStyle style, 44 const char16_t* pattern, 45 int32_t patternLength, 46 const char* locale, 47 UParseError* parseErr, 48 UErrorCode* status) { 49 if(U_FAILURE(*status)) { 50 return nullptr; 51 } 52 53 NumberFormat *retVal = nullptr; 54 55 switch(style) { 56 case UNUM_DECIMAL: 57 case UNUM_CURRENCY: 58 case UNUM_PERCENT: 59 case UNUM_SCIENTIFIC: 60 case UNUM_CURRENCY_ISO: 61 case UNUM_CURRENCY_PLURAL: 62 case UNUM_CURRENCY_ACCOUNTING: 63 case UNUM_CASH_CURRENCY: 64 case UNUM_CURRENCY_STANDARD: 65 retVal = NumberFormat::createInstance(Locale(locale), style, *status); 66 break; 67 68 case UNUM_PATTERN_DECIMAL: { 69 UParseError tErr; 70 /* UnicodeString can handle the case when patternLength = -1. */ 71 const UnicodeString pat(pattern, patternLength); 72 73 if(parseErr==nullptr){ 74 parseErr = &tErr; 75 } 76 77 DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status); 78 if(syms == nullptr) { 79 *status = U_MEMORY_ALLOCATION_ERROR; 80 return nullptr; 81 } 82 if (U_FAILURE(*status)) { 83 delete syms; 84 return nullptr; 85 } 86 87 retVal = new DecimalFormat(pat, syms, *parseErr, *status); 88 if(retVal == nullptr) { 89 delete syms; 90 } 91 } break; 92 93 #if U_HAVE_RBNF 94 case UNUM_PATTERN_RULEBASED: { 95 UParseError tErr; 96 /* UnicodeString can handle the case when patternLength = -1. */ 97 const UnicodeString pat(pattern, patternLength); 98 99 if(parseErr==nullptr){ 100 parseErr = &tErr; 101 } 102 103 retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status); 104 } break; 105 106 case UNUM_SPELLOUT: 107 retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status); 108 break; 109 110 case UNUM_ORDINAL: 111 retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status); 112 break; 113 114 case UNUM_DURATION: 115 retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status); 116 break; 117 118 case UNUM_NUMBERING_SYSTEM: { 119 // if the locale ID specifies a numbering system, go through NumberFormat::createInstance() 120 // to handle it properly (we have to specify UNUM_DEFAULT to get it to handle the numbering 121 // system, but we'll always get a RuleBasedNumberFormat back); otherwise, just go ahead and 122 // create a RuleBasedNumberFormat ourselves 123 UErrorCode localErr = U_ZERO_ERROR; 124 Locale localeObj(locale); 125 int32_t keywordLength = localeObj.getKeywordValue("numbers", nullptr, 0, localErr); 126 if (keywordLength > 0) { 127 retVal = NumberFormat::createInstance(localeObj, UNUM_DEFAULT, *status); 128 } else { 129 retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, localeObj, *status); 130 } 131 } break; 132 #endif 133 134 case UNUM_DECIMAL_COMPACT_SHORT: 135 retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status); 136 break; 137 138 case UNUM_DECIMAL_COMPACT_LONG: 139 retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status); 140 break; 141 142 default: 143 *status = U_UNSUPPORTED_ERROR; 144 return nullptr; 145 } 146 147 if(retVal == nullptr && U_SUCCESS(*status)) { 148 *status = U_MEMORY_ALLOCATION_ERROR; 149 } 150 151 if (U_FAILURE(*status) && retVal != nullptr) { 152 delete retVal; 153 retVal = nullptr; 154 } 155 156 return reinterpret_cast<UNumberFormat *>(retVal); 157 } 158 159 U_CAPI void U_EXPORT2 160 unum_close(UNumberFormat* fmt) 161 { 162 delete (NumberFormat*) fmt; 163 } 164 165 U_CAPI UNumberFormat* U_EXPORT2 166 unum_clone(const UNumberFormat *fmt, 167 UErrorCode *status) 168 { 169 if(U_FAILURE(*status)) 170 return nullptr; 171 172 Format* res = nullptr; 173 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt); 174 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf); 175 if (df != nullptr) { 176 res = df->clone(); 177 } else { 178 const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf); 179 U_ASSERT(rbnf != nullptr); 180 res = rbnf->clone(); 181 } 182 183 if (res == nullptr) { 184 *status = U_MEMORY_ALLOCATION_ERROR; 185 return nullptr; 186 } 187 188 return (UNumberFormat*) res; 189 } 190 191 U_CAPI int32_t U_EXPORT2 192 unum_format( const UNumberFormat* fmt, 193 int32_t number, 194 char16_t* result, 195 int32_t resultLength, 196 UFieldPosition *pos, 197 UErrorCode* status) 198 { 199 return unum_formatInt64(fmt, number, result, resultLength, pos, status); 200 } 201 202 U_CAPI int32_t U_EXPORT2 203 unum_formatInt64(const UNumberFormat* fmt, 204 int64_t number, 205 char16_t* result, 206 int32_t resultLength, 207 UFieldPosition *pos, 208 UErrorCode* status) 209 { 210 if(U_FAILURE(*status)) 211 return -1; 212 213 UnicodeString res; 214 if(!(result==nullptr && resultLength==0)) { 215 // nullptr destination for pure preflighting: empty dummy string 216 // otherwise, alias the destination buffer 217 res.setTo(result, 0, resultLength); 218 } 219 220 FieldPosition fp; 221 222 if (pos != nullptr) 223 fp.setField(pos->field); 224 225 ((const NumberFormat*)fmt)->format(number, res, fp, *status); 226 227 if (pos != nullptr) { 228 pos->beginIndex = fp.getBeginIndex(); 229 pos->endIndex = fp.getEndIndex(); 230 } 231 232 return res.extract(result, resultLength, *status); 233 } 234 235 U_CAPI int32_t U_EXPORT2 236 unum_formatDouble( const UNumberFormat* fmt, 237 double number, 238 char16_t* result, 239 int32_t resultLength, 240 UFieldPosition *pos, /* 0 if ignore */ 241 UErrorCode* status) 242 { 243 244 if(U_FAILURE(*status)) return -1; 245 246 UnicodeString res; 247 if(!(result==nullptr && resultLength==0)) { 248 // nullptr destination for pure preflighting: empty dummy string 249 // otherwise, alias the destination buffer 250 res.setTo(result, 0, resultLength); 251 } 252 253 FieldPosition fp; 254 255 if (pos != nullptr) 256 fp.setField(pos->field); 257 258 ((const NumberFormat*)fmt)->format(number, res, fp, *status); 259 260 if (pos != nullptr) { 261 pos->beginIndex = fp.getBeginIndex(); 262 pos->endIndex = fp.getEndIndex(); 263 } 264 265 return res.extract(result, resultLength, *status); 266 } 267 268 U_CAPI int32_t U_EXPORT2 269 unum_formatDoubleForFields(const UNumberFormat* format, 270 double number, 271 char16_t* result, 272 int32_t resultLength, 273 UFieldPositionIterator* fpositer, 274 UErrorCode* status) 275 { 276 if (U_FAILURE(*status)) 277 return -1; 278 279 if (result == nullptr ? resultLength != 0 : resultLength < 0) { 280 *status = U_ILLEGAL_ARGUMENT_ERROR; 281 return -1; 282 } 283 284 UnicodeString res; 285 if (result != nullptr) { 286 // nullptr destination for pure preflighting: empty dummy string 287 // otherwise, alias the destination buffer 288 res.setTo(result, 0, resultLength); 289 } 290 291 ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status); 292 293 return res.extract(result, resultLength, *status); 294 } 295 296 U_CAPI int32_t U_EXPORT2 297 unum_formatDecimal(const UNumberFormat* fmt, 298 const char * number, 299 int32_t length, 300 char16_t* result, 301 int32_t resultLength, 302 UFieldPosition *pos, /* 0 if ignore */ 303 UErrorCode* status) { 304 305 if(U_FAILURE(*status)) { 306 return -1; 307 } 308 if ((result == nullptr && resultLength != 0) || resultLength < 0) { 309 *status = U_ILLEGAL_ARGUMENT_ERROR; 310 return -1; 311 } 312 313 FieldPosition fp; 314 if (pos != nullptr) { 315 fp.setField(pos->field); 316 } 317 318 if (length < 0) { 319 length = static_cast<int32_t>(uprv_strlen(number)); 320 } 321 StringPiece numSP(number, length); 322 Formattable numFmtbl(numSP, *status); 323 324 UnicodeString resultStr; 325 if (resultLength > 0) { 326 // Alias the destination buffer. 327 resultStr.setTo(result, 0, resultLength); 328 } 329 ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status); 330 if (pos != nullptr) { 331 pos->beginIndex = fp.getBeginIndex(); 332 pos->endIndex = fp.getEndIndex(); 333 } 334 return resultStr.extract(result, resultLength, *status); 335 } 336 337 338 339 340 U_CAPI int32_t U_EXPORT2 341 unum_formatDoubleCurrency(const UNumberFormat* fmt, 342 double number, 343 char16_t* currency, 344 char16_t* result, 345 int32_t resultLength, 346 UFieldPosition* pos, /* ignored if 0 */ 347 UErrorCode* status) { 348 if (U_FAILURE(*status)) return -1; 349 350 UnicodeString res; 351 if (!(result==nullptr && resultLength==0)) { 352 // nullptr destination for pure preflighting: empty dummy string 353 // otherwise, alias the destination buffer 354 res.setTo(result, 0, resultLength); 355 } 356 357 FieldPosition fp; 358 if (pos != nullptr) { 359 fp.setField(pos->field); 360 } 361 CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status); 362 // Check for null pointer. 363 if (tempCurrAmnt == nullptr) { 364 *status = U_MEMORY_ALLOCATION_ERROR; 365 return -1; 366 } 367 Formattable n(tempCurrAmnt); 368 ((const NumberFormat*)fmt)->format(n, res, fp, *status); 369 370 if (pos != nullptr) { 371 pos->beginIndex = fp.getBeginIndex(); 372 pos->endIndex = fp.getEndIndex(); 373 } 374 375 return res.extract(result, resultLength, *status); 376 } 377 378 static void 379 parseRes(Formattable& res, 380 const UNumberFormat* fmt, 381 const char16_t* text, 382 int32_t textLength, 383 int32_t *parsePos /* 0 = start */, 384 UErrorCode *status) 385 { 386 if(U_FAILURE(*status)) 387 return; 388 389 const UnicodeString src(static_cast<UBool>(textLength == -1), text, textLength); 390 ParsePosition pp; 391 392 if (parsePos != nullptr) 393 pp.setIndex(*parsePos); 394 395 reinterpret_cast<const NumberFormat*>(fmt)->parse(src, res, pp); 396 397 if(pp.getErrorIndex() != -1) { 398 *status = U_PARSE_ERROR; 399 if (parsePos != nullptr) { 400 *parsePos = pp.getErrorIndex(); 401 } 402 } else if (parsePos != nullptr) { 403 *parsePos = pp.getIndex(); 404 } 405 } 406 407 U_CAPI int32_t U_EXPORT2 408 unum_parse( const UNumberFormat* fmt, 409 const char16_t* text, 410 int32_t textLength, 411 int32_t *parsePos /* 0 = start */, 412 UErrorCode *status) 413 { 414 Formattable res; 415 parseRes(res, fmt, text, textLength, parsePos, status); 416 return res.getLong(*status); 417 } 418 419 U_CAPI int64_t U_EXPORT2 420 unum_parseInt64( const UNumberFormat* fmt, 421 const char16_t* text, 422 int32_t textLength, 423 int32_t *parsePos /* 0 = start */, 424 UErrorCode *status) 425 { 426 Formattable res; 427 parseRes(res, fmt, text, textLength, parsePos, status); 428 return res.getInt64(*status); 429 } 430 431 U_CAPI double U_EXPORT2 432 unum_parseDouble( const UNumberFormat* fmt, 433 const char16_t* text, 434 int32_t textLength, 435 int32_t *parsePos /* 0 = start */, 436 UErrorCode *status) 437 { 438 Formattable res; 439 parseRes(res, fmt, text, textLength, parsePos, status); 440 return res.getDouble(*status); 441 } 442 443 U_CAPI int32_t U_EXPORT2 444 unum_parseDecimal(const UNumberFormat* fmt, 445 const char16_t* text, 446 int32_t textLength, 447 int32_t *parsePos /* 0 = start */, 448 char *outBuf, 449 int32_t outBufLength, 450 UErrorCode *status) 451 { 452 if (U_FAILURE(*status)) { 453 return -1; 454 } 455 if ((outBuf == nullptr && outBufLength != 0) || outBufLength < 0) { 456 *status = U_ILLEGAL_ARGUMENT_ERROR; 457 return -1; 458 } 459 Formattable res; 460 parseRes(res, fmt, text, textLength, parsePos, status); 461 StringPiece sp = res.getDecimalNumber(*status); 462 if (U_FAILURE(*status)) { 463 return -1; 464 } else if (sp.size() > outBufLength) { 465 *status = U_BUFFER_OVERFLOW_ERROR; 466 } else if (sp.size() == outBufLength) { 467 uprv_strncpy(outBuf, sp.data(), sp.size()); 468 *status = U_STRING_NOT_TERMINATED_WARNING; 469 } else { 470 U_ASSERT(outBufLength > 0); 471 uprv_strcpy(outBuf, sp.data()); 472 } 473 return sp.size(); 474 } 475 476 U_CAPI double U_EXPORT2 477 unum_parseDoubleCurrency(const UNumberFormat* fmt, 478 const char16_t* text, 479 int32_t textLength, 480 int32_t* parsePos, /* 0 = start */ 481 char16_t* currency, 482 UErrorCode* status) { 483 double doubleVal = 0.0; 484 currency[0] = 0; 485 if (U_FAILURE(*status)) { 486 return doubleVal; 487 } 488 const UnicodeString src(textLength == -1, text, textLength); 489 ParsePosition pp; 490 if (parsePos != nullptr) { 491 pp.setIndex(*parsePos); 492 } 493 *status = U_PARSE_ERROR; // assume failure, reset if succeed 494 LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp)); 495 if (pp.getErrorIndex() != -1) { 496 if (parsePos != nullptr) { 497 *parsePos = pp.getErrorIndex(); 498 } 499 } else { 500 if (parsePos != nullptr) { 501 *parsePos = pp.getIndex(); 502 } 503 if (pp.getIndex() > 0) { 504 *status = U_ZERO_ERROR; 505 u_strcpy(currency, currAmt->getISOCurrency()); 506 doubleVal = currAmt->getNumber().getDouble(*status); 507 } 508 } 509 return doubleVal; 510 } 511 512 U_CAPI const char* U_EXPORT2 513 unum_getAvailable(int32_t index) 514 { 515 return uloc_getAvailable(index); 516 } 517 518 U_CAPI int32_t U_EXPORT2 519 unum_countAvailable() 520 { 521 return uloc_countAvailable(); 522 } 523 524 U_CAPI bool U_EXPORT2 525 unum_hasAttribute(const UNumberFormat* fmt, 526 UNumberFormatAttribute attr) 527 { 528 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt); 529 bool isDecimalFormat = dynamic_cast<const DecimalFormat*>(nf) != nullptr; 530 531 switch (attr) { 532 case UNUM_LENIENT_PARSE: 533 case UNUM_MAX_INTEGER_DIGITS: 534 case UNUM_MIN_INTEGER_DIGITS: 535 case UNUM_INTEGER_DIGITS: 536 case UNUM_MAX_FRACTION_DIGITS: 537 case UNUM_MIN_FRACTION_DIGITS: 538 case UNUM_FRACTION_DIGITS: 539 case UNUM_ROUNDING_MODE: 540 return true; 541 default: 542 return isDecimalFormat; 543 } 544 } 545 546 U_CAPI int32_t U_EXPORT2 547 unum_getAttribute(const UNumberFormat* fmt, 548 UNumberFormatAttribute attr) 549 { 550 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt); 551 if (attr == UNUM_LENIENT_PARSE) { 552 // Supported for all subclasses 553 return nf->isLenient(); 554 } 555 else if (attr == UNUM_MAX_INTEGER_DIGITS) { 556 return nf->getMaximumIntegerDigits(); 557 } 558 else if (attr == UNUM_MIN_INTEGER_DIGITS) { 559 return nf->getMinimumIntegerDigits(); 560 } 561 else if (attr == UNUM_INTEGER_DIGITS) { 562 // TODO: what should this return? 563 return nf->getMinimumIntegerDigits(); 564 } 565 else if (attr == UNUM_MAX_FRACTION_DIGITS) { 566 return nf->getMaximumFractionDigits(); 567 } 568 else if (attr == UNUM_MIN_FRACTION_DIGITS) { 569 return nf->getMinimumFractionDigits(); 570 } 571 else if (attr == UNUM_FRACTION_DIGITS) { 572 // TODO: what should this return? 573 return nf->getMinimumFractionDigits(); 574 } 575 else if (attr == UNUM_ROUNDING_MODE) { 576 return nf->getRoundingMode(); 577 } 578 579 // The remaining attributes are only supported for DecimalFormat 580 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf); 581 if (df != nullptr) { 582 UErrorCode ignoredStatus = U_ZERO_ERROR; 583 return df->getAttribute(attr, ignoredStatus); 584 } 585 586 return -1; 587 } 588 589 U_CAPI void U_EXPORT2 590 unum_setAttribute( UNumberFormat* fmt, 591 UNumberFormatAttribute attr, 592 int32_t newValue) 593 { 594 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt); 595 if (attr == UNUM_LENIENT_PARSE) { 596 // Supported for all subclasses 597 // keep this here as the class may not be a DecimalFormat 598 return nf->setLenient(newValue != 0); 599 } 600 else if (attr == UNUM_MAX_INTEGER_DIGITS) { 601 return nf->setMaximumIntegerDigits(newValue); 602 } 603 else if (attr == UNUM_MIN_INTEGER_DIGITS) { 604 return nf->setMinimumIntegerDigits(newValue); 605 } 606 else if (attr == UNUM_INTEGER_DIGITS) { 607 nf->setMinimumIntegerDigits(newValue); 608 return nf->setMaximumIntegerDigits(newValue); 609 } 610 else if (attr == UNUM_MAX_FRACTION_DIGITS) { 611 return nf->setMaximumFractionDigits(newValue); 612 } 613 else if (attr == UNUM_MIN_FRACTION_DIGITS) { 614 return nf->setMinimumFractionDigits(newValue); 615 } 616 else if (attr == UNUM_FRACTION_DIGITS) { 617 nf->setMinimumFractionDigits(newValue); 618 return nf->setMaximumFractionDigits(newValue); 619 } 620 else if (attr == UNUM_ROUNDING_MODE) { 621 return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue); 622 } 623 624 // The remaining attributes are only supported for DecimalFormat 625 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf); 626 if (df != nullptr) { 627 UErrorCode ignoredStatus = U_ZERO_ERROR; 628 df->setAttribute(attr, newValue, ignoredStatus); 629 } 630 } 631 632 U_CAPI double U_EXPORT2 633 unum_getDoubleAttribute(const UNumberFormat* fmt, 634 UNumberFormatAttribute attr) 635 { 636 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt); 637 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf); 638 if (df != nullptr && attr == UNUM_ROUNDING_INCREMENT) { 639 return df->getRoundingIncrement(); 640 } else { 641 return -1.0; 642 } 643 } 644 645 U_CAPI void U_EXPORT2 646 unum_setDoubleAttribute( UNumberFormat* fmt, 647 UNumberFormatAttribute attr, 648 double newValue) 649 { 650 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt); 651 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf); 652 if (df != nullptr && attr == UNUM_ROUNDING_INCREMENT) { 653 df->setRoundingIncrement(newValue); 654 } 655 } 656 657 U_CAPI int32_t U_EXPORT2 658 unum_getTextAttribute(const UNumberFormat* fmt, 659 UNumberFormatTextAttribute tag, 660 char16_t* result, 661 int32_t resultLength, 662 UErrorCode* status) 663 { 664 if(U_FAILURE(*status)) 665 return -1; 666 667 UnicodeString res; 668 if(!(result==nullptr && resultLength==0)) { 669 // nullptr destination for pure preflighting: empty dummy string 670 // otherwise, alias the destination buffer 671 res.setTo(result, 0, resultLength); 672 } 673 674 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt); 675 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf); 676 const RuleBasedNumberFormat* rbnf = nullptr; // cast is below for performance 677 if (df != nullptr) { 678 switch(tag) { 679 case UNUM_POSITIVE_PREFIX: 680 df->getPositivePrefix(res); 681 break; 682 683 case UNUM_POSITIVE_SUFFIX: 684 df->getPositiveSuffix(res); 685 break; 686 687 case UNUM_NEGATIVE_PREFIX: 688 df->getNegativePrefix(res); 689 break; 690 691 case UNUM_NEGATIVE_SUFFIX: 692 df->getNegativeSuffix(res); 693 break; 694 695 case UNUM_PADDING_CHARACTER: 696 res = df->getPadCharacterString(); 697 break; 698 699 case UNUM_CURRENCY_CODE: 700 res = UnicodeString(df->getCurrency()); 701 break; 702 703 default: 704 *status = U_UNSUPPORTED_ERROR; 705 return -1; 706 } 707 } else if ((rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf)) != nullptr) { 708 U_ASSERT(rbnf != nullptr); 709 if (tag == UNUM_DEFAULT_RULESET) { 710 res = rbnf->getDefaultRuleSetName(); 711 } else if (tag == UNUM_PUBLIC_RULESETS) { 712 int32_t count = rbnf->getNumberOfRuleSetNames(); 713 for (int i = 0; i < count; ++i) { 714 res += rbnf->getRuleSetName(i); 715 res += (char16_t)0x003b; // semicolon 716 } 717 } else { 718 *status = U_UNSUPPORTED_ERROR; 719 return -1; 720 } 721 } else { 722 *status = U_UNSUPPORTED_ERROR; 723 return -1; 724 } 725 726 return res.extract(result, resultLength, *status); 727 } 728 729 U_CAPI void U_EXPORT2 730 unum_setTextAttribute( UNumberFormat* fmt, 731 UNumberFormatTextAttribute tag, 732 const char16_t* newValue, 733 int32_t newValueLength, 734 UErrorCode *status) 735 { 736 if(U_FAILURE(*status)) 737 return; 738 739 UnicodeString val(newValue, newValueLength); 740 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt); 741 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf); 742 if (df != nullptr) { 743 switch(tag) { 744 case UNUM_POSITIVE_PREFIX: 745 df->setPositivePrefix(val); 746 break; 747 748 case UNUM_POSITIVE_SUFFIX: 749 df->setPositiveSuffix(val); 750 break; 751 752 case UNUM_NEGATIVE_PREFIX: 753 df->setNegativePrefix(val); 754 break; 755 756 case UNUM_NEGATIVE_SUFFIX: 757 df->setNegativeSuffix(val); 758 break; 759 760 case UNUM_PADDING_CHARACTER: 761 df->setPadCharacter(val); 762 break; 763 764 case UNUM_CURRENCY_CODE: 765 df->setCurrency(val.getTerminatedBuffer(), *status); 766 break; 767 768 default: 769 *status = U_UNSUPPORTED_ERROR; 770 break; 771 } 772 } else { 773 RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf); 774 U_ASSERT(rbnf != nullptr); 775 if (tag == UNUM_DEFAULT_RULESET) { 776 rbnf->setDefaultRuleSet(val, *status); 777 } else { 778 *status = U_UNSUPPORTED_ERROR; 779 } 780 } 781 } 782 783 U_CAPI int32_t U_EXPORT2 784 unum_toPattern( const UNumberFormat* fmt, 785 UBool isPatternLocalized, 786 char16_t* result, 787 int32_t resultLength, 788 UErrorCode* status) 789 { 790 if(U_FAILURE(*status)) 791 return -1; 792 793 UnicodeString pat; 794 if(!(result==nullptr && resultLength==0)) { 795 // nullptr destination for pure preflighting: empty dummy string 796 // otherwise, alias the destination buffer 797 pat.setTo(result, 0, resultLength); 798 } 799 800 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt); 801 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf); 802 const RuleBasedNumberFormat* rbnf = nullptr; // cast is below for performance 803 if (df != nullptr) { 804 if(isPatternLocalized) 805 df->toLocalizedPattern(pat); 806 else 807 df->toPattern(pat); 808 } else if ((rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf)) != nullptr) { 809 pat = rbnf->getRules(); 810 } else { 811 // leave `pat` empty 812 } 813 return pat.extract(result, resultLength, *status); 814 } 815 816 U_CAPI int32_t U_EXPORT2 817 unum_getSymbol(const UNumberFormat *fmt, 818 UNumberFormatSymbol symbol, 819 char16_t *buffer, 820 int32_t size, 821 UErrorCode *status) UPRV_NO_SANITIZE_UNDEFINED { 822 if(status==nullptr || U_FAILURE(*status)) { 823 return 0; 824 } 825 if(fmt==nullptr || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) { 826 *status=U_ILLEGAL_ARGUMENT_ERROR; 827 return 0; 828 } 829 const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt); 830 const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf); 831 if (dcf == nullptr) { 832 *status = U_UNSUPPORTED_ERROR; 833 return 0; 834 } 835 836 return dcf-> 837 getDecimalFormatSymbols()-> 838 getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol). 839 extract(buffer, size, *status); 840 } 841 842 U_CAPI void U_EXPORT2 843 unum_setSymbol(UNumberFormat *fmt, 844 UNumberFormatSymbol symbol, 845 const char16_t *value, 846 int32_t length, 847 UErrorCode *status) UPRV_NO_SANITIZE_UNDEFINED { 848 if(status==nullptr || U_FAILURE(*status)) { 849 return; 850 } 851 if(fmt==nullptr || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==nullptr || length<-1) { 852 *status=U_ILLEGAL_ARGUMENT_ERROR; 853 return; 854 } 855 NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt); 856 DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf); 857 if (dcf == nullptr) { 858 *status = U_UNSUPPORTED_ERROR; 859 return; 860 } 861 862 DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols()); 863 symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol, 864 UnicodeString(value, length)); /* UnicodeString can handle the case when length = -1. */ 865 dcf->setDecimalFormatSymbols(symbols); 866 } 867 868 U_CAPI void U_EXPORT2 869 unum_applyPattern( UNumberFormat *fmt, 870 UBool localized, 871 const char16_t *pattern, 872 int32_t patternLength, 873 UParseError *parseError, 874 UErrorCode* status) 875 { 876 UErrorCode tStatus = U_ZERO_ERROR; 877 UParseError tParseError; 878 879 if(parseError == nullptr){ 880 parseError = &tParseError; 881 } 882 883 if(status==nullptr){ 884 status = &tStatus; 885 } 886 887 int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength); 888 const UnicodeString pat((char16_t*)pattern, len, len); 889 890 // Verify if the object passed is a DecimalFormat object 891 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt); 892 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf); 893 if (df != nullptr) { 894 if(localized) { 895 df->applyLocalizedPattern(pat,*parseError, *status); 896 } else { 897 df->applyPattern(pat,*parseError, *status); 898 } 899 } else { 900 *status = U_UNSUPPORTED_ERROR; 901 return; 902 } 903 } 904 905 U_CAPI const char* U_EXPORT2 906 unum_getLocaleByType(const UNumberFormat *fmt, 907 ULocDataLocaleType type, 908 UErrorCode* status) 909 { 910 if (fmt == nullptr) { 911 if (U_SUCCESS(*status)) { 912 *status = U_ILLEGAL_ARGUMENT_ERROR; 913 } 914 return nullptr; 915 } 916 return ((const Format*)fmt)->getLocaleID(type, *status); 917 } 918 919 U_CAPI void U_EXPORT2 920 unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status) 921 { 922 if (U_FAILURE(*status)) { 923 return; 924 } 925 ((NumberFormat*)fmt)->setContext(value, *status); 926 } 927 928 U_CAPI UDisplayContext U_EXPORT2 929 unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status) 930 { 931 if (U_FAILURE(*status)) { 932 return (UDisplayContext)0; 933 } 934 return ((const NumberFormat*)fmt)->getContext(type, *status); 935 } 936 937 U_CAPI UFormattable * U_EXPORT2 938 unum_parseToUFormattable(const UNumberFormat* fmt, 939 UFormattable *result, 940 const char16_t* text, 941 int32_t textLength, 942 int32_t* parsePos, /* 0 = start */ 943 UErrorCode* status) { 944 UFormattable *newFormattable = nullptr; 945 if (U_FAILURE(*status)) return result; 946 if (fmt == nullptr || (text==nullptr && textLength!=0)) { 947 *status = U_ILLEGAL_ARGUMENT_ERROR; 948 return result; 949 } 950 if (result == nullptr) { // allocate if not allocated. 951 newFormattable = result = ufmt_open(status); 952 } 953 parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status); 954 if (U_FAILURE(*status) && newFormattable != nullptr) { 955 ufmt_close(newFormattable); 956 result = nullptr; // deallocate if there was a parse error 957 } 958 return result; 959 } 960 961 U_CAPI int32_t U_EXPORT2 962 unum_formatUFormattable(const UNumberFormat* fmt, 963 const UFormattable *number, 964 char16_t *result, 965 int32_t resultLength, 966 UFieldPosition *pos, /* ignored if 0 */ 967 UErrorCode *status) { 968 if (U_FAILURE(*status)) { 969 return 0; 970 } 971 if (fmt == nullptr || number==nullptr || 972 (result==nullptr ? resultLength!=0 : resultLength<0)) { 973 *status = U_ILLEGAL_ARGUMENT_ERROR; 974 return 0; 975 } 976 UnicodeString res(result, 0, resultLength); 977 978 FieldPosition fp; 979 980 if (pos != nullptr) 981 fp.setField(pos->field); 982 983 ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status); 984 985 if (pos != nullptr) { 986 pos->beginIndex = fp.getBeginIndex(); 987 pos->endIndex = fp.getEndIndex(); 988 } 989 990 return res.extract(result, resultLength, *status); 991 } 992 993 #endif /* #if !UCONFIG_NO_FORMATTING */